feat(desktop): bundle rc.2 official runtime for release builds

This commit is contained in:
techflag
2026-09-25 01:11:09 +08:00
parent 86fd4646fb
commit 8bf05b9727
19 changed files with 291 additions and 55 deletions
+2
View File
@@ -119,6 +119,7 @@ jobs:
path: ${{ steps.yarn-cache.outputs.dir }}
key: yarn-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
- run: yarn install --immutable
- run: yarn upstream:install
- run: yarn workspace dsh-plugin-desktop check:win-package
- name: Build Windows installer
env:
@@ -165,6 +166,7 @@ jobs:
path: ${{ steps.yarn-cache.outputs.dir }}
key: yarn-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
- run: yarn install --immutable
- run: yarn upstream:install
- run: yarn workspace dsh-plugin-desktop check:mac-package
- name: Build macOS smoke artifact
env:
+2
View File
@@ -4,3 +4,5 @@ node_modules/
build/workdsh-runtime
build/.workdsh-release-*
build/.workdsh-node
build/.workdsh-primary-runtime-cache
build/official-primary-runtime
+9 -6
View File
@@ -125,16 +125,17 @@
"verify:notices": "node scripts/verify-licenses.mjs --notices THIRD_PARTY_NOTICES.md",
"prepare:electron-native": "node scripts/prepare-fs-ext.ts",
"prepare:workdsh-runtime": "node scripts/prepare-workdsh-runtime.mjs",
"prepare:workdsh-primary-runtime": "node scripts/prepare-workdsh-primary-runtime.mjs",
"check": "yarn run build && yarn run typecheck && yarn run test && yarn run verify:closure && yarn run verify:cli && yarn run verify:loader && yarn run verify:profile && yarn run verify:licenses && yarn run verify:operations",
"check:win-package": "yarn workspace dsh-community-market build && yarn run build && yarn run typecheck && vitest run tests/package.spec.ts tests/package-win.spec.ts tests/desktop-installer-quit.spec.ts tests/installer-nsh.spec.ts tests/update-checker.spec.ts tests/update-download.spec.ts tests/verify-win-installer.spec.ts tests/verify-win-portable.spec.ts tests/verify-packaged-runtime.spec.ts tests/windows-pwsh-sandbox.spec.ts tests/windows-volume-diagnostics.spec.ts tests/window-options.spec.ts tests/safe-mode.spec.ts && yarn run verify:closure",
"check:mac-package": "yarn workspace dsh-community-market build && yarn run build && yarn run typecheck && vitest run tests/package.spec.ts tests/package-mac.spec.ts tests/verify-mac-smoke.spec.ts tests/verify-packaged-runtime.spec.ts tests/mac-universal.spec.ts && yarn run verify:closure",
"start": "node lib/bin.js",
"dev": "yarn run build && yarn run prepare:electron-native && node lib/bin.js",
"package:dir": "yarn run build && yarn run prepare:electron-native && yarn run prepare:workdsh-runtime && node scripts/package-dir.mjs",
"dist:mac": "yarn run prepare:workdsh-runtime && node scripts/release-mac.ts",
"dist:mac-smoke": "yarn run prepare:workdsh-runtime && node scripts/package-mac.ts",
"dist:win": "yarn run prepare:workdsh-runtime && node scripts/package-win.ts",
"dist:win-portable": "yarn run prepare:workdsh-runtime && node scripts/package-win-portable.ts",
"package:dir": "yarn run build && yarn run prepare:electron-native && yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-dir.mjs",
"dist:mac": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/release-mac.ts",
"dist:mac-smoke": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-mac.ts",
"dist:win": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win.ts",
"dist:win-portable": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win-portable.ts",
"prepack": "yarn run check"
},
"dependencies": {
@@ -355,7 +356,9 @@
"to": "workdsh-runtime",
"filter": [
"profiles/workdsh/**",
"node/**"
"node/**",
"primary-runtime/**",
"office-skills/**"
]
}
],
@@ -1,7 +1,7 @@
/** Build an unsigned macOS DMG smoke artifact on a native macOS host. */
import { spawnSync } from 'node:child_process'
import { rmSync } from 'node:fs'
import { existsSync, rmSync } from 'node:fs'
import { createRequire } from 'node:module'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
@@ -32,6 +32,8 @@ export interface MacSmokePackageOptions {
readonly prepareRuntime: () => void
/** Absolute electron-builder CLI module. */
readonly builderCli: string
/** Local Electron distribution when already installed, avoiding another download. */
readonly electronDist?: string
/** Absolute packaged-DMG verification script. */
readonly verifier: string
/** Node executable used to run package-local scripts. */
@@ -65,6 +67,7 @@ function defaultOptions(): MacSmokePackageOptions {
const workspaceRoot = resolve(desktopRoot, '..')
const require = createRequire(import.meta.url)
const outputDir = resolve(desktopRoot, 'dist', 'mac-smoke', process.env.WORKDSH_MAC_ARCH ?? process.arch)
const electronDist = resolve(dirname(require.resolve('electron/package.json')), 'dist')
return {
env: process.env,
platform: process.platform,
@@ -80,6 +83,7 @@ function defaultOptions(): MacSmokePackageOptions {
prepareInstalledMacUniversalRuntime(desktopRoot)
},
builderCli: require.resolve('electron-builder/cli.js'),
...(existsSync(resolve(electronDist, 'Electron.app')) ? { electronDist } : {}),
verifier: fileURLToPath(new URL('./verify-mac-smoke.ts', import.meta.url)),
nodeExecutable: process.execPath,
run,
@@ -141,6 +145,7 @@ export function packageMacSmoke(options: MacSmokePackageOptions = defaultOptions
'--config.mac.notarize=false',
'--config.npmRebuild=false',
`--config.directories.output=${options.outputDir}`,
...(options.electronDist === undefined ? [] : [`--config.electronDist=${options.electronDist}`]),
],
options.desktopRoot,
electronBuilderEnvironment({
@@ -0,0 +1,58 @@
#!/usr/bin/env node
import { spawnSync } from 'node:child_process'
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const desktopRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const upstreamRoot = resolve(desktopRoot, '..', 'deepseek-harness')
const target = process.platform === 'win32' ? 'win-x64'
: process.platform === 'darwin' ? `mac-${process.env.WORKDSH_MAC_ARCH ?? process.arch}`
: undefined
if (target === undefined || !['win-x64', 'mac-arm64', 'mac-x64'].includes(target)) {
throw new Error(`Unsupported WorkDSH primary runtime target: ${target ?? process.platform}`)
}
const output = join(desktopRoot, 'build', 'workdsh-runtime')
const cache = join(desktopRoot, 'build', '.workdsh-primary-runtime-cache')
const corepack = process.platform === 'win32' ? 'corepack.cmd' : 'corepack'
const result = spawnSync(corepack, [
'pnpm', 'run', 'prepare:primary-runtime', '--target', target, '--output', output, '--cache', cache,
], {
cwd: upstreamRoot,
env: { ...process.env, CI: 'true' },
stdio: 'inherit',
shell: process.platform === 'win32',
})
if (result.error) throw result.error
if (result.status !== 0) throw new Error(`Official primary runtime preparation failed: ${result.status}`)
const manifestPath = join(output, 'primary-runtime', 'runtime.json')
if (!existsSync(manifestPath) || !existsSync(join(output, 'office-skills'))) {
throw new Error('Official primary runtime payload is incomplete')
}
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
if (manifest.desktopVersion !== '0.1.7-rc.2' || manifest.platform !== process.platform
|| manifest.arch !== target.slice(4)) {
throw new Error(`Official primary runtime metadata does not match ${target} / rc.2`)
}
const profile = join(output, 'profiles', 'workdsh')
const packagePath = join(profile, 'package.json')
if (!existsSync(packagePath)) throw new Error('WorkDSH release profile must be prepared first')
const profilePackage = JSON.parse(readFileSync(packagePath, 'utf8'))
const packages = [
'@deepseek-ai/dsh-tool-workspace-dependencies',
'@deepseek-ai/dsh-skill-office',
]
if (packages.some(name => profilePackage.dependencies?.[name] !== '0.1.7-rc.2'
|| !existsSync(join(profile, 'node_modules', name, 'package.json')))) {
const pnpm = process.platform === 'win32' ? 'npx.cmd' : 'npx'
const install = spawnSync(pnpm, [
'--yes', '[email protected]', '--dir', profile, 'add', '--save-exact',
...packages.map(name => `${name}@0.1.7-rc.2`),
], { env: process.env, stdio: 'inherit', shell: process.platform === 'win32' })
if (install.error) throw install.error
if (install.status !== 0) throw new Error(`Official Office plugins failed to install: ${install.status}`)
}
const patch = `# Official DeepSeek Harness Desktop workspace dependencies and Office skills.\n- insert:\n - id: workspace-dependencies\n name: '@deepseek-ai/dsh-tool-workspace-dependencies'\n config:\n source: !!js "process.env.DSH_BUNDLED_PRIMARY_RUNTIME"\n root: !!js "process.getBuiltinModule('node:path').join(process.env.DSH_HOME, 'dsh-runtimes', 'dsh-primary-runtime')"\n - id: skill-office\n name: '@deepseek-ai/dsh-skill-office'\n config:\n assetRoot: !!js "process.getBuiltinModule('node:path').join(process.env.DSH_BUNDLED_PRIMARY_RUNTIME, '..', 'office-skills')"\n node: !!js "process.getBuiltinModule('node:path').join(process.env.DSH_BUNDLED_PRIMARY_RUNTIME, 'dependencies', 'node', 'bin', process.platform === 'win32' ? 'node.exe' : 'node')"\n`
writeFileSync(join(profile, 'cordis.patch.yml'), patch)
console.log(`Prepared official DeepSeek Harness ${target} primary runtime at ${output}`)
@@ -31,9 +31,10 @@ async function installReleasedProfile() {
const base = `https://github.com/techflag/workdsh/releases/download/v${WORKDSH_VERSION}`
const manifestPath = join(releaseDir, 'release-manifest.json')
await download(`${base}/release-manifest.json`, manifestPath)
const rawInstallerPath = join(releaseDir, 'install-workdsh.original.mjs')
const installerPath = join(releaseDir, 'install-workdsh.mjs')
await download(`${base}/install-workdsh.mjs`, installerPath)
let installer = readFileSync(installerPath, 'utf8')
await download(`${base}/install-workdsh.mjs`, rawInstallerPath)
let installer = readFileSync(rawInstallerPath, 'utf8')
installer = installer.replace(
'profilePackage.packageManager = manifest.packageManager;',
"profilePackage.packageManager = manifest.packageManager;\n profilePackage.devEngines = { ...profilePackage.devEngines, packageManager: { name: 'pnpm', version: manifest.packageManager.slice('pnpm@'.length), onFail: 'ignore' } };",
@@ -56,9 +57,24 @@ async function installReleasedProfile() {
}
}
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n')
const installSpawn = process.platform === 'win32' ? 'portableSpawn' : 'spawnSync'
installer = readFileSync(installerPath, 'utf8').replace(
" execute(['plugin', '--profile', profile, 'add', join(directory, item.filename)]);",
" execute(['plugin', '--profile', profile, 'allow-version', `${name}@${item.version}`, '--dsh-version', expectedHarness, '--accept-risk']);\n execute(['plugin', '--profile', profile, 'add', join(directory, item.filename)]);",
` execute(['plugin', '--profile', profile, 'allow-version', \`\${name}@\${item.version}\`, '--dsh-version', expectedHarness, '--accept-risk']);
// The DSH plugin-manager wrapper can retain an idle pnpm process after a
// completed local tarball add. Use the same pinned pnpm directly; the
// release tarball hash and exact compatibility approval were checked above.
const profileDir = join(dshHome, 'profiles', profile);
const added = ${installSpawn}(corepack, ['--dir', profileDir, 'add', '--save-exact', join(directory, item.filename)], { stdio: 'inherit' });
if (added.error) throw added.error;
if (added.status !== 0) process.exit(added.status ?? 1);
if (name === 'workdsh-bundle') {
const profilePackage = JSON.parse(readFileSync(profileManifest, 'utf8'));
const bundles = profilePackage.dsh?.profile?.bundles ?? [];
if (!bundles.includes(name)) bundles.push(name);
profilePackage.dsh = { ...profilePackage.dsh, profile: { ...profilePackage.dsh?.profile, bundles } };
writeFileSync(profileManifest, JSON.stringify(profilePackage, null, 2) + '\\n');
}`,
)
writeFileSync(installerPath, installer)
for (const item of manifest.packages) {
@@ -99,8 +115,8 @@ async function prepareNodeExecutable(path) {
if (process.platform !== 'win32') chmodSync(path, 0o755)
return
}
const targetArch = process.env.WORKDSH_MAC_ARCH
if (targetArch !== undefined && targetArch !== 'x64' && targetArch !== 'arm64') {
const targetArch = process.env.WORKDSH_MAC_ARCH ?? process.arch
if (targetArch !== 'x64' && targetArch !== 'arm64') {
throw new Error(`unsupported macOS target architecture: ${targetArch}`)
}
if (targetArch === process.arch) {
@@ -108,15 +124,14 @@ async function prepareNodeExecutable(path) {
chmodSync(path, 0o755)
return
}
const downloadArch = targetArch ?? (process.arch === 'arm64' ? 'x64' : 'arm64')
const downloadArch = targetArch
const cache = join(desktopRoot, 'build', '.workdsh-node')
const archive = join(cache, `node-v${process.versions.node}-darwin-${downloadArch}.tar.gz`)
const extracted = join(cache, `node-v${process.versions.node}-darwin-${downloadArch}`, 'bin', 'node')
mkdirSync(cache, { recursive: true })
await download(`https://nodejs.org/dist/v${process.versions.node}/node-v${process.versions.node}-darwin-${downloadArch}.tar.gz`, archive)
if (!existsSync(extracted)) run('/usr/bin/tar', ['-xzf', archive, '-C', cache])
if (targetArch === undefined) run('/usr/bin/lipo', ['-create', process.execPath, extracted, '-output', path])
else cpSync(extracted, path)
cpSync(extracted, path)
chmodSync(path, 0o755)
}
@@ -132,7 +147,23 @@ const installedDshVersion = candidate => {
return undefined
}
}
const source = candidates.find(candidate => installedDshVersion(candidate) === DSH_VERSION)
const releasePackages = [
'workdsh-provider-identity-local', 'workdsh-plugin-audit', 'workdsh-plugin-access',
'workdsh-plugin-skills', 'workdsh-plugin-experts', 'workdsh-plugin-connectors',
'workdsh-plugin-activity', 'workdsh-plugin-office', 'workdsh-plugin-library',
'workdsh-plugin-projects', 'workdsh-bundle',
]
const isPreparedProfile = candidate => {
if (installedDshVersion(candidate) !== DSH_VERSION) return false
if (!releasePackages.every(name => existsSync(join(candidate, 'node_modules', name, 'package.json')))) return false
try {
const profile = JSON.parse(readFileSync(join(candidate, 'package.json'), 'utf8'))
return profile.dsh?.profile?.bundles?.includes('workdsh-bundle') === true
} catch {
return false
}
}
const source = candidates.find(isPreparedProfile)
if (source) {
rmSync(output, { recursive: true, force: true })
@@ -141,7 +172,7 @@ if (source) {
// Clone into a real directory; APFS copy-on-write keeps local preparation fast.
if (process.platform === 'darwin') run('/bin/cp', ['-cR', resolve(source), destination])
else cpSync(resolve(source), destination, { recursive: true, dereference: true })
} else if (installedDshVersion(destination) !== DSH_VERSION || !existsSync(cli)) {
} else if (!isPreparedProfile(destination) || !existsSync(cli)) {
rmSync(output, { recursive: true, force: true })
await installReleasedProfile()
}
+6 -1
View File
@@ -17,7 +17,7 @@ import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
const PROFILE_NAME = 'workdsh'
const RUNTIME_VERSION = '0.1.0-alpha.8'
const RUNTIME_VERSION = '0.1.0-alpha.9+dsh-0.1.7-rc.2'
const READY_PATTERN = /dsh web:\s+(http:\/\/127\.0\.0\.1:\d+\/?\?token=[^\s]+)/u
let runtime: ChildProcess | undefined
@@ -47,6 +47,10 @@ function bundledNodeExecutable(): string {
)
}
function bundledPrimaryRuntime(): string {
return join(process.resourcesPath, 'workdsh-runtime', 'primary-runtime')
}
function materializeRuntimeProfile(home: string): string {
const source = bundledProfileDirectory()
const target = join(home, 'profiles', PROFILE_NAME)
@@ -126,6 +130,7 @@ function startRuntime(home: string, profileDir: string): void {
env: {
...process.env,
DSH_HOME: home,
DSH_BUNDLED_PRIMARY_RUNTIME: bundledPrimaryRuntime(),
ELECTRON_RUN_AS_NODE: undefined,
},
stdio: ['ignore', 'pipe', 'pipe'],
@@ -912,7 +912,7 @@ describe('published package surface', () => {
expect(manifest.scripts?.['prepare:electron-native']).toBe('node scripts/prepare-fs-ext.ts')
expect(manifest.scripts?.dev).toContain('yarn run prepare:electron-native')
expect(manifest.scripts?.['package:dir'])
.toBe('yarn run build && yarn run prepare:electron-native && yarn run prepare:workdsh-runtime && node scripts/package-dir.mjs')
.toBe('yarn run build && yarn run prepare:electron-native && yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-dir.mjs')
expect(packageDir).toContain("CSC_IDENTITY_AUTO_DISCOVERY: 'false'")
expect(packageDir).toContain("'--config.forceCodeSigning=false'")
expect(packageDir).toContain("'--config.mac.identity=null'")
@@ -921,10 +921,10 @@ describe('published package surface', () => {
expect(packageDir).toContain("require.resolve('electron/package.json')")
expect(packageDir).toContain('--config.electronDist=')
expect(packageDir).toContain('electronBuilderEnvironment')
expect(manifest.scripts?.['dist:mac']).toBe('yarn run prepare:workdsh-runtime && node scripts/release-mac.ts')
expect(manifest.scripts?.['dist:mac-smoke']).toBe('yarn run prepare:workdsh-runtime && node scripts/package-mac.ts')
expect(manifest.scripts?.['dist:win']).toBe('yarn run prepare:workdsh-runtime && node scripts/package-win.ts')
expect(manifest.scripts?.['dist:win-portable']).toBe('yarn run prepare:workdsh-runtime && node scripts/package-win-portable.ts')
expect(manifest.scripts?.['dist:mac']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/release-mac.ts')
expect(manifest.scripts?.['dist:mac-smoke']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-mac.ts')
expect(manifest.scripts?.['dist:win']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win.ts')
expect(manifest.scripts?.['dist:win-portable']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win-portable.ts')
expect(manifest.scripts?.['check:win-package']).toContain('yarn workspace dsh-community-market build')
expect(manifest.scripts?.['check:win-package']).toContain('yarn run build')
expect(manifest.scripts?.['check:win-package']).toContain('yarn run typecheck')
+2
View File
@@ -5,3 +5,5 @@ node_modules/
build/workdsh-runtime
build/.workdsh-release-*
build/.workdsh-node
build/.workdsh-primary-runtime-cache
build/official-primary-runtime
+11 -8
View File
@@ -129,14 +129,14 @@
"check:mac-package": "yarn workspace dsh-community-market build && yarn run build && yarn run typecheck && vitest run tests/package.spec.ts tests/package-mac.spec.ts tests/verify-mac-smoke.spec.ts tests/verify-packaged-runtime.spec.ts tests/mac-universal.spec.ts && yarn run verify:closure",
"start": "node lib/bin.js",
"dev": "yarn run build && node lib/bin.js",
"package:dir": "yarn run build && yarn run prepare:electron-native && yarn run prepare:workdsh-runtime && node scripts/package-dir.mjs",
"dist:mac": "yarn run prepare:workdsh-runtime && node scripts/release-mac.ts",
"dist:mac-smoke": "yarn run prepare:workdsh-runtime && node scripts/package-mac.ts",
"dist:win": "yarn run prepare:workdsh-runtime && node scripts/package-win.ts",
"dist:win-portable": "yarn run prepare:workdsh-runtime && node scripts/package-win-portable.ts",
"package:dir": "yarn run build && yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-dir.mjs",
"dist:mac": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/release-mac.ts",
"dist:mac-smoke": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-mac.ts",
"dist:win": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win.ts",
"dist:win-portable": "yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win-portable.ts",
"prepack": "yarn run check",
"prepare:electron-native": "node scripts/prepare-fs-ext.ts",
"prepare:workdsh-runtime": "node scripts/prepare-workdsh-runtime.mjs"
"prepare:workdsh-runtime": "node scripts/prepare-workdsh-runtime.mjs",
"prepare:workdsh-primary-runtime": "node scripts/prepare-workdsh-primary-runtime.mjs"
},
"dependencies": {
"@deepseek-ai/cordis": "4.0.2",
@@ -332,6 +332,7 @@
"asar": {
"smartUnpack": true
},
"npmRebuild": false,
"afterPack": "./scripts/verify-packaged-runtime.ts",
"afterAllArtifactBuild": "./scripts/verify-electron-fuses.ts",
"electronFuses": {
@@ -443,7 +444,9 @@
"to": "workdsh-runtime",
"filter": [
"profiles/workdsh/**",
"node/**"
"node/**",
"primary-runtime/**",
"office-skills/**"
]
}
]
@@ -0,0 +1,15 @@
/** Dependency-collection policy shared by Electron Builder entry points. */
/**
* Keep the Desktop package on Electron Builder's bounded physical traversal.
* Its Yarn Berry collector delegates to `npm list --all`, which expands the
* outer stable and Beta workspace instead of the selected app's runtime graph.
*/
export function electronBuilderEnvironment(
environment: NodeJS.ProcessEnv,
): NodeJS.ProcessEnv {
return {
...environment,
DSH_ELECTRON_BUILDER_TRAVERSAL_ONLY: '1',
}
}
+12 -3
View File
@@ -3,13 +3,16 @@
import { spawnSync } from 'node:child_process'
import { createRequire } from 'node:module'
import { dirname, resolve } from 'node:path'
import { existsSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { electronBuilderEnvironment } from './electron-builder-environment.ts'
import { withoutWindowsSigningSecrets } from './package-win.ts'
import { withoutMacReleaseSecrets } from './release-preflight.ts'
const require = createRequire(import.meta.url)
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
const builderCli = require.resolve('electron-builder/cli.js')
const electronDist = resolve(dirname(require.resolve('electron/package.json')), 'dist')
/** Electron Builder overrides that make the directory build unconditionally unsigned. */
export const UNSIGNED_DIRECTORY_BUILD_ARGS = Object.freeze([
@@ -28,10 +31,10 @@ export const UNSIGNED_DIRECTORY_BUILD_ARGS = Object.freeze([
* @returns {NodeJS.ProcessEnv}
*/
export function unsignedDirectoryBuildEnvironment(environment) {
return {
return electronBuilderEnvironment({
...withoutWindowsSigningSecrets(withoutMacReleaseSecrets(environment)),
CSC_IDENTITY_AUTO_DISCOVERY: 'false',
}
})
}
/**
@@ -40,6 +43,7 @@ export function unsignedDirectoryBuildEnvironment(environment) {
* env?: NodeJS.ProcessEnv,
* cwd?: string,
* electronBuilderCli?: string,
* electronDistPath?: string,
* nodeExecutable?: string,
* run?: typeof spawnSync,
* }} [options]
@@ -48,9 +52,14 @@ export function packageDirectory(options = {}) {
const run = options.run ?? spawnSync
const nodeExecutable = options.nodeExecutable ?? process.execPath
const electronBuilderCli = options.electronBuilderCli ?? builderCli
const configuredElectronDist = options.electronDistPath ?? electronDist
const result = run(
nodeExecutable,
[electronBuilderCli, ...UNSIGNED_DIRECTORY_BUILD_ARGS],
[
electronBuilderCli,
...UNSIGNED_DIRECTORY_BUILD_ARGS,
...(existsSync(configuredElectronDist) ? [`--config.electronDist=${configuredElectronDist}`] : []),
],
{
cwd: options.cwd ?? packageRoot,
env: unsignedDirectoryBuildEnvironment(options.env ?? process.env),
+9 -3
View File
@@ -1,12 +1,13 @@
/** Build an unsigned macOS DMG smoke artifact on a native macOS host. */
import { spawnSync } from 'node:child_process'
import { rmSync } from 'node:fs'
import { existsSync, rmSync } from 'node:fs'
import { createRequire } from 'node:module'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { withoutMacReleaseSecrets } from './release-preflight.ts'
import { prepareInstalledMacUniversalRuntime } from './mac-universal.ts'
import { electronBuilderEnvironment } from './electron-builder-environment.ts'
/** Injectable native macOS packaging boundary used by focused tests. */
export interface MacSmokePackageOptions {
@@ -30,6 +31,8 @@ export interface MacSmokePackageOptions {
readonly prepareRuntime: () => void
/** Absolute electron-builder CLI module. */
readonly builderCli: string
/** Local Electron distribution when already installed, avoiding another download. */
readonly electronDist?: string
/** Absolute packaged-DMG verification script. */
readonly verifier: string
/** Node executable used to run package-local scripts. */
@@ -63,6 +66,7 @@ function defaultOptions(): MacSmokePackageOptions {
const workspaceRoot = resolve(desktopRoot, '..')
const require = createRequire(import.meta.url)
const outputDir = resolve(desktopRoot, 'dist', 'mac-smoke', process.env.WORKDSH_MAC_ARCH ?? process.arch)
const electronDist = resolve(dirname(require.resolve('electron/package.json')), 'dist')
return {
env: process.env,
platform: process.platform,
@@ -74,6 +78,7 @@ function defaultOptions(): MacSmokePackageOptions {
resetOutput: () => rmSync(outputDir, { recursive: true, force: true }),
prepareRuntime: () => prepareInstalledMacUniversalRuntime(desktopRoot),
builderCli: require.resolve('electron-builder/cli.js'),
...(existsSync(resolve(electronDist, 'Electron.app')) ? { electronDist } : {}),
verifier: fileURLToPath(new URL('./verify-mac-smoke.ts', import.meta.url)),
nodeExecutable: process.execPath,
run,
@@ -135,12 +140,13 @@ export function packageMacSmoke(options: MacSmokePackageOptions = defaultOptions
'--config.mac.notarize=false',
'--config.npmRebuild=false',
`--config.directories.output=${options.outputDir}`,
...(options.electronDist === undefined ? [] : [`--config.electronDist=${options.electronDist}`]),
],
options.desktopRoot,
{
electronBuilderEnvironment({
...cleanEnvironment,
CSC_IDENTITY_AUTO_DISCOVERY: 'false',
},
}),
)
options.run(
options.nodeExecutable,
@@ -0,0 +1,58 @@
#!/usr/bin/env node
import { spawnSync } from 'node:child_process'
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const desktopRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const upstreamRoot = resolve(desktopRoot, '..', 'deepseek-harness')
const target = process.platform === 'win32' ? 'win-x64'
: process.platform === 'darwin' ? `mac-${process.env.WORKDSH_MAC_ARCH ?? process.arch}`
: undefined
if (target === undefined || !['win-x64', 'mac-arm64', 'mac-x64'].includes(target)) {
throw new Error(`Unsupported WorkDSH primary runtime target: ${target ?? process.platform}`)
}
const output = join(desktopRoot, 'build', 'workdsh-runtime')
const cache = join(desktopRoot, 'build', '.workdsh-primary-runtime-cache')
const corepack = process.platform === 'win32' ? 'corepack.cmd' : 'corepack'
const result = spawnSync(corepack, [
'pnpm', 'run', 'prepare:primary-runtime', '--target', target, '--output', output, '--cache', cache,
], {
cwd: upstreamRoot,
env: { ...process.env, CI: 'true' },
stdio: 'inherit',
shell: process.platform === 'win32',
})
if (result.error) throw result.error
if (result.status !== 0) throw new Error(`Official primary runtime preparation failed: ${result.status}`)
const manifestPath = join(output, 'primary-runtime', 'runtime.json')
if (!existsSync(manifestPath) || !existsSync(join(output, 'office-skills'))) {
throw new Error('Official primary runtime payload is incomplete')
}
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
if (manifest.desktopVersion !== '0.1.7-rc.2' || manifest.platform !== process.platform
|| manifest.arch !== target.slice(4)) {
throw new Error(`Official primary runtime metadata does not match ${target} / rc.2`)
}
const profile = join(output, 'profiles', 'workdsh')
const packagePath = join(profile, 'package.json')
if (!existsSync(packagePath)) throw new Error('WorkDSH release profile must be prepared first')
const profilePackage = JSON.parse(readFileSync(packagePath, 'utf8'))
const packages = [
'@deepseek-ai/dsh-tool-workspace-dependencies',
'@deepseek-ai/dsh-skill-office',
]
if (packages.some(name => profilePackage.dependencies?.[name] !== '0.1.7-rc.2'
|| !existsSync(join(profile, 'node_modules', name, 'package.json')))) {
const pnpm = process.platform === 'win32' ? 'npx.cmd' : 'npx'
const install = spawnSync(pnpm, [
'--yes', '[email protected]', '--dir', profile, 'add', '--save-exact',
...packages.map(name => `${name}@0.1.7-rc.2`),
], { env: process.env, stdio: 'inherit', shell: process.platform === 'win32' })
if (install.error) throw install.error
if (install.status !== 0) throw new Error(`Official Office plugins failed to install: ${install.status}`)
}
const patch = `# Official DeepSeek Harness Desktop workspace dependencies and Office skills.\n- insert:\n - id: workspace-dependencies\n name: '@deepseek-ai/dsh-tool-workspace-dependencies'\n config:\n source: !!js "process.env.DSH_BUNDLED_PRIMARY_RUNTIME"\n root: !!js "process.getBuiltinModule('node:path').join(process.env.DSH_HOME, 'dsh-runtimes', 'dsh-primary-runtime')"\n - id: skill-office\n name: '@deepseek-ai/dsh-skill-office'\n config:\n assetRoot: !!js "process.getBuiltinModule('node:path').join(process.env.DSH_BUNDLED_PRIMARY_RUNTIME, '..', 'office-skills')"\n node: !!js "process.getBuiltinModule('node:path').join(process.env.DSH_BUNDLED_PRIMARY_RUNTIME, 'dependencies', 'node', 'bin', process.platform === 'win32' ? 'node.exe' : 'node')"\n`
writeFileSync(join(profile, 'cordis.patch.yml'), patch)
console.log(`Prepared official DeepSeek Harness ${target} primary runtime at ${output}`)
@@ -31,9 +31,10 @@ async function installReleasedProfile() {
const base = `https://github.com/techflag/workdsh/releases/download/v${WORKDSH_VERSION}`
const manifestPath = join(releaseDir, 'release-manifest.json')
await download(`${base}/release-manifest.json`, manifestPath)
const rawInstallerPath = join(releaseDir, 'install-workdsh.original.mjs')
const installerPath = join(releaseDir, 'install-workdsh.mjs')
await download(`${base}/install-workdsh.mjs`, installerPath)
let installer = readFileSync(installerPath, 'utf8')
await download(`${base}/install-workdsh.mjs`, rawInstallerPath)
let installer = readFileSync(rawInstallerPath, 'utf8')
installer = installer.replace(
'profilePackage.packageManager = manifest.packageManager;',
"profilePackage.packageManager = manifest.packageManager;\n profilePackage.devEngines = { ...profilePackage.devEngines, packageManager: { name: 'pnpm', version: manifest.packageManager.slice('pnpm@'.length), onFail: 'ignore' } };",
@@ -56,9 +57,24 @@ async function installReleasedProfile() {
}
}
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n')
const installSpawn = process.platform === 'win32' ? 'portableSpawn' : 'spawnSync'
installer = readFileSync(installerPath, 'utf8').replace(
" execute(['plugin', '--profile', profile, 'add', join(directory, item.filename)]);",
" execute(['plugin', '--profile', profile, 'allow-version', `${name}@${item.version}`, '--dsh-version', expectedHarness, '--accept-risk']);\n execute(['plugin', '--profile', profile, 'add', join(directory, item.filename)]);",
` execute(['plugin', '--profile', profile, 'allow-version', \`\${name}@\${item.version}\`, '--dsh-version', expectedHarness, '--accept-risk']);
// The DSH plugin-manager wrapper can retain an idle pnpm process after a
// completed local tarball add. Use the same pinned pnpm directly; the
// release tarball hash and exact compatibility approval were checked above.
const profileDir = join(dshHome, 'profiles', profile);
const added = ${installSpawn}(corepack, ['--dir', profileDir, 'add', '--save-exact', join(directory, item.filename)], { stdio: 'inherit' });
if (added.error) throw added.error;
if (added.status !== 0) process.exit(added.status ?? 1);
if (name === 'workdsh-bundle') {
const profilePackage = JSON.parse(readFileSync(profileManifest, 'utf8'));
const bundles = profilePackage.dsh?.profile?.bundles ?? [];
if (!bundles.includes(name)) bundles.push(name);
profilePackage.dsh = { ...profilePackage.dsh, profile: { ...profilePackage.dsh?.profile, bundles } };
writeFileSync(profileManifest, JSON.stringify(profilePackage, null, 2) + '\\n');
}`,
)
writeFileSync(installerPath, installer)
for (const item of manifest.packages) {
@@ -99,8 +115,8 @@ async function prepareNodeExecutable(path) {
if (process.platform !== 'win32') chmodSync(path, 0o755)
return
}
const targetArch = process.env.WORKDSH_MAC_ARCH
if (targetArch !== undefined && targetArch !== 'x64' && targetArch !== 'arm64') {
const targetArch = process.env.WORKDSH_MAC_ARCH ?? process.arch
if (targetArch !== 'x64' && targetArch !== 'arm64') {
throw new Error(`unsupported macOS target architecture: ${targetArch}`)
}
if (targetArch === process.arch) {
@@ -108,15 +124,14 @@ async function prepareNodeExecutable(path) {
chmodSync(path, 0o755)
return
}
const downloadArch = targetArch ?? (process.arch === 'arm64' ? 'x64' : 'arm64')
const downloadArch = targetArch
const cache = join(desktopRoot, 'build', '.workdsh-node')
const archive = join(cache, `node-v${process.versions.node}-darwin-${downloadArch}.tar.gz`)
const extracted = join(cache, `node-v${process.versions.node}-darwin-${downloadArch}`, 'bin', 'node')
mkdirSync(cache, { recursive: true })
await download(`https://nodejs.org/dist/v${process.versions.node}/node-v${process.versions.node}-darwin-${downloadArch}.tar.gz`, archive)
if (!existsSync(extracted)) run('/usr/bin/tar', ['-xzf', archive, '-C', cache])
if (targetArch === undefined) run('/usr/bin/lipo', ['-create', process.execPath, extracted, '-output', path])
else cpSync(extracted, path)
cpSync(extracted, path)
chmodSync(path, 0o755)
}
@@ -132,7 +147,23 @@ const installedDshVersion = candidate => {
return undefined
}
}
const source = candidates.find(candidate => installedDshVersion(candidate) === DSH_VERSION)
const releasePackages = [
'workdsh-provider-identity-local', 'workdsh-plugin-audit', 'workdsh-plugin-access',
'workdsh-plugin-skills', 'workdsh-plugin-experts', 'workdsh-plugin-connectors',
'workdsh-plugin-activity', 'workdsh-plugin-office', 'workdsh-plugin-library',
'workdsh-plugin-projects', 'workdsh-bundle',
]
const isPreparedProfile = candidate => {
if (installedDshVersion(candidate) !== DSH_VERSION) return false
if (!releasePackages.every(name => existsSync(join(candidate, 'node_modules', name, 'package.json')))) return false
try {
const profile = JSON.parse(readFileSync(join(candidate, 'package.json'), 'utf8'))
return profile.dsh?.profile?.bundles?.includes('workdsh-bundle') === true
} catch {
return false
}
}
const source = candidates.find(isPreparedProfile)
if (source) {
rmSync(output, { recursive: true, force: true })
@@ -141,7 +172,7 @@ if (source) {
// Clone into a real directory; APFS copy-on-write keeps local preparation fast.
if (process.platform === 'darwin') run('/bin/cp', ['-cR', resolve(source), destination])
else cpSync(resolve(source), destination, { recursive: true, dereference: true })
} else if (installedDshVersion(destination) !== DSH_VERSION || !existsSync(cli)) {
} else if (!isPreparedProfile(destination) || !existsSync(cli)) {
rmSync(output, { recursive: true, force: true })
await installReleasedProfile()
}
+6 -1
View File
@@ -17,7 +17,7 @@ import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
const PROFILE_NAME = 'workdsh'
const RUNTIME_VERSION = '0.1.0-alpha.8'
const RUNTIME_VERSION = '0.1.0-alpha.9+dsh-0.1.7-rc.2'
const READY_PATTERN = /dsh web:\s+(http:\/\/127\.0\.0\.1:\d+\/?\?token=[^\s]+)/u
let runtime: ChildProcess | undefined
@@ -47,6 +47,10 @@ function bundledNodeExecutable(): string {
)
}
function bundledPrimaryRuntime(): string {
return join(process.resourcesPath, 'workdsh-runtime', 'primary-runtime')
}
function materializeRuntimeProfile(home: string): string {
const source = bundledProfileDirectory()
const target = join(home, 'profiles', PROFILE_NAME)
@@ -126,6 +130,7 @@ function startRuntime(home: string, profileDir: string): void {
env: {
...process.env,
DSH_HOME: home,
DSH_BUNDLED_PRIMARY_RUNTIME: bundledPrimaryRuntime(),
ELECTRON_RUN_AS_NODE: undefined,
},
stdio: ['ignore', 'pipe', 'pipe'],
@@ -78,6 +78,7 @@ describe('macOS DMG smoke packaging', () => {
PATH: '/usr/bin:/bin',
SAFE_VALUE: 'kept',
CSC_IDENTITY_AUTO_DISCOVERY: 'false',
DSH_ELECTRON_BUILDER_TRAVERSAL_ONLY: '1',
},
})
expect(calls[2]).toEqual({
+5 -5
View File
@@ -832,16 +832,16 @@ describe('published package surface', () => {
expect(manifest.scripts?.build).toContain('node scripts/generate-windows-app-icon.mjs')
expect(manifest.scripts?.build).toContain('node scripts/generate-mac-app-icon.mjs')
expect(manifest.scripts?.['package:dir'])
.toBe('yarn run build && yarn run prepare:electron-native && yarn run prepare:workdsh-runtime && node scripts/package-dir.mjs')
.toBe('yarn run build && yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-dir.mjs')
expect(packageDir).toContain("CSC_IDENTITY_AUTO_DISCOVERY: 'false'")
expect(packageDir).toContain("'--config.forceCodeSigning=false'")
expect(packageDir).toContain("'--config.mac.identity=null'")
expect(packageDir).toContain("'--config.mac.notarize=false'")
expect(packageDir).toContain("'--config.win.signExecutable=false'")
expect(manifest.scripts?.['dist:mac']).toBe('yarn run prepare:workdsh-runtime && node scripts/release-mac.ts')
expect(manifest.scripts?.['dist:mac-smoke']).toBe('yarn run prepare:workdsh-runtime && node scripts/package-mac.ts')
expect(manifest.scripts?.['dist:win']).toBe('yarn run prepare:workdsh-runtime && node scripts/package-win.ts')
expect(manifest.scripts?.['dist:win-portable']).toBe('yarn run prepare:workdsh-runtime && node scripts/package-win-portable.ts')
expect(manifest.scripts?.['dist:mac']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/release-mac.ts')
expect(manifest.scripts?.['dist:mac-smoke']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-mac.ts')
expect(manifest.scripts?.['dist:win']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win.ts')
expect(manifest.scripts?.['dist:win-portable']).toBe('yarn run prepare:workdsh-runtime && yarn run prepare:workdsh-primary-runtime && node scripts/package-win-portable.ts')
expect(manifest.scripts?.['check:win-package']).toContain('yarn workspace dsh-community-market build')
expect(manifest.scripts?.['check:win-package']).toContain('yarn run build')
expect(manifest.scripts?.['check:win-package']).toContain('yarn run typecheck')
+2 -2
View File
@@ -10,8 +10,8 @@
"package": "dsh-plugin-desktop"
},
"beta": {
"commit": "82a5fd61a7cf5c293cec4bdff68f455398d685e9",
"sourceVersion": "0.1.3-alpha.2",
"commit": "477b4f420553e8a52c2fbccc464d7561b239c443",
"sourceVersion": "0.1.7-rc.2",
"runtimePackageVersion": "0.1.3-alpha.2",
"runtimeSource": "vendor/dsh-runtime/0.1.3-alpha.2/manifest.json",
"package": "dsh-plugin-desktop-beta"