From 0dac34c3388c2c4fc77b5764df847b72095d6589 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 30 Sep 2026 21:57:11 +0800 Subject: [PATCH 1/5] fix(desktop): pin and validate Koffi 3.1.1 --- apps/desktop-host/package.json | 2 +- apps/desktop/README.i18n.yaml | 4 +-- apps/desktop/README.md | 2 ++ apps/desktop/README.zh.md | 2 ++ apps/desktop/scripts/prepare-dsh.ts | 8 ++--- pnpm-lock.yaml | 2 +- scripts/check-workspace-constraints.spec.ts | 23 +++++++++++- scripts/check-workspace-constraints.ts | 20 +++++++++++ scripts/koffi-policy.spec.ts | 39 +++++++++++++++++++++ scripts/koffi-policy.ts | 29 +++++++++++++++ 10 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 scripts/koffi-policy.spec.ts create mode 100644 scripts/koffi-policy.ts diff --git a/apps/desktop-host/package.json b/apps/desktop-host/package.json index fe870e6308..57704598d8 100644 --- a/apps/desktop-host/package.json +++ b/apps/desktop-host/package.json @@ -11,7 +11,7 @@ "lib/cli.js" ], "dependencies": { - "koffi": "^3.1.0", + "koffi": "3.1.1", "@deepseek-ai/libreoffice-kit": "^0.1.1", "@deepseek-ai/cordis": "workspace:~", "@deepseek-ai/dsh": "workspace:*", diff --git a/apps/desktop/README.i18n.yaml b/apps/desktop/README.i18n.yaml index 6f4cf94723..b280b215fc 100644 --- a/apps/desktop/README.i18n.yaml +++ b/apps/desktop/README.i18n.yaml @@ -57,8 +57,8 @@ en: f176a8b1c7de3064 zh: 6ea2dbe6bb808c34 /deepseek-harness-desktop/package/windows-ev-signing: - en: 8efe3498dbe8686d - zh: a88c16f20a9430f3 + en: 7a049a4cd52604b3 + zh: cd73f9c96c6a9984 /deepseek-harness-desktop/updates: en: d0df867b69cbffa4 zh: eeb47b79b86fe5ee diff --git a/apps/desktop/README.md b/apps/desktop/README.md index 13e742edcb..ca7b97c8a2 100644 --- a/apps/desktop/README.md +++ b/apps/desktop/README.md @@ -396,6 +396,8 @@ Every package command builds the repository, packs the first-party production cl macOS packaging writes `Contents/Resources/app-update.yml` while assembling the App and before code signing, including the directory build that feeds the parallel ZIP and DMG lanes. The signing hook verifies the exact feed and updater cache directory. Both lane copies and the promoted App are checked again before the release completion record is written; a missing or mismatched configuration prevents artifact promotion and therefore prevents upload. +Koffi consumers, including the private Desktop Host, pin `3.1.1`; `pnpm run constraints` checks every workspace declaration. `prepare:dsh` generates a fresh production lockfile from the packed manifests, independently of the repository lockfile, and rejects missing Koffi or any other Koffi JavaScript/native package version before installation. Upgrade all consumers and the shared [version check](../../scripts/koffi-policy.ts) together after qualifying source builds without optional prebuilts and the packed production install. + An unpacked artifact contains Electron, the materialized dsh production tree, pnpm, and the shell application. Installer size and filesystem size differ; release qualification measures both, plus the profile’s plugin storage and first-launch latency. The runtime trades more application files for eliminating core package installation on the user’s machine. ## Updates diff --git a/apps/desktop/README.zh.md b/apps/desktop/README.zh.md index dc3283bb00..fc240b9f03 100644 --- a/apps/desktop/README.zh.md +++ b/apps/desktop/README.zh.md @@ -398,6 +398,8 @@ pnpm run prepare:desktop macOS 打包在组装 App 时、代码签名前写入 `Contents/Resources/app-update.yml`,供并行 ZIP 与 DMG 路线使用的目录构建也执行此操作。签名钩子验证准确的更新源和 updater 缓存目录。写入发布完成记录前,流程会再次检查两条路线的副本和最终移入的 App;配置缺失或不匹配会阻止移入产物,因而也会阻止上传。 +所有 Koffi 使用方(包括私有 Desktop Host)固定使用 `3.1.1`;`pnpm run constraints` 检查每个工作区的声明。`prepare:dsh` 根据打包后的 manifest 生成独立于仓库锁文件的新生产锁文件,并在安装前拒绝缺失 Koffi 或包含其他版本 Koffi JavaScript/原生包的结果。升级前须验证不含可选预编译包的源码构建和打包后的生产安装,再同步更新所有使用方及共享的[版本检查](../../scripts/koffi-policy.ts)。 + 未压缩产物包含 Electron、物化后的 dsh 生产依赖树、pnpm,以及壳应用。安装包大小与文件系统占用不同;发布验收需要测量两者,以及 profile 插件存储和首次启动耗时。此布局用更多应用内文件换取消除用户机器上的核心包安装过程。 ## 更新 diff --git a/apps/desktop/scripts/prepare-dsh.ts b/apps/desktop/scripts/prepare-dsh.ts index 442e01757e..c11e9b6301 100644 --- a/apps/desktop/scripts/prepare-dsh.ts +++ b/apps/desktop/scripts/prepare-dsh.ts @@ -32,6 +32,7 @@ import { import { desktopTargetPlatform, resolveDesktopBuildTarget, resolveDesktopTargetBuildPaths } from './desktop-build-paths.mjs' import { desktopRuntimeFileExclusion } from './runtime-file-policy.ts' import { selectOfficeEngine } from '../../../scripts/libreoffice-packages.mjs' +import { verifyKoffiLockfile } from '../../../scripts/koffi-policy.ts' const APP_ROOT = resolve(import.meta.dirname, '..') const BUILD_PATHS = resolveDesktopTargetBuildPaths() @@ -123,10 +124,9 @@ async function main(): Promise { createRuntimeProjectMetadata(BUILD_ROOT, release) }) await packagingStep(process.env.DSH_DESKTOP_PACKAGING_RUN_DIR, 'runtime:lockfile', () => runPnpm(['install', '--lockfile-only'])) - verifyDesktopCoreLockfile( - readFileSync(join(BUILD_ROOT, 'pnpm-lock.yaml'), 'utf8'), - readDesktopCorePackageSet(BUILD_ROOT, release.version), - ) + const lockfile = readFileSync(join(BUILD_ROOT, 'pnpm-lock.yaml'), 'utf8') + verifyDesktopCoreLockfile(lockfile, readDesktopCorePackageSet(BUILD_ROOT, release.version)) + verifyKoffiLockfile(lockfile) await packagingStep(process.env.DSH_DESKTOP_PACKAGING_RUN_DIR, 'runtime:install', () => runPnpm(['install', '--prod', '--frozen-lockfile', '--trust-lockfile'])) const packageSet = readDesktopCorePackageSet(BUILD_ROOT, release.version) const targetName = resolveDesktopBuildTarget() diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b5c2234db..3cd66adcaf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -733,7 +733,7 @@ importers: specifier: ^0.1.1 version: 0.1.1 koffi: - specifier: ^3.1.0 + specifier: 3.1.1 version: 3.1.1 devDependencies: '@deepseek-ai/cordis-plugin-include': diff --git a/scripts/check-workspace-constraints.spec.ts b/scripts/check-workspace-constraints.spec.ts index 3307aa3956..ea589e2812 100644 --- a/scripts/check-workspace-constraints.spec.ts +++ b/scripts/check-workspace-constraints.spec.ts @@ -10,6 +10,7 @@ import { } from './experimental-package-policy.ts' import { checkDshFamilyVersion, + checkKoffiVersions, checkWorkspaceManifest, checkWorkspaceProtocol, checkExperimentalDependencyIsolation, @@ -76,6 +77,24 @@ describe('workspace dependency ranges', () => { }) }) +describe('Koffi version alignment', () => { + it.each(['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const)( + 'requires the qualified exact version in %s', (section) => { + const consumer = (version: string): WorkspaceManifest => ({ + dir: 'apps/desktop-host', + manifest: { name: 'private-host', private: true, [section]: { koffi: version } }, + }) + expect(checkKoffiVersions([consumer('3.1.1')])).toEqual([]) + for (const version of ['^3.1.0', '^3.1.1', '~3.1.1', '*', '3.3.2']) { + expect(checkKoffiVersions([consumer(version)])).toEqual([ + `private-host: ${section}.koffi must use 3.1.1, got ${version}`, + ]) + } + expect(checkKoffiVersions([{ dir: '.', manifest: { [section]: { unrelated: '^1.0.0' } } }])).toEqual([]) + }, + ) +}) + describe('workspace manifest discovery', () => { it('checks root, app, runtime, tooling, and newly declared members while honoring exclusions', () => { const root = mkdtempSync(join(tmpdir(), 'dsh-workspace-ranges-')) @@ -89,12 +108,14 @@ describe('workspace manifest discovery', () => { mkdirSync(join(root, dir), { recursive: true }) writeFileSync(join(root, dir, 'package.json'), JSON.stringify(dir === 'packages/core/runtime' ? { name: '@deepseek-ai/dsh-runtime' } - : { dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^' } })) + : { dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^', koffi: '^3.1.0' } })) } const manifests = readWorkspaceManifests(root) expect(manifests.map(entry => entry.dir).sort()).toEqual([...consumers, 'packages/core/runtime'].sort()) expect(checkWorkspaceProtocol(manifests).sort()).toEqual(consumers.map(dir => `${dir}: dependencies.@deepseek-ai/dsh-runtime must use workspace:*, got workspace:^`).sort()) + expect(checkKoffiVersions(manifests).sort()).toEqual(consumers.map(dir => + `${dir}: dependencies.koffi must use 3.1.1, got ^3.1.0`).sort()) }) it.each(['', 'null', '{}', 'packages: []', 'packages: [false]', 'packages: [""]', 'packages: wrong'])( diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index 13deaa24d9..c57affd34e 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -17,6 +17,7 @@ import { hasTypertRemoteNavigation, isForbiddenPublicationFile } from './publica import type { DshBundleManifest } from '../packages/util/package-manifest/src/types.ts' import { OPTIONAL_BUNDLES, bundlePatchFiles } from '../packages/boot/app-boot/src/profile.ts' import { collectProjectReferenceFaceViolations } from './project-reference-faces.ts' +import { KOFFI_VERSION } from './koffi-policy.ts' const root = resolve(import.meta.dirname, '..') // Publication rules cover these package trees; dependency rules read all pnpm members. @@ -613,6 +614,24 @@ export function checkWorkspaceProtocol(manifests: readonly WorkspaceManifest[]): return errors } +/** + * Require the qualified Koffi pin in every workspace, including private applications. + * @param manifests - Root and all declared workspace manifests. + * @returns Diagnostics for declarations that could install a different Koffi version. + */ +export function checkKoffiVersions(manifests: readonly WorkspaceManifest[]): string[] { + const errors: string[] = [] + for (const { dir, manifest } of manifests) { + for (const section of dependencySections) { + const version = manifest[section]?.koffi + if (version !== undefined && version !== KOFFI_VERSION) { + errors.push(`${manifest.name ?? dir}: ${section}.koffi must use ${KOFFI_VERSION}, got ${version}`) + } + } + } + return errors +} + /** Run the repository constraint gate. */ export function main(): void { const manifests = readWorkspaceManifests(root) @@ -620,6 +639,7 @@ export function main(): void { ...checkRepositoryVersion(), ...workspaceManifests().flatMap(checkWorkspaceManifest), ...checkWorkspaceProtocol(manifests), + ...checkKoffiVersions(manifests), ...checkExperimentalDependencyIsolation(manifests), ...checkHierarchyShape(), ...collectProjectReferenceFaceViolations(root), diff --git a/scripts/koffi-policy.spec.ts b/scripts/koffi-policy.spec.ts new file mode 100644 index 0000000000..d7dc87fdde --- /dev/null +++ b/scripts/koffi-policy.spec.ts @@ -0,0 +1,39 @@ +/** Koffi resolution checks for freshly generated Desktop lockfiles. */ + +import { dump } from 'js-yaml' +import { describe, expect, it } from 'vitest' +import { verifyKoffiLockfile } from './koffi-policy.ts' + +function lockfile(...packages: string[]): string { + return dump({ lockfileVersion: '9.0', packages: Object.fromEntries(packages.map(name => [name, {}])) }) +} + +describe('Desktop Koffi lockfile', () => { + it('accepts the qualified JavaScript and platform packages alongside unrelated dependencies', () => { + expect(() => { + verifyKoffiLockfile(lockfile( + 'koffi@3.1.1', '@koromix/koffi-darwin-arm64@3.1.1', '@koromix/koffi-win32-x64@3.1.1', 'unrelated@3.3.2', + )) + }).not.toThrow() + expect(() => { verifyKoffiLockfile(lockfile('koffi@3.1.1')) }).not.toThrow() + }) + + it.each(['koffi@3.3.2', '@koromix/koffi-darwin-arm64@3.3.2', '@koromix/koffi-win32-x64@3.3.2'])( + 'rejects an additional divergent resolution: %s', (entry) => { + expect(() => { verifyKoffiLockfile(lockfile('koffi@3.1.1', entry)) }) + .toThrow(`lockfile resolved ${entry}; all Koffi packages must use 3.1.1`) + }, + ) + + it.each([lockfile(), lockfile('koffi@3.3.2'), lockfile('@koromix/koffi-linux-x64@3.1.1')])( + 'requires the qualified JavaScript package: %s', (text) => { + expect(() => { verifyKoffiLockfile(text) }).toThrow('lockfile must resolve koffi@3.1.1') + }, + ) + + it.each(['', '{}', 'packages: []', 'packages: null', 'packages: invalid'])( + 'rejects a missing or invalid package mapping: %s', (text) => { + expect(() => { verifyKoffiLockfile(text) }).toThrow('lockfile must contain a packages mapping') + }, + ) +}) diff --git a/scripts/koffi-policy.ts b/scripts/koffi-policy.ts new file mode 100644 index 0000000000..404c31476d --- /dev/null +++ b/scripts/koffi-policy.ts @@ -0,0 +1,29 @@ +/** Shared Koffi pin for workspace declarations and fresh Desktop production installs. */ + +import { load as loadYaml } from 'js-yaml' + +/** Version qualified for source builds when optional native prebuilts are omitted. */ +export const KOFFI_VERSION = '3.1.1' + +/** + * Reject missing or divergent Koffi resolutions before installing the Desktop runtime. + * @param lockfile - Freshly generated pnpm lockfile text. + * @throws When Koffi is absent or its JavaScript or native packages use another version. + */ +export function verifyKoffiLockfile(lockfile: string): void { + const data: unknown = loadYaml(lockfile) + if (typeof data !== 'object' || data === null || !('packages' in data) + || typeof data.packages !== 'object' || data.packages === null || Array.isArray(data.packages)) { + throw new Error('Koffi: lockfile must contain a packages mapping') + } + const packages = Object.keys(data.packages) + if (!packages.includes(`koffi@${KOFFI_VERSION}`)) { + throw new Error(`Koffi: lockfile must resolve koffi@${KOFFI_VERSION}`) + } + for (const entry of packages) { + const match = /^(koffi|@koromix\/koffi-[^@]+)@(.+)$/u.exec(entry) + if (match !== null && match[2] !== KOFFI_VERSION) { + throw new Error(`Koffi: lockfile resolved ${entry}; all Koffi packages must use ${KOFFI_VERSION}`) + } + } +} From 8d4503f3f06b421b07e7005d287bbfba26ed3991 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 30 Sep 2026 22:15:39 +0800 Subject: [PATCH 2/5] fix(desktop): preserve and verify production dependency resolutions --- apps/desktop/README.i18n.yaml | 4 +- apps/desktop/README.md | 4 +- apps/desktop/README.zh.md | 4 +- apps/desktop/scripts/dependency-lock.ts | 165 +++++++++++++++++++ apps/desktop/scripts/prepare-dsh.ts | 7 +- apps/desktop/src/core-package-set.ts | 24 --- apps/desktop/tests/core-package-set.spec.ts | 18 -- apps/desktop/tests/dependency-lock.spec.ts | 172 ++++++++++++++++++++ scripts/check-workspace-constraints.ts | 3 +- scripts/koffi-policy.spec.ts | 39 ----- scripts/koffi-policy.ts | 29 ---- 11 files changed, 350 insertions(+), 119 deletions(-) create mode 100644 apps/desktop/scripts/dependency-lock.ts create mode 100644 apps/desktop/tests/dependency-lock.spec.ts delete mode 100644 scripts/koffi-policy.spec.ts delete mode 100644 scripts/koffi-policy.ts diff --git a/apps/desktop/README.i18n.yaml b/apps/desktop/README.i18n.yaml index b280b215fc..cbfd20f8f8 100644 --- a/apps/desktop/README.i18n.yaml +++ b/apps/desktop/README.i18n.yaml @@ -57,8 +57,8 @@ en: f176a8b1c7de3064 zh: 6ea2dbe6bb808c34 /deepseek-harness-desktop/package/windows-ev-signing: - en: 7a049a4cd52604b3 - zh: cd73f9c96c6a9984 + en: 8408737b507cc3c1 + zh: 0b450629d3d5ae14 /deepseek-harness-desktop/updates: en: d0df867b69cbffa4 zh: eeb47b79b86fe5ee diff --git a/apps/desktop/README.md b/apps/desktop/README.md index ca7b97c8a2..745a4723c6 100644 --- a/apps/desktop/README.md +++ b/apps/desktop/README.md @@ -396,7 +396,9 @@ Every package command builds the repository, packs the first-party production cl macOS packaging writes `Contents/Resources/app-update.yml` while assembling the App and before code signing, including the directory build that feeds the parallel ZIP and DMG lanes. The signing hook verifies the exact feed and updater cache directory. Both lane copies and the promoted App are checked again before the release completion record is written; a missing or mismatched configuration prevents artifact promotion and therefore prevents upload. -Koffi consumers, including the private Desktop Host, pin `3.1.1`; `pnpm run constraints` checks every workspace declaration. `prepare:dsh` generates a fresh production lockfile from the packed manifests, independently of the repository lockfile, and rejects missing Koffi or any other Koffi JavaScript/native package version before installation. Upgrade all consumers and the shared [version check](../../scripts/koffi-policy.ts) together after qualifying source builds without optional prebuilts and the packed production install. +Koffi consumers, including the private Desktop Host, pin `3.1.1`; `pnpm run constraints` checks every workspace declaration. Upgrade all consumers together after qualifying source builds without optional prebuilts and the packed production install. + +`prepare:dsh` seeds production resolution from the repository lockfile and carries its overrides and patch files into the disposable build project. The [dependency check](scripts/dependency-lock.ts) requires every registry package version, integrity and applied patch to match that baseline before installation; dependency snapshots must resolve completely. First-party packages must use the verified local tarballs. Optional workspace platform packages omitted from those tarballs use their exact workspace version from the registry. Existing locked versions and peer contexts are permitted, so unrelated major versions need not be forced together. Update and qualify repository dependencies before changing the production graph. An unpacked artifact contains Electron, the materialized dsh production tree, pnpm, and the shell application. Installer size and filesystem size differ; release qualification measures both, plus the profile’s plugin storage and first-launch latency. The runtime trades more application files for eliminating core package installation on the user’s machine. diff --git a/apps/desktop/README.zh.md b/apps/desktop/README.zh.md index fc240b9f03..20f6adf5f0 100644 --- a/apps/desktop/README.zh.md +++ b/apps/desktop/README.zh.md @@ -398,7 +398,9 @@ pnpm run prepare:desktop macOS 打包在组装 App 时、代码签名前写入 `Contents/Resources/app-update.yml`,供并行 ZIP 与 DMG 路线使用的目录构建也执行此操作。签名钩子验证准确的更新源和 updater 缓存目录。写入发布完成记录前,流程会再次检查两条路线的副本和最终移入的 App;配置缺失或不匹配会阻止移入产物,因而也会阻止上传。 -所有 Koffi 使用方(包括私有 Desktop Host)固定使用 `3.1.1`;`pnpm run constraints` 检查每个工作区的声明。`prepare:dsh` 根据打包后的 manifest 生成独立于仓库锁文件的新生产锁文件,并在安装前拒绝缺失 Koffi 或包含其他版本 Koffi JavaScript/原生包的结果。升级前须验证不含可选预编译包的源码构建和打包后的生产安装,再同步更新所有使用方及共享的[版本检查](../../scripts/koffi-policy.ts)。 +所有 Koffi 使用方(包括私有 Desktop Host)固定使用 `3.1.1`;`pnpm run constraints` 检查每个工作区的声明。升级前须验证不含可选预编译包的源码构建和打包后的生产安装,再同步更新所有使用方。 + +`prepare:dsh` 以仓库锁文件作为生产依赖解析的起点,并将其中的 overrides 和补丁文件带入临时构建项目。[依赖检查](scripts/dependency-lock.ts)在安装前要求每个 registry 包的版本、完整性信息和实际应用的补丁与此基准一致,依赖快照中的引用必须完整。第一方包必须使用已验证的本地 tarball。未包含在这些 tarball 中的可选工作区平台包从 registry 获取,但版本固定为其工作区版本。允许仓库已锁定的多版本及 peer 上下文,无需强行合并不同主版本。修改生产依赖图前须先更新并验证仓库依赖。 未压缩产物包含 Electron、物化后的 dsh 生产依赖树、pnpm,以及壳应用。安装包大小与文件系统占用不同;发布验收需要测量两者,以及 profile 插件存储和首次启动耗时。此布局用更多应用内文件换取消除用户机器上的核心包安装过程。 diff --git a/apps/desktop/scripts/dependency-lock.ts b/apps/desktop/scripts/dependency-lock.ts new file mode 100644 index 0000000000..0dfa05dcc3 --- /dev/null +++ b/apps/desktop/scripts/dependency-lock.ts @@ -0,0 +1,165 @@ +/** Preserve repository dependency resolutions and patches in the packed Desktop runtime. */ + +import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' +import { join, resolve } from 'node:path' +import { isDeepStrictEqual } from 'node:util' +import { dump, load } from 'js-yaml' +import { readWorkspaceManifests } from '../../../scripts/check-workspace-constraints.ts' +import { desktopCorePackageSpec, type DesktopCorePackageSet } from '../src/core-package-set.ts' + +function mapping(value: unknown, subject: string): Record { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new Error(`desktop dependencies: ${subject} must be a mapping`) + } + return value as Record +} + +function strings(value: unknown, subject: string): Record { + return Object.fromEntries(Object.entries(mapping(value, subject)).map(([key, entry]) => { + if (typeof entry !== 'string') throw new Error(`desktop dependencies: ${subject}.${key} must be a string`) + return [key, entry] + })) +} + +function parseLockfile(text: string, subject: string) { + const data = mapping(load(text), subject) + if (data.lockfileVersion !== '9.0') throw new Error(`desktop dependencies: ${subject} must use lockfile version 9.0`) + const packages = mapping(data.packages, `${subject}.packages`) + if (Object.keys(packages).length === 0) throw new Error(`desktop dependencies: ${subject}.packages must not be empty`) + const snapshots = mapping(data.snapshots, `${subject}.snapshots`) + const patchedDependencies = strings(data.patchedDependencies ?? {}, `${subject}.patchedDependencies`) + return { data, packages, snapshots, patchedDependencies } +} + +function dependencyPolicy(repositoryRoot: string, packageSet: DesktopCorePackageSet) { + const lock = parseLockfile(readFileSync(join(repositoryRoot, 'pnpm-lock.yaml'), 'utf8'), 'repository lockfile') + const workspace = mapping(load(readFileSync(join(repositoryRoot, 'pnpm-workspace.yaml'), 'utf8')), 'repository workspace') + const patches = strings(workspace.patchedDependencies ?? {}, 'repository workspace.patchedDependencies') + const overrides = strings(workspace.overrides ?? {}, 'repository workspace.overrides') + const members = new Map(readWorkspaceManifests(repositoryRoot).map(entry => [entry.manifest.name, entry.manifest])) + const packed = new Set(packageSet.packages.map(entry => entry.name)) + const optionalWorkspaceVersions: Record = {} + for (const entry of packageSet.packages) { + const manifest = members.get(entry.name) + if (manifest === undefined) throw new Error(`desktop dependencies: ${entry.name} is not a workspace member`) + for (const name of Object.keys(manifest.optionalDependencies ?? {})) { + const optional = members.get(name) + if (packed.has(name) || optional === undefined) continue + if (optional.version === undefined) throw new Error(`desktop dependencies: ${name} has no workspace version`) + optionalWorkspaceVersions[name] = optional.version + } + } + return { lock, patches, overrides, optionalWorkspaceVersions } +} + +/** + * Seed the disposable production project with repository resolutions and patch files. + * @param projectDir - Staged project containing local tarballs and its generated workspace configuration. + * @param repositoryRoot - Checkout whose lockfile and patches qualified those tarballs. + * @param packageSet - Verified local first-party tarballs. + */ +export function prepareDesktopDependencyLock(projectDir: string, repositoryRoot: string, packageSet: DesktopCorePackageSet): void { + const policy = dependencyPolicy(repositoryRoot, packageSet) + const path = join(projectDir, 'pnpm-workspace.yaml') + const workspace = mapping(load(readFileSync(path, 'utf8')), 'production workspace') + workspace.overrides = { + ...policy.overrides, + ...policy.optionalWorkspaceVersions, + ...strings(workspace.overrides ?? {}, 'production workspace.overrides'), + } + const patchedDependencies: Record = {} + const patchDir = 'dependency-patches' + mkdirSync(join(projectDir, patchDir), { recursive: true }) + for (const [index, [name, source]] of Object.entries(policy.patches).sort(([left], [right]) => left.localeCompare(right)).entries()) { + const destination = `${patchDir}/${String(index)}.patch` + copyFileSync(resolve(repositoryRoot, source), join(projectDir, destination)) + patchedDependencies[name] = destination + } + workspace.patchedDependencies = patchedDependencies + // The repository also patches build-only dependencies absent from the production graph. + workspace.allowUnusedPatches = true + writeFileSync(path, dump(workspace)) + writeFileSync(join(projectDir, 'pnpm-lock.yaml'), dump({ + ...policy.lock.data, + settings: { ...mapping(policy.lock.data.settings, 'repository lockfile.settings'), autoInstallPeers: false }, + overrides: workspace.overrides, + importers: { '.': {} }, + })) +} + +/** + * Reject production resolutions outside the repository lock and verified local package set. + * Existing repository versions, including distinct compatible dependency trees, remain permitted. + * @param text - Production lockfile generated from the seeded project. + * @param repositoryRoot - Checkout supplying the dependency and patch baseline. + * @param packageSet - Verified local first-party tarballs. + * @throws When a package version, integrity, local tarball, or applied patch differs from its baseline. + */ +export function verifyDesktopDependencyLock(text: string, repositoryRoot: string, packageSet: DesktopCorePackageSet): void { + const policy = dependencyPolicy(repositoryRoot, packageSet) + const actual = parseLockfile(text, 'production lockfile') + const packed = new Map(packageSet.packages.map(entry => [entry.name, entry])) + const errors: string[] = [] + for (const [key, value] of Object.entries(actual.packages)) { + const match = /^((?:@[^/]+\/)?[^@]+)@(.+)$/u.exec(key) + const name = match?.[1] + const version = match?.[2] + if (name === undefined || version === undefined) { + errors.push(`invalid package identity ${key}`) + continue + } + const resolution = mapping(mapping(value, key).resolution, `${key}.resolution`) + const local = packed.get(name) + if (local !== undefined) { + const spec = desktopCorePackageSpec(local).replace('file:./', 'file:') + if (version !== spec || resolution.integrity !== local.integrity || resolution.tarball !== spec) { + errors.push(`${key} must resolve to the verified local tarball ${spec}`) + } + continue + } + const expected = policy.lock.packages[key] + if (expected === undefined) { + if (policy.optionalWorkspaceVersions[name] !== version || typeof resolution.integrity !== 'string') { + errors.push(`${key} is absent from the repository lockfile; update and qualify the repository dependency first`) + } + continue + } + if (!isDeepStrictEqual(resolution, mapping(expected, `repository ${key}`).resolution)) { + errors.push(`${key} resolution differs from the repository lockfile`) + } + } + const snapshots = Object.keys(actual.snapshots) + for (const key of Object.keys(actual.packages)) { + const patch = policy.lock.patchedDependencies[key] + if (actual.patchedDependencies[key] !== patch) errors.push(`${key} patch differs from the repository lockfile`) + const instances = snapshots.filter(snapshot => snapshot.split('(')[0] === key) + if (instances.length === 0) errors.push(`${key} has no dependency snapshot`) + for (const snapshot of instances) { + if (/\(patch_hash=([^)]+)\)/u.exec(snapshot)?.[1] !== patch) { + errors.push(`${snapshot} does not apply the repository patch`) + } + } + } + const importers = mapping(actual.data.importers, 'production lockfile.importers') + if (importers['.'] === undefined) errors.push('missing production root importer') + for (const [owner, value] of [...Object.entries(importers), ...Object.entries(actual.snapshots)]) { + const entry = mapping(value, owner) + for (const section of ['dependencies', 'optionalDependencies']) { + for (const [name, dependency] of Object.entries(mapping(entry[section] ?? {}, `${owner}.${section}`))) { + const reference = typeof dependency === 'string' ? dependency : mapping(dependency, `${owner}.${name}`).version + if (typeof reference !== 'string' + || (actual.snapshots[`${name}@${reference}`] === undefined && actual.snapshots[reference] === undefined)) { + errors.push(`${owner}.${section}.${name} has no resolved dependency snapshot`) + } + } + } + } + for (const snapshot of snapshots) { + if (actual.packages[snapshot.split('(')[0] ?? ''] === undefined) errors.push(`${snapshot} has no package resolution`) + } + for (const entry of packageSet.packages) { + const key = `${entry.name}@${desktopCorePackageSpec(entry).replace('file:./', 'file:')}` + if (actual.packages[key] === undefined) errors.push(`missing local package ${entry.name}`) + } + if (errors.length > 0) throw new Error(`desktop dependencies:\n${errors.join('\n')}`) +} diff --git a/apps/desktop/scripts/prepare-dsh.ts b/apps/desktop/scripts/prepare-dsh.ts index c11e9b6301..17005a6c23 100644 --- a/apps/desktop/scripts/prepare-dsh.ts +++ b/apps/desktop/scripts/prepare-dsh.ts @@ -15,7 +15,6 @@ import { DESKTOP_PACKAGES_DIR, DESKTOP_PACKAGE_SET_FILE, readDesktopCorePackageSet, - verifyDesktopCoreLockfile, } from '../src/core-package-set.ts' import { smokePrimaryRuntime } from './prepare-primary-runtime.ts' import { smokePreparedRuntime } from './smoke-prepared-runtime.ts' @@ -32,7 +31,7 @@ import { import { desktopTargetPlatform, resolveDesktopBuildTarget, resolveDesktopTargetBuildPaths } from './desktop-build-paths.mjs' import { desktopRuntimeFileExclusion } from './runtime-file-policy.ts' import { selectOfficeEngine } from '../../../scripts/libreoffice-packages.mjs' -import { verifyKoffiLockfile } from '../../../scripts/koffi-policy.ts' +import { prepareDesktopDependencyLock, verifyDesktopDependencyLock } from './dependency-lock.ts' const APP_ROOT = resolve(import.meta.dirname, '..') const BUILD_PATHS = resolveDesktopTargetBuildPaths() @@ -122,11 +121,11 @@ async function main(): Promise { copyFileSync(join(PACKAGE_SET_ROOT, DESKTOP_PACKAGE_SET_FILE), join(BUILD_ROOT, DESKTOP_PACKAGE_SET_FILE)) cpSync(join(PACKAGE_SET_ROOT, DESKTOP_PACKAGES_DIR), join(BUILD_ROOT, DESKTOP_PACKAGES_DIR), { recursive: true }) createRuntimeProjectMetadata(BUILD_ROOT, release) + prepareDesktopDependencyLock(BUILD_ROOT, resolve(APP_ROOT, '..', '..'), readDesktopCorePackageSet(BUILD_ROOT, release.version)) }) await packagingStep(process.env.DSH_DESKTOP_PACKAGING_RUN_DIR, 'runtime:lockfile', () => runPnpm(['install', '--lockfile-only'])) const lockfile = readFileSync(join(BUILD_ROOT, 'pnpm-lock.yaml'), 'utf8') - verifyDesktopCoreLockfile(lockfile, readDesktopCorePackageSet(BUILD_ROOT, release.version)) - verifyKoffiLockfile(lockfile) + verifyDesktopDependencyLock(lockfile, resolve(APP_ROOT, '..', '..'), readDesktopCorePackageSet(BUILD_ROOT, release.version)) await packagingStep(process.env.DSH_DESKTOP_PACKAGING_RUN_DIR, 'runtime:install', () => runPnpm(['install', '--prod', '--frozen-lockfile', '--trust-lockfile'])) const packageSet = readDesktopCorePackageSet(BUILD_ROOT, release.version) const targetName = resolveDesktopBuildTarget() diff --git a/apps/desktop/src/core-package-set.ts b/apps/desktop/src/core-package-set.ts index 0c148e223f..41711d6613 100644 --- a/apps/desktop/src/core-package-set.ts +++ b/apps/desktop/src/core-package-set.ts @@ -157,27 +157,3 @@ export function verifyDesktopCorePackageSet( } return packageSet } - -function escapeRegExp(value: string): string { - return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&') -} - -/** - * Reject a lockfile that resolved any packaged core name through a registry version. - * @param lockfile - Generated pnpm lockfile text. - * @param packageSet - Verified local core package set. - */ -export function verifyDesktopCoreLockfile( - lockfile: string, - packageSet: DesktopCorePackageSet, -): void { - for (const record of packageSet.packages) { - const registryResolution = new RegExp( - `^ ['"]?${escapeRegExp(record.name)}@${escapeRegExp(record.version)}(?:\\([^\\r\\n]*\\))?['"]?:`, - 'mu', - ) - if (registryResolution.test(lockfile)) { - throw new Error(`desktop package set: lockfile resolved ${record.name}@${record.version} outside the local package set`) - } - } -} diff --git a/apps/desktop/tests/core-package-set.spec.ts b/apps/desktop/tests/core-package-set.spec.ts index 0b28a2ec3d..f84effa614 100644 --- a/apps/desktop/tests/core-package-set.spec.ts +++ b/apps/desktop/tests/core-package-set.spec.ts @@ -9,7 +9,6 @@ import { desktopCorePackageOverrides, desktopDshPackageSpec, parseDesktopCorePackageSet, - verifyDesktopCoreLockfile, verifyDesktopCorePackageSet, type DesktopCorePackageRecord, } from '../src/core-package-set.ts' @@ -83,21 +82,4 @@ describe('desktop core package set', () => { expect(() => verifyDesktopCorePackageSet(root, '1.2.3')).toThrow(/does not match its descriptor/u) }) - it('rejects registry resolutions for names supplied by the local package set', () => { - const dsh = record('@deepseek-ai/dsh', 'dsh.tgz', Buffer.from('dsh')) - const host = record('@deepseek-ai/dsh-desktop-host', 'host.tgz', Buffer.from('host')) - const packageSet = parseDesktopCorePackageSet({ schemaVersion: 1, packages: [dsh, host] }) - expect(() => { - verifyDesktopCoreLockfile( - "packages:\n '@deepseek-ai/dsh@file:desktop-packages/dsh.tgz':\n resolution: {}\n", - packageSet, - ) - }).not.toThrow() - expect(() => { - verifyDesktopCoreLockfile( - "packages:\n '@deepseek-ai/dsh@1.2.3':\n resolution: {integrity: sha512-registry}\n", - packageSet, - ) - }).toThrow(/outside the local package set/u) - }) }) diff --git a/apps/desktop/tests/dependency-lock.spec.ts b/apps/desktop/tests/dependency-lock.spec.ts new file mode 100644 index 0000000000..3a4b93f880 --- /dev/null +++ b/apps/desktop/tests/dependency-lock.spec.ts @@ -0,0 +1,172 @@ +/** Repository dependency and patch preservation in a disposable Desktop install. */ + +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { dump, load } from 'js-yaml' +import { describe, expect, it, onTestFinished } from 'vitest' +import { prepareDesktopDependencyLock, verifyDesktopDependencyLock } from '../scripts/dependency-lock.ts' +import { desktopCorePackageOverrides, desktopCorePackageSpec, type DesktopCorePackageSet } from '../src/core-package-set.ts' + +interface Lockfile { + lockfileVersion: string + settings: { autoInstallPeers: boolean } + importers: Record }> + packages: Record + snapshots: Record }> + patchedDependencies: Record +} + +function fixture() { + const root = mkdtempSync(join(tmpdir(), 'dsh-dependency-lock-')) + onTestFinished(() => { rmSync(root, { recursive: true, force: true }) }) + const project = join(root, 'project') + mkdirSync(project) + mkdirSync(join(root, 'patches')) + writeFileSync(join(root, 'package.json'), '{}') + const members = [ + ['apps/cli', { name: '@deepseek-ai/dsh', version: '1.0.0' }], + ['apps/host', { name: '@deepseek-ai/dsh-desktop-host', version: '1.0.0', optionalDependencies: { '@test/native': '^1.0.0' } }], + ['native/linux', { name: '@test/native', version: '1.0.0' }], + ] as const + for (const [dir, manifest] of members) { + mkdirSync(join(root, dir), { recursive: true }) + writeFileSync(join(root, dir, 'package.json'), JSON.stringify(manifest)) + } + writeFileSync(join(root, 'patches/runtime.patch'), 'runtime patch\n') + writeFileSync(join(root, 'patches/build.patch'), 'build patch\n') + writeFileSync(join(root, 'pnpm-workspace.yaml'), dump({ + packages: ['apps/*', 'native/*'], + overrides: { '@deepseek-ai/dsh': 'link:apps/cli', 'parent>child': '1.0.0' }, + patchedDependencies: { 'library@1.0.0': 'patches/runtime.patch', 'build-only@1.0.0': 'patches/build.patch' }, + })) + const source: Lockfile = { + lockfileVersion: '9.0', settings: { autoInstallPeers: true }, importers: { '.': { dependencies: {} } }, + packages: { + 'library@1.0.0': { resolution: { integrity: 'sha512-one' } }, + 'library@2.0.0': { resolution: { integrity: 'sha512-two' } }, + 'build-only@1.0.0': { resolution: { integrity: 'sha512-build' } }, + }, + snapshots: { 'library@1.0.0(patch_hash=runtime)': {}, 'library@2.0.0': {}, 'build-only@1.0.0(patch_hash=build)': {} }, + patchedDependencies: { 'library@1.0.0': 'runtime', 'build-only@1.0.0': 'build' }, + } + writeFileSync(join(root, 'pnpm-lock.yaml'), dump(source)) + const set: DesktopCorePackageSet = { + schemaVersion: 1, + packages: members.slice(0, 2).map(([, manifest], index) => ({ + name: manifest.name, version: manifest.version, file: `${String(index)}.tgz`, bytes: 1, integrity: `sha512-local${String(index)}`, + })), + } + const local = Object.fromEntries(set.packages.map((entry) => { + const spec = desktopCorePackageSpec(entry).replace('file:./', 'file:') + return [`${entry.name}@${spec}`, { version: entry.version, resolution: { tarball: spec, integrity: entry.integrity } }] + })) + const actual: Lockfile = { + ...source, + importers: { '.': { dependencies: Object.fromEntries(set.packages.map((entry) => { + const spec = desktopCorePackageSpec(entry).replace('file:./', 'file:') + return [entry.name, { specifier: spec, version: spec }] + })) } }, + packages: { ...local, 'library@1.0.0': source.packages['library@1.0.0']!, 'library@2.0.0': source.packages['library@2.0.0']! }, + snapshots: { + ...Object.fromEntries(Object.keys(local).map(key => [key, { dependencies: { library: '1.0.0(patch_hash=runtime)', alias: 'library@2.0.0' } }])), + 'library@1.0.0(patch_hash=runtime)': {}, 'library@2.0.0': {}, + }, + patchedDependencies: { ...source.patchedDependencies }, + } + writeFileSync(join(project, 'pnpm-workspace.yaml'), dump({ + packages: ['.'], nodeLinker: 'hoisted', autoInstallPeers: false, + overrides: desktopCorePackageOverrides(set), allowBuilds: { library: true }, + })) + return { root, project, source, actual, set, localKey: Object.keys(local)[0]! } +} + +describe('Desktop dependency lock', () => { + it('seeds repository resolutions, overrides and patches while preserving the source checkout', () => { + const { root, project, source, set } = fixture() + prepareDesktopDependencyLock(project, root, set) + expect(load(readFileSync(join(project, 'pnpm-workspace.yaml'), 'utf8'))).toMatchObject({ + nodeLinker: 'hoisted', autoInstallPeers: false, allowBuilds: { library: true }, allowUnusedPatches: true, + overrides: { ...desktopCorePackageOverrides(set), '@test/native': '1.0.0', 'parent>child': '1.0.0' }, + patchedDependencies: { 'build-only@1.0.0': 'dependency-patches/0.patch', 'library@1.0.0': 'dependency-patches/1.patch' }, + }) + expect(readFileSync(join(project, 'dependency-patches/0.patch'), 'utf8')).toBe('build patch\n') + expect(readFileSync(join(project, 'dependency-patches/1.patch'), 'utf8')).toBe('runtime patch\n') + expect(load(readFileSync(join(project, 'pnpm-lock.yaml'), 'utf8'))).toMatchObject({ + packages: source.packages, snapshots: source.snapshots, patchedDependencies: source.patchedDependencies, + importers: { '.': {} }, settings: { autoInstallPeers: false }, + }) + expect(load(readFileSync(join(root, 'pnpm-lock.yaml'), 'utf8'))).toEqual(source) + }) + + it('accepts existing major versions, npm aliases and peer contexts without installing build-only dependencies', () => { + const { root, actual, set } = fixture() + actual.snapshots['library@2.0.0(peer@1.0.0)'] = {} + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).not.toThrow() + }) + + it.each(['another-library@1.0.0', 'library@3.0.0', '@scope/native@2.0.0'])( + 'rejects a new dependency or version: %s', (key) => { + const { root, actual, set } = fixture() + actual.packages[key] = { resolution: { integrity: 'sha512-unqualified' } } + actual.snapshots[key] = {} + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow(`${key} is absent from the repository lockfile`) + }, + ) + + it('rejects changed registry integrity', () => { + const { root, actual, set } = fixture() + actual.packages['library@2.0.0']!.resolution.integrity = 'sha512-changed' + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('resolution differs from the repository lockfile') + }) + + it('requires both patch metadata and the patched dependency snapshot', () => { + const { root, actual, set } = fixture() + delete actual.patchedDependencies['library@1.0.0'] + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('patch differs from the repository lockfile') + actual.patchedDependencies['library@1.0.0'] = 'runtime' + delete actual.snapshots['library@1.0.0(patch_hash=runtime)'] + actual.snapshots['library@1.0.0'] = {} + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('does not apply the repository patch') + }) + + it('rejects missing package metadata, dependency snapshots and local tarballs', () => { + const { root, actual, set, localKey } = fixture() + delete actual.packages['library@2.0.0'] + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('has no package resolution') + delete actual.snapshots['library@2.0.0'] + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('has no resolved dependency snapshot') + actual.packages = Object.fromEntries(Object.entries(actual.packages).filter(([key]) => key !== localKey)) + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('missing local package') + }) + + it.each(['1.0.0', '9.0.0'])( + 'rejects a registry copy of a locally packed package at version %s', (version) => { + const { root, actual, set } = fixture() + actual.packages[`@deepseek-ai/dsh@${version}`] = { resolution: { integrity: 'sha512-registry' } } + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('must resolve to the verified local tarball') + }, + ) + + it('rejects corrupted local tarball integrity', () => { + const { root, actual, set, localKey } = fixture() + actual.packages[localKey]!.resolution.integrity = 'sha512-corrupt' + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('must resolve to the verified local tarball') + }) + + it('allows unpacked optional workspace platforms only at their exact source version', () => { + const { root, actual, set } = fixture() + actual.packages['@test/native@1.0.0'] = { resolution: { integrity: 'sha512-platform' } } + actual.snapshots['@test/native@1.0.0'] = {} + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).not.toThrow() + actual.packages['@test/native@1.0.1'] = { resolution: { integrity: 'sha512-other-platform' } } + expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('@test/native@1.0.1 is absent') + }) + + it.each(['{}', 'lockfileVersion: "8.0"', 'lockfileVersion: "9.0"\npackages: {}', 'lockfileVersion: "9.0"\npackages: []'])( + 'rejects an invalid or empty production lockfile: %s', (text) => { + const { root, set } = fixture() + expect(() => { verifyDesktopDependencyLock(text, root, set) }).toThrow('desktop dependencies:') + }, + ) +}) diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index c57affd34e..a494ec1171 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -17,7 +17,6 @@ import { hasTypertRemoteNavigation, isForbiddenPublicationFile } from './publica import type { DshBundleManifest } from '../packages/util/package-manifest/src/types.ts' import { OPTIONAL_BUNDLES, bundlePatchFiles } from '../packages/boot/app-boot/src/profile.ts' import { collectProjectReferenceFaceViolations } from './project-reference-faces.ts' -import { KOFFI_VERSION } from './koffi-policy.ts' const root = resolve(import.meta.dirname, '..') // Publication rules cover these package trees; dependency rules read all pnpm members. @@ -552,6 +551,8 @@ function checkRepositoryVersion(): string[] { const dependencySections = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const /** Dependency sections present in an installed runtime. */ const runtimeDependencySections = ['dependencies', 'optionalDependencies', 'peerDependencies'] as const +/** Koffi version qualified for source builds without optional native prebuilts. */ +const KOFFI_VERSION = '3.1.1' /** * Prevent an official runtime from requiring an experimental package. The dsh installation's `dependencies` diff --git a/scripts/koffi-policy.spec.ts b/scripts/koffi-policy.spec.ts deleted file mode 100644 index d7dc87fdde..0000000000 --- a/scripts/koffi-policy.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** Koffi resolution checks for freshly generated Desktop lockfiles. */ - -import { dump } from 'js-yaml' -import { describe, expect, it } from 'vitest' -import { verifyKoffiLockfile } from './koffi-policy.ts' - -function lockfile(...packages: string[]): string { - return dump({ lockfileVersion: '9.0', packages: Object.fromEntries(packages.map(name => [name, {}])) }) -} - -describe('Desktop Koffi lockfile', () => { - it('accepts the qualified JavaScript and platform packages alongside unrelated dependencies', () => { - expect(() => { - verifyKoffiLockfile(lockfile( - 'koffi@3.1.1', '@koromix/koffi-darwin-arm64@3.1.1', '@koromix/koffi-win32-x64@3.1.1', 'unrelated@3.3.2', - )) - }).not.toThrow() - expect(() => { verifyKoffiLockfile(lockfile('koffi@3.1.1')) }).not.toThrow() - }) - - it.each(['koffi@3.3.2', '@koromix/koffi-darwin-arm64@3.3.2', '@koromix/koffi-win32-x64@3.3.2'])( - 'rejects an additional divergent resolution: %s', (entry) => { - expect(() => { verifyKoffiLockfile(lockfile('koffi@3.1.1', entry)) }) - .toThrow(`lockfile resolved ${entry}; all Koffi packages must use 3.1.1`) - }, - ) - - it.each([lockfile(), lockfile('koffi@3.3.2'), lockfile('@koromix/koffi-linux-x64@3.1.1')])( - 'requires the qualified JavaScript package: %s', (text) => { - expect(() => { verifyKoffiLockfile(text) }).toThrow('lockfile must resolve koffi@3.1.1') - }, - ) - - it.each(['', '{}', 'packages: []', 'packages: null', 'packages: invalid'])( - 'rejects a missing or invalid package mapping: %s', (text) => { - expect(() => { verifyKoffiLockfile(text) }).toThrow('lockfile must contain a packages mapping') - }, - ) -}) diff --git a/scripts/koffi-policy.ts b/scripts/koffi-policy.ts deleted file mode 100644 index 404c31476d..0000000000 --- a/scripts/koffi-policy.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** Shared Koffi pin for workspace declarations and fresh Desktop production installs. */ - -import { load as loadYaml } from 'js-yaml' - -/** Version qualified for source builds when optional native prebuilts are omitted. */ -export const KOFFI_VERSION = '3.1.1' - -/** - * Reject missing or divergent Koffi resolutions before installing the Desktop runtime. - * @param lockfile - Freshly generated pnpm lockfile text. - * @throws When Koffi is absent or its JavaScript or native packages use another version. - */ -export function verifyKoffiLockfile(lockfile: string): void { - const data: unknown = loadYaml(lockfile) - if (typeof data !== 'object' || data === null || !('packages' in data) - || typeof data.packages !== 'object' || data.packages === null || Array.isArray(data.packages)) { - throw new Error('Koffi: lockfile must contain a packages mapping') - } - const packages = Object.keys(data.packages) - if (!packages.includes(`koffi@${KOFFI_VERSION}`)) { - throw new Error(`Koffi: lockfile must resolve koffi@${KOFFI_VERSION}`) - } - for (const entry of packages) { - const match = /^(koffi|@koromix\/koffi-[^@]+)@(.+)$/u.exec(entry) - if (match !== null && match[2] !== KOFFI_VERSION) { - throw new Error(`Koffi: lockfile resolved ${entry}; all Koffi packages must use ${KOFFI_VERSION}`) - } - } -} From cc11f9145cc1716080eb35cd1c3d02ab579ae9a9 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 30 Sep 2026 23:11:09 +0800 Subject: [PATCH 3/5] fix(desktop): limit dependency alignment to Koffi pin --- apps/desktop/README.i18n.yaml | 4 +- apps/desktop/README.md | 4 - apps/desktop/README.zh.md | 4 - apps/desktop/scripts/dependency-lock.ts | 165 ------------------- apps/desktop/scripts/prepare-dsh.ts | 9 +- apps/desktop/src/core-package-set.ts | 24 +++ apps/desktop/tests/core-package-set.spec.ts | 18 ++ apps/desktop/tests/dependency-lock.spec.ts | 172 -------------------- scripts/check-workspace-constraints.spec.ts | 23 +-- scripts/check-workspace-constraints.ts | 21 --- 10 files changed, 50 insertions(+), 394 deletions(-) delete mode 100644 apps/desktop/scripts/dependency-lock.ts delete mode 100644 apps/desktop/tests/dependency-lock.spec.ts diff --git a/apps/desktop/README.i18n.yaml b/apps/desktop/README.i18n.yaml index cbfd20f8f8..6f4cf94723 100644 --- a/apps/desktop/README.i18n.yaml +++ b/apps/desktop/README.i18n.yaml @@ -57,8 +57,8 @@ en: f176a8b1c7de3064 zh: 6ea2dbe6bb808c34 /deepseek-harness-desktop/package/windows-ev-signing: - en: 8408737b507cc3c1 - zh: 0b450629d3d5ae14 + en: 8efe3498dbe8686d + zh: a88c16f20a9430f3 /deepseek-harness-desktop/updates: en: d0df867b69cbffa4 zh: eeb47b79b86fe5ee diff --git a/apps/desktop/README.md b/apps/desktop/README.md index 745a4723c6..13e742edcb 100644 --- a/apps/desktop/README.md +++ b/apps/desktop/README.md @@ -396,10 +396,6 @@ Every package command builds the repository, packs the first-party production cl macOS packaging writes `Contents/Resources/app-update.yml` while assembling the App and before code signing, including the directory build that feeds the parallel ZIP and DMG lanes. The signing hook verifies the exact feed and updater cache directory. Both lane copies and the promoted App are checked again before the release completion record is written; a missing or mismatched configuration prevents artifact promotion and therefore prevents upload. -Koffi consumers, including the private Desktop Host, pin `3.1.1`; `pnpm run constraints` checks every workspace declaration. Upgrade all consumers together after qualifying source builds without optional prebuilts and the packed production install. - -`prepare:dsh` seeds production resolution from the repository lockfile and carries its overrides and patch files into the disposable build project. The [dependency check](scripts/dependency-lock.ts) requires every registry package version, integrity and applied patch to match that baseline before installation; dependency snapshots must resolve completely. First-party packages must use the verified local tarballs. Optional workspace platform packages omitted from those tarballs use their exact workspace version from the registry. Existing locked versions and peer contexts are permitted, so unrelated major versions need not be forced together. Update and qualify repository dependencies before changing the production graph. - An unpacked artifact contains Electron, the materialized dsh production tree, pnpm, and the shell application. Installer size and filesystem size differ; release qualification measures both, plus the profile’s plugin storage and first-launch latency. The runtime trades more application files for eliminating core package installation on the user’s machine. ## Updates diff --git a/apps/desktop/README.zh.md b/apps/desktop/README.zh.md index 20f6adf5f0..dc3283bb00 100644 --- a/apps/desktop/README.zh.md +++ b/apps/desktop/README.zh.md @@ -398,10 +398,6 @@ pnpm run prepare:desktop macOS 打包在组装 App 时、代码签名前写入 `Contents/Resources/app-update.yml`,供并行 ZIP 与 DMG 路线使用的目录构建也执行此操作。签名钩子验证准确的更新源和 updater 缓存目录。写入发布完成记录前,流程会再次检查两条路线的副本和最终移入的 App;配置缺失或不匹配会阻止移入产物,因而也会阻止上传。 -所有 Koffi 使用方(包括私有 Desktop Host)固定使用 `3.1.1`;`pnpm run constraints` 检查每个工作区的声明。升级前须验证不含可选预编译包的源码构建和打包后的生产安装,再同步更新所有使用方。 - -`prepare:dsh` 以仓库锁文件作为生产依赖解析的起点,并将其中的 overrides 和补丁文件带入临时构建项目。[依赖检查](scripts/dependency-lock.ts)在安装前要求每个 registry 包的版本、完整性信息和实际应用的补丁与此基准一致,依赖快照中的引用必须完整。第一方包必须使用已验证的本地 tarball。未包含在这些 tarball 中的可选工作区平台包从 registry 获取,但版本固定为其工作区版本。允许仓库已锁定的多版本及 peer 上下文,无需强行合并不同主版本。修改生产依赖图前须先更新并验证仓库依赖。 - 未压缩产物包含 Electron、物化后的 dsh 生产依赖树、pnpm,以及壳应用。安装包大小与文件系统占用不同;发布验收需要测量两者,以及 profile 插件存储和首次启动耗时。此布局用更多应用内文件换取消除用户机器上的核心包安装过程。 ## 更新 diff --git a/apps/desktop/scripts/dependency-lock.ts b/apps/desktop/scripts/dependency-lock.ts deleted file mode 100644 index 0dfa05dcc3..0000000000 --- a/apps/desktop/scripts/dependency-lock.ts +++ /dev/null @@ -1,165 +0,0 @@ -/** Preserve repository dependency resolutions and patches in the packed Desktop runtime. */ - -import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' -import { join, resolve } from 'node:path' -import { isDeepStrictEqual } from 'node:util' -import { dump, load } from 'js-yaml' -import { readWorkspaceManifests } from '../../../scripts/check-workspace-constraints.ts' -import { desktopCorePackageSpec, type DesktopCorePackageSet } from '../src/core-package-set.ts' - -function mapping(value: unknown, subject: string): Record { - if (typeof value !== 'object' || value === null || Array.isArray(value)) { - throw new Error(`desktop dependencies: ${subject} must be a mapping`) - } - return value as Record -} - -function strings(value: unknown, subject: string): Record { - return Object.fromEntries(Object.entries(mapping(value, subject)).map(([key, entry]) => { - if (typeof entry !== 'string') throw new Error(`desktop dependencies: ${subject}.${key} must be a string`) - return [key, entry] - })) -} - -function parseLockfile(text: string, subject: string) { - const data = mapping(load(text), subject) - if (data.lockfileVersion !== '9.0') throw new Error(`desktop dependencies: ${subject} must use lockfile version 9.0`) - const packages = mapping(data.packages, `${subject}.packages`) - if (Object.keys(packages).length === 0) throw new Error(`desktop dependencies: ${subject}.packages must not be empty`) - const snapshots = mapping(data.snapshots, `${subject}.snapshots`) - const patchedDependencies = strings(data.patchedDependencies ?? {}, `${subject}.patchedDependencies`) - return { data, packages, snapshots, patchedDependencies } -} - -function dependencyPolicy(repositoryRoot: string, packageSet: DesktopCorePackageSet) { - const lock = parseLockfile(readFileSync(join(repositoryRoot, 'pnpm-lock.yaml'), 'utf8'), 'repository lockfile') - const workspace = mapping(load(readFileSync(join(repositoryRoot, 'pnpm-workspace.yaml'), 'utf8')), 'repository workspace') - const patches = strings(workspace.patchedDependencies ?? {}, 'repository workspace.patchedDependencies') - const overrides = strings(workspace.overrides ?? {}, 'repository workspace.overrides') - const members = new Map(readWorkspaceManifests(repositoryRoot).map(entry => [entry.manifest.name, entry.manifest])) - const packed = new Set(packageSet.packages.map(entry => entry.name)) - const optionalWorkspaceVersions: Record = {} - for (const entry of packageSet.packages) { - const manifest = members.get(entry.name) - if (manifest === undefined) throw new Error(`desktop dependencies: ${entry.name} is not a workspace member`) - for (const name of Object.keys(manifest.optionalDependencies ?? {})) { - const optional = members.get(name) - if (packed.has(name) || optional === undefined) continue - if (optional.version === undefined) throw new Error(`desktop dependencies: ${name} has no workspace version`) - optionalWorkspaceVersions[name] = optional.version - } - } - return { lock, patches, overrides, optionalWorkspaceVersions } -} - -/** - * Seed the disposable production project with repository resolutions and patch files. - * @param projectDir - Staged project containing local tarballs and its generated workspace configuration. - * @param repositoryRoot - Checkout whose lockfile and patches qualified those tarballs. - * @param packageSet - Verified local first-party tarballs. - */ -export function prepareDesktopDependencyLock(projectDir: string, repositoryRoot: string, packageSet: DesktopCorePackageSet): void { - const policy = dependencyPolicy(repositoryRoot, packageSet) - const path = join(projectDir, 'pnpm-workspace.yaml') - const workspace = mapping(load(readFileSync(path, 'utf8')), 'production workspace') - workspace.overrides = { - ...policy.overrides, - ...policy.optionalWorkspaceVersions, - ...strings(workspace.overrides ?? {}, 'production workspace.overrides'), - } - const patchedDependencies: Record = {} - const patchDir = 'dependency-patches' - mkdirSync(join(projectDir, patchDir), { recursive: true }) - for (const [index, [name, source]] of Object.entries(policy.patches).sort(([left], [right]) => left.localeCompare(right)).entries()) { - const destination = `${patchDir}/${String(index)}.patch` - copyFileSync(resolve(repositoryRoot, source), join(projectDir, destination)) - patchedDependencies[name] = destination - } - workspace.patchedDependencies = patchedDependencies - // The repository also patches build-only dependencies absent from the production graph. - workspace.allowUnusedPatches = true - writeFileSync(path, dump(workspace)) - writeFileSync(join(projectDir, 'pnpm-lock.yaml'), dump({ - ...policy.lock.data, - settings: { ...mapping(policy.lock.data.settings, 'repository lockfile.settings'), autoInstallPeers: false }, - overrides: workspace.overrides, - importers: { '.': {} }, - })) -} - -/** - * Reject production resolutions outside the repository lock and verified local package set. - * Existing repository versions, including distinct compatible dependency trees, remain permitted. - * @param text - Production lockfile generated from the seeded project. - * @param repositoryRoot - Checkout supplying the dependency and patch baseline. - * @param packageSet - Verified local first-party tarballs. - * @throws When a package version, integrity, local tarball, or applied patch differs from its baseline. - */ -export function verifyDesktopDependencyLock(text: string, repositoryRoot: string, packageSet: DesktopCorePackageSet): void { - const policy = dependencyPolicy(repositoryRoot, packageSet) - const actual = parseLockfile(text, 'production lockfile') - const packed = new Map(packageSet.packages.map(entry => [entry.name, entry])) - const errors: string[] = [] - for (const [key, value] of Object.entries(actual.packages)) { - const match = /^((?:@[^/]+\/)?[^@]+)@(.+)$/u.exec(key) - const name = match?.[1] - const version = match?.[2] - if (name === undefined || version === undefined) { - errors.push(`invalid package identity ${key}`) - continue - } - const resolution = mapping(mapping(value, key).resolution, `${key}.resolution`) - const local = packed.get(name) - if (local !== undefined) { - const spec = desktopCorePackageSpec(local).replace('file:./', 'file:') - if (version !== spec || resolution.integrity !== local.integrity || resolution.tarball !== spec) { - errors.push(`${key} must resolve to the verified local tarball ${spec}`) - } - continue - } - const expected = policy.lock.packages[key] - if (expected === undefined) { - if (policy.optionalWorkspaceVersions[name] !== version || typeof resolution.integrity !== 'string') { - errors.push(`${key} is absent from the repository lockfile; update and qualify the repository dependency first`) - } - continue - } - if (!isDeepStrictEqual(resolution, mapping(expected, `repository ${key}`).resolution)) { - errors.push(`${key} resolution differs from the repository lockfile`) - } - } - const snapshots = Object.keys(actual.snapshots) - for (const key of Object.keys(actual.packages)) { - const patch = policy.lock.patchedDependencies[key] - if (actual.patchedDependencies[key] !== patch) errors.push(`${key} patch differs from the repository lockfile`) - const instances = snapshots.filter(snapshot => snapshot.split('(')[0] === key) - if (instances.length === 0) errors.push(`${key} has no dependency snapshot`) - for (const snapshot of instances) { - if (/\(patch_hash=([^)]+)\)/u.exec(snapshot)?.[1] !== patch) { - errors.push(`${snapshot} does not apply the repository patch`) - } - } - } - const importers = mapping(actual.data.importers, 'production lockfile.importers') - if (importers['.'] === undefined) errors.push('missing production root importer') - for (const [owner, value] of [...Object.entries(importers), ...Object.entries(actual.snapshots)]) { - const entry = mapping(value, owner) - for (const section of ['dependencies', 'optionalDependencies']) { - for (const [name, dependency] of Object.entries(mapping(entry[section] ?? {}, `${owner}.${section}`))) { - const reference = typeof dependency === 'string' ? dependency : mapping(dependency, `${owner}.${name}`).version - if (typeof reference !== 'string' - || (actual.snapshots[`${name}@${reference}`] === undefined && actual.snapshots[reference] === undefined)) { - errors.push(`${owner}.${section}.${name} has no resolved dependency snapshot`) - } - } - } - } - for (const snapshot of snapshots) { - if (actual.packages[snapshot.split('(')[0] ?? ''] === undefined) errors.push(`${snapshot} has no package resolution`) - } - for (const entry of packageSet.packages) { - const key = `${entry.name}@${desktopCorePackageSpec(entry).replace('file:./', 'file:')}` - if (actual.packages[key] === undefined) errors.push(`missing local package ${entry.name}`) - } - if (errors.length > 0) throw new Error(`desktop dependencies:\n${errors.join('\n')}`) -} diff --git a/apps/desktop/scripts/prepare-dsh.ts b/apps/desktop/scripts/prepare-dsh.ts index 17005a6c23..442e01757e 100644 --- a/apps/desktop/scripts/prepare-dsh.ts +++ b/apps/desktop/scripts/prepare-dsh.ts @@ -15,6 +15,7 @@ import { DESKTOP_PACKAGES_DIR, DESKTOP_PACKAGE_SET_FILE, readDesktopCorePackageSet, + verifyDesktopCoreLockfile, } from '../src/core-package-set.ts' import { smokePrimaryRuntime } from './prepare-primary-runtime.ts' import { smokePreparedRuntime } from './smoke-prepared-runtime.ts' @@ -31,7 +32,6 @@ import { import { desktopTargetPlatform, resolveDesktopBuildTarget, resolveDesktopTargetBuildPaths } from './desktop-build-paths.mjs' import { desktopRuntimeFileExclusion } from './runtime-file-policy.ts' import { selectOfficeEngine } from '../../../scripts/libreoffice-packages.mjs' -import { prepareDesktopDependencyLock, verifyDesktopDependencyLock } from './dependency-lock.ts' const APP_ROOT = resolve(import.meta.dirname, '..') const BUILD_PATHS = resolveDesktopTargetBuildPaths() @@ -121,11 +121,12 @@ async function main(): Promise { copyFileSync(join(PACKAGE_SET_ROOT, DESKTOP_PACKAGE_SET_FILE), join(BUILD_ROOT, DESKTOP_PACKAGE_SET_FILE)) cpSync(join(PACKAGE_SET_ROOT, DESKTOP_PACKAGES_DIR), join(BUILD_ROOT, DESKTOP_PACKAGES_DIR), { recursive: true }) createRuntimeProjectMetadata(BUILD_ROOT, release) - prepareDesktopDependencyLock(BUILD_ROOT, resolve(APP_ROOT, '..', '..'), readDesktopCorePackageSet(BUILD_ROOT, release.version)) }) await packagingStep(process.env.DSH_DESKTOP_PACKAGING_RUN_DIR, 'runtime:lockfile', () => runPnpm(['install', '--lockfile-only'])) - const lockfile = readFileSync(join(BUILD_ROOT, 'pnpm-lock.yaml'), 'utf8') - verifyDesktopDependencyLock(lockfile, resolve(APP_ROOT, '..', '..'), readDesktopCorePackageSet(BUILD_ROOT, release.version)) + verifyDesktopCoreLockfile( + readFileSync(join(BUILD_ROOT, 'pnpm-lock.yaml'), 'utf8'), + readDesktopCorePackageSet(BUILD_ROOT, release.version), + ) await packagingStep(process.env.DSH_DESKTOP_PACKAGING_RUN_DIR, 'runtime:install', () => runPnpm(['install', '--prod', '--frozen-lockfile', '--trust-lockfile'])) const packageSet = readDesktopCorePackageSet(BUILD_ROOT, release.version) const targetName = resolveDesktopBuildTarget() diff --git a/apps/desktop/src/core-package-set.ts b/apps/desktop/src/core-package-set.ts index 41711d6613..0c148e223f 100644 --- a/apps/desktop/src/core-package-set.ts +++ b/apps/desktop/src/core-package-set.ts @@ -157,3 +157,27 @@ export function verifyDesktopCorePackageSet( } return packageSet } + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&') +} + +/** + * Reject a lockfile that resolved any packaged core name through a registry version. + * @param lockfile - Generated pnpm lockfile text. + * @param packageSet - Verified local core package set. + */ +export function verifyDesktopCoreLockfile( + lockfile: string, + packageSet: DesktopCorePackageSet, +): void { + for (const record of packageSet.packages) { + const registryResolution = new RegExp( + `^ ['"]?${escapeRegExp(record.name)}@${escapeRegExp(record.version)}(?:\\([^\\r\\n]*\\))?['"]?:`, + 'mu', + ) + if (registryResolution.test(lockfile)) { + throw new Error(`desktop package set: lockfile resolved ${record.name}@${record.version} outside the local package set`) + } + } +} diff --git a/apps/desktop/tests/core-package-set.spec.ts b/apps/desktop/tests/core-package-set.spec.ts index f84effa614..0b28a2ec3d 100644 --- a/apps/desktop/tests/core-package-set.spec.ts +++ b/apps/desktop/tests/core-package-set.spec.ts @@ -9,6 +9,7 @@ import { desktopCorePackageOverrides, desktopDshPackageSpec, parseDesktopCorePackageSet, + verifyDesktopCoreLockfile, verifyDesktopCorePackageSet, type DesktopCorePackageRecord, } from '../src/core-package-set.ts' @@ -82,4 +83,21 @@ describe('desktop core package set', () => { expect(() => verifyDesktopCorePackageSet(root, '1.2.3')).toThrow(/does not match its descriptor/u) }) + it('rejects registry resolutions for names supplied by the local package set', () => { + const dsh = record('@deepseek-ai/dsh', 'dsh.tgz', Buffer.from('dsh')) + const host = record('@deepseek-ai/dsh-desktop-host', 'host.tgz', Buffer.from('host')) + const packageSet = parseDesktopCorePackageSet({ schemaVersion: 1, packages: [dsh, host] }) + expect(() => { + verifyDesktopCoreLockfile( + "packages:\n '@deepseek-ai/dsh@file:desktop-packages/dsh.tgz':\n resolution: {}\n", + packageSet, + ) + }).not.toThrow() + expect(() => { + verifyDesktopCoreLockfile( + "packages:\n '@deepseek-ai/dsh@1.2.3':\n resolution: {integrity: sha512-registry}\n", + packageSet, + ) + }).toThrow(/outside the local package set/u) + }) }) diff --git a/apps/desktop/tests/dependency-lock.spec.ts b/apps/desktop/tests/dependency-lock.spec.ts deleted file mode 100644 index 3a4b93f880..0000000000 --- a/apps/desktop/tests/dependency-lock.spec.ts +++ /dev/null @@ -1,172 +0,0 @@ -/** Repository dependency and patch preservation in a disposable Desktop install. */ - -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { dump, load } from 'js-yaml' -import { describe, expect, it, onTestFinished } from 'vitest' -import { prepareDesktopDependencyLock, verifyDesktopDependencyLock } from '../scripts/dependency-lock.ts' -import { desktopCorePackageOverrides, desktopCorePackageSpec, type DesktopCorePackageSet } from '../src/core-package-set.ts' - -interface Lockfile { - lockfileVersion: string - settings: { autoInstallPeers: boolean } - importers: Record }> - packages: Record - snapshots: Record }> - patchedDependencies: Record -} - -function fixture() { - const root = mkdtempSync(join(tmpdir(), 'dsh-dependency-lock-')) - onTestFinished(() => { rmSync(root, { recursive: true, force: true }) }) - const project = join(root, 'project') - mkdirSync(project) - mkdirSync(join(root, 'patches')) - writeFileSync(join(root, 'package.json'), '{}') - const members = [ - ['apps/cli', { name: '@deepseek-ai/dsh', version: '1.0.0' }], - ['apps/host', { name: '@deepseek-ai/dsh-desktop-host', version: '1.0.0', optionalDependencies: { '@test/native': '^1.0.0' } }], - ['native/linux', { name: '@test/native', version: '1.0.0' }], - ] as const - for (const [dir, manifest] of members) { - mkdirSync(join(root, dir), { recursive: true }) - writeFileSync(join(root, dir, 'package.json'), JSON.stringify(manifest)) - } - writeFileSync(join(root, 'patches/runtime.patch'), 'runtime patch\n') - writeFileSync(join(root, 'patches/build.patch'), 'build patch\n') - writeFileSync(join(root, 'pnpm-workspace.yaml'), dump({ - packages: ['apps/*', 'native/*'], - overrides: { '@deepseek-ai/dsh': 'link:apps/cli', 'parent>child': '1.0.0' }, - patchedDependencies: { 'library@1.0.0': 'patches/runtime.patch', 'build-only@1.0.0': 'patches/build.patch' }, - })) - const source: Lockfile = { - lockfileVersion: '9.0', settings: { autoInstallPeers: true }, importers: { '.': { dependencies: {} } }, - packages: { - 'library@1.0.0': { resolution: { integrity: 'sha512-one' } }, - 'library@2.0.0': { resolution: { integrity: 'sha512-two' } }, - 'build-only@1.0.0': { resolution: { integrity: 'sha512-build' } }, - }, - snapshots: { 'library@1.0.0(patch_hash=runtime)': {}, 'library@2.0.0': {}, 'build-only@1.0.0(patch_hash=build)': {} }, - patchedDependencies: { 'library@1.0.0': 'runtime', 'build-only@1.0.0': 'build' }, - } - writeFileSync(join(root, 'pnpm-lock.yaml'), dump(source)) - const set: DesktopCorePackageSet = { - schemaVersion: 1, - packages: members.slice(0, 2).map(([, manifest], index) => ({ - name: manifest.name, version: manifest.version, file: `${String(index)}.tgz`, bytes: 1, integrity: `sha512-local${String(index)}`, - })), - } - const local = Object.fromEntries(set.packages.map((entry) => { - const spec = desktopCorePackageSpec(entry).replace('file:./', 'file:') - return [`${entry.name}@${spec}`, { version: entry.version, resolution: { tarball: spec, integrity: entry.integrity } }] - })) - const actual: Lockfile = { - ...source, - importers: { '.': { dependencies: Object.fromEntries(set.packages.map((entry) => { - const spec = desktopCorePackageSpec(entry).replace('file:./', 'file:') - return [entry.name, { specifier: spec, version: spec }] - })) } }, - packages: { ...local, 'library@1.0.0': source.packages['library@1.0.0']!, 'library@2.0.0': source.packages['library@2.0.0']! }, - snapshots: { - ...Object.fromEntries(Object.keys(local).map(key => [key, { dependencies: { library: '1.0.0(patch_hash=runtime)', alias: 'library@2.0.0' } }])), - 'library@1.0.0(patch_hash=runtime)': {}, 'library@2.0.0': {}, - }, - patchedDependencies: { ...source.patchedDependencies }, - } - writeFileSync(join(project, 'pnpm-workspace.yaml'), dump({ - packages: ['.'], nodeLinker: 'hoisted', autoInstallPeers: false, - overrides: desktopCorePackageOverrides(set), allowBuilds: { library: true }, - })) - return { root, project, source, actual, set, localKey: Object.keys(local)[0]! } -} - -describe('Desktop dependency lock', () => { - it('seeds repository resolutions, overrides and patches while preserving the source checkout', () => { - const { root, project, source, set } = fixture() - prepareDesktopDependencyLock(project, root, set) - expect(load(readFileSync(join(project, 'pnpm-workspace.yaml'), 'utf8'))).toMatchObject({ - nodeLinker: 'hoisted', autoInstallPeers: false, allowBuilds: { library: true }, allowUnusedPatches: true, - overrides: { ...desktopCorePackageOverrides(set), '@test/native': '1.0.0', 'parent>child': '1.0.0' }, - patchedDependencies: { 'build-only@1.0.0': 'dependency-patches/0.patch', 'library@1.0.0': 'dependency-patches/1.patch' }, - }) - expect(readFileSync(join(project, 'dependency-patches/0.patch'), 'utf8')).toBe('build patch\n') - expect(readFileSync(join(project, 'dependency-patches/1.patch'), 'utf8')).toBe('runtime patch\n') - expect(load(readFileSync(join(project, 'pnpm-lock.yaml'), 'utf8'))).toMatchObject({ - packages: source.packages, snapshots: source.snapshots, patchedDependencies: source.patchedDependencies, - importers: { '.': {} }, settings: { autoInstallPeers: false }, - }) - expect(load(readFileSync(join(root, 'pnpm-lock.yaml'), 'utf8'))).toEqual(source) - }) - - it('accepts existing major versions, npm aliases and peer contexts without installing build-only dependencies', () => { - const { root, actual, set } = fixture() - actual.snapshots['library@2.0.0(peer@1.0.0)'] = {} - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).not.toThrow() - }) - - it.each(['another-library@1.0.0', 'library@3.0.0', '@scope/native@2.0.0'])( - 'rejects a new dependency or version: %s', (key) => { - const { root, actual, set } = fixture() - actual.packages[key] = { resolution: { integrity: 'sha512-unqualified' } } - actual.snapshots[key] = {} - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow(`${key} is absent from the repository lockfile`) - }, - ) - - it('rejects changed registry integrity', () => { - const { root, actual, set } = fixture() - actual.packages['library@2.0.0']!.resolution.integrity = 'sha512-changed' - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('resolution differs from the repository lockfile') - }) - - it('requires both patch metadata and the patched dependency snapshot', () => { - const { root, actual, set } = fixture() - delete actual.patchedDependencies['library@1.0.0'] - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('patch differs from the repository lockfile') - actual.patchedDependencies['library@1.0.0'] = 'runtime' - delete actual.snapshots['library@1.0.0(patch_hash=runtime)'] - actual.snapshots['library@1.0.0'] = {} - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('does not apply the repository patch') - }) - - it('rejects missing package metadata, dependency snapshots and local tarballs', () => { - const { root, actual, set, localKey } = fixture() - delete actual.packages['library@2.0.0'] - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('has no package resolution') - delete actual.snapshots['library@2.0.0'] - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('has no resolved dependency snapshot') - actual.packages = Object.fromEntries(Object.entries(actual.packages).filter(([key]) => key !== localKey)) - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('missing local package') - }) - - it.each(['1.0.0', '9.0.0'])( - 'rejects a registry copy of a locally packed package at version %s', (version) => { - const { root, actual, set } = fixture() - actual.packages[`@deepseek-ai/dsh@${version}`] = { resolution: { integrity: 'sha512-registry' } } - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('must resolve to the verified local tarball') - }, - ) - - it('rejects corrupted local tarball integrity', () => { - const { root, actual, set, localKey } = fixture() - actual.packages[localKey]!.resolution.integrity = 'sha512-corrupt' - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('must resolve to the verified local tarball') - }) - - it('allows unpacked optional workspace platforms only at their exact source version', () => { - const { root, actual, set } = fixture() - actual.packages['@test/native@1.0.0'] = { resolution: { integrity: 'sha512-platform' } } - actual.snapshots['@test/native@1.0.0'] = {} - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).not.toThrow() - actual.packages['@test/native@1.0.1'] = { resolution: { integrity: 'sha512-other-platform' } } - expect(() => { verifyDesktopDependencyLock(dump(actual), root, set) }).toThrow('@test/native@1.0.1 is absent') - }) - - it.each(['{}', 'lockfileVersion: "8.0"', 'lockfileVersion: "9.0"\npackages: {}', 'lockfileVersion: "9.0"\npackages: []'])( - 'rejects an invalid or empty production lockfile: %s', (text) => { - const { root, set } = fixture() - expect(() => { verifyDesktopDependencyLock(text, root, set) }).toThrow('desktop dependencies:') - }, - ) -}) diff --git a/scripts/check-workspace-constraints.spec.ts b/scripts/check-workspace-constraints.spec.ts index ea589e2812..3307aa3956 100644 --- a/scripts/check-workspace-constraints.spec.ts +++ b/scripts/check-workspace-constraints.spec.ts @@ -10,7 +10,6 @@ import { } from './experimental-package-policy.ts' import { checkDshFamilyVersion, - checkKoffiVersions, checkWorkspaceManifest, checkWorkspaceProtocol, checkExperimentalDependencyIsolation, @@ -77,24 +76,6 @@ describe('workspace dependency ranges', () => { }) }) -describe('Koffi version alignment', () => { - it.each(['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const)( - 'requires the qualified exact version in %s', (section) => { - const consumer = (version: string): WorkspaceManifest => ({ - dir: 'apps/desktop-host', - manifest: { name: 'private-host', private: true, [section]: { koffi: version } }, - }) - expect(checkKoffiVersions([consumer('3.1.1')])).toEqual([]) - for (const version of ['^3.1.0', '^3.1.1', '~3.1.1', '*', '3.3.2']) { - expect(checkKoffiVersions([consumer(version)])).toEqual([ - `private-host: ${section}.koffi must use 3.1.1, got ${version}`, - ]) - } - expect(checkKoffiVersions([{ dir: '.', manifest: { [section]: { unrelated: '^1.0.0' } } }])).toEqual([]) - }, - ) -}) - describe('workspace manifest discovery', () => { it('checks root, app, runtime, tooling, and newly declared members while honoring exclusions', () => { const root = mkdtempSync(join(tmpdir(), 'dsh-workspace-ranges-')) @@ -108,14 +89,12 @@ describe('workspace manifest discovery', () => { mkdirSync(join(root, dir), { recursive: true }) writeFileSync(join(root, dir, 'package.json'), JSON.stringify(dir === 'packages/core/runtime' ? { name: '@deepseek-ai/dsh-runtime' } - : { dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^', koffi: '^3.1.0' } })) + : { dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^' } })) } const manifests = readWorkspaceManifests(root) expect(manifests.map(entry => entry.dir).sort()).toEqual([...consumers, 'packages/core/runtime'].sort()) expect(checkWorkspaceProtocol(manifests).sort()).toEqual(consumers.map(dir => `${dir}: dependencies.@deepseek-ai/dsh-runtime must use workspace:*, got workspace:^`).sort()) - expect(checkKoffiVersions(manifests).sort()).toEqual(consumers.map(dir => - `${dir}: dependencies.koffi must use 3.1.1, got ^3.1.0`).sort()) }) it.each(['', 'null', '{}', 'packages: []', 'packages: [false]', 'packages: [""]', 'packages: wrong'])( diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index a494ec1171..13deaa24d9 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -551,8 +551,6 @@ function checkRepositoryVersion(): string[] { const dependencySections = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const /** Dependency sections present in an installed runtime. */ const runtimeDependencySections = ['dependencies', 'optionalDependencies', 'peerDependencies'] as const -/** Koffi version qualified for source builds without optional native prebuilts. */ -const KOFFI_VERSION = '3.1.1' /** * Prevent an official runtime from requiring an experimental package. The dsh installation's `dependencies` @@ -615,24 +613,6 @@ export function checkWorkspaceProtocol(manifests: readonly WorkspaceManifest[]): return errors } -/** - * Require the qualified Koffi pin in every workspace, including private applications. - * @param manifests - Root and all declared workspace manifests. - * @returns Diagnostics for declarations that could install a different Koffi version. - */ -export function checkKoffiVersions(manifests: readonly WorkspaceManifest[]): string[] { - const errors: string[] = [] - for (const { dir, manifest } of manifests) { - for (const section of dependencySections) { - const version = manifest[section]?.koffi - if (version !== undefined && version !== KOFFI_VERSION) { - errors.push(`${manifest.name ?? dir}: ${section}.koffi must use ${KOFFI_VERSION}, got ${version}`) - } - } - } - return errors -} - /** Run the repository constraint gate. */ export function main(): void { const manifests = readWorkspaceManifests(root) @@ -640,7 +620,6 @@ export function main(): void { ...checkRepositoryVersion(), ...workspaceManifests().flatMap(checkWorkspaceManifest), ...checkWorkspaceProtocol(manifests), - ...checkKoffiVersions(manifests), ...checkExperimentalDependencyIsolation(manifests), ...checkHierarchyShape(), ...collectProjectReferenceFaceViolations(root), From 64c5255843bd0a1a644a6062d180bf28b95170f5 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 1 Oct 2026 01:17:17 +0800 Subject: [PATCH 4/5] perf(deps): align desktop dependencies and share client libraries --- apps/desktop/package.json | 2 +- packages/api/account-controller/package.json | 2 +- packages/api/gateway/package.json | 2 +- packages/api/job-controller/package.json | 2 +- packages/api/remotes/package.json | 2 +- packages/api/session-controller/package.json | 2 +- packages/api/settings-controller/package.json | 2 +- packages/api/terminal-controller/package.json | 2 +- .../api/workspace-controller/package.json | 2 +- packages/api/workspace-files/package.json | 2 +- .../attachment/attachment-local/package.json | 2 +- packages/boot/hmr/package.json | 2 +- packages/boot/plugin-manager/package.json | 2 +- packages/client/connection/package.json | 2 +- packages/client/file-upload/package.json | 2 +- packages/client/modules/README.i18n.yaml | 4 +- packages/client/modules/README.md | 2 +- packages/client/modules/README.zh.md | 2 +- .../client/product-analytics/package.json | 2 +- packages/client/tsdown.client.ts | 2 +- packages/client/ui-conversation/package.json | 2 +- .../client/ui-plugin-manager/package.json | 2 +- packages/client/ui-sidebar-right/package.json | 2 +- .../tests/client-bundle.client.spec.ts | 1 + packages/client/web/README.i18n.yaml | 8 +- packages/client/web/README.md | 5 +- packages/client/web/README.zh.md | 5 +- packages/client/web/package.json | 4 +- packages/client/web/src/platform.ts | 1 + packages/client/web/src/seed.ts | 4 + .../context/session-reference/package.json | 2 +- packages/context/time-context/package.json | 2 +- packages/context/tmux-context/package.json | 2 +- packages/core/agent-loop/package.json | 2 +- .../credentials-local/package.json | 2 +- .../deepseek-account-platform/package.json | 2 +- packages/document/office-to-pdf/package.json | 2 +- packages/experimental/agent-team/package.json | 2 +- .../api-speech-to-text/package.json | 2 +- .../README.i18n.yaml | 4 +- .../browser-use-stagehand-native/README.md | 2 +- .../browser-use-stagehand-native/README.zh.md | 2 +- .../browser-use-stagehand-native/package.json | 2 +- .../package.json | 2 +- .../speech-to-text-sensevoice/package.json | 2 +- .../webworker-runtime/package.json | 2 +- .../cordis-host-runner/package.json | 2 +- .../feedback/command-feedback/package.json | 2 +- .../feedback/message-feedback/package.json | 2 +- packages/fs/fs-local/package.json | 2 +- packages/goal/goal/package.json | 2 +- packages/host/plugin-inventory/package.json | 2 +- .../host/product-telemetry-otel/package.json | 6 +- packages/interaction/commands/package.json | 2 +- .../permission-presets/package.json | 2 +- .../interaction/user-questions/package.json | 2 +- packages/llm/llm-retry/package.json | 2 +- packages/llm/llm/package.json | 2 +- packages/llm/token-meter/package.json | 2 +- packages/mcp/mcp-client/package.json | 2 +- packages/plan/plan-mode/package.json | 2 +- .../preset/agent-preset-registry/package.json | 2 +- packages/sandbox/sandbox-policy/package.json | 2 +- packages/schedule/schedule/package.json | 2 +- .../session-projection-cache/package.json | 2 +- .../session/session-projection/package.json | 2 +- packages/session/session-stats/package.json | 2 +- .../session-telemetry-otel/package.json | 6 +- packages/session/session-title/package.json | 2 +- .../session/session-turn-outline/package.json | 2 +- packages/skill/skill-filesystem/package.json | 2 +- packages/spill/spill-policy/package.json | 2 +- packages/ssh/fs-ssh/package.json | 2 +- packages/ssh/sandbox-ssh/package.json | 2 +- packages/ssh/ssh/package.json | 2 +- packages/ssh/subprocess-ssh/package.json | 2 +- packages/storage/storage-domain/package.json | 2 +- .../subagent-claude-code/package.json | 2 +- packages/subagent/subagent/package.json | 2 +- packages/subagent/tool-subagent/package.json | 2 +- packages/telemetry/otel/README.i18n.yaml | 4 +- packages/telemetry/otel/README.md | 2 + packages/telemetry/otel/README.zh.md | 2 + packages/telemetry/otel/package.json | 12 +- .../telemetry/otel/src/event-transport.ts | 6 +- packages/telemetry/otel/src/transport.ts | 6 +- packages/todo/tool-todo/package.json | 2 +- packages/typert/generator/package.json | 2 +- packages/typert/loader/package.json | 2 +- packages/typert/registry/package.json | 2 +- packages/util/chunked-list/package.json | 2 +- packages/util/http-proxy/package.json | 2 +- packages/web/web-fetch-http/package.json | 2 +- packages/workspace/workspace/package.json | 2 +- pnpm-lock.yaml | 759 +++++++++--------- 95 files changed, 520 insertions(+), 473 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 3eaf57f56a..0cbc1a43ac 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -66,7 +66,7 @@ "js-yaml": "^4.2.0", "koffi": "3.1.1", "pnpm": "11.7.0", - "sharp": "^0.35.3", + "sharp": "0.35.5", "typescript": "^6.0.3", "@deepseek-ai/dsh-deepseek-account": "workspace:*", "@types/ws": "^8.18.1", diff --git a/packages/api/account-controller/package.json b/packages/api/account-controller/package.json index 0bda49aa57..9af1722160 100644 --- a/packages/api/account-controller/package.json +++ b/packages/api/account-controller/package.json @@ -44,7 +44,7 @@ ], "license": "MIT", "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/api/gateway/package.json b/packages/api/gateway/package.json index d2bd53e59f..7f0eebd42d 100644 --- a/packages/api/gateway/package.json +++ b/packages/api/gateway/package.json @@ -75,6 +75,6 @@ "@deepseek-ai/dsh-util-crypto": "workspace:*", "@types/ws": "^8.18.1", "@deepseek-ai/cordis": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/api/job-controller/package.json b/packages/api/job-controller/package.json index 99c3b80395..b57e49ce91 100644 --- a/packages/api/job-controller/package.json +++ b/packages/api/job-controller/package.json @@ -67,7 +67,7 @@ "dependencies": { "@deepseek-ai/dsh-typert-protocol": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~" diff --git a/packages/api/remotes/package.json b/packages/api/remotes/package.json index 0a46885712..98810858a2 100644 --- a/packages/api/remotes/package.json +++ b/packages/api/remotes/package.json @@ -86,7 +86,7 @@ "@deepseek-ai/dsh-user-approval": "workspace:*", "@deepseek-ai/dsh-user-questions": "workspace:*", "@deepseek-ai/cordis": "workspace:~", - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-command-feedback": "workspace:*", "@deepseek-ai/dsh-api-terminal-controller": "workspace:*", "@deepseek-ai/dsh-plugin-manager": "workspace:*", diff --git a/packages/api/session-controller/package.json b/packages/api/session-controller/package.json index dc50269e26..7a8d0460ec 100644 --- a/packages/api/session-controller/package.json +++ b/packages/api/session-controller/package.json @@ -73,7 +73,7 @@ "@deepseek-ai/dsh-deque": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", "mime-types": "^3.0.2", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/api/settings-controller/package.json b/packages/api/settings-controller/package.json index 8601923a52..076e1a27f3 100644 --- a/packages/api/settings-controller/package.json +++ b/packages/api/settings-controller/package.json @@ -45,7 +45,7 @@ "license": "MIT", "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/api/terminal-controller/package.json b/packages/api/terminal-controller/package.json index aea86312b3..6fdd717d01 100644 --- a/packages/api/terminal-controller/package.json +++ b/packages/api/terminal-controller/package.json @@ -60,7 +60,7 @@ "@deepseek-ai/schemastery": "workspace:~", "@xterm/headless": "^6.0.0", "@xterm/addon-serialize": "^0.14.0", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/dsh-subprocess": "workspace:*", diff --git a/packages/api/workspace-controller/package.json b/packages/api/workspace-controller/package.json index 8cd898beed..7a780cdac4 100644 --- a/packages/api/workspace-controller/package.json +++ b/packages/api/workspace-controller/package.json @@ -72,7 +72,7 @@ "@deepseek-ai/dsh-deque": "workspace:*", "@deepseek-ai/dsh-native-command": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/api/workspace-files/package.json b/packages/api/workspace-files/package.json index d1537d23c5..e6f27def7d 100644 --- a/packages/api/workspace-files/package.json +++ b/packages/api/workspace-files/package.json @@ -55,7 +55,7 @@ "@deepseek-ai/dsh-deque": "workspace:*", "@deepseek-ai/dsh-typert-protocol": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~" diff --git a/packages/attachment/attachment-local/package.json b/packages/attachment/attachment-local/package.json index 5f25e49265..46d8e56ff4 100644 --- a/packages/attachment/attachment-local/package.json +++ b/packages/attachment/attachment-local/package.json @@ -28,7 +28,7 @@ "dependencies": { "@deepseek-ai/dsh-lazy-require": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "sharp": "^0.35.3" + "sharp": "0.35.5" }, "devDependencies": { "@deepseek-ai/dsh-attachment": "workspace:*", diff --git a/packages/boot/hmr/package.json b/packages/boot/hmr/package.json index 5e61624165..42186fd631 100644 --- a/packages/boot/hmr/package.json +++ b/packages/boot/hmr/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@babel/code-frame": "^7.29.0", - "chokidar": "^4.0.3", + "chokidar": "5.0.0", "picomatch": "^4.0.3", "@deepseek-ai/schemastery": "workspace:~" }, diff --git a/packages/boot/plugin-manager/package.json b/packages/boot/plugin-manager/package.json index 6e6104d60a..01b243a953 100644 --- a/packages/boot/plugin-manager/package.json +++ b/packages/boot/plugin-manager/package.json @@ -61,7 +61,7 @@ "@deepseek-ai/schemastery": "workspace:~", "execa": "^10.0.0", "yaml": "^2.9.0", - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-util-values": "workspace:*" }, "peerDependencies": { diff --git a/packages/client/connection/package.json b/packages/client/connection/package.json index ac61c45e70..c017be0fc1 100644 --- a/packages/client/connection/package.json +++ b/packages/client/connection/package.json @@ -36,7 +36,7 @@ "dependencies": { "@deepseek-ai/dsh-credentials": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "files": [ "lib/index.js", diff --git a/packages/client/file-upload/package.json b/packages/client/file-upload/package.json index 858ff12775..3c3152a76f 100644 --- a/packages/client/file-upload/package.json +++ b/packages/client/file-upload/package.json @@ -62,7 +62,7 @@ "lib/typert.remote-client.d.ts" ], "dependencies": { - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-typert-protocol": "workspace:*", "@deepseek-ai/dsh-brand": "workspace:*" }, diff --git a/packages/client/modules/README.i18n.yaml b/packages/client/modules/README.i18n.yaml index 4ab13cc6e9..ebb8ecbb3a 100644 --- a/packages/client/modules/README.i18n.yaml +++ b/packages/client/modules/README.i18n.yaml @@ -27,8 +27,8 @@ en: 45740a56e931d094 zh: b3362af77c804459 /deepseek-ai-dsh-client-modules/use-this-package/sharing-modules: - en: 0aaf0693db8bb203 - zh: 9f4738cdc6b55c26 + en: 1778b5a63ecde5e8 + zh: 537b4f8c755af8ad /deepseek-ai-dsh-client-modules/use-this-package/build-requirements: en: b6a4d3b901c89efe zh: 615b5f3eec41f281 diff --git a/packages/client/modules/README.md b/packages/client/modules/README.md index 3388eb2ae4..8224ab0ac7 100644 --- a/packages/client/modules/README.md +++ b/packages/client/modules/README.md @@ -43,7 +43,7 @@ An open Web page follows the Host's complete module graph through the HMR transp ### Sharing modules -The shell seeds a frozen module table (`PLATFORM_MODULES`: React, Cordis, and static UI libraries); every dynamic bundle resolves its externals against exactly that baseline. `dsh.client.external` adds only exact non-baseline requests, each answered by the dynamic package row it names or an exact static-table key. Type-only imports are erased and create no request. Composition rejects malformed requests, missing suppliers, self-requests, and synchronous request cycles. +The shell seeds a frozen module table ([`PLATFORM_MODULES`](../web/README.md#the-shared-module-table)); every dynamic bundle resolves its externals against exactly that baseline. `dsh.client.external` adds only exact non-baseline requests, each answered by the dynamic package row it names or an exact static-table key. Type-only imports are erased and create no request. Composition rejects malformed requests, missing suppliers, self-requests, and synchronous request cycles. ### Build requirements diff --git a/packages/client/modules/README.zh.md b/packages/client/modules/README.zh.md index 3cbc600ee5..c972fe38d4 100644 --- a/packages/client/modules/README.zh.md +++ b/packages/client/modules/README.zh.md @@ -43,7 +43,7 @@ application combo 脚本只携带每个插件的 `client.js` 入口,并在启 ### 共享模块 -外壳初始化一张冻结的模块表(`PLATFORM_MODULES`:React、Cordis 与静态 UI 库);每个动态 bundle 都精确针对该基座解析其 external。`dsh.client.external` 只添加基座之外的精确请求;系统会将每个请求解析到其指定的动态包 row 或完全匹配的静态表键。纯类型 import 会被擦除,不产生请求。组合阶段会拒绝畸形请求、缺失提供方、自请求与同步请求环。 +外壳初始化一张冻结的模块表([`PLATFORM_MODULES`](../web/README.zh.md#the-shared-module-table));每个动态 bundle 都精确针对该基座解析其 external。`dsh.client.external` 只添加基座之外的精确请求;系统会将每个请求解析到其指定的动态包 row 或完全匹配的静态表键。纯类型 import 会被擦除,不产生请求。组合阶段会拒绝畸形请求、缺失提供方、自请求与同步请求环。 ### 构建要求 diff --git a/packages/client/product-analytics/package.json b/packages/client/product-analytics/package.json index 48cc366c90..05f601ce67 100644 --- a/packages/client/product-analytics/package.json +++ b/packages/client/product-analytics/package.json @@ -77,6 +77,6 @@ "dependencies": { "@deepseek-ai/dsh-typert-protocol": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/client/tsdown.client.ts b/packages/client/tsdown.client.ts index 215001dbb9..e422333e6d 100644 --- a/packages/client/tsdown.client.ts +++ b/packages/client/tsdown.client.ts @@ -491,7 +491,7 @@ function clientConfig(id: string, entry: string, clientBanner?: (fileName: strin deps: { neverBundle: isRequested, // Anything NOT requested from the loader module table must inline - // (wire/type layers, zod, clsx — every non-shared dep). A require() the + // (wire/type layers, clsx — every non-shared dep). A require() the // table cannot answer is a guaranteed runtime throw, so the rule is the // package's own request list: requested specifiers stay imports, // everything else is bundled. diff --git a/packages/client/ui-conversation/package.json b/packages/client/ui-conversation/package.json index 73b7c388bb..31931ca146 100644 --- a/packages/client/ui-conversation/package.json +++ b/packages/client/ui-conversation/package.json @@ -87,7 +87,7 @@ "@lexical/headless": "^0.49.0", "react-dom": "^18.2.0", "@types/react-dom": "~18.3.0", - "zod": "^4.4.3", + "zod": "4.6.5", "lexical": "^0.49.0", "clsx": "^2.0.0", "@lexical/utils": "^0.49.0", diff --git a/packages/client/ui-plugin-manager/package.json b/packages/client/ui-plugin-manager/package.json index 28398e793f..f3ce50ee96 100644 --- a/packages/client/ui-plugin-manager/package.json +++ b/packages/client/ui-plugin-manager/package.json @@ -87,7 +87,7 @@ "dependencies": { "@deepseek-ai/dsh-timeout": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-typert-protocol": "workspace:*" } } diff --git a/packages/client/ui-sidebar-right/package.json b/packages/client/ui-sidebar-right/package.json index 399d28530f..5a1b9f76bd 100644 --- a/packages/client/ui-sidebar-right/package.json +++ b/packages/client/ui-sidebar-right/package.json @@ -70,7 +70,7 @@ "picomatch": "^4.0.4", "clsx": "^2.0.0", "@deepseek-ai/dsh-util-crypto": "workspace:*", - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-client-shortcuts": "workspace:*", "@deepseek-ai/dsh-brand": "workspace:*" }, diff --git a/packages/client/ui-trajectory/tests/client-bundle.client.spec.ts b/packages/client/ui-trajectory/tests/client-bundle.client.spec.ts index a50cf0fe4d..238afec5a0 100644 --- a/packages/client/ui-trajectory/tests/client-bundle.client.spec.ts +++ b/packages/client/ui-trajectory/tests/client-bundle.client.spec.ts @@ -50,6 +50,7 @@ describe('tsdown client artifact', () => { ['react', await import('react')], ['react/jsx-runtime', await import('react/jsx-runtime')], ['react-dom', await import('react-dom')], + ['@tanstack/react-virtual', await import('@tanstack/react-virtual')], ['@deepseek-ai/dsh-client-store', await import('@deepseek-ai/dsh-client-store')], ['@deepseek-ai/dsh-client-ui-conversation/client', await import('@deepseek-ai/dsh-client-ui-conversation/client')], ['@deepseek-ai/dsh-client-ui-primitives', await import('@deepseek-ai/dsh-client-ui-primitives')], diff --git a/packages/client/web/README.i18n.yaml b/packages/client/web/README.i18n.yaml index 3f8cb1d37e..ef087cfbff 100644 --- a/packages/client/web/README.i18n.yaml +++ b/packages/client/web/README.i18n.yaml @@ -21,11 +21,11 @@ en: f3b01aa878764e5c zh: f02eab65d441bfe0 /deepseek-ai-dsh-client-web/use-this-package/the-boot-page: - en: add354591107b80d - zh: 41136254a00d785e + en: 1757ef1631612ff5 + zh: d2d3fd0313908c12 /deepseek-ai-dsh-client-web/use-this-package/the-shared-module-table: - en: 8380cd70b861a3a8 - zh: 5a331deb7ad8fca1 + en: 33b256e108a7bd6a + zh: 3b2b1368721803b7 /deepseek-ai-dsh-client-web/use-this-package/configuration: en: 942959cb40ee31a1 zh: 9c86ac2cf6a13976 diff --git a/packages/client/web/README.md b/packages/client/web/README.md index 6b84bc4a87..d826c6bad5 100644 --- a/packages/client/web/README.md +++ b/packages/client/web/README.md @@ -39,9 +39,12 @@ Boot runs in two stages: the module stage adopts the parser-loaded bootstrap bat The boot page uses plain DOM and local CSS, so bundle and plugin-activation failures remain visible: it shows one spinner node whose CSS arc grows as entries activate, and reports per-entry status. The spinner and its animation phase persist until the full UI replaces the boot page. A plugin that fails import or activation is reported by name with the reason (missing service, import failure, or state) instead of a blank page. The console contains the original import error. + ### The shared module table -`PLATFORM_MODULES` (in `src/platform.ts`) names the shell-seeded shared modules — React, Cordis, and static UI libraries — and together with `PRELOADED_CLIENT_EXTERNALS` (the parser-preloaded runtime row) defines the implicit external baseline every dynamic bundle resolves against. `dsh.client.external` adds only exact non-baseline requests; see [shared modules and the module graph](../AGENTS.md#shared-modules-and-the-module-graph). +`PLATFORM_MODULES` (in `src/platform.ts`) names the shell-seeded shared modules — React, Cordis, Zod (`zod`), TanStack Virtual (`@tanstack/react-virtual`), and static UI libraries — and together with `PRELOADED_CLIENT_EXTERNALS` (the parser-preloaded runtime row) defines the implicit external baseline every dynamic bundle resolves against. `dsh.client.external` adds only exact non-baseline requests; see [shared modules and the module graph](../AGENTS.md#shared-modules-and-the-module-graph). + +Built-in and installed browser plugins in the same page receive the same module instances. The shell supplies the dependency versions declared in this package's `package.json`; the module table does not negotiate versions per plugin. External plugins that use these modules must target a host that provides the required specifiers and APIs, and keep those imports external when building their client bundle. Inlined dependencies remain private to their bundle; Host code and Workers resolve their dependencies separately. ### Configuration diff --git a/packages/client/web/README.zh.md b/packages/client/web/README.zh.md index fe3b5ce1a9..7740caeabf 100644 --- a/packages/client/web/README.zh.md +++ b/packages/client/web/README.zh.md @@ -39,9 +39,12 @@ kind: "package-library" 启动页只使用原生 DOM 与本地 CSS,因此 bundle 与插件激活失败保持可见:它显示一个 spinner 节点,其 CSS 圆弧随 entry 激活而增长,并逐 entry 报告状态。spinner 及其动画相位会一直保留,直到完整 UI 替换启动页。导入或激活失败的插件会按名称报告并给出原因(缺失服务、导入失败或状态),而不是白屏。控制台包含原始导入错误。 + ### 共享模块表 -`PLATFORM_MODULES`(位于 `src/platform.ts`)列出外壳预置的共享模块——React、Cordis 与静态 UI 库——并与 `PRELOADED_CLIENT_EXTERNALS`(parser 预载的运行时行)一起定义每个动态 bundle 解析所依据的隐式 external 基座。`dsh.client.external` 只添加基座之外的精确请求;参见[共享模块与模块图](../AGENTS.md#shared-modules-and-the-module-graph)。 +`PLATFORM_MODULES`(位于 `src/platform.ts`)列出外壳预置的共享模块——React、Cordis、Zod(`zod`)、TanStack Virtual(`@tanstack/react-virtual`)与静态 UI 库——并与 `PRELOADED_CLIENT_EXTERNALS`(parser 预载的运行时行)一起定义每个动态 bundle 解析所依据的隐式 external 基座。`dsh.client.external` 只添加基座之外的精确请求;参见[共享模块与模块图](../AGENTS.md#shared-modules-and-the-module-graph)。 + +同一页面中的内置浏览器插件和已安装的浏览器插件获得相同的模块实例。外壳提供本包 `package.json` 声明的依赖版本,模块表不会为每个插件协商版本。使用这些模块的外部插件必须以提供所需模块标识符和 API 的宿主为目标,并在构建客户端 bundle 时将相应导入保留为 external。内联依赖仍归各自 bundle 私有;Host 代码与 Worker 单独解析其依赖。 ### 配置 diff --git a/packages/client/web/package.json b/packages/client/web/package.json index ac485419a3..697b5e0860 100644 --- a/packages/client/web/package.json +++ b/packages/client/web/package.json @@ -40,7 +40,9 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^6.0.3", - "@deepseek-ai/dsh-host-webserver": "workspace:*" + "@deepseek-ai/dsh-host-webserver": "workspace:*", + "zod": "4.6.5", + "@tanstack/react-virtual": "3.14.9" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~" diff --git a/packages/client/web/src/platform.ts b/packages/client/web/src/platform.ts index 2549966986..3103555215 100644 --- a/packages/client/web/src/platform.ts +++ b/packages/client/web/src/platform.ts @@ -7,6 +7,7 @@ /** The module specifiers the shell shares into the frozen module table. */ export const PLATFORM_MODULES = [ 'react', 'react/jsx-runtime', 'react-dom', 'react-dom/client', '@deepseek-ai/cordis', + 'zod', '@tanstack/react-virtual', '@deepseek-ai/dsh-client-store', '@deepseek-ai/dsh-client-ui-slots', '@deepseek-ai/dsh-client-ui-primitives', diff --git a/packages/client/web/src/seed.ts b/packages/client/web/src/seed.ts index d41f338d42..bbba6643f3 100644 --- a/packages/client/web/src/seed.ts +++ b/packages/client/web/src/seed.ts @@ -11,6 +11,8 @@ import * as ReactJsxRuntime from 'react/jsx-runtime' import * as ReactDom from 'react-dom' import * as ReactDomClient from 'react-dom/client' import * as Cordis from '@deepseek-ai/cordis' +import * as Zod from 'zod' +import * as ReactVirtual from '@tanstack/react-virtual' import * as ClientStore from '@deepseek-ai/dsh-client-store' import * as UiSlots from '@deepseek-ai/dsh-client-ui-slots' import * as UiPrimitives from '@deepseek-ai/dsh-client-ui-primitives' @@ -31,6 +33,8 @@ export function getStaticModules(): Record { 'react-dom': ReactDom, 'react-dom/client': ReactDomClient, '@deepseek-ai/cordis': Cordis, + 'zod': Zod, + '@tanstack/react-virtual': ReactVirtual, '@deepseek-ai/dsh-client-store': ClientStore, '@deepseek-ai/dsh-client-ui-slots': UiSlots, '@deepseek-ai/dsh-client-ui-primitives': UiPrimitives, diff --git a/packages/context/session-reference/package.json b/packages/context/session-reference/package.json index 9233524b78..fbeb899cb9 100644 --- a/packages/context/session-reference/package.json +++ b/packages/context/session-reference/package.json @@ -47,7 +47,7 @@ "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/context/time-context/package.json b/packages/context/time-context/package.json index fb9e0546e3..ffdf362891 100644 --- a/packages/context/time-context/package.json +++ b/packages/context/time-context/package.json @@ -36,7 +36,7 @@ "dependencies": { "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/context/tmux-context/package.json b/packages/context/tmux-context/package.json index 85fc97f16c..5fd1c698bf 100644 --- a/packages/context/tmux-context/package.json +++ b/packages/context/tmux-context/package.json @@ -28,7 +28,7 @@ "license": "MIT", "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/dsh-agent": "workspace:*", diff --git a/packages/core/agent-loop/package.json b/packages/core/agent-loop/package.json index f1f6641d8a..0702e29b52 100644 --- a/packages/core/agent-loop/package.json +++ b/packages/core/agent-loop/package.json @@ -46,7 +46,7 @@ "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-llm-deepseek-api-key": "workspace:*", diff --git a/packages/credentials/credentials-local/package.json b/packages/credentials/credentials-local/package.json index 287631dbdf..d207befa67 100644 --- a/packages/credentials/credentials-local/package.json +++ b/packages/credentials/credentials-local/package.json @@ -34,7 +34,7 @@ "@deepseek-ai/cordis": "workspace:~" }, "dependencies": { - "chokidar": "^4.0.3", + "chokidar": "5.0.0", "@deepseek-ai/schemastery": "workspace:~", "yaml": "^2.9.0" }, diff --git a/packages/credentials/deepseek-account-platform/package.json b/packages/credentials/deepseek-account-platform/package.json index f64fa6f374..23b18c7262 100644 --- a/packages/credentials/deepseek-account-platform/package.json +++ b/packages/credentials/deepseek-account-platform/package.json @@ -47,6 +47,6 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/document/office-to-pdf/package.json b/packages/document/office-to-pdf/package.json index e0c4a4964c..f7865652dc 100644 --- a/packages/document/office-to-pdf/package.json +++ b/packages/document/office-to-pdf/package.json @@ -59,6 +59,6 @@ "@deepseek-ai/schemastery": "workspace:~", "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/dsh-typert-protocol": "workspace:*", - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/experimental/agent-team/package.json b/packages/experimental/agent-team/package.json index 1dc6c72c00..6d689aec5c 100644 --- a/packages/experimental/agent-team/package.json +++ b/packages/experimental/agent-team/package.json @@ -45,7 +45,7 @@ "dependencies": { "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/experimental/api-speech-to-text/package.json b/packages/experimental/api-speech-to-text/package.json index 4ca69fa9a5..9e8877bb62 100644 --- a/packages/experimental/api-speech-to-text/package.json +++ b/packages/experimental/api-speech-to-text/package.json @@ -45,7 +45,7 @@ "license": "MIT", "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/experimental/browser-use-stagehand-native/README.i18n.yaml b/packages/experimental/browser-use-stagehand-native/README.i18n.yaml index 6befe7b2bf..9e285081a6 100644 --- a/packages/experimental/browser-use-stagehand-native/README.i18n.yaml +++ b/packages/experimental/browser-use-stagehand-native/README.i18n.yaml @@ -24,8 +24,8 @@ en: fea3ad16a77fc478 zh: cf551a8a2d183f93 /deepseek-ai-dsh-experimental-browser-use-stagehand-native/understand-the-implementation: - en: 63e42e22af64f7df - zh: d8218ad3e12a8ebe + en: 4e656c3eae3c0fa5 + zh: 431142e13f775dff /deepseek-ai-dsh-experimental-browser-use-stagehand-native/further-exploration: en: eff8f4541eb26ca7 zh: 76a61fe9bd48df2a diff --git a/packages/experimental/browser-use-stagehand-native/README.md b/packages/experimental/browser-use-stagehand-native/README.md index 671a900d5d..3007449c5a 100644 --- a/packages/experimental/browser-use-stagehand-native/README.md +++ b/packages/experimental/browser-use-stagehand-native/README.md @@ -90,7 +90,7 @@ env -u NODE_USE_ENV_PROXY DSH_STAGEHAND_E2E=1 pnpm exec vitest run --config vite The host owns each launched Chromium process and its temporary profile before waiting for CDP readiness. Chromium receives the standard scrubbed child environment, preserving paths, locale, and proxy settings while excluding credential-shaped variables and DSH identity. Both modes connect the SDK inside a dedicated Worker. The Worker receives no ambient environment except the explicit source TypeScript configuration path, so its CDP connection does not inherit host proxy settings. SDK close waits for active operations. Cleanup terminates the connection Worker after the configured SDK grace; launch also kills and awaits its owned Chromium process before removing the profile. Attached external browsers remain open. Cleanup failures follow the [ownership limits](#known-limitations-and-deferred-work) below. -The [native runtime](src/native.ts) passes the explicit model configuration to Stagehand's public initialization API. Stagehand owns the model requests, response validation, and token accounting inside its browser extension. DSH records browser tool inputs and returned data, including SDK result metadata, through the existing Session log. Underlying inference request/response capture and integration into DSH Session usage accounting are deferred. +The [native runtime](src/native.ts) passes the explicit model configuration to Stagehand's public initialization API. The adapter pins Zod to the version required by Stagehand because extraction passes Zod schemas to the SDK. Stagehand owns the model requests, response validation, and token accounting inside its browser extension. DSH records browser tool inputs and returned data, including SDK result metadata, through the existing Session log. Underlying inference request/response capture and integration into DSH Session usage accounting are deferred. No invariant companion is published: every browser operation uses the resource owner's single acquired handle, with no separately maintained browser relationship to compare. diff --git a/packages/experimental/browser-use-stagehand-native/README.zh.md b/packages/experimental/browser-use-stagehand-native/README.zh.md index 69f3c115c6..65e592fa44 100644 --- a/packages/experimental/browser-use-stagehand-native/README.zh.md +++ b/packages/experimental/browser-use-stagehand-native/README.zh.md @@ -90,7 +90,7 @@ env -u NODE_USE_ENV_PROXY DSH_STAGEHAND_E2E=1 pnpm exec vitest run --config vite 宿主在等待 CDP 就绪前即拥有启动的 Chromium 进程及其临时配置目录。Chromium 接收标准清理后的子进程环境,保留路径、区域设置和代理配置,排除凭据形式的变量及 DSH 身份信息。两种模式都在独立 Worker 中连接 SDK。Worker 除显式的源码 TypeScript 配置路径外不接收宿主环境,因此其 CDP 连接不继承宿主代理设置。SDK 关闭会等待活动操作。清理在配置的 SDK 宽限时间后终止连接 Worker;启动模式还会终止并等待自有 Chromium 进程退出,再移除配置目录。外部连接的浏览器保持运行。清理失败遵循下方的[所有权限制](#known-limitations-and-deferred-work)。 -[原生运行时](src/native.ts)将显式模型配置传入 Stagehand 的公开初始化 API。Stagehand 在其浏览器扩展中负责模型请求、响应验证与 token 计量。DSH 通过现有 Session 日志记录浏览器工具输入和返回数据,包括 SDK 结果元数据。底层推理请求/响应捕获及其与 DSH Session 用量计量的集成均属暂缓工作。 +[原生运行时](src/native.ts)将显式模型配置传入 Stagehand 的公开初始化 API。适配器将 Zod 固定为 Stagehand 要求的版本,因为提取操作会向 SDK 传递 Zod schema。Stagehand 在其浏览器扩展中负责模型请求、响应验证与 token 计量。DSH 通过现有 Session 日志记录浏览器工具输入和返回数据,包括 SDK 结果元数据。底层推理请求/响应捕获及其与 DSH Session 用量计量的集成均属暂缓工作。 此包不发布不变量配套模块:每次浏览器操作都使用资源所有者获取的唯一句柄,没有独立维护、需要比较的浏览器关系。 diff --git a/packages/experimental/browser-use-stagehand-native/package.json b/packages/experimental/browser-use-stagehand-native/package.json index f4b4d91c6c..3561c8c82e 100644 --- a/packages/experimental/browser-use-stagehand-native/package.json +++ b/packages/experimental/browser-use-stagehand-native/package.json @@ -44,7 +44,7 @@ "@deepseek-ai/dsh-mcp-client": "workspace:*", "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3", + "zod": "4.4.3", "@deepseek-ai/dsh-subprocess": "workspace:*", "@puppeteer/browsers": "3.2.2" }, diff --git a/packages/experimental/computer-use-cua-driver-native/package.json b/packages/experimental/computer-use-cua-driver-native/package.json index 2aaaeacc33..77f940611e 100644 --- a/packages/experimental/computer-use-cua-driver-native/package.json +++ b/packages/experimental/computer-use-cua-driver-native/package.json @@ -38,7 +38,7 @@ "@deepseek-ai/dsh-mcp-client": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", "@trycua/cua-driver": "0.28.0", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/experimental/speech-to-text-sensevoice/package.json b/packages/experimental/speech-to-text-sensevoice/package.json index ffe213d76d..070283ae44 100644 --- a/packages/experimental/speech-to-text-sensevoice/package.json +++ b/packages/experimental/speech-to-text-sensevoice/package.json @@ -35,7 +35,7 @@ "dependencies": { "@deepseek-ai/schemastery": "workspace:~", "@deepseek-ai/dsh-timeout": "workspace:*", - "zod": "^4.4.3", + "zod": "4.6.5", "sherpa-onnx-node": "1.13.8" }, "peerDependencies": { diff --git a/packages/experimental/webworker-runtime/package.json b/packages/experimental/webworker-runtime/package.json index 96744710d4..2091c3adc3 100644 --- a/packages/experimental/webworker-runtime/package.json +++ b/packages/experimental/webworker-runtime/package.json @@ -64,7 +64,7 @@ "@deepseek-ai/node-addon-system": "workspace:~", "@types/picomatch": "^3.0.2", "@types/readable-stream": "^4.0.24", - "chokidar": "^5.0.0" + "chokidar": "5.0.0" }, "files": [ "lib/index.js", diff --git a/packages/extensions/cordis-host-runner/package.json b/packages/extensions/cordis-host-runner/package.json index 92ef34a7b9..66cbb892bf 100644 --- a/packages/extensions/cordis-host-runner/package.json +++ b/packages/extensions/cordis-host-runner/package.json @@ -46,7 +46,7 @@ "dependencies": { "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/feedback/command-feedback/package.json b/packages/feedback/command-feedback/package.json index f61e534230..7da39e79ec 100644 --- a/packages/feedback/command-feedback/package.json +++ b/packages/feedback/command-feedback/package.json @@ -51,7 +51,7 @@ "@deepseek-ai/dsh-typert-protocol": "workspace:*" }, "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis-plugin-include": "workspace:~", diff --git a/packages/feedback/message-feedback/package.json b/packages/feedback/message-feedback/package.json index 0fcd3466de..e7655db733 100644 --- a/packages/feedback/message-feedback/package.json +++ b/packages/feedback/message-feedback/package.json @@ -54,7 +54,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis-plugin-include": "workspace:~", diff --git a/packages/fs/fs-local/package.json b/packages/fs/fs-local/package.json index 544e62e3ea..6968b9bb08 100644 --- a/packages/fs/fs-local/package.json +++ b/packages/fs/fs-local/package.json @@ -31,7 +31,7 @@ "@deepseek-ai/cordis": "workspace:~" }, "dependencies": { - "chokidar": "^4.0.3", + "chokidar": "5.0.0", "koffi": "3.1.1", "@deepseek-ai/schemastery": "workspace:~" }, diff --git a/packages/goal/goal/package.json b/packages/goal/goal/package.json index 35f256f51b..2e4bb6dfe0 100644 --- a/packages/goal/goal/package.json +++ b/packages/goal/goal/package.json @@ -65,7 +65,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-agent": "workspace:*", diff --git a/packages/host/plugin-inventory/package.json b/packages/host/plugin-inventory/package.json index 118222bbe9..560fb30b06 100644 --- a/packages/host/plugin-inventory/package.json +++ b/packages/host/plugin-inventory/package.json @@ -44,7 +44,7 @@ ], "license": "MIT", "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis-plugin-loader": "workspace:~", diff --git a/packages/host/product-telemetry-otel/package.json b/packages/host/product-telemetry-otel/package.json index b6441dbaa3..b073013fe1 100644 --- a/packages/host/product-telemetry-otel/package.json +++ b/packages/host/product-telemetry-otel/package.json @@ -28,9 +28,9 @@ "license": "MIT", "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "@opentelemetry/api-logs": "^0.220.0", - "@opentelemetry/otlp-exporter-base": "^0.220.0", - "@opentelemetry/sdk-logs": "^0.220.0" + "@opentelemetry/api-logs": "0.222.0", + "@opentelemetry/otlp-exporter-base": "0.222.0", + "@opentelemetry/sdk-logs": "0.222.0" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/interaction/commands/package.json b/packages/interaction/commands/package.json index 78c097c210..90f85f427d 100644 --- a/packages/interaction/commands/package.json +++ b/packages/interaction/commands/package.json @@ -65,7 +65,7 @@ }, "dependencies": { "@deepseek-ai/dsh-util-crypto": "workspace:*", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-agent": "workspace:*", diff --git a/packages/interaction/permission-presets/package.json b/packages/interaction/permission-presets/package.json index b62f95b780..006e8e6336 100644 --- a/packages/interaction/permission-presets/package.json +++ b/packages/interaction/permission-presets/package.json @@ -66,7 +66,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-shell": "workspace:*", diff --git a/packages/interaction/user-questions/package.json b/packages/interaction/user-questions/package.json index 308573db67..d114d91191 100644 --- a/packages/interaction/user-questions/package.json +++ b/packages/interaction/user-questions/package.json @@ -64,7 +64,7 @@ "@deepseek-ai/dsh-tools": "workspace:*" }, "dependencies": { - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/schemastery": "workspace:~" } } diff --git a/packages/llm/llm-retry/package.json b/packages/llm/llm-retry/package.json index 23a9af15a4..b82b65efd6 100644 --- a/packages/llm/llm-retry/package.json +++ b/packages/llm/llm-retry/package.json @@ -47,7 +47,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-brand": "workspace:*", diff --git a/packages/llm/llm/package.json b/packages/llm/llm/package.json index 045e9f9d60..8cc20a6867 100644 --- a/packages/llm/llm/package.json +++ b/packages/llm/llm/package.json @@ -66,7 +66,7 @@ "dependencies": { "@deepseek-ai/dsh-util-crypto": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-timeout": "workspace:*", "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/dsh-util-values": "workspace:*", diff --git a/packages/llm/token-meter/package.json b/packages/llm/token-meter/package.json index 3ee75c9ce8..28d707832e 100644 --- a/packages/llm/token-meter/package.json +++ b/packages/llm/token-meter/package.json @@ -47,7 +47,7 @@ "dependencies": { "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/mcp/mcp-client/package.json b/packages/mcp/mcp-client/package.json index 4baa63b528..6515b7cb58 100644 --- a/packages/mcp/mcp-client/package.json +++ b/packages/mcp/mcp-client/package.json @@ -56,7 +56,7 @@ "@deepseek-ai/dsh-http-proxy": "workspace:*", "@modelcontextprotocol/server": "2.0.0", "@modelcontextprotocol/node": "2.0.0", - "zod": "^4.4.3", + "zod": "4.6.5", "@deepseek-ai/dsh-mcp-resources": "workspace:*", "@deepseek-ai/dsh-system-prompt": "workspace:*" }, diff --git a/packages/plan/plan-mode/package.json b/packages/plan/plan-mode/package.json index 4993239e90..6cdf157f73 100644 --- a/packages/plan/plan-mode/package.json +++ b/packages/plan/plan-mode/package.json @@ -59,7 +59,7 @@ }, "dependencies": { "@deepseek-ai/dsh-brand": "workspace:*", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-agent": "workspace:*", diff --git a/packages/preset/agent-preset-registry/package.json b/packages/preset/agent-preset-registry/package.json index 3a6155037d..949b1601d8 100644 --- a/packages/preset/agent-preset-registry/package.json +++ b/packages/preset/agent-preset-registry/package.json @@ -69,7 +69,7 @@ "dependencies": { "@deepseek-ai/dsh-app-boot": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3", + "zod": "4.6.5", "js-yaml": "^4.2.0" }, "devDependencies": { diff --git a/packages/sandbox/sandbox-policy/package.json b/packages/sandbox/sandbox-policy/package.json index 6c68317073..2e4d809c63 100644 --- a/packages/sandbox/sandbox-policy/package.json +++ b/packages/sandbox/sandbox-policy/package.json @@ -42,7 +42,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-agent": "workspace:*", diff --git a/packages/schedule/schedule/package.json b/packages/schedule/schedule/package.json index ad8a1808d2..ccef3f485c 100644 --- a/packages/schedule/schedule/package.json +++ b/packages/schedule/schedule/package.json @@ -69,7 +69,7 @@ "dependencies": { "@deepseek-ai/schemastery": "workspace:~", "@js-temporal/polyfill": "0.5.1", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis-plugin-loader": "workspace:~", diff --git a/packages/session/session-projection-cache/package.json b/packages/session/session-projection-cache/package.json index c18fb2eb0b..dc43ce148b 100644 --- a/packages/session/session-projection-cache/package.json +++ b/packages/session/session-projection-cache/package.json @@ -29,7 +29,7 @@ "dependencies": { "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/session/session-projection/package.json b/packages/session/session-projection/package.json index a0d37af6ec..899179b67c 100644 --- a/packages/session/session-projection/package.json +++ b/packages/session/session-projection/package.json @@ -32,7 +32,7 @@ ], "license": "MIT", "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/dsh-session": "workspace:*", diff --git a/packages/session/session-stats/package.json b/packages/session/session-stats/package.json index 957f1e8718..0cddd1db46 100644 --- a/packages/session/session-stats/package.json +++ b/packages/session/session-stats/package.json @@ -42,7 +42,7 @@ "@deepseek-ai/cordis": "workspace:~" }, "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis-plugin-include": "workspace:~", diff --git a/packages/session/session-telemetry-otel/package.json b/packages/session/session-telemetry-otel/package.json index 229bfd1c1f..5c4fab01f0 100644 --- a/packages/session/session-telemetry-otel/package.json +++ b/packages/session/session-telemetry-otel/package.json @@ -27,9 +27,9 @@ ], "license": "MIT", "dependencies": { - "@opentelemetry/api-logs": "^0.220.0", - "@opentelemetry/otlp-exporter-base": "^0.220.0", - "@opentelemetry/sdk-logs": "^0.220.0", + "@opentelemetry/api-logs": "0.222.0", + "@opentelemetry/otlp-exporter-base": "0.222.0", + "@opentelemetry/sdk-logs": "0.222.0", "@deepseek-ai/schemastery": "workspace:~" }, "peerDependencies": { diff --git a/packages/session/session-title/package.json b/packages/session/session-title/package.json index a2c3abdf5f..3310f6ab3c 100644 --- a/packages/session/session-title/package.json +++ b/packages/session/session-title/package.json @@ -52,7 +52,7 @@ "dependencies": { "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/session/session-turn-outline/package.json b/packages/session/session-turn-outline/package.json index 530be0f6ac..8ec9958192 100644 --- a/packages/session/session-turn-outline/package.json +++ b/packages/session/session-turn-outline/package.json @@ -42,7 +42,7 @@ "@deepseek-ai/dsh-session-projection": "workspace:*" }, "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/skill/skill-filesystem/package.json b/packages/skill/skill-filesystem/package.json index 4c0abe11d4..31cc78045d 100644 --- a/packages/skill/skill-filesystem/package.json +++ b/packages/skill/skill-filesystem/package.json @@ -33,7 +33,7 @@ "@deepseek-ai/cordis": "workspace:~" }, "dependencies": { - "chokidar": "^5.0.0", + "chokidar": "5.0.0", "@deepseek-ai/schemastery": "workspace:~", "yaml": "^2.4.2" }, diff --git a/packages/spill/spill-policy/package.json b/packages/spill/spill-policy/package.json index bab1b6b026..d62c86dc93 100644 --- a/packages/spill/spill-policy/package.json +++ b/packages/spill/spill-policy/package.json @@ -68,6 +68,6 @@ "@deepseek-ai/dsh-ptc-runtime": "workspace:*", "@deepseek-ai/dsh-attachment-local": "workspace:*", "@deepseek-ai/dsh-tool-fs": "workspace:*", - "sharp": "^0.35.3" + "sharp": "0.35.5" } } diff --git a/packages/ssh/fs-ssh/package.json b/packages/ssh/fs-ssh/package.json index e82cdd8803..dd3868299d 100644 --- a/packages/ssh/fs-ssh/package.json +++ b/packages/ssh/fs-ssh/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/ssh/sandbox-ssh/package.json b/packages/ssh/sandbox-ssh/package.json index 816ed6c8e7..3d2edd509a 100644 --- a/packages/ssh/sandbox-ssh/package.json +++ b/packages/ssh/sandbox-ssh/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/ssh/ssh/package.json b/packages/ssh/ssh/package.json index 2514b9811a..5998f89f81 100644 --- a/packages/ssh/ssh/package.json +++ b/packages/ssh/ssh/package.json @@ -59,7 +59,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/ssh/subprocess-ssh/package.json b/packages/ssh/subprocess-ssh/package.json index 7c5c801fdc..7aea2efd6c 100644 --- a/packages/ssh/subprocess-ssh/package.json +++ b/packages/ssh/subprocess-ssh/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/storage/storage-domain/package.json b/packages/storage/storage-domain/package.json index 729a00bd81..5c99bfe4f2 100644 --- a/packages/storage/storage-domain/package.json +++ b/packages/storage/storage-domain/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/dsh-invariants": "workspace:*", diff --git a/packages/subagent/subagent-claude-code/package.json b/packages/subagent/subagent-claude-code/package.json index d830b63d8e..b3eda4b569 100644 --- a/packages/subagent/subagent-claude-code/package.json +++ b/packages/subagent/subagent-claude-code/package.json @@ -46,7 +46,7 @@ "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", "@modelcontextprotocol/sdk": "^1.29.0", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/subagent/subagent/package.json b/packages/subagent/subagent/package.json index 607e13ebf6..d0ef0309ee 100644 --- a/packages/subagent/subagent/package.json +++ b/packages/subagent/subagent/package.json @@ -57,7 +57,7 @@ "@deepseek-ai/dsh-chunked-list": "workspace:*", "@deepseek-ai/dsh-util-values": "workspace:*", "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/subagent/tool-subagent/package.json b/packages/subagent/tool-subagent/package.json index f1c0488372..d344b601bf 100644 --- a/packages/subagent/tool-subagent/package.json +++ b/packages/subagent/tool-subagent/package.json @@ -51,7 +51,7 @@ }, "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis-plugin-loader": "workspace:~", diff --git a/packages/telemetry/otel/README.i18n.yaml b/packages/telemetry/otel/README.i18n.yaml index 16787b0056..c7ca770233 100644 --- a/packages/telemetry/otel/README.i18n.yaml +++ b/packages/telemetry/otel/README.i18n.yaml @@ -18,8 +18,8 @@ en: f141a9d909c555d8 zh: e4f5b690ccb1337c /deepseek-ai-dsh-otel/understand-the-implementation: - en: 0976ab2c661529bb - zh: 9653db33fc70195d + en: 3c475a975498a19a + zh: ae7e26fc2450a222 /deepseek-ai-dsh-otel/further-exploration: en: ee17b991de098cc0 zh: f90257e411921f2b diff --git a/packages/telemetry/otel/README.md b/packages/telemetry/otel/README.md index 6d993d0a8a..c1d04d073b 100644 --- a/packages/telemetry/otel/README.md +++ b/packages/telemetry/otel/README.md @@ -36,6 +36,8 @@ Headers are explicit. The service does not add a channel header or inherit ambie `src/index.ts` registers the service; `event-log.ts` owns ordinary SDK batching; `session-log.ts` owns byte/count scheduling; `transport.ts` supplies the Session SDK JSON HTTP delegate; `event-transport.ts` uses Got for cancellable ordinary-event HTTP requests and retry waits with SDK serialization and export accounting. No global OTel provider is installed. The Session processor measures each record once, groups conservative sizes, and waits for the SDK concurrency queue to clear after every callback before sending another request. +OpenTelemetry SDK dependencies use exact versions from one coordinated release across this service and its two adapters. Exporter self-metrics use the SDK's no-op meter; channels create no metrics pipeline. + No runtime invariant companion is published: channel creation registers no independent domain state, and collector delivery cannot be inferred from local queues. Composition tests exercise independent channels and service removal; adapter tests cover dependent-fiber cleanup and feedback authorization. diff --git a/packages/telemetry/otel/README.zh.md b/packages/telemetry/otel/README.zh.md index b90596a0d6..6a8bdc8854 100644 --- a/packages/telemetry/otel/README.zh.md +++ b/packages/telemetry/otel/README.zh.md @@ -36,6 +36,8 @@ Header 显式提供。服务不会附加 channel header,也不继承环境中 `src/index.ts` 注册服务;`event-log.ts` 负责普通事件的 SDK 聚合;`session-log.ts` 负责字节和条数调度;`transport.ts` 提供 Session 的 SDK JSON HTTP delegate;`event-transport.ts` 使用 Got 实现可取消的普通事件 HTTP 请求和重试等待,序列化与导出计数仍由 SDK 负责。不安装全局 OTel provider。Session processor 对每条记录只计量一次,按保守大小组包,并在每次回调后等待 SDK 并发队列清理完成才发送下一请求。 +本服务及其两个适配器的 OpenTelemetry SDK 依赖使用同一配套版本系列的精确版本。Exporter 自身的指标使用 SDK 的空操作 meter;通道不创建指标上报管线。 + 不发布运行时不变式伴生入口:通道创建不注册独立领域状态,无法从本地队列推断 collector 是否收到记录。组合测试覆盖独立通道和服务移除;适配器测试覆盖依赖 fiber 清理与反馈授权。 diff --git a/packages/telemetry/otel/package.json b/packages/telemetry/otel/package.json index 8d97441dc5..84a81a0686 100644 --- a/packages/telemetry/otel/package.json +++ b/packages/telemetry/otel/package.json @@ -28,12 +28,12 @@ "license": "MIT", "dependencies": { "@opentelemetry/api": "^1.9.1", - "@opentelemetry/api-logs": "^0.220.0", - "@opentelemetry/otlp-exporter-base": "^0.220.0", - "@opentelemetry/resources": "^2.9.0", - "@opentelemetry/sdk-logs": "^0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/otlp-transformer": "^0.220.0", + "@opentelemetry/api-logs": "0.222.0", + "@opentelemetry/otlp-exporter-base": "0.222.0", + "@opentelemetry/resources": "2.11.0", + "@opentelemetry/sdk-logs": "0.222.0", + "@opentelemetry/core": "2.11.0", + "@opentelemetry/otlp-transformer": "0.222.0", "got": "^14.6.6" }, "peerDependencies": { diff --git a/packages/telemetry/otel/src/event-transport.ts b/packages/telemetry/otel/src/event-transport.ts index 88d5a78f6a..fe0c60f79b 100644 --- a/packages/telemetry/otel/src/event-transport.ts +++ b/packages/telemetry/otel/src/event-transport.ts @@ -3,7 +3,8 @@ import type { Agent as HttpsAgent } from 'node:https' import { gzipSync } from 'node:zlib' import got from 'got' import { createOtlpNetworkExportDelegate, OTLPExporterBase, type OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base' -import { JsonLogsSerializer } from '@opentelemetry/otlp-transformer' +import { createOtlpHttpExporterMetrics } from '@opentelemetry/otlp-exporter-base/node-http' +import { JsonLogsSerializer, LogsExporterMetricsHelper } from '@opentelemetry/otlp-transformer' import type { LogRecordExporter } from '@opentelemetry/sdk-logs' import { logTransportOptions } from './transport.ts' @@ -16,7 +17,8 @@ import { logTransportOptions } from './transport.ts' export function createEventLogExporter(options: OTLPExporterNodeConfigBase & { url: string }, signal: AbortSignal): LogRecordExporter { const config = logTransportOptions(options) let agent: ReturnType | undefined - const exporter = new OTLPExporterBase(createOtlpNetworkExportDelegate(config, JsonLogsSerializer, { + const metrics = createOtlpHttpExporterMetrics('otlp_http_log_exporter', LogsExporterMetricsHelper, config.url, undefined) + const exporter = new OTLPExporterBase(createOtlpNetworkExportDelegate(config, JsonLogsSerializer, metrics, { async send(data, timeoutMillis) { signal.throwIfAborted() agent ??= config.agentFactory(new URL(config.url).protocol) diff --git a/packages/telemetry/otel/src/transport.ts b/packages/telemetry/otel/src/transport.ts index ef59a96992..c2d61d37c2 100644 --- a/packages/telemetry/otel/src/transport.ts +++ b/packages/telemetry/otel/src/transport.ts @@ -1,7 +1,7 @@ /** Explicit OTLP JSON transport for feedback-authorized Session logs. */ import { createOtlpHttpExportDelegate, getSharedConfigurationFromEnvironment, httpAgentFactoryFromOptions } from '@opentelemetry/otlp-exporter-base/node-http' import { getSharedConfigurationDefaults, mergeOtlpSharedConfigurationWithDefaults, OTLPExporterBase, type OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base' -import { JsonLogsSerializer } from '@opentelemetry/otlp-transformer' +import { JsonLogsSerializer, LogsExporterMetricsHelper } from '@opentelemetry/otlp-transformer' import type { LogRecordExporter } from '@opentelemetry/sdk-logs' /** @@ -10,7 +10,9 @@ import type { LogRecordExporter } from '@opentelemetry/sdk-logs' * @returns the exporter owned by one independent log pipeline. */ export function createLogExporter(options: OTLPExporterNodeConfigBase & { url: string }): LogRecordExporter { - return new OTLPExporterBase(createOtlpHttpExportDelegate(logTransportOptions(options), JsonLogsSerializer)) + return new OTLPExporterBase(createOtlpHttpExportDelegate( + logTransportOptions(options), JsonLogsSerializer, 'otlp_http_log_exporter', LogsExporterMetricsHelper, undefined, + )) } /** diff --git a/packages/todo/tool-todo/package.json b/packages/todo/tool-todo/package.json index 1641c5d9fb..af4873244d 100644 --- a/packages/todo/tool-todo/package.json +++ b/packages/todo/tool-todo/package.json @@ -38,7 +38,7 @@ "license": "MIT", "dependencies": { "@deepseek-ai/schemastery": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/dsh-agent": "workspace:*", diff --git a/packages/typert/generator/package.json b/packages/typert/generator/package.json index 50bd715865..7cbde6f8d9 100644 --- a/packages/typert/generator/package.json +++ b/packages/typert/generator/package.json @@ -42,6 +42,6 @@ "@deepseek-ai/dsh-tool-cordis": "workspace:*", "@deepseek-ai/dsh-typert-registry": "workspace:*", "@deepseek-ai/cordis": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/typert/loader/package.json b/packages/typert/loader/package.json index 34edcec983..dcbbd81f8b 100644 --- a/packages/typert/loader/package.json +++ b/packages/typert/loader/package.json @@ -39,6 +39,6 @@ "@deepseek-ai/cordis-plugin-loader": "workspace:~", "@deepseek-ai/dsh-typert-registry": "workspace:*", "@deepseek-ai/cordis": "workspace:~", - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/typert/registry/package.json b/packages/typert/registry/package.json index e374b9cacf..66098943d0 100644 --- a/packages/typert/registry/package.json +++ b/packages/typert/registry/package.json @@ -48,7 +48,7 @@ ], "license": "MIT", "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:~" diff --git a/packages/util/chunked-list/package.json b/packages/util/chunked-list/package.json index d2d27867ee..598c62f9f1 100644 --- a/packages/util/chunked-list/package.json +++ b/packages/util/chunked-list/package.json @@ -33,6 +33,6 @@ "@deepseek-ai/cordis": "workspace:~" }, "dependencies": { - "zod": "^4.4.3" + "zod": "4.6.5" } } diff --git a/packages/util/http-proxy/package.json b/packages/util/http-proxy/package.json index 2275e12629..53165ec478 100644 --- a/packages/util/http-proxy/package.json +++ b/packages/util/http-proxy/package.json @@ -30,7 +30,7 @@ "@deepseek-ai/cordis": "workspace:~" }, "dependencies": { - "undici": "^8.10.0" + "undici": "8.11.2" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/web/web-fetch-http/package.json b/packages/web/web-fetch-http/package.json index 1019d7da9c..ea5869e212 100644 --- a/packages/web/web-fetch-http/package.json +++ b/packages/web/web-fetch-http/package.json @@ -35,7 +35,7 @@ "dependencies": { "@deepseek-ai/schemastery": "workspace:~", "ipaddr.js": "^2.5.0", - "undici": "^8.10.0" + "undici": "8.11.2" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/packages/workspace/workspace/package.json b/packages/workspace/workspace/package.json index 52ed1ad7e1..ad21abd651 100644 --- a/packages/workspace/workspace/package.json +++ b/packages/workspace/workspace/package.json @@ -47,7 +47,7 @@ }, "dependencies": { "@deepseek-ai/dsh-brand": "workspace:*", - "zod": "^4.4.3" + "zod": "4.6.5" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cd66adcaf..c26042013c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -433,7 +433,7 @@ importers: devDependencies: '@agentclientprotocol/sdk': specifier: 1.4.0 - version: 1.4.0(zod@4.4.3) + version: 1.4.0(zod@4.6.5) '@deepseek-ai/dsh-acp': specifier: workspace:* version: link:../../packages/acp/acp @@ -679,8 +679,8 @@ importers: specifier: ^18.2.0 version: 18.3.1(react@18.3.1) sharp: - specifier: ^0.35.3 - version: 0.35.3(@types/node@22.20.0) + specifier: 0.35.5 + version: 0.35.5(@types/node@22.20.0) typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1019,7 +1019,7 @@ importers: dependencies: '@agentclientprotocol/sdk': specifier: 1.4.0 - version: 1.4.0(zod@4.4.3) + version: 1.4.0(zod@4.6.5) '@deepseek-ai/dsh-brand': specifier: workspace:* version: link:../../util/brand @@ -1073,8 +1073,8 @@ importers: packages/api/account-controller: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1135,8 +1135,8 @@ importers: specifier: ^8.18.1 version: 8.18.1 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/api/job-controller: dependencies: @@ -1147,8 +1147,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1296,8 +1296,8 @@ importers: specifier: workspace:* version: link:../../interaction/user-questions zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/api/session-controller: dependencies: @@ -1314,8 +1314,8 @@ importers: specifier: ^3.0.2 version: 3.0.2 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1450,8 +1450,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1496,8 +1496,8 @@ importers: specifier: ^6.0.0 version: 6.0.0 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1554,8 +1554,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1603,8 +1603,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1658,8 +1658,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery sharp: - specifier: ^0.35.3 - version: 0.35.3(@types/node@22.20.0) + specifier: 0.35.5 + version: 0.35.5(@types/node@22.20.0) devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -1787,8 +1787,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery chokidar: - specifier: ^4.0.3 - version: 4.0.3 + specifier: 5.0.0 + version: 5.0.0 picomatch: specifier: ^4.0.3 version: 4.0.4 @@ -1845,8 +1845,8 @@ importers: specifier: ^2.9.0 version: 2.9.0 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -2827,8 +2827,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -2864,8 +2864,8 @@ importers: specifier: workspace:* version: link:../../typert/protocol zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -2990,8 +2990,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -3612,8 +3612,8 @@ importers: specifier: ^18.2.0 version: 18.3.1(react@18.3.1) zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/client/ui-deliverables: dependencies: @@ -4357,8 +4357,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -5641,8 +5641,8 @@ importers: specifier: ^18.2.0 version: 18.3.1(react@18.3.1) zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/client/ui-sidebar-terminal: devDependencies: @@ -6328,6 +6328,9 @@ importers: '@deepseek-ai/dsh-host-webserver': specifier: workspace:* version: link:../../host/webserver + '@tanstack/react-virtual': + specifier: 3.14.9 + version: 3.14.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/react': specifier: ~18.3.1 version: 18.3.31 @@ -6343,6 +6346,9 @@ importers: typescript: specifier: ^6.0.3 version: 6.0.3 + zod: + specifier: 4.6.5 + version: 4.6.5 packages/compaction/command-compact: devDependencies: @@ -6646,8 +6652,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -6722,8 +6728,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -6780,8 +6786,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -6878,8 +6884,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -7088,8 +7094,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery chokidar: - specifier: ^4.0.3 - version: 4.0.3 + specifier: 5.0.0 + version: 5.0.0 yaml: specifier: ^2.9.0 version: 2.9.0 @@ -7131,8 +7137,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -7245,8 +7251,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -7276,8 +7282,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -7350,8 +7356,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -7628,7 +7634,7 @@ importers: specifier: 3.2.2 version: 3.2.2(yauzl@3.4.0) zod: - specifier: ^4.4.3 + specifier: 4.4.3 version: 4.4.3 devDependencies: '@deepseek-ai/cordis': @@ -7858,8 +7864,8 @@ importers: specifier: 0.28.0 version: 0.28.0 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -8003,8 +8009,8 @@ importers: specifier: 1.13.8 version: 1.13.8 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -8230,7 +8236,7 @@ importers: specifier: ^4.0.24 version: 4.0.24 chokidar: - specifier: ^5.0.0 + specifier: 5.0.0 version: 5.0.0 packages/extensions/cordis-client-runner: @@ -8272,8 +8278,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -8384,8 +8390,8 @@ importers: packages/feedback/command-feedback: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -8424,8 +8430,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -8482,8 +8488,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery chokidar: - specifier: ^4.0.3 - version: 4.0.3 + specifier: 5.0.0 + version: 5.0.0 koffi: specifier: 3.1.1 version: 3.1.1 @@ -8741,8 +8747,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9147,8 +9153,8 @@ importers: packages/host/plugin-inventory: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9178,14 +9184,14 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery '@opentelemetry/api-logs': - specifier: ^0.220.0 - version: 0.220.0 + specifier: 0.222.0 + version: 0.222.0 '@opentelemetry/otlp-exporter-base': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-logs': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9243,8 +9249,8 @@ importers: specifier: workspace:* version: link:../../util/crypto zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9280,8 +9286,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9379,8 +9385,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9529,8 +9535,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9707,7 +9713,7 @@ importers: version: link:../../../vendor/schemastery '@earendil-works/pi-ai': specifier: ^0.87.1 - version: 0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(supports-color@9.4.0)(ws@8.21.0)(zod@4.4.3) + version: 0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5))(supports-color@9.4.0)(ws@8.21.0)(zod@4.6.5) devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9755,8 +9761,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -9862,8 +9868,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -10044,10 +10050,10 @@ importers: version: 2026.7.4 '@modelcontextprotocol/server-filesystem': specifier: ^2026.7.4 - version: 2026.7.10(zod@4.4.3) + version: 2026.7.10(zod@4.6.5) zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/mcp/mcp-resources: dependencies: @@ -10083,8 +10089,8 @@ importers: specifier: workspace:* version: link:../../util/brand zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -10169,8 +10175,8 @@ importers: specifier: ^4.2.0 version: 4.3.1 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -10370,8 +10376,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -10444,8 +10450,8 @@ importers: specifier: 0.5.1 version: 0.5.1 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11075,8 +11081,8 @@ importers: packages/session/session-projection: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11094,8 +11100,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11119,8 +11125,8 @@ importers: packages/session/session-stats: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11159,14 +11165,14 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery '@opentelemetry/api-logs': - specifier: ^0.220.0 - version: 0.220.0 + specifier: 0.222.0 + version: 0.222.0 '@opentelemetry/otlp-exporter-base': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-logs': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11229,8 +11235,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11356,8 +11362,8 @@ importers: packages/session/session-turn-outline: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -11852,7 +11858,7 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery chokidar: - specifier: ^5.0.0 + specifier: 5.0.0 version: 5.0.0 yaml: specifier: ^2.4.2 @@ -12074,8 +12080,8 @@ importers: specifier: workspace:* version: link:../../core/tools sharp: - specifier: ^0.35.3 - version: 0.35.3(@types/node@22.20.0) + specifier: 0.35.5 + version: 0.35.5(@types/node@22.20.0) packages/ssh/fs-ssh: dependencies: @@ -12083,8 +12089,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12108,8 +12114,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12127,8 +12133,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12188,8 +12194,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12216,8 +12222,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12270,8 +12276,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12341,7 +12347,7 @@ importers: dependencies: '@agentclientprotocol/sdk': specifier: 1.4.0 - version: 1.4.0(zod@4.4.3) + version: 1.4.0(zod@4.6.5) '@deepseek-ai/dsh-brand': specifier: workspace:* version: link:../../util/brand @@ -12399,10 +12405,10 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: 0.3.263 - version: 0.3.263(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3) + version: 0.3.263(@anthropic-ai/sdk@0.93.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5))(zod@4.6.5) '@anthropic-ai/sdk': specifier: 0.93.0 - version: 0.93.0(zod@4.4.3) + version: 0.93.0(zod@4.6.5) '@deepseek-ai/dsh-brand': specifier: workspace:* version: link:../../util/brand @@ -12411,10 +12417,10 @@ importers: version: link:../../../vendor/schemastery '@modelcontextprotocol/sdk': specifier: ^1.29.0 - version: 1.29.0(zod@4.4.3) + version: 1.29.0(zod@4.6.5) zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12773,8 +12779,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -12939,23 +12945,23 @@ importers: specifier: ^1.9.1 version: 1.9.1 '@opentelemetry/api-logs': - specifier: ^0.220.0 - version: 0.220.0 + specifier: 0.222.0 + version: 0.222.0 '@opentelemetry/core': - specifier: 2.9.0 - version: 2.9.0(@opentelemetry/api@1.9.1) + specifier: 2.11.0 + version: 2.11.0(@opentelemetry/api@1.9.1) '@opentelemetry/otlp-exporter-base': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) '@opentelemetry/otlp-transformer': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) '@opentelemetry/resources': - specifier: ^2.9.0 - version: 2.10.0(@opentelemetry/api@1.9.1) + specifier: 2.11.0 + version: 2.11.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-logs': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.1) + specifier: 0.222.0 + version: 0.222.0(@opentelemetry/api@1.9.1) got: specifier: ^14.6.6 version: 14.6.6 @@ -13322,7 +13328,7 @@ importers: dependencies: '@agentclientprotocol/sdk': specifier: 1.4.0 - version: 1.4.0(zod@4.4.3) + version: 1.4.0(zod@4.6.5) '@deepseek-ai/cordis-plugin-include': specifier: workspace:~ version: link:../../../vendor/include @@ -13388,8 +13394,8 @@ importers: specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -13450,8 +13456,8 @@ importers: specifier: workspace:* version: link:../registry zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/typert/loader: dependencies: @@ -13472,8 +13478,8 @@ importers: specifier: workspace:* version: link:../registry zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 packages/typert/protocol: dependencies: @@ -13488,8 +13494,8 @@ importers: packages/typert/registry: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -13513,8 +13519,8 @@ importers: packages/util/chunked-list: dependencies: zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -13547,8 +13553,8 @@ importers: packages/util/http-proxy: dependencies: undici: - specifier: ^8.10.0 - version: 8.10.0 + specifier: 8.11.2 + version: 8.11.2 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -13694,8 +13700,8 @@ importers: specifier: ^2.5.0 version: 2.5.0 undici: - specifier: ^8.10.0 - version: 8.10.0 + specifier: 8.11.2 + version: 8.11.2 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -14078,8 +14084,8 @@ importers: specifier: workspace:* version: link:../../util/brand zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: 4.6.5 + version: 4.6.5 devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -15848,160 +15854,160 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.35.3': - resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.35.3': - resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-freebsd-wasm32@0.35.3': - resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} engines: {node: '>=20.9.0'} os: [freebsd] - '@img/sharp-libvips-darwin-arm64@1.3.2': - resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.3.2': - resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.3.2': - resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.3.2': - resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.3.2': - resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.3.2': - resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.3.2': - resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.3.2': - resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.3.2': - resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.3.2': - resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.35.3': - resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.35.3': - resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.35.3': - resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.35.3': - resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.35.3': - resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.35.3': - resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.35.3': - resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.35.3': - resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.35.3': - resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} engines: {node: '>=20.9.0'} - '@img/sharp-webcontainers-wasm32@0.35.3': - resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.35.3': - resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.35.3': - resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.35.3': - resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -16422,16 +16428,16 @@ packages: cpu: [x64] os: [win32] - '@opentelemetry/api-logs@0.220.0': - resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} + '@opentelemetry/api-logs@0.222.0': + resolution: {integrity: sha512-9mb1If+IF6u0ZVXkHQ6ogEae5HwA6ajIVUgpSDQyRASxft6BSXHvBvPooRle3yFN/fKnCdSOnuu0OC3PLcF6+g==} engines: {node: '>=8.0.0'} '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/core@2.10.0': - resolution: {integrity: sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==} + '@opentelemetry/core@2.11.0': + resolution: {integrity: sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -16442,44 +16448,38 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/otlp-exporter-base@0.220.0': - resolution: {integrity: sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==} + '@opentelemetry/otlp-exporter-base@0.222.0': + resolution: {integrity: sha512-YbywG3veEm2Fb6TbdxRkuquWob6eVWXuA8/Ba1tXz9jHfUqpdE3keilOHEtPboC4CvS1bjeeVfNkWGOOrLj+lw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-transformer@0.220.0': - resolution: {integrity: sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==} + '@opentelemetry/otlp-transformer@0.222.0': + resolution: {integrity: sha512-/F3BZ89+CJQnZkMh2tCrtcdB+XT2Dxhj4FFE+WPQ//413hmFL0/RfEX6vgOIWGhiSzrkHWTK3+6SiT7K5/g/jQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/resources@2.10.0': - resolution: {integrity: sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==} + '@opentelemetry/resources@2.11.0': + resolution: {integrity: sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/resources@2.9.0': - resolution: {integrity: sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - - '@opentelemetry/sdk-logs@0.220.0': - resolution: {integrity: sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==} + '@opentelemetry/sdk-logs@0.222.0': + resolution: {integrity: sha512-+19YHODIjaUCArxleaJtuufFZVpz/xvvK+VllQqE+W8hHolxdoRwHfK/s667zezwh1hkx6FFF+oYzetYgqK+Bg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' - '@opentelemetry/sdk-metrics@2.9.0': - resolution: {integrity: sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==} + '@opentelemetry/sdk-metrics@2.11.0': + resolution: {integrity: sha512-7GXXcObyHyDUUSG+L+kJoquty01bzm7ivE7+SSgXXJcHuPzGviptxwARmI2c+bnnxjexGQbJnyNlN8HxBP/Y7A==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.9.0 <1.10.0' - '@opentelemetry/sdk-trace@2.9.0': - resolution: {integrity: sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==} + '@opentelemetry/sdk-trace@2.11.0': + resolution: {integrity: sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' @@ -21119,8 +21119,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.35.3: - resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} engines: {node: '>=20.9.0'} peerDependencies: '@types/node': '*' @@ -21588,8 +21588,8 @@ packages: resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} engines: {node: '>=20.18.1'} - undici@8.10.0: - resolution: {integrity: sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==} + undici@8.11.2: + resolution: {integrity: sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==} engines: {node: '>=22.19.0'} unicode-properties@1.4.1: @@ -22089,6 +22089,9 @@ packages: zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.5: + resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} + zustand@4.4.7: resolution: {integrity: sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==} engines: {node: '>=12.7.0'} @@ -22109,9 +22112,9 @@ packages: snapshots: - '@agentclientprotocol/sdk@1.4.0(zod@4.4.3)': + '@agentclientprotocol/sdk@1.4.0(zod@4.6.5)': dependencies: - zod: 4.4.3 + zod: 4.6.5 '@algolia/abtesting@1.21.2': dependencies: @@ -22254,11 +22257,11 @@ snapshots: '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.263': optional: true - '@anthropic-ai/claude-agent-sdk@0.3.263(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3)': + '@anthropic-ai/claude-agent-sdk@0.3.263(@anthropic-ai/sdk@0.93.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5))(zod@4.6.5)': dependencies: - '@anthropic-ai/sdk': 0.93.0(zod@4.4.3) - '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) - zod: 4.4.3 + '@anthropic-ai/sdk': 0.93.0(zod@4.6.5) + '@modelcontextprotocol/sdk': 1.29.0(zod@4.6.5) + zod: 4.6.5 optionalDependencies: '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.263 '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.263 @@ -22269,18 +22272,18 @@ snapshots: '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.263 '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.263 - '@anthropic-ai/sdk@0.124.0(zod@4.4.3)': + '@anthropic-ai/sdk@0.124.0(zod@4.6.5)': dependencies: json-schema-to-ts: 3.1.1 standardwebhooks: 1.1.1 optionalDependencies: - zod: 4.4.3 + zod: 4.6.5 - '@anthropic-ai/sdk@0.93.0(zod@4.4.3)': + '@anthropic-ai/sdk@0.93.0(zod@4.6.5)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: - zod: 4.4.3 + zod: 4.6.5 '@asamuzakjp/css-color@5.1.11': dependencies: @@ -22733,16 +22736,16 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' - '@earendil-works/pi-ai@0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(supports-color@9.4.0)(ws@8.21.0)(zod@4.4.3)': + '@earendil-works/pi-ai@0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5))(supports-color@9.4.0)(ws@8.21.0)(zod@4.6.5)': dependencies: - '@anthropic-ai/sdk': 0.124.0(zod@4.4.3) + '@anthropic-ai/sdk': 0.124.0(zod@4.6.5) '@aws-sdk/client-bedrock-runtime': 3.1127.0 '@earendil-works/pi-telemetry': 0.87.1 - '@google/genai': 2.21.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)) + '@google/genai': 2.21.0(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5)) '@smithy/node-http-handler': 4.12.1 http-proxy-agent: 9.1.0(supports-color@9.4.0) https-proxy-agent: 9.1.0(supports-color@9.4.0) - openai: 6.40.0(ws@8.21.0)(zod@4.4.3) + openai: 6.40.0(ws@8.21.0)(zod@4.6.5) partial-json: 0.1.7 typebox: 1.3.27 transitivePeerDependencies: @@ -23194,14 +23197,14 @@ snapshots: react-dom: 18.3.1(react@18.3.1) regenerator-runtime: 0.14.1 - '@google/genai@2.21.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))': + '@google/genai@2.21.0(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5))': dependencies: google-auth-library: 10.7.0 p-retry: 4.6.2 protobufjs: 7.6.4 ws: 8.21.0 optionalDependencies: - '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) + '@modelcontextprotocol/sdk': 1.29.0(zod@4.6.5) transitivePeerDependencies: - bufferutil - supports-color @@ -23241,108 +23244,108 @@ snapshots: '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.35.3': + '@img/sharp-darwin-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-arm64': 1.3.4 optional: true - '@img/sharp-darwin-x64@0.35.3': + '@img/sharp-darwin-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.4 optional: true - '@img/sharp-freebsd-wasm32@0.35.3': + '@img/sharp-freebsd-wasm32@0.35.5': dependencies: - '@img/sharp-wasm32': 0.35.3 + '@img/sharp-wasm32': 0.35.5 optional: true - '@img/sharp-libvips-darwin-arm64@1.3.2': + '@img/sharp-libvips-darwin-arm64@1.3.4': optional: true - '@img/sharp-libvips-darwin-x64@1.3.2': + '@img/sharp-libvips-darwin-x64@1.3.4': optional: true - '@img/sharp-libvips-linux-arm64@1.3.2': + '@img/sharp-libvips-linux-arm64@1.3.4': optional: true - '@img/sharp-libvips-linux-arm@1.3.2': + '@img/sharp-libvips-linux-arm@1.3.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.3.2': + '@img/sharp-libvips-linux-ppc64@1.3.4': optional: true - '@img/sharp-libvips-linux-riscv64@1.3.2': + '@img/sharp-libvips-linux-riscv64@1.3.4': optional: true - '@img/sharp-libvips-linux-s390x@1.3.2': + '@img/sharp-libvips-linux-s390x@1.3.4': optional: true - '@img/sharp-libvips-linux-x64@1.3.2': + '@img/sharp-libvips-linux-x64@1.3.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.3.2': + '@img/sharp-libvips-linuxmusl-x64@1.3.4': optional: true - '@img/sharp-linux-arm64@0.35.3': + '@img/sharp-linux-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.4 optional: true - '@img/sharp-linux-arm@0.35.3': + '@img/sharp-linux-arm@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.4 optional: true - '@img/sharp-linux-ppc64@0.35.3': + '@img/sharp-linux-ppc64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.4 optional: true - '@img/sharp-linux-riscv64@0.35.3': + '@img/sharp-linux-riscv64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.4 optional: true - '@img/sharp-linux-s390x@0.35.3': + '@img/sharp-linux-s390x@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.4 optional: true - '@img/sharp-linux-x64@0.35.3': + '@img/sharp-linux-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.4 optional: true - '@img/sharp-linuxmusl-arm64@0.35.3': + '@img/sharp-linuxmusl-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 optional: true - '@img/sharp-linuxmusl-x64@0.35.3': + '@img/sharp-linuxmusl-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 optional: true - '@img/sharp-wasm32@0.35.3': + '@img/sharp-wasm32@0.35.5': dependencies: '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-webcontainers-wasm32@0.35.3': + '@img/sharp-webcontainers-wasm32@0.35.5': dependencies: - '@img/sharp-wasm32': 0.35.3 + '@img/sharp-wasm32': 0.35.5 optional: true - '@img/sharp-win32-arm64@0.35.3': + '@img/sharp-win32-arm64@0.35.5': optional: true - '@img/sharp-win32-ia32@0.35.3': + '@img/sharp-win32-ia32@0.35.5': optional: true - '@img/sharp-win32-x64@0.35.3': + '@img/sharp-win32-x64@0.35.5': optional: true '@isaacs/cliui@8.0.2': @@ -23608,6 +23611,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.29.0(zod@4.6.5)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.29) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.29 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.6.5 + zod-to-json-schema: 3.25.2(zod@4.6.5) + transitivePeerDependencies: + - supports-color + '@modelcontextprotocol/server-everything@2026.7.4': dependencies: '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) @@ -23619,9 +23644,9 @@ snapshots: - '@cfworker/json-schema' - supports-color - '@modelcontextprotocol/server-filesystem@2026.7.10(zod@4.4.3)': + '@modelcontextprotocol/server-filesystem@2026.7.10(zod@4.6.5)': dependencies: - '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) + '@modelcontextprotocol/sdk': 1.29.0(zod@4.6.5) diff: 8.0.4 glob: 10.5.0 minimatch: 10.2.5 @@ -23750,13 +23775,13 @@ snapshots: '@openai/codex@0.153.4-win32-x64': optional: true - '@opentelemetry/api-logs@0.220.0': + '@opentelemetry/api-logs@0.222.0': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api@1.9.1': {} - '@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.43.0 @@ -23766,53 +23791,47 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/otlp-exporter-base@0.220.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-exporter-base@0.222.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer@0.220.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-transformer@0.222.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.220.0 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.222.0 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.222.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.11.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/resources@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-logs@0.222.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.222.0 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/sdk-logs@0.220.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-metrics@2.11.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.220.0 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.43.0 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace@2.11.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - - '@opentelemetry/sdk-trace@2.9.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 '@opentelemetry/semantic-conventions@1.43.0': {} @@ -28099,10 +28118,10 @@ snapshots: powershell-utils: 0.2.1 wsl-utils: 1.0.0 - openai@6.40.0(ws@8.21.0)(zod@4.4.3): + openai@6.40.0(ws@8.21.0)(zod@4.6.5): optionalDependencies: ws: 8.21.0 - zod: 4.4.3 + zod: 4.6.5 opener@1.5.2: {} @@ -28756,37 +28775,37 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.35.3(@types/node@22.20.0): + sharp@0.35.5(@types/node@22.20.0): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.35.3 - '@img/sharp-darwin-x64': 0.35.3 - '@img/sharp-freebsd-wasm32': 0.35.3 - '@img/sharp-libvips-darwin-arm64': 1.3.2 - '@img/sharp-libvips-darwin-x64': 1.3.2 - '@img/sharp-libvips-linux-arm': 1.3.2 - '@img/sharp-libvips-linux-arm64': 1.3.2 - '@img/sharp-libvips-linux-ppc64': 1.3.2 - '@img/sharp-libvips-linux-riscv64': 1.3.2 - '@img/sharp-libvips-linux-s390x': 1.3.2 - '@img/sharp-libvips-linux-x64': 1.3.2 - '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 - '@img/sharp-libvips-linuxmusl-x64': 1.3.2 - '@img/sharp-linux-arm': 0.35.3 - '@img/sharp-linux-arm64': 0.35.3 - '@img/sharp-linux-ppc64': 0.35.3 - '@img/sharp-linux-riscv64': 0.35.3 - '@img/sharp-linux-s390x': 0.35.3 - '@img/sharp-linux-x64': 0.35.3 - '@img/sharp-linuxmusl-arm64': 0.35.3 - '@img/sharp-linuxmusl-x64': 0.35.3 - '@img/sharp-webcontainers-wasm32': 0.35.3 - '@img/sharp-win32-arm64': 0.35.3 - '@img/sharp-win32-ia32': 0.35.3 - '@img/sharp-win32-x64': 0.35.3 + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 '@types/node': 22.20.0 shebang-command@2.0.0: @@ -29266,7 +29285,7 @@ snapshots: undici@7.28.0: {} - undici@8.10.0: {} + undici@8.11.2: {} unicode-properties@1.4.1: dependencies: @@ -29789,8 +29808,14 @@ snapshots: dependencies: zod: 4.4.3 + zod-to-json-schema@3.25.2(zod@4.6.5): + dependencies: + zod: 4.6.5 + zod@4.4.3: {} + zod@4.6.5: {} + zustand@4.4.7(@types/react@18.3.31)(immer@10.2.0)(react@18.3.1): dependencies: use-sync-external-store: 1.2.0(react@18.3.1) From be7d58308cc680dda6f054bcfc4a174c22846d31 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 1 Oct 2026 11:09:13 +0800 Subject: [PATCH 5/5] fix(hmr): exclude unrelated files from config watchers --- packages/boot/hmr/README.i18n.yaml | 4 +-- packages/boot/hmr/README.md | 2 +- packages/boot/hmr/README.zh.md | 2 +- packages/boot/hmr/src/watch-config.ts | 9 ++++-- packages/boot/hmr/tests/watch-config.spec.ts | 30 ++++++++++++++++++++ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/packages/boot/hmr/README.i18n.yaml b/packages/boot/hmr/README.i18n.yaml index 7e4bce6b3b..f8b402ec5c 100644 --- a/packages/boot/hmr/README.i18n.yaml +++ b/packages/boot/hmr/README.i18n.yaml @@ -21,8 +21,8 @@ en: 45ee194ad781d603 zh: b3d7fcd8ed73717c /deepseek-ai-dsh-hmr/understand-the-implementation: - en: 5c7ff789d5d6b653 - zh: 46ef96a031ac87bd + en: 89055c33d92fcd20 + zh: 36595bd6e9765368 /deepseek-ai-dsh-hmr/model-experience: en: 215e7ba838619b7b zh: a311da3843709f90 diff --git a/packages/boot/hmr/README.md b/packages/boot/hmr/README.md index c4405697c6..1c60647eab 100644 --- a/packages/boot/hmr/README.md +++ b/packages/boot/hmr/README.md @@ -54,7 +54,7 @@ Chokidar options, including polling, retain their existing meaning. Exact config
Implementation internals — click to expand -`watchConfig()` registers an awaited configuration handler. `runExclusive()` serializes configuration changes and Loader updates with automatic reloads and rejects nested transactions. Package installation and removal run outside this queue. HMR does not acquire the package writer lock; manifest notifications reload only when the ordered `dsh.profile.bundles` list changes. Profile and home patch changes also trigger recomposition. File events received during a configuration transaction are processed afterward. Include refreshes and profile reconciliation reach plugins through ordinary Loader entry updates; Loader commits volatile-only changes in place. +`watchConfig()` registers an awaited configuration handler and watches only its target path and required parent directories; sibling files, including temporary writer locks, are excluded before native watcher creation. `runExclusive()` serializes configuration changes and Loader updates with automatic reloads and rejects nested transactions. Package installation and removal run outside this queue. HMR does not acquire the package writer lock; manifest notifications reload only when the ordered `dsh.profile.bundles` list changes. Profile and home patch changes also trigger recomposition. File events received during a configuration transaction are processed afterward. Include refreshes and profile reconciliation reach plugins through ordinary Loader entry updates; Loader commits volatile-only changes in place. App-boot owns profile parsing and patch precedence. HMR reads the launcher’s data-only `profileContext`, registers the profile manifest and both user patch watches during initialization, and waits for application readiness before processing changes. Its disposal closes the watchers and cancels reloads waiting for startup. HMR also owns module-cache replacement and reload scheduling. Configuration watchers start outside the active transaction context so later notifications can enter the queue. No invariant companion is published because the queue and watcher registrations have no independent persisted projection. diff --git a/packages/boot/hmr/README.zh.md b/packages/boot/hmr/README.zh.md index 6c82c3db8e..14920ae540 100644 --- a/packages/boot/hmr/README.zh.md +++ b/packages/boot/hmr/README.zh.md @@ -54,7 +54,7 @@ Chokidar 选项(包括轮询)保持原有含义。精确配置监听同时
实现细节——点击展开 -`watchConfig()` 注册会被等待的配置处理器。`runExclusive()` 将配置变更、Loader 更新与自动重载串行化,并拒绝嵌套事务。包安装和删除在该队列之外执行。HMR 不获取包操作写锁;manifest 通知仅在有序的 `dsh.profile.bundles` 列表变化时触发重载。profile 与 home patch 变化也会触发重新组合。配置事务期间收到的文件事件在事务结束后处理。 Include 刷新和 profile 重载都通过普通的 Loader 条目更新到达插件;仅 volatile 变化由 Loader 就地提交。 +`watchConfig()` 注册会被等待的配置处理器,仅监听目标路径及必要的父目录;同级文件(包括临时写锁)在创建原生 watcher 前即被排除。`runExclusive()` 将配置变更、Loader 更新与自动重载串行化,并拒绝嵌套事务。包安装和删除在该队列之外执行。HMR 不获取包操作写锁;manifest 通知仅在有序的 `dsh.profile.bundles` 列表变化时触发重载。profile 与 home patch 变化也会触发重新组合。配置事务期间收到的文件事件在事务结束后处理。 Include 刷新和 profile 重载都通过普通的 Loader 条目更新到达插件;仅 volatile 变化由 Loader 就地提交。 App-boot 负责 profile 解析和 patch 优先级规则。HMR 读取启动器提供的纯数据 `profileContext`,在初始化时注册 profile manifest 和两份用户 patch 的监听,并等待应用就绪后处理更改。销毁 HMR 时会关闭监听器并取消等待启动的重载。HMR 也负责模块缓存替换和重载调度。配置监听器在当前事务上下文之外启动,使后续通知可以进入队列。不发布 invariant 伴生入口,因为队列和监听注册没有独立的持久投影。 diff --git a/packages/boot/hmr/src/watch-config.ts b/packages/boot/hmr/src/watch-config.ts index 6a03be2d76..e3265993c9 100644 --- a/packages/boot/hmr/src/watch-config.ts +++ b/packages/boot/hmr/src/watch-config.ts @@ -1,5 +1,5 @@ /** Exact-path watching for live profile patch files outside Cordis module roots. */ -import { dirname, relative, resolve } from 'node:path' +import { dirname, relative, resolve, sep } from 'node:path' import { realpath, stat } from 'node:fs/promises' import { watch, type ChokidarOptions } from 'chokidar' import type { Context } from '@deepseek-ai/cordis' @@ -25,7 +25,8 @@ async function findWatchRoot(filename: string): Promise<{ filename: string; root } /** - * Watch one patch path, including missing parents, and serialize refresh callbacks. + * Watch one patch path and its parent chain without subscribing to sibling files or directories. + * Missing parents are observed as they appear; refresh callbacks run serially. * @param ctx Context that owns watcher disposal and receives refresh failures. * @param filename Absolute patch-file path. * @param options Deployment watcher options; configuration watches enable write stabilization by default. @@ -46,6 +47,10 @@ export async function watchConfig( const watcher = watch(target.root, { // Stabilized events bypass Chokidar's lossy 50 ms change-event throttle. awaitWriteFinish: true, ...watchOptions, depth: target.depth, ignoreInitial: false, + ignored: (path) => { + const remainder = relative(resolve(path), target.filename) + return remainder === '..' || remainder.startsWith(`..${sep}`) + }, }) paths.add(target.filename) const state = { dirty: false } diff --git a/packages/boot/hmr/tests/watch-config.spec.ts b/packages/boot/hmr/tests/watch-config.spec.ts index db31c0b654..0eb9809f9e 100644 --- a/packages/boot/hmr/tests/watch-config.spec.ts +++ b/packages/boot/hmr/tests/watch-config.spec.ts @@ -10,6 +10,7 @@ import { watchConfig } from '../src/watch-config.ts' import Hmr from '../src/index.ts' import Loader from '@deepseek-ai/cordis-plugin-loader' import Timer from '@deepseek-ai/cordis-plugin-timer' +import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write' import { afterEach, describe, expect, it, onTestFinished, vi } from 'vitest' import { FSWatcher, type ChokidarOptions } from 'chokidar' @@ -80,6 +81,35 @@ describe('HMR exact config paths', () => { for (const root of hmrRoots.splice(0)) rmSync(root, { recursive: true, force: true }) }) + it.each([false, true])('excludes sibling files while observing config replacement (missing parents: %s)', { timeout: 20_000 }, async (missingParents) => { + const dir = realpathSync(mkdtempSync(join(tmpdir(), 'dsh-hmr-config-scope-'))) + onTestFinished(() => { rmSync(dir, { recursive: true, force: true }) }) + const filename = join(dir, ...(missingParents ? ['later', 'nested'] : []), 'package.json') + writeFileSync(join(dir, 'package.json.lock'), 'held') + mkdirSync(join(dir, 'unrelated')) + writeFileSync(join(dir, 'unrelated', 'config.yml'), 'ignored') + if (!missingParents) writeFileSync(filename, 'initial') + const ctx = new Context() + onTestFinished(() => ctx.fiber.dispose()) + let watcher!: FSWatcher + const previousFactory = configWatch.create + onTestFinished(() => { configWatch.create = previousFactory }) + configWatch.create = (options) => { + watcher = new FSWatcher(options) + return watcher.add(dir) + } + const observed: string[] = [] + await watchConfig(ctx, filename, {}, () => { observed.push(readFileSync(filename, 'utf8')) }) + expect(watcher.getWatched()[dir]).not.toContain('package.json.lock') + expect(watcher.getWatched()[dir]).not.toContain('unrelated') + ensureNativeWatchLive(dir) + await writeFileAtomic(filename, 'created', { mode: 0o600 }) + await vi.waitFor(() => { expect(observed).toContain('created') }, { timeout: 8_000 }) + await writeFileAtomic(filename, 'replaced', { mode: 0o600 }) + await vi.waitFor(() => { expect(observed).toContain('replaced') }, { timeout: 8_000 }) + expect(watcher.getWatched()[dir]).not.toContain('package.json.lock') + }) + it.each(['relative', 'absolute'])('observes %s module roots through a filesystem alias', { timeout: 30_000 }, async (rootKind) => { const target = mkdtempSync(join(tmpdir(), 'dsh-hmr-module-canonical-')) const alias = `${target}-alias`