From fc416a3d3c73429f8e3dfe90b6b0d7a9b9f8f256 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Fri, 30 Oct 2026 11:05:08 +0800 Subject: [PATCH 1/5] test(dsh): expose bounded npm preparation timings Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- plugins/dsh/scripts/smoke-native-host.mjs | 53 ++++++++++++++++++++-- plugins/dsh/test/smoke-native-host.test.ts | 28 +++++++++++- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/plugins/dsh/scripts/smoke-native-host.mjs b/plugins/dsh/scripts/smoke-native-host.mjs index e32d92911..716614a03 100644 --- a/plugins/dsh/scripts/smoke-native-host.mjs +++ b/plugins/dsh/scripts/smoke-native-host.mjs @@ -1,7 +1,7 @@ import { spawn } from 'node:child_process'; import { createHash, randomUUID } from 'node:crypto'; import { closeSync, openSync } from 'node:fs'; -import { access, chmod, lstat, mkdir, mkdtemp, readFile, readdir, realpath, stat, writeFile } from 'node:fs/promises'; +import { access, chmod, open, lstat, mkdir, mkdtemp, readFile, readdir, realpath, stat, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -206,6 +206,50 @@ export function safeProbeFailure(log, probe) { return undefined; } +// npm emits completed timers incrementally with --timing, even when killed before +// its final timing.json. Never expose arbitrary timer names, URLs or log lines. +const npmPreparationLogLimit = 1024 * 1024; +export function summarizeNpmPreparation(log, truncated = false) { + const phases = new Set(['idealTree', 'idealTree:init', 'idealTree:userRequests', 'idealTree:buildDeps', + 'idealTree:fixDepFlags', 'reify', 'reify:loadTrees', 'reify:diffTrees', 'reify:retireShallow', + 'reify:createSparse', 'reify:loadBundles', 'reify:unpack', 'reify:unretire', 'reify:build', + 'reify:trash', 'reify:save', 'command:install']); + const result = { completedTimingsMs: {}, lastCompletedPhase: null, + cacheObservations: { hit: 0, miss: 0, revalidated: 0 }, truncated: truncated || log.length > npmPreparationLogLimit }; + let bounded = log.slice(-npmPreparationLogLimit); + if (result.truncated) { + const newline = bounded.indexOf('\n'); + bounded = newline < 0 ? '' : bounded.slice(newline + 1); + } + for (const line of bounded.split('\n')) { + const timer = /^npm timing ([A-Za-z:]+) Completed in ([0-9]+)ms\r?$/.exec(line); + if (timer && phases.has(timer[1])) { + const elapsed = Number(timer[2]); + if (Number.isSafeInteger(elapsed) && elapsed <= 3600000) { + result.completedTimingsMs[timer[1]] = elapsed; + result.lastCompletedPhase = timer[1]; + } + } + const request = /^npm http fetch GET [0-9]{3} \S+ [0-9]+ms \(cache (hit|miss|revalidated)\)\r?$/.exec(line); + if (request) result.cacheObservations[request[1]]++; + // npm also logs package-cache lookups separately from HTTP fetch responses. + if (/^npm http cache \S+ [0-9]+ms \(cache hit\)\r?$/.test(line)) result.cacheObservations.hit++; + } + return result; +} + +async function readPreparationLog(path) { + let file; + try { + file = await open(path, 'r'); + const { size } = await file.stat(); + const buffer = Buffer.alloc(Math.min(size, npmPreparationLogLimit)); + const { bytesRead } = await file.read(buffer, 0, buffer.length, Math.max(0, size - buffer.length)); + return { text: buffer.subarray(0, bytesRead).toString('utf8'), truncated: size > buffer.length }; + } catch { return { text: '', truncated: false }; } + finally { await file?.close(); } +} + // Only npm's public download content is shared; every Host/config/profile stays fresh. export async function prepareDownloadCache(path) { if (!isAbsolute(path)) throw new Error('Download cache must be an absolute temporary directory.'); @@ -304,13 +348,14 @@ async function main() { try { const installStarted = Date.now(); try { - await run('install-host', [npm, 'install', '--prefix', root, '--ignore-scripts', '--no-audit', '--no-fund', + await run('install-host', [npm, 'install', '--timing', '--loglevel=http', '--prefix', root, '--ignore-scripts', '--no-audit', '--no-fund', '--registry=https://registry.npmjs.org', `@deepseek-ai/dsh@${dshVersion}`, `pnpm@${PNPM_VERSION}`], 600000); } finally { env.npm_config_cache = join(root, 'npm-cache'); summary.preparation.elapsedMs = Date.now() - installStarted; - const installLog = await readFile(join(root, 'logs/install-host.log'), 'utf8').catch(() => ''); - summary.preparation.observedCodes = knownHostFailureCodes(installLog); + const installLog = await readPreparationLog(join(root, 'logs/install-host.log')); + summary.preparation.observedCodes = knownHostFailureCodes(installLog.text); + summary.preparation.npm = summarizeNpmPreparation(installLog.text, installLog.truncated); } const dsh = join(root, 'node_modules/@deepseek-ai/dsh/lib/bin.js'); await access(dsh); diff --git a/plugins/dsh/test/smoke-native-host.test.ts b/plugins/dsh/test/smoke-native-host.test.ts index 397e8f77d..e4274de67 100644 --- a/plugins/dsh/test/smoke-native-host.test.ts +++ b/plugins/dsh/test/smoke-native-host.test.ts @@ -4,7 +4,7 @@ import { tmpdir } from 'node:os'; import { join } from 'node:path'; // Node-only CI entry; keep its helpers importable without starting a Host or downloading dependencies. // @ts-expect-error The development-only Node entry has no TypeScript declarations. -import { prepareDownloadCache, scenarioProbes, hostInstallManifest, selectDshVersion, supportedDshVersions, isolatedEnvironment, profileInstallManifest, retainedCordisFamily, runBounded, selectTarball } from '../scripts/smoke-native-host.mjs'; +import { summarizeNpmPreparation, prepareDownloadCache, scenarioProbes, hostInstallManifest, selectDshVersion, supportedDshVersions, isolatedEnvironment, profileInstallManifest, retainedCordisFamily, runBounded, selectTarball } from '../scripts/smoke-native-host.mjs'; const roots: string[] = []; async function root() { @@ -283,3 +283,29 @@ test('trusted temporary base aliases accept lexical and canonical children but n } } }); + + +test('npm preparation diagnostics retain only bounded known timing and cache observations', () => { + const result = summarizeNpmPreparation([ + 'npm timing idealTree:init Completed in 12ms', + 'npm timing idealTree:buildDeps Completed in 345ms', + 'npm timing reify:unpack Completed in 500ms', + 'npm timing secret/token Completed in 8ms', + 'npm http fetch GET 200 https://private.invalid/token 23ms (cache miss)', + 'npm http fetch GET 200 https://private.invalid/token 4ms (cache hit)', + 'npm http fetch GET 200 https://private.invalid/token 5ms (cache revalidated)', + 'npm timing reify Completed in 99999999999999999ms', + 'npm http cache diagnostic-fixture@http://private.invalid/package.tgz 0ms (cache hit)', + ].join('\n')); + expect(result).toEqual({ completedTimingsMs: { 'idealTree:init': 12, 'idealTree:buildDeps': 345, 'reify:unpack': 500 }, + lastCompletedPhase: 'reify:unpack', cacheObservations: { hit: 2, miss: 1, revalidated: 1 }, truncated: false }); + expect(JSON.stringify(result)).not.toMatch(/secret|token|private/); + expect(summarizeNpmPreparation('x'.repeat(1024 * 1024 + 1)).truncated).toBe(true); +}); + + +test('truncated npm diagnostic tails discard the partial first line', () => { + const result = summarizeNpmPreparation('npm timing reify Completed in 1ms\nnpm timing idealTree Completed in 2ms', true); + expect(result.completedTimingsMs).toEqual({ idealTree: 2 }); + expect(result.lastCompletedPhase).toBe('idealTree'); +}); From 74e6d93b7b8558fc728803d261cf25e9aa2d637f Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Fri, 30 Oct 2026 11:21:46 +0800 Subject: [PATCH 2/5] fix(dsh): prefer compatible dependency reuse in Host smoke Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- .../changes/add-dsh-native-plugin/verification.md | 11 +++++++++++ plugins/dsh/scripts/smoke-native-host.mjs | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/openspec/changes/add-dsh-native-plugin/verification.md b/openspec/changes/add-dsh-native-plugin/verification.md index 0c390c5da..c25077b2c 100644 --- a/openspec/changes/add-dsh-native-plugin/verification.md +++ b/openspec/changes/add-dsh-native-plugin/verification.md @@ -560,3 +560,14 @@ Windows Node 24.2.0、DSH 0.2.0-rc.2、Chrome 156 的新隔离 Profile 已通过 兼容审查补充:日志搬迁改为先排他 link 原记录,持久化目标目录后 unlink 源记录并持久化源目录,再写扩展后继;双份需完整相等,原字节 SHA 备份不覆盖。独立定向日志/投影 15 测试、74 断言及 CLI typecheck 通过,不代表全套与真实旧包矩阵完成。无效入口投影为 unreadable,Host 不再默认 enabled,补充卡片与模型上下文测试通过。 旧消费者不必理解 activation 日志。中断启用后的合法标准入口仍可能被旧版正常管理;新恢复在写入前必须比较身份、版本、installedAt、指纹与归属,变化即 unknown 并保留现场。该有限保证替代“旧版必能阻止全部待恢复操作”的过度承诺;真实旧包在 moved 阶段写入后的恢复验收仍须单列。CLI 安全转换 v3 不扫描全机 Host 日志,保留原日志与技能文件;NativeRuntime 处理自己日志域的 pending 恢复。 + + +### Windows 官方 Host 准备超时诊断(2026-10-30) + +DSH 0.6.0 发布检查在 Windows / DSH 0.2.1-rc.2 的 `install-host` 阶段两次达到 600 秒上限,均未进入技能探针;不能将该失败解释为启停断言失败。公开下载缓存存在不证明依赖解析或解包已加速。诊断摘要新增有界、白名单 npm 阶段计时及缓存观察计数,原始日志仍私有;计数不是去重请求数或完整缓存命中率。 + +本机诊断发现新版 Host 依赖树存在多份嵌套同版本 Zod。隔离 npm Registry 的最小相容范围实验中,SDK 范围 `^3.25.0 || ^4.0.0` 与十二个 exact `4.4.3` 消费方共存:默认解析为根 `4.6.7` 加十二份 `4.4.3`,`--prefer-dedupe` 则保留一份 `4.4.3`;两棵树均通过 npm 依赖约束检查。此前不相容 major 的实验不代表这个实际依赖形状。 + +候选调整仅在官方 Host 准备命令增加 `--prefer-dedupe`,不添加 Zod override、直接依赖、忽略 peer 的选项,也不改变安装脚本禁用、空白 Profile、进程清理、600 秒准备上限或业务断言。它可能在原范围内选择较旧的兼容依赖,因此仍须验证实际 Host 依赖身份和完整探针。 + +当前只确认最小图的重复减少;真实 Windows 冷安装耗时、两版 Host 启停/恢复、其余平台及最终发布包验收仍待完成,不宣称超时已解决。修改验收脚本不等于改变已发布 CLI 或 DSH 产品运行逻辑。 diff --git a/plugins/dsh/scripts/smoke-native-host.mjs b/plugins/dsh/scripts/smoke-native-host.mjs index 716614a03..b9b3816b0 100644 --- a/plugins/dsh/scripts/smoke-native-host.mjs +++ b/plugins/dsh/scripts/smoke-native-host.mjs @@ -348,7 +348,8 @@ async function main() { try { const installStarted = Date.now(); try { - await run('install-host', [npm, 'install', '--timing', '--loglevel=http', '--prefix', root, '--ignore-scripts', '--no-audit', '--no-fund', + // Prefer reuse within the original exact/range/peer constraints to reduce duplicate files. + await run('install-host', [npm, 'install', '--prefer-dedupe', '--timing', '--loglevel=http', '--prefix', root, '--ignore-scripts', '--no-audit', '--no-fund', '--registry=https://registry.npmjs.org', `@deepseek-ai/dsh@${dshVersion}`, `pnpm@${PNPM_VERSION}`], 600000); } finally { env.npm_config_cache = join(root, 'npm-cache'); From 0708f64b9f8d20c126e106f8a87b4e46449fa4c4 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Fri, 30 Oct 2026 13:51:18 +0800 Subject: [PATCH 3/5] test(dsh): retain safe install admission diagnostics Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- .../add-dsh-native-plugin/verification.md | 6 ++++-- plugins/dsh/scripts/smoke-native-host.mjs | 11 ++++++++++- .../integration/skill-availability-fixture.mjs | 1 + plugins/dsh/test/probe-diagnostics.test.ts | 18 ++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/openspec/changes/add-dsh-native-plugin/verification.md b/openspec/changes/add-dsh-native-plugin/verification.md index c25077b2c..cd54c3174 100644 --- a/openspec/changes/add-dsh-native-plugin/verification.md +++ b/openspec/changes/add-dsh-native-plugin/verification.md @@ -566,8 +566,10 @@ Windows Node 24.2.0、DSH 0.2.0-rc.2、Chrome 156 的新隔离 Profile 已通过 DSH 0.6.0 发布检查在 Windows / DSH 0.2.1-rc.2 的 `install-host` 阶段两次达到 600 秒上限,均未进入技能探针;不能将该失败解释为启停断言失败。公开下载缓存存在不证明依赖解析或解包已加速。诊断摘要新增有界、白名单 npm 阶段计时及缓存观察计数,原始日志仍私有;计数不是去重请求数或完整缓存命中率。 -本机诊断发现新版 Host 依赖树存在多份嵌套同版本 Zod。隔离 npm Registry 的最小相容范围实验中,SDK 范围 `^3.25.0 || ^4.0.0` 与十二个 exact `4.4.3` 消费方共存:默认解析为根 `4.6.7` 加十二份 `4.4.3`,`--prefer-dedupe` 则保留一份 `4.4.3`;两棵树均通过 npm 依赖约束检查。此前不相容 major 的实验不代表这个实际依赖形状。 +本机诊断发现新版 Host 依赖树存在多份嵌套同版本 Zod。隔离 npm Registry 的最小相容范围实验中,SDK 范围 `^3.25.0 || ^4.0.0` 与十二个 exact `4.4.3` 消费方共存:默认解析为根 `4.6.7` 加十二份 `4.4.3`,`--prefer-dedupe` 则保留一份 `4.4.3`;两棵树均通过 npm 依赖约束检查。 候选调整仅在官方 Host 准备命令增加 `--prefer-dedupe`,不添加 Zod override、直接依赖、忽略 peer 的选项,也不改变安装脚本禁用、空白 Profile、进程清理、600 秒准备上限或业务断言。它可能在原范围内选择较旧的兼容依赖,因此仍须验证实际 Host 依赖身份和完整探针。 -当前只确认最小图的重复减少;真实 Windows 冷安装耗时、两版 Host 启停/恢复、其余平台及最终发布包验收仍待完成,不宣称超时已解决。修改验收脚本不等于改变已发布 CLI 或 DSH 产品运行逻辑。 +真实 Windows Node 24.2.0 / npm 11.3.0 的新版 Host lock-only 对照确认:默认 687 个安装位置、51 份 Zod,prefer-dedupe 为 636 个安装位置、1 份 Zod。本机两次完整冷安装仍达到 600 秒上限;减少重复依赖并不证明冷安装超时已解决。 + +候选提交 `74e6d93b7` 的 [CI 40996963179](https://github.com/iflytek/skillhub/actions/runs/40996963179) 中,旧版 Host 的 Windows Node 24.2.0 完整探针通过,准备耗时 348647ms;Windows Node 24 的准备完成(459541ms),但随后技能可用性探针在 user-install 的 accepted 断言失败。Linux/macOS 基础检查通过,后续官方 Host 和启停矩阵因前置失败未执行,不能算通过。安装工具返回状态与固定失败码需要补充诊断;保留现有断言。最终发布包验收仍待完成。修改验收脚本不等于改变已发布 CLI 或 DSH 产品运行逻辑。 diff --git a/plugins/dsh/scripts/smoke-native-host.mjs b/plugins/dsh/scripts/smoke-native-host.mjs index b9b3816b0..117aa2171 100644 --- a/plugins/dsh/scripts/smoke-native-host.mjs +++ b/plugins/dsh/scripts/smoke-native-host.mjs @@ -125,7 +125,16 @@ export function safeAvailabilityCheckpoint(value) { const checkpoints = ['setup', 'install', 'install-poll', 'reference', 'before-digest', 'execute', 'assertion', 'after-digest', 'mutation']; const assertions = ['none', 'isError', 'kind', 'schemaVersion', 'association', 'scope', 'integrity', 'discovery', 'name', 'reason', 'invocation', 'installation', 'namespace', 'slug', 'version', 'fingerprint', 'render', 'privacy', 'unchanged', 'accepted', 'completed', 'reference']; if (!scenarios.includes(value.scenario) || !checkpoints.includes(value.checkpoint) || !assertions.includes(value.assertion)) return undefined; - return { scenario: value.scenario, checkpoint: value.checkpoint, assertion: value.assertion }; + const result = { scenario: value.scenario, checkpoint: value.checkpoint, assertion: value.assertion }; + const statuses = ['accepted', 'not-confirmed', 'awaiting-confirmation', 'cancelled']; + // Mirror the public installationFailureCodes contract; never forward error messages or IDs. + const codes = ['CONTEXT_STALE', 'REQUEST_CONFLICT', 'SOURCE_NOT_CONFIGURED', 'SOURCE_DENIED', + 'SKILL_UNAVAILABLE', 'RATE_LIMITED', 'SOURCE_UNAVAILABLE', 'TARGET_UNAVAILABLE', 'UNCONFIRMED']; + if (statuses.includes(value.install?.status)) { + result.install = { status: value.install.status }; + if (codes.includes(value.install.code)) result.install.code = value.install.code; + } + return result; } export function safeToggleCheckpoint(value) { diff --git a/plugins/dsh/test/integration/skill-availability-fixture.mjs b/plugins/dsh/test/integration/skill-availability-fixture.mjs index 803421514..6f455ad6c 100644 --- a/plugins/dsh/test/integration/skill-availability-fixture.mjs +++ b/plugins/dsh/test/integration/skill-availability-fixture.mjs @@ -97,6 +97,7 @@ async function run(ctx, root, signal, checkpoint) { checkpoint.operation = { deadlineReached: false }; mark('install'); const result = await execute('astron_skillhub_install', { namespace, slug: 'document-helper', scope }); + checkpoint.install = { status: result.value?.status, code: result.value?.code }; mark('assertion', 'isError'); assert.equal(result.isError, false); mark('assertion', 'accepted'); diff --git a/plugins/dsh/test/probe-diagnostics.test.ts b/plugins/dsh/test/probe-diagnostics.test.ts index 2585082a7..dcde01c28 100644 --- a/plugins/dsh/test/probe-diagnostics.test.ts +++ b/plugins/dsh/test/probe-diagnostics.test.ts @@ -1,4 +1,5 @@ import { expect, test } from 'bun:test'; +import { installationFailureCodes } from '../src/host/installation-failure'; // @ts-expect-error The development-only Node entry has no TypeScript declarations. import { safeProbeFailure } from '../scripts/smoke-native-host.mjs'; @@ -80,3 +81,20 @@ test('operation observations and Host codes whitelist every field without reveal expect(safeProbeFailure(JSON.stringify({ ...base, probe: 'runtime-baseline' }), 'runtime-baseline').operation).toBeUndefined(); } }); + +test('availability admission diagnostics expose only known install status and failure code', () => { + const checkpoint = { scenario: 'user-install', checkpoint: 'assertion', assertion: 'accepted', + install: { status: 'not-confirmed', code: 'TARGET_UNAVAILABLE', message: '/secret/token' } }; + const record = { passed: false, probe: 'skill-availability', stage: 'host-assertion', + failureCode: 'HOST_ASSERTION_FAILED', diagnostics: { availability: checkpoint } }; + const safe = safeProbeFailure(JSON.stringify(record), 'skill-availability'); + expect(safe.availability.install).toEqual({ status: 'not-confirmed', code: 'TARGET_UNAVAILABLE' }); + expect(JSON.stringify(safe)).not.toContain('secret'); + for (const code of installationFailureCodes) { + checkpoint.install.code = code; + expect(safeProbeFailure(JSON.stringify(record), 'skill-availability').availability.install.code).toBe(code); + } + checkpoint.install.status = '/private/status'; + checkpoint.install.code = '/private/code'; + expect(safeProbeFailure(JSON.stringify(record), 'skill-availability').availability.install).toBeUndefined(); +}); From a431833b33bcf7523949537c50b9409c00c70ce3 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Fri, 30 Oct 2026 14:02:20 +0800 Subject: [PATCH 4/5] test(dsh): use explicit ESM failure-code import Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- plugins/dsh/test/probe-diagnostics.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dsh/test/probe-diagnostics.test.ts b/plugins/dsh/test/probe-diagnostics.test.ts index dcde01c28..acfae96b9 100644 --- a/plugins/dsh/test/probe-diagnostics.test.ts +++ b/plugins/dsh/test/probe-diagnostics.test.ts @@ -1,5 +1,5 @@ import { expect, test } from 'bun:test'; -import { installationFailureCodes } from '../src/host/installation-failure'; +import { installationFailureCodes } from '../src/host/installation-failure.js'; // @ts-expect-error The development-only Node entry has no TypeScript declarations. import { safeProbeFailure } from '../scripts/smoke-native-host.mjs'; From 20fd579827edae76789a5e7ac6fe29a6fb40a381 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Fri, 30 Oct 2026 14:44:42 +0800 Subject: [PATCH 5/5] chore(dsh): prepare version 0.6.1 publication Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- .../changes/add-dsh-native-plugin/release-guide.md | 12 ++++++------ .../changes/add-dsh-native-plugin/release-notes.md | 10 +++++----- .../changes/add-dsh-native-plugin/verification.md | 5 +++++ plugins/dsh/README.en.md | 10 +++++----- plugins/dsh/README.md | 10 +++++----- plugins/dsh/package.json | 2 +- 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/openspec/changes/add-dsh-native-plugin/release-guide.md b/openspec/changes/add-dsh-native-plugin/release-guide.md index e4a2c3923..d1a3cbc07 100644 --- a/openspec/changes/add-dsh-native-plugin/release-guide.md +++ b/openspec/changes/add-dsh-native-plugin/release-guide.md @@ -12,14 +12,14 @@ ### 1.1 当前候选与发布顺序 -本轮拟发布 CLI `0.3.0`(`cli-v0.3.0`)和 DSH `0.6.0`(`dsh-v0.6.0`),范围为技能启停、统一只读检查更新、紧凑已安装卡片,以及发布前库存兼容修复。不发布服务端镜像或部署 SaaS。 +CLI `0.3.0`(`cli-v0.3.0`)已发布,本轮继续发布 DSH `0.6.1`(`dsh-v0.6.1`),范围为技能启停、统一只读检查更新、紧凑已安装卡片,以及发布前库存兼容修复。不发布服务端镜像或部署 SaaS。 共享库存保持严格 v2,不写入 `installationState`;启停状态从可信的 `SKILL.md` / `SKILL.md.disabled` 入口派生,不要求 CLI 用户同步升级。已发布 CLI `0.2.0` 的正常查询和普通目标管理必须继续兼容;默认更新、同步及 Suite 不得无意重新启用停用目标。旧 CLI 显式 force 重装、更新、同步仍按原覆盖语义执行,可能恢复标准入口;显式 remove 仍可删除,新版重新读取须反映真实变化。 1. 使用真实旧公开 CLI `0.2.0`、DSH `0.5.0` 建立基线,在同一隔离 HOME 交替操作,验证普通/停用目标混存、来源与位置隔离、默认保护和显式覆盖语义。仅证明拒写或字节未损坏不算兼容通过。 2. 读 v1/v2 不迁移。未发布 v3 必须在锁内校验身份、入口与未完成事务,备份原始字节后安全转换 v2;普通操作日志保持旧 DSH 可读,启停日志隔离影响。并发及五阶段强杀恢复重新验收。 -3. 完成候选检查、双 RC、跨平台、真实浏览器及草稿保护;旧候选结果仅在输入等价时可复用。兼容修复正在进行,未通过前阻断发布。 -4. 通过后按专用工作流依次发布 CLI 和 DSH,核对公开字节、干净安装和升级保留。此顺序是交付安排,不是要求用户同步升级 CLI。当前不声明任何候选已发布。 +3. 完成候选检查、双 RC、跨平台、真实浏览器及草稿保护;旧候选结果仅在输入等价时可复用。兼容修复及真实旧包验收已通过;最终版本包和公开包仍按本流程单独验收。 +4. CLI 0.3.0 已完成公开字节及安装验收,不重复发布;DSH 0.6.1 通过后按专用工作流发布,核对公开字节、干净安装和升级保留。此顺序是交付安排,不是要求用户同步升级 CLI。保留已存在的 `dsh-v0.6.0` 标签,不移动到新提交;DSH 0.6.1 公开验收完成前不声明已发布。 旧消费者不承诺识别启停专用日志:中断启用已留下合法标准入口时,旧版仍可能执行合法管理。新恢复必须先核精确目标身份、版本、时间、指纹和归属,发现旧版变更即保留现场并返回 unknown,不能用旧意图覆盖新内容。CLI 的 v3 转换只核当前库存和入口并保留日志,不扫描全机 Host;NativeRuntime 在自己的日志域先处理恢复。 @@ -105,7 +105,7 @@ Host 准备允许通过显式 `--download-cache` 共享受校验临时目录中 ### 2.3 隔离环境验证 -本次 `0.6.0` 候选分别验证 DSH `0.2.0-rc.2` 与 `0.2.1-rc.2`,Node `>=24.2.0 <25`。Host、app-boot、核心模块及注入 Client 模块须为同一精确发行版。新 RC 仅使用 `4.0.5 / 1.0.6 / 1.0.10 / 1.1.7`;旧 RC 的 Cordis、Loader、Include、Timer 须为已验证的完整组合:`4.0.4 / 1.0.5 / 1.0.9 / 1.1.6` 或 `4.0.5 / 1.0.6 / 1.0.10 / 1.1.7`,不得交叉混装;以实际 Host 解析结果为准。已发布 `0.1.0` 尚不包含后一组合支持及历史回执修复,`0.1.1` 起包含这些修复,`0.2.0` 延续此兼容基线;发布前使用本次 tarball 验证。在独立测试账户或容器中准备 Web Profile、工作区和测试技能,连接测试 Registry。仅隔离 Profile/DSH home 不足以隔离共享 inventory。 +本次 `0.6.1` 候选分别验证 DSH `0.2.0-rc.2` 与 `0.2.1-rc.2`,Node `>=24.2.0 <25`。Host、app-boot、核心模块及注入 Client 模块须为同一精确发行版。新 RC 仅使用 `4.0.5 / 1.0.6 / 1.0.10 / 1.1.7`;旧 RC 的 Cordis、Loader、Include、Timer 须为已验证的完整组合:`4.0.4 / 1.0.5 / 1.0.9 / 1.1.6` 或 `4.0.5 / 1.0.6 / 1.0.10 / 1.1.7`,不得交叉混装;以实际 Host 解析结果为准。已发布 `0.1.0` 尚不包含后一组合支持及历史回执修复,`0.1.1` 起包含这些修复,`0.2.0` 延续此兼容基线;发布前使用本次 tarball 验证。在独立测试账户或容器中准备 Web Profile、工作区和测试技能,连接测试 Registry。仅隔离 Profile/DSH home 不足以隔离共享 inventory。 首次创建测试 Web Profile,然后安装本地候选包: @@ -190,7 +190,7 @@ SaaS 使用其现有流水线部署;公共接口契约、测试数据规则与 ### 4.1 独立发布流程 -插件使用独立版本,tag 前缀固定为 `dsh-v`(本次为 `dsh-v0.6.0`),不复用 CLI 的 `cli-v*` 发布流程。专用工作流为 `.github/workflows/release-dsh-plugin.yml`;发布前仍须确认 npm 包名、兼容基线及候选包验收,本次候选为 `0.6.0`,manifest 已显式设为 `private: false`;缺省 Registry 为 `https://skill.xfyun.cn`,显式空串/空白仍断开,已有自定义来源保留。发布前分别验证缺省、断开和自定义配置,以及正式域名的固定版本安装、状态识别和本地管理。正式发布仍以最终提交、候选验收和审批结果为准。 +插件使用独立版本,tag 前缀固定为 `dsh-v`(本次为 `dsh-v0.6.1`),不复用 CLI 的 `cli-v*` 发布流程。专用工作流为 `.github/workflows/release-dsh-plugin.yml`;发布前仍须确认 npm 包名、兼容基线及候选包验收,本次候选为 `0.6.1`,manifest 已显式设为 `private: false`;缺省 Registry 为 `https://skill.xfyun.cn`,显式空串/空白仍断开,已有自定义来源保留。发布前分别验证缺省、断开和自定义配置,以及正式域名的固定版本安装、状态识别和本地管理。正式发布仍以最终提交、候选验收和审批结果为准。 发布流程依次完成:校验版本 → 测试与构建 → 生成并检查 tarball → 隔离 DSH 候选验收 → 发布审批 → 发布 npm → 校验已发布包。当前工作流自动执行版本校验、测试与构建、包检查、上传及完整性校验;隔离 DSH 的 UI、真实模型和平台验收按本次确认范围另行执行,未验项目须单独注明;CI 矩阵成功不等同于这些验收通过。工作流使用仓库的 `NPM_TOKEN` 发布凭证,源码及 npm 包不包含凭证;配置了环境保护规则时还须完成对应审批。 @@ -213,7 +213,7 @@ SaaS 使用其现有流水线部署;公共接口契约、测试数据规则与 ### 4.3 发布说明 -`0.6.0` 的变更说明见 [release-notes.md](release-notes.md)。正式版本发布前按最终候选及验收结果更新,不沿用开发版本的支持声明。 +`0.6.1` 的变更说明见 [release-notes.md](release-notes.md)。正式版本发布前按最终候选及验收结果更新,不沿用开发版本的支持声明。 每个版本包含: diff --git a/openspec/changes/add-dsh-native-plugin/release-notes.md b/openspec/changes/add-dsh-native-plugin/release-notes.md index d3a9a0587..98ca6e7a3 100644 --- a/openspec/changes/add-dsh-native-plugin/release-notes.md +++ b/openspec/changes/add-dsh-native-plugin/release-notes.md @@ -1,15 +1,15 @@ # SkillHub DSH 原生插件发布说明 -## 0.6.0 候选:启停、检查更新与紧凑卡片 +## 0.6.1 候选:启停、检查更新与紧凑卡片 - **受管理技能启停**:[#1025](https://github.com/iflytek/skillhub/pull/1025) 按确认的位置将 `SKILL.md` 转换为 `SKILL.md.disabled`,启用恢复入口,保留目录和资源。更新停用安装后仍保持停用;文件修改、共享归属、目标被占用及不可信记录仍阻止写操作。停用不撤回已加载会话内容,也不停止任务。 - **统一检查、逐项更新**:[#1030](https://github.com/iflytek/skillhub/pull/1030) 主动只读检查当前来源库存,渐进显示结果和失败重试。一次可信快照、有界并发、同来源技能共用远端 resolve;取消及上下文变化不接纳迟到结果。真正更新仍进入详情按位置确认,不提供批量自动覆盖。 - **日常围绕使用技能**:[#1032](https://github.com/iflytek/skillhub/pull/1032) 已安装页采用桌面两列、窄屏一列的紧凑横向卡片,显示真实本地名称、一行摘要和实际安装版本;至多两个语义标签。整卡进入详情,保留使用技能主按钮,管理安装/检查更新收进更多菜单。单卡检查不清除其他卡结果,使用和菜单不误触详情。 -- **库存兼容**:共享库存保持严格 v2,不写入 `installationState`;启停状态从可信的 `SKILL.md` / `SKILL.md.disabled` 入口派生,不要求 CLI 用户同步升级。已发布 CLI `0.2.0` 的正常查询和普通目标管理必须继续兼容;默认更新、同步及 Suite 不得无意重新启用停用目标。旧 CLI 显式 force 重装、更新、同步仍按原覆盖语义执行,可能恢复标准入口;显式 remove 仍可删除,新版重新读取须反映真实变化。 未发布 v3 的安全转换、普通/启停日志兼容隔离及真实旧包交替验收正在进行;未通过前阻断发布。 +- **库存兼容**:共享库存保持严格 v2,不写入 `installationState`;启停状态从可信的 `SKILL.md` / `SKILL.md.disabled` 入口派生,不要求 CLI 用户同步升级。已发布 CLI `0.2.0` 的正常查询和普通目标管理必须继续兼容;默认更新、同步及 Suite 不得无意重新启用停用目标。旧 CLI 显式 force 重装、更新、同步仍按原覆盖语义执行,可能恢复标准入口;显式 remove 仍可删除,新版重新读取须反映真实变化。 [#1033](https://github.com/iflytek/skillhub/pull/1033) 已完成未发布 v3 的安全转换、普通/启停日志兼容隔离及真实旧包交替验收。 - **交付边界**:保留现有双 RC、Node/Cordis 与来源边界;详情官网链接仅使用 API 的安全 `webUrl`,缺失即隐藏。该增量不包含 SaaS 部署、场景助手或技能清单导入导出。 -上述包含已合并功能及正在实施的发布前兼容修复,不声明 `0.6.0`/CLI `0.3.0` 已发布,也不把历史功能验收等同本轮最终候选、跨平台恢复或公开包验收。发布顺序和限制见 [发布指南](release-guide.md),结果由 [验证记录](verification.md) 单独维护。 +上述功能及库存兼容修复已合并。CLI `0.3.0` 已发布;DSH `0.6.1` 仍是候选,不把历史功能验收等同最终版本包或公开包验收。发布顺序和限制见 [发布指南](release-guide.md),结果由 [验证记录](verification.md) 单独维护。 ## 0.5.0 技能可用性诊断 @@ -20,7 +20,7 @@ ## 版本与交付状态 -当前准备版本为 DSH `0.6.0` 和配套 CLI `0.3.0`,尚不据此声明已公开发布。历史版本说明保留;实际公开状态以对应 npm 版本和专用发布工作流为准。 +当前准备版本为 DSH `0.6.1`;CLI `0.3.0` 已发布并完成公开包验收,不重复发布。保留已存在的 `dsh-v0.6.0` 标签,DSH 候选使用新标签 `dsh-v0.6.1`,尚不据此声明 DSH 已公开发布。历史版本说明保留;实际公开状态以对应 npm 版本和专用发布工作流为准。 `@astron-team/skillhub-dsh@0.3.1` 已发布,独立标签为 `dsh-v0.3.1`。[发布准备 PR #995](https://github.com/iflytek/skillhub/pull/995) 已合并,[专用发布工作流](https://github.com/iflytek/skillhub/actions/runs/39556075587) 成功;[公开 npm 包](https://www.npmjs.com/package/@astron-team/skillhub-dsh/v/0.3.1) 与工作流产物逐字节一致,发布时 `latest` 指向 `0.3.1`。两版 Linux 的严格安装、原生探针及浏览器操作复验通过,测试工件与公开包字节一致,结果见 [验证摘要](verification.md)。历史已发布版本保持不变。 @@ -110,7 +110,7 @@ Node 保持 `>=24.2.0 <25`。精确兼容与验证边界见 [兼容设计](compa ## 安装、更新与维护 -`0.6.0` 公开可用后,可通过 `dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.6.0 --ignore-scripts` 安装到已有 Web Profile;发布前使用本地候选 tarball。发布前从源码执行 `bun run check` 后生成 `.tgz`,使用固定版本 DSH 的 `plugin ... add` 安装。具体准备、命令、配置和测试流程见 [中文指南](../../../plugins/dsh/README.md)、[英文指南](../../../plugins/dsh/README.en.md) 及 [发布指南](release-guide.md)。 +`0.6.1` 公开可用后,可通过 `dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.6.1 --ignore-scripts` 安装到已有 Web Profile;发布前使用本地候选 tarball。发布前从源码执行 `bun run check` 后生成 `.tgz`,使用固定版本 DSH 的 `plugin ... add` 安装。具体准备、命令、配置和测试流程见 [中文指南](../../../plugins/dsh/README.md)、[英文指南](../../../plugins/dsh/README.en.md) 及 [发布指南](release-guide.md)。 更新或回退前保留原包和校验值、停止新操作并处理待恢复事务,然后停止 Host、安装兼容包并重新启动。浏览器旧资源可强制刷新;这不能代替 Host 依赖重载。禁用或移除包不会卸载技能,不应删除技能目录、inventory 或操作日志。 diff --git a/openspec/changes/add-dsh-native-plugin/verification.md b/openspec/changes/add-dsh-native-plugin/verification.md index cd54c3174..4d6a1179e 100644 --- a/openspec/changes/add-dsh-native-plugin/verification.md +++ b/openspec/changes/add-dsh-native-plugin/verification.md @@ -573,3 +573,8 @@ DSH 0.6.0 发布检查在 Windows / DSH 0.2.1-rc.2 的 `install-host` 阶段两 真实 Windows Node 24.2.0 / npm 11.3.0 的新版 Host lock-only 对照确认:默认 687 个安装位置、51 份 Zod,prefer-dedupe 为 636 个安装位置、1 份 Zod。本机两次完整冷安装仍达到 600 秒上限;减少重复依赖并不证明冷安装超时已解决。 候选提交 `74e6d93b7` 的 [CI 40996963179](https://github.com/iflytek/skillhub/actions/runs/40996963179) 中,旧版 Host 的 Windows Node 24.2.0 完整探针通过,准备耗时 348647ms;Windows Node 24 的准备完成(459541ms),但随后技能可用性探针在 user-install 的 accepted 断言失败。Linux/macOS 基础检查通过,后续官方 Host 和启停矩阵因前置失败未执行,不能算通过。安装工具返回状态与固定失败码需要补充诊断;保留现有断言。最终发布包验收仍待完成。修改验收脚本不等于改变已发布 CLI 或 DSH 产品运行逻辑。 + + +后续固定提交 `a431833b33bcf7523949537c50b9409c00c70ce3` 的 [CI 41011761831](https://github.com/iflytek/skillhub/actions/runs/41011761831) 已通过全部 14 项 DSH 检查。Windows / Host 0.2.1-rc.2 的启停与关闭监听场景准备分别耗时 348044ms、295943ms;Host 0.2.0-rc.2 分别为 291219ms、322063ms,均在全新 Profile 中通过真实探针。此前安装接受断言失败本轮未复现;新增诊断保留其固定状态和错误码,不修改断言。 + +本机部分缓存复测仍在 600787ms 超时,因此上述结果证明该固定提交的 CI 矩阵通过,不保证所有 Windows 环境在 600 秒内完成。旧 `dsh-v0.6.0` 标签保持不变;后续发布候选调整为 DSH 0.6.1,使用独立新标签。CLI 0.3.0 已发布,不重复发布,也不发布 SkillHub 应用 Release。0.6.1 发布身份、安装包及公开 npm 验收按发布流程单独验证。 diff --git a/plugins/dsh/README.en.md b/plugins/dsh/README.en.md index 173ac76c2..6170ce360 100644 --- a/plugins/dsh/README.en.md +++ b/plugins/dsh/README.en.md @@ -12,7 +12,7 @@ Version `0.4.0` uses the independent `dsh-v0.4.0` tag. It adds versioned example `0.5.0` adds read-only skill availability diagnosis in installed cards and conversations, with separate integrity, discovery and invocation-policy results. It retains the compatibility and inventory format of `0.4.0`. -`0.6.0` includes managed enable/disable, unified read-only update checks, and compact horizontal installed cards with a More menu. Shared inventory remains v2 without a coordinated CLI upgrade. Compatibility fixes and real historical-package acceptance are in progress; release remains blocked until they pass. Check npm for public availability. +`0.6.1` includes managed enable/disable, unified read-only update checks, and compact horizontal installed cards with a More menu. Shared inventory remains v2 without a coordinated CLI upgrade. Compatibility acceptance with the actual CLI 0.2.0 package has passed. Check npm for public availability. ## Use an installed skill @@ -78,8 +78,8 @@ Published `0.1.0` still requires the original Cordis `4.0.4` baseline and does n Query the exact npm version first and install only after confirming availability. Check DSH, Node and a complete Cordis combination listed above, stop the target Web Profile Host, then install the plugin. A verified local tarball can also be installed using the next section: ```sh -npm view @astron-team/skillhub-dsh@0.6.0 version -dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.6.0 --ignore-scripts +npm view @astron-team/skillhub-dsh@0.6.1 version +dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.6.1 --ignore-scripts dsh --profile skillhub-test --host 127.0.0.1 --port 0 --no-open ``` @@ -89,7 +89,7 @@ Replace `skillhub-test` with the intended Web Profile; initial creation is docum Shared inventory remains strict v2 without a persisted `installationState`; activation is derived from trusted `SKILL.md` / `SKILL.md.disabled` entries. A coordinated CLI upgrade is not required. Published CLI `0.2.0` must retain normal queries and ordinary-target management; default update, sync and Suite paths must not unintentionally enable disabled targets. Historical explicit force install, upgrade and sync retain their overwrite semantics and may restore the standard entry; explicit remove retains deletion semantics. New readers must reflect these actual file changes. -Reading v1/v2 does not migrate it. Any v3 inventory from unpublished builds requires identity, entry and pending-transaction validation, an original-byte backup under the same lock, and safe conversion to v2. Never restore a stale backup over newer records. Ordinary journals remain readable by historical DSH; toggle journals isolate compatibility impact. Compatibility implementation and real historical-package acceptance are in progress; release remains blocked until they pass. +Reading v1/v2 does not migrate it. Any v3 inventory from unpublished builds requires identity, entry and pending-transaction validation, an original-byte backup under the same lock, and safe conversion to v2. Never restore a stale backup over newer records. Ordinary journals remain readable by historical DSH; toggle journals isolate compatibility impact. Compatibility acceptance using alternating operations with actual historical packages has passed; check npm for public availability. Authors provide examples at the fixed `.skillhub/examples.json` path inside each skill package. The file keeps its location after installation and follows the skill's version and fingerprint; no separate global example copy is created. Skills without examples use a custom task; invalid declarations remain ordinary files without exposing invalid examples. @@ -223,7 +223,7 @@ Choose “管理安装 → 检查可用性” on a conversational installed-skil The result distinguishes local integrity, current-session discovery, and user/model invocation policies. Shadowing, local modifications and unknown Host state are separate outcomes. A name-only lookup reports Host observations without proving installation ownership or integrity. Diagnosis never modifies, removes or enables/disables a skill, edits a draft, or sends a message. A historical result is not a guarantee about a later invocation. -## Managed skill enable/disable (0.6.0) +## Managed skill enable/disable (0.6.1) Open “管理安装” and choose enable or disable on the explicit location row. User and project copies are independent: disabling the user copy does not disable a project copy. UI and conversation mutations require real human confirmation. `astron_skillhub_disable` / `astron_skillhub_enable` accept fresh installation references, never arbitrary paths. diff --git a/plugins/dsh/README.md b/plugins/dsh/README.md index 435aec020..c4a659cf5 100644 --- a/plugins/dsh/README.md +++ b/plugins/dsh/README.md @@ -12,7 +12,7 @@ SkillHub 的 DSH 原生插件。在 DSH 侧栏打开 **技能中心**,匿名 `0.5.0` 新增技能卡片及对话中的只读可用性诊断,分别报告文件完整性、宿主发现和调用策略,保留 `0.4.0` 的兼容范围及库存格式。 -`0.6.0` 包含受管理技能启停、统一只读检查更新,以及横向已安装卡片和更多菜单。共享库存继续使用 v2,不要求用户同步升级 CLI;兼容修复及真实旧包验收进行中,未通过前阻断发布。公开可用状态以 npm 为准。 +`0.6.1` 包含受管理技能启停、统一只读检查更新,以及横向已安装卡片和更多菜单。共享库存继续使用 v2,不要求用户同步升级 CLI;已通过与 CLI 0.2.0 的真实旧包兼容验收。公开可用状态以 npm 为准。 ## 使用已安装技能 @@ -78,8 +78,8 @@ npm pack --ignore-scripts --pack-destination /absolute/path/to/candidate-output 先查询 npm 上的精确版本,确认可用后安装。核对 DSH、Node 和上表完整 Cordis 组合,停止目标 Web Profile 的 Host,再执行插件安装;也可按下一节安装已验证的本地 tarball: ```sh -npm view @astron-team/skillhub-dsh@0.6.0 version -dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.6.0 --ignore-scripts +npm view @astron-team/skillhub-dsh@0.6.1 version +dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.6.1 --ignore-scripts dsh --profile skillhub-test --host 127.0.0.1 --port 0 --no-open ``` @@ -89,7 +89,7 @@ dsh --profile skillhub-test --host 127.0.0.1 --port 0 --no-open 共享库存保持严格 v2,不写入 `installationState`;启停状态从可信的 `SKILL.md` / `SKILL.md.disabled` 入口派生,不要求 CLI 用户同步升级。已发布 CLI `0.2.0` 的正常查询和普通目标管理必须继续兼容;默认更新、同步及 Suite 不得无意重新启用停用目标。旧 CLI 显式 force 重装、更新、同步仍按原覆盖语义执行,可能恢复标准入口;显式 remove 仍可删除,新版重新读取须反映真实变化。 -读取 v1/v2 不迁移。未发布构建产生的 v3 必须在身份、入口与未完成事务校验后,同锁保存原字节备份并安全转换为 v2;不能恢复过时备份覆盖新记录。旧 DSH 普通管理日志保持兼容,启停日志隔离影响。兼容修复及真实旧包验收正在进行,未通过前阻断发布。 +读取 v1/v2 不迁移。未发布构建产生的 v3 必须在身份、入口与未完成事务校验后,同锁保存原字节备份并安全转换为 v2;不能恢复过时备份覆盖新记录。旧 DSH 普通管理日志保持兼容,启停日志隔离影响。已通过真实旧包交替操作的兼容验收;公开可用状态以 npm 为准。 案例由作者随技能包提供固定文件 `.skillhub/examples.json`,安装后保持相同位置,跟随技能版本和指纹,不创建另一个全局案例副本。无案例时使用自定义任务;无效声明按普通文件保留,不提供错误的案例入口。 @@ -228,7 +228,7 @@ dsh plugin --profile skillhub-test remove @astron-team/skillhub-dsh 诊断分别核验本地文件、当前会话加载结果,以及用户/模型调用策略。同名技能生效、本地修改和宿主无法核验会给出不同结论。按技能名查询只说明当前宿主观察到的事实,不证明安装来源或内容完整性。检查不会修改、卸载、启停技能或发送消息;历史结果不保证下一次调用仍然可用。 -## 受管理技能启停(0.6.0) +## 受管理技能启停(0.6.1) 在“管理安装”中,对明确位置选择“停用”或“启用”。用户级和项目级副本独立管理;停用用户副本不会关闭项目副本。页面与对话均需真实用户确认,取消不写文件。对话工具 `astron_skillhub_disable` / `astron_skillhub_enable` 使用新查询中的位置引用,不能提交自由路径。 diff --git a/plugins/dsh/package.json b/plugins/dsh/package.json index f0e270fb1..605158007 100644 --- a/plugins/dsh/package.json +++ b/plugins/dsh/package.json @@ -1,6 +1,6 @@ { "name": "@astron-team/skillhub-dsh", - "version": "0.6.0", + "version": "0.6.1", "private": false, "type": "module", "license": "Apache-2.0",