fix: omit ConPTY sources from non-Windows Desktop packages

This commit is contained in:
kingwl committed 2026-09-30 19:51:06 +08:00
1 parent 97bbbdfa13
commit db1d900f6d
5 files changed
+65 -6

No files matched your search

+2 -2
View File
@@ -45,8 +45,8 @@
en: f461b255133384cc
zh: 2b9db718f22fdd04
/deepseek-harness-desktop/package/runtime-file-selection:
en: f0e345fd89868803
zh: fd2c775ad23fa2f0
en: 8554894a83bceee8
zh: c9dfe823c06abc9e
/deepseek-harness-desktop/package/upload-updates:
en: 72073b2e72590067
zh: 63b1f9790395c37d
+1 -1
View File
@@ -237,7 +237,7 @@ Each target owns its packed package inputs, prepared runtime, package set, dsh t
### Runtime file selection
Desktop packs workspace packages locally and installs external dependencies through the target's bundled Node and pnpm. [Desktop's file policy](scripts/runtime-file-policy.ts) then filters the immutable `resources/app.asar/dsh/node_modules` copy before signing and integrity sealing. It omits TypeScript declarations, recognized JavaScript/CSS/TypeScript source maps, TypeScript build caches, Domino's test directory, selected native compiler outputs, and node-pty prebuilds for other platforms. It preserves runtime JavaScript, native modules and their DLL/EXE helpers, WASM, unknown assets, licenses, and notices. Dependency manifests pass through electron-builder's metadata cleanup before integrity sealing, so archiving preserves their recorded bytes. The policy does not alter npm tarballs, the bundled package manager, or user-installed plugin files.
Desktop packs workspace packages locally and installs external dependencies through the target's bundled Node and pnpm. [Desktop's file policy](scripts/runtime-file-policy.ts) then filters the immutable `resources/app.asar/dsh/node_modules` copy before signing and integrity sealing. It omits TypeScript declarations, recognized JavaScript/CSS/TypeScript source maps, TypeScript build caches, Domino's test directory, selected native compiler outputs, and node-pty prebuilds for other platforms. Non-Windows targets also omit `node-pty/third_party/conpty`; Windows targets retain that directory. It preserves runtime JavaScript, target native modules and their DLL/EXE helpers, WASM, unknown assets, licenses, and notices. Dependency manifests pass through electron-builder's metadata cleanup before integrity sealing, so archiving preserves their recorded bytes. The policy does not alter npm tarballs, the bundled package manager, or user-installed plugin files.
The [Office conversion provider](../../packages/document/office-to-pdf/README.md) carries the target’s declared native engine, or WASM when the kit declares no matching native target. Preparation rejects a missing target engine before packaging. The complete Office dependencies, including CLI, JavaScript libraries, and the selected engine’s executables, data, licenses, and notices, are unpacked under `resources/app.asar.unpacked/dsh/node_modules/`. The Desktop Host resolves engine manifests to these physical directories and supplies loaded skills with absolute standalone Node and unpacked CLI paths. Node lives in `resources/runtime/primary-runtime/dependencies/node/bin/`; the CLI is the unpacked `@deepseek-ai/libreoffice-kit/lib/cli.js`. On macOS, the native helper receives the JIT entitlement required by [LibreOffice’s UNO bridge](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in).
+1 -1
View File
@@ -239,7 +239,7 @@ macOS arm64 命令要求 Apple Silicon。macOS x64 命令可以在 Intel macOS
### 运行时文件筛选
Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安装外部依赖。[Desktop 文件策略](scripts/runtime-file-policy.ts)随后在签名和完整性封装前过滤不可变的 `resources/app.asar/dsh/node_modules` 副本。它排除 TypeScript 声明、已识别的 JavaScript/CSS/TypeScript source map、TypeScript 构建缓存、Domino 测试目录、选定的原生编译器输出和其他平台的 node-pty 预构建文件。它保留运行时 JavaScript、原生模块及其 DLL/EXE 辅助文件、WASM、未知资源、许可证和 notices。依赖清单在完整性封装前经过 electron-builder 的元数据清理,确保归档保持已记录的字节。该策略不修改 npm tarball、捆绑的包管理器或用户安装的插件文件。
Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安装外部依赖。[Desktop 文件策略](scripts/runtime-file-policy.ts)随后在签名和完整性封装前过滤不可变的 `resources/app.asar/dsh/node_modules` 副本。它排除 TypeScript 声明、已识别的 JavaScript/CSS/TypeScript source map、TypeScript 构建缓存、Domino 测试目录、选定的原生编译器输出和其他平台的 node-pty 预构建文件。非 Windows 目标还会排除 `node-pty/third_party/conpty`;Windows 目标保留该目录。它保留运行时 JavaScript、目标平台的原生模块及其 DLL/EXE 辅助文件、WASM、未知资源、许可证和 notices。依赖清单在完整性封装前经过 electron-builder 的元数据清理,确保归档保持已记录的字节。该策略不修改 npm tarball、捆绑的包管理器或用户安装的插件文件。
[Office 转换提供方](../../packages/document/office-to-pdf/README.zh.md)携带目标已声明的原生引擎;kit 未声明匹配原生目标时携带 WASM 引擎。准备阶段在打包前拒绝缺少目标引擎的情况。完整 Office 依赖(CLI、JavaScript 库和选定引擎的可执行文件、数据、许可证及 notices)解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下。Desktop Host 将引擎清单解析到这些物理目录,并向加载的技能提供独立 Node 和解包后 CLI 的绝对路径。Node 位于 `resources/runtime/primary-runtime/dependencies/node/bin/`;CLI 位于解包后的 `@deepseek-ai/libreoffice-kit/lib/cli.js`。macOS 上的原生辅助程序获得 [LibreOffice UNO 桥](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in)所需的 JIT entitlement。
+5 -2
View File
@@ -1,7 +1,7 @@
/** Desktop-only omissions from already installed production npm packages. */
/**
* Identify build and diagnostic files omitted from the immutable Desktop runtime.
* Identify build, diagnostic and other-platform files omitted from the immutable Desktop runtime.
* Unrecognized assets and target runtime binaries are retained. Paths name the copied
* node_modules tree, including nested package containers.
* @param path - Path relative to the production node_modules directory.
@@ -16,7 +16,7 @@ export function desktopRuntimeFileExclusion(
if (parts.some(part => ['.bin', '.pnpm', '.modules.yaml', '.pnpm-workspace-state-v1.json'].includes(part))) {
return 'package-manager metadata'
}
const file = parts.at(-1) ?? ''
const file = parts.at(-1)!
if (/\.(?:[cm]?[jt]s|css)\.map$/u.test(file)) return 'source map'
if (/\.d\.[cm]?ts$/u.test(file)) return 'TypeScript declaration'
if (/\.tsbuildinfo$/u.test(file)) return 'TypeScript build cache'
@@ -34,6 +34,9 @@ export function desktopRuntimeFileExclusion(
return 'fs-ext build configuration'
}
if (name === '@mixmark-io/domino' && (entry === 'test' || entry.startsWith('test/'))) return 'Domino test fixtures'
if (name === 'node-pty' && target.platform !== 'win32' && /^third_party\/conpty(?:\/|$)/u.test(entry)) {
return 'node-pty Windows ConPTY sources'
}
if (name === 'node-pty' && entry.startsWith('prebuilds/')) {
const platform = packageParts[nameParts + 1]
if (platform !== undefined && platform !== `${target.platform}-${target.arch}`) return 'node-pty other platform'
@@ -85,6 +85,62 @@ it('retains native prebuilds for the selected macOS architecture', () => {
expect(desktopRuntimeFileExclusion('node-pty/prebuilds/win32-x64/conpty.node', mac, 'darwin-arm64')).toBeDefined()
})
it.each([
['darwin', 'arm64'], ['darwin', 'x64'],
['linux', 'arm64'], ['linux', 'x64'],
['win32', 'arm64'], ['win32', 'x64'],
] as const)('copies ConPTY sources only for Windows targets (%s/%s)', (platform, arch) => {
const root = mkdtempSync(join(tmpdir(), 'desktop-conpty-policy-'))
try {
const source = join(root, 'source')
const output = join(root, 'output')
const prefixes = ['', '@example/outer/node_modules/']
const conpty = ['arm64', 'x64'].flatMap(cpu => ['conpty.dll', 'OpenConsole.exe'].map(
file => `node-pty/third_party/conpty/1.25.260303002/win10-${cpu}/${file}`,
))
const native = platform === 'win32'
? ['conpty.node', 'conpty_console_list.node', 'conpty/conpty.dll', 'conpty/OpenConsole.exe']
: ['pty.node', 'spawn-helper']
const retained = [
...native.map(file => `node-pty/prebuilds/${platform}-${arch}/${file}`),
...native.map(file => `node-pty/build/Release/${file}`),
'node-pty/lib/index.js', 'node-pty/LICENSE',
'node-pty/third_party/conpty-notes/README.md', 'node-pty/third_party/conpty.dll',
'other/third_party/conpty/conpty.dll',
]
for (const prefix of prefixes) {
for (const path of [...conpty, ...retained]) {
mkdirSync(join(source, prefix, path, '..'), { recursive: true })
writeFileSync(join(source, prefix, path), `payload:${prefix}${path}`)
}
}
cpSync(source, output, {
recursive: true, dereference: true,
filter: (path) => {
const entry = relative(source, path)
return desktopRuntimeFileExclusion(
platform === 'win32' ? entry.replaceAll('/', '\\') : entry,
{ platform, arch }, `${platform}-${arch}`,
) === undefined
},
})
for (const prefix of prefixes) {
expect(existsSync(join(output, prefix, 'node-pty/third_party/conpty'))).toBe(platform === 'win32')
for (const path of conpty) {
expect(existsSync(join(output, prefix, path)), `${prefix}${path}`).toBe(platform === 'win32')
}
for (const path of [...retained, ...(platform === 'win32' ? conpty : [])]) {
expect(readFileSync(join(output, prefix, path), 'utf8')).toBe(`payload:${prefix}${path}`)
}
for (const path of conpty) {
expect(readFileSync(join(source, prefix, path), 'utf8')).toBe(`payload:${prefix}${path}`)
}
}
} finally {
rmSync(root, { recursive: true, force: true })
}
})
it.each([
['linux', 'x64', 'linux-x64'],
['linux', 'arm64', 'wasm'],