@xiaoyuyu6420/dsh-backup 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -131,6 +131,8 @@ Tried it? Tell us what broke, what's missing, what you liked — it directly sha
131
131
  <details>
132
132
  <summary>Recent releases</summary>
133
133
 
134
+ - **0.11.2** — doctor line-level SessionHeader validation aligned with the host `isHeaderLine` (closes the known gap from 0.11.0): `version`/`createdAt`/`delegationDepth` type + non-negative-safe-integer checks (including `-0` rejection), optional `seedLength`/`origin`/`agentPreset` branches, and retired `sandboxMode`/`approvalPolicy` fields the host reader rejects — headers the host refuses to load are now flagged instead of reported healthy. Verified field-by-field against the compiled host source (both trains; the rc.1 checker is the strict superset) with an independent review verdict of ALIGN; 11 bad-header negative samples + repair round-trip added to the suite.
135
+ - **0.11.1** — dsh `0.1.2-rc.1` compatibility: adapts to the removal of `settingsNamespace` from `@deepseek-ai/dsh-settings` (settings now register under the plain `dsh-backup` namespace — value-identical, so existing settings, backups and archives survive an in-place update), works behind the new forced web auth (303 + HttpOnly cookie), and widens peer ranges to `^0.1.1-rc.2 || ^0.1.2-rc.1`. Verified on both trains with real-host e2e (32/32 each) plus an in-place 0.11.0 → 0.11.1 upgrade test (settings preserved, old archives restorable).
134
136
  - **0.11.0** — doctor container-contract check: the first zstd frame must decode to exactly one header line, byte-precise (non-empty, first newline at the last byte — aligned with the host reader). Single-frame rewrites, stray blank lines in the first frame, a missing trailing newline and skippable frames are now flagged corrupt (previously reported healthy while the host refused to load them); the rescue console checks in sync. Found via a community audit on deepseek-harness #1047.
135
137
  - **0.10.0** — typed backups: back up just what you need (`/backup --types skills,sessions`) and merge-restore a subset (`/backup restore <archive> --types skills`); per-type archives rotate in their own bucket. Credential-type archives stay out of GitHub sync; cross-machine guardrails unchanged.
136
138
  - **0.9.1** — feedback entry point in the panel; README overhaul. UX hardening from a six-agent review: restore-confirm button made visible again (missing theme fallback), snapshot self-deletion during snapshot-restore fixed, node discovery for the double-click rescue launcher, friendlier error messages with concrete next steps.
package/README.zh.md CHANGED
@@ -131,6 +131,8 @@ dsh plugin --profile web add github:xiaoyuyu6420/dsh-backup
131
131
  <details>
132
132
  <summary>最近的版本</summary>
133
133
 
134
+ - **0.11.2** —— doctor 行级 SessionHeader 校验对齐宿主 `isHeaderLine`(闭环 0.11.0 已知遗留):补 `version`/`createdAt`/`delegationDepth` 类型与非负安全整数三连(含 `-0` 拒绝)、`seedLength`/`origin`/`agentPreset` 可选分支、退役字段 `sandboxMode`/`approvalPolicy`——宿主拒载的 header 不再被误报健康。对照双列车宿主编译产物逐字段验证(rc.1 为严格超集),独立复核结论 ALIGN;测试套新增 11 种坏 header 负样本 + 修复往返。
135
+ - **0.11.1** —— 适配 dsh `0.1.2-rc.1`:跟随 `@deepseek-ai/dsh-settings` 移除 `settingsNamespace`(改用普通 `dsh-backup` 命名空间注册——取值完全一致,原地更新后设置、备份与旧归档全部无损),支持 Web 强制鉴权(303 + HttpOnly cookie),peer 范围放宽为 `^0.1.1-rc.2 || ^0.1.2-rc.1`。双列车真宿主 e2e 各 32/32 通过,另做了 0.11.0 → 0.11.1 原地升级测试(设置保留、旧归档可恢复)。
134
136
  - **0.11.0** —— doctor 容器契约校验:首帧必须解出「恰好一行 header、单个换行结尾」(字节精确,对齐宿主读端)。单帧重写、首帧多余空行、缺行尾、skippable 帧现在都会判损坏(此前报健康但宿主拒载);救援台同步。来自 deepseek-harness 官方讨论区 #1047 的社区审计。
135
137
  - **0.10.0** —— 分类型备份:只备份需要的部分(`/backup --types skills,sessions`),按类型 merge 恢复(`/backup restore <归档> --types skills`);类型归档独立轮换不挤全量配额。含凭据的类型归档永不进 GitHub 同步,跨机护栏不变。
136
138
  - **0.9.1** —— 面板新增反馈入口;README 重做。六路 agent UX 深审后的加固:恢复确认按钮补主题色兜底重新可见、修复恢复快照时自毁目标快照的 bug、双击救援启动器自动探测 node、报错文案全面改为"人话 + 下一步"。
package/lib/client.js CHANGED
@@ -450,5 +450,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
450
450
  color: var(--dsw-alias-state-error-primary, #e53e3e);
451
451
  line-height: 1.5;
452
452
  }
453
- `;var pm={name:"@xiaoyuyu6420/dsh-backup",version:"0.11.0",description:"Backup, restore, download and GitHub-sync DeepSeek Harness user data (~/.dsh): /backup, scheduled auto-backup that survives restarts, sha256 checksums, integrity verify, rotation, credential redaction with a local vault (plaintext never leaves the machine), cross-machine restore preflight with github pull, and a visual Settings panel. Cross-platform (macOS/Linux/Windows). \u4E00\u952E\u5907\u4EFD\u4E0E\u6062\u590D DSH \u6570\u636E\uFF1A\u5B9A\u65F6\u81EA\u52A8\u5907\u4EFD\u3001\u5B8C\u6574\u6027\u6821\u9A8C\u3001\u51ED\u636E\u9ED8\u8BA4\u8131\u654F\uFF08\u660E\u6587\u53EA\u5B58\u672C\u673A vault\uFF09\u3001\u8DE8\u673A\u6062\u590D\u9884\u68C0\u4E0E github pull \u62C9\u53D6\uFF0C\u9644 Settings \u53EF\u89C6\u9762\u677F\u3002",type:"module",packageManager:"pnpm@11.24.0",main:"lib/index.js",exports:{".":"./lib/index.js","./client":"./lib/client.js","./cordis.patch.yml":"./cordis.patch.yml","./package.json":"./package.json"},files:["lib","rescue","cordis.patch.yml","README.md","README.zh.md","LICENSE"],bin:{"dsh-rescue":"./rescue/rescue.mjs"},dsh:{bundle:{patch:"./cordis.patch.yml"},client:{platform:"web",inject:["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings"]}},keywords:["dsh","dsh-plugin","deepseek-harness","backup","\u5907\u4EFD","restore","\u6062\u590D","schedule","\u81EA\u52A8\u5907\u4EFD","cross-platform","rescue","doctor","upgrade-snapshot","\u6570\u636E\u5B89\u5168"],peerDependencies:{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-commands":"^0.1.1-rc.2","@deepseek-ai/dsh-fs":"^0.1.1-rc.2","@deepseek-ai/dsh-settings":"^0.1.1-rc.2","@deepseek-ai/dsh-subprocess":"^0.1.1-rc.2","@deepseek-ai/dsh-tools":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2","@deepseek-ai/schemastery":"^3.18.1"},devDependencies:{esbuild:"^0.25.0",react:"^19.0.0","react-dom":"^19.0.0",zod:"^4.4.3"},engines:{node:">=20"},license:"MIT",repository:{type:"git",url:"git+https://github.com/xiaoyuyu6420/dsh-backup.git"},homepage:"https://github.com/xiaoyuyu6420/dsh-backup#readme",bugs:{url:"https://github.com/xiaoyuyu6420/dsh-backup/issues"},publishConfig:{access:"public"}};var Cn="settings.backupPanel",Ig=pm.name,jg=["slots","locale","remote"],Pg=y.object({destination:y.string(),dshHome:y.string(),keepDefault:y.number().int(),autoHours:y.number().int(),lastAuto:y.string().nullable(),backups:y.array(y.object({name:y.string(),size:y.number().int().nullable()})),typedBackups:y.array(y.object({name:y.string(),size:y.number().int().nullable(),types:y.array(y.string())})).optional()}),Ug=y.object({ok:y.boolean(),summary:y.string(),path:y.string(),sha:y.string(),stale:y.number().int(),keep:y.number().int(),types:y.array(y.string()).optional(),hasCredentials:y.boolean().optional()}),Dg=y.object({ok:y.boolean(),summary:y.string(),results:y.array(y.object({name:y.string(),ok:y.boolean(),note:y.string()}))}),Og=y.object({ok:y.boolean(),dryRun:y.boolean(),summary:y.string(),archive:y.string().nullable().optional(),files:y.number().int().nullable().optional(),aside:y.string().nullable().optional(),snapshotPath:y.string().nullable().optional(),sample:y.array(y.string()).optional(),preflight:y.array(y.string()).optional(),targetExists:y.boolean().nullable().optional(),merge:y.boolean().optional(),types:y.array(y.string()).optional(),willOverwrite:y.array(y.string()).optional(),restored:y.number().int().optional(),kept:y.array(y.string()).optional()}),Ng=y.object({ok:y.boolean(),hours:y.number().int(),summary:y.string()}),Zg=y.object({repoRaw:y.string().nullable(),repo:y.string().nullable(),tokenSet:y.boolean(),syncDir:y.string(),lastPush:y.string().nullable(),lastError:y.string().nullable()}),Tg=y.object({ok:y.boolean(),summary:y.string(),pushed:y.boolean(),tooBig:y.array(y.string())}),Eg=y.object({ok:y.boolean(),summary:y.string(),pulled:y.array(y.string()),corrupt:y.array(y.string()),total:y.number().int()}),Ag=y.object({ok:y.boolean(),summary:y.string()}),Lg=y.object({ok:y.boolean(),repo:y.string().nullable(),summary:y.string()}),Rg={name:"keep",wire:"keep",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#keep",schema:y.number().int().positive().optional()},acceptsUndefined:!0},Hu={name:"selector",wire:"selector",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#selector",schema:y.string().optional()},acceptsUndefined:!0},Cg={name:"dryRun",wire:"dryRun",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#dryRun",schema:y.boolean().optional()},acceptsUndefined:!0},Fg={name:"syncDeps",wire:"syncDeps",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#syncDeps",schema:y.boolean().optional()},acceptsUndefined:!0},Jg={name:"hours",wire:"hours",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#hours",schema:y.number().int().min(0).max(720)},acceptsUndefined:!0},Vg={name:"repo",wire:"repo",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#repo",schema:y.string().optional()},acceptsUndefined:!0},fm={name:"types",wire:"types",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#types",schema:y.array(y.string()).optional()},acceptsUndefined:!0};function de(t,r,i,o){return Object.freeze({id:`dsh-backup#backupPanel/${t}`,service:"backupPanel",namespace:"backupPanel",method:t,invocation:Object.freeze({kind:"direct"}),parameters:Object.freeze(r.map(e=>Object.freeze({...e,codec:Object.freeze(e.codec)}))),...o?{cancellation:Object.freeze({parameter:"signal"})}:{},result:Object.freeze({mode:"strict",typeSymbol:`dsh-backup/types#${t}Result`,schema:i})})}var gm=Object.freeze({package:"dsh-backup",descriptors:Object.freeze([de("status",[],Pg,!1),de("backup",[Rg,fm],Ug,!0),de("verify",[Hu],Dg,!0),de("restore",[Hu,Cg,fm,Fg],Og,!0),de("setAuto",[Jg],Ng,!1),de("githubStatus",[],Zg,!1),de("githubSyncNow",[],Tg,!0),de("githubPull",[],Eg,!0),de("removeEntry",[Hu],Ag,!0),de("setGithubRepo",[Vg],Lg,!1)])});function me(t){if(!t.ok){let r=t.error,i=r&&r.message?`${r.code}: ${r.message}`:"backupPanel \u8C03\u7528\u5931\u8D25";throw new Error(`\u64CD\u4F5C\u6CA1\u6709\u5B8C\u6210\uFF1A\u9762\u677F\u6682\u65F6\u8FDE\u4E0D\u4E0A\u540E\u53F0\uFF0C\u8BF7\u91CD\u8BD5\uFF1B\u82E5\u53CD\u590D\u51FA\u73B0\u8BF7\u91CD\u542F dsh web\uFF08\u6280\u672F\u7EC6\u8282: ${i}\uFF09`)}return t.value}function Mg(t){t.effect(()=>t.locale.register(Cn,{zh:lm,en:dm}),"dsh-backup: dictionaries"),t.effect(()=>mm(),"dsh-backup: stylesheet"),t.effect(()=>{let r=null,i=!0,o=!1;return(async()=>{try{r=await t.remote.$mount(gm)}catch(e){console.error("dsh-backup: backupPanel mount failed:",e)}i=!1,o&&r?.()})(),()=>{o=!0,i||r?.()}},"dsh-backup: remote contribution"),t.inject(["remote.backupPanel"],r=>{let i=r.locale.bind(Cn),o=()=>r.remote.backupPanel,e={status:async()=>me(await o().status()),backup:async(n,a)=>me(await o().backup(n,a)),verify:async n=>me(await o().verify(n)),restore:async(n,a,c,s)=>me(await o().restore(n,a,c,s)),setAuto:async n=>me(await o().setAuto(n)),githubStatus:async()=>me(await o().githubStatus()),githubSyncNow:async()=>me(await o().githubSyncNow()),githubPull:async()=>me(await o().githubPull()),removeEntry:async n=>me(await o().removeEntry(n)),setGithubRepo:async n=>me(await o().setGithubRepo(n))};r.slots.inject("settings.plugins.tab",()=>r.slots.register({name:"settings.plugins.tab",id:"backup",order:35,label:()=>i("tab"),locale:Cn,inject:()=>({panel:e})},sm))})}
453
+ `;var pm={name:"@xiaoyuyu6420/dsh-backup",version:"0.11.2",description:"Backup, restore, download and GitHub-sync DeepSeek Harness user data (~/.dsh): /backup, scheduled auto-backup that survives restarts, sha256 checksums, integrity verify, rotation, credential redaction with a local vault (plaintext never leaves the machine), cross-machine restore preflight with github pull, and a visual Settings panel. Cross-platform (macOS/Linux/Windows). \u4E00\u952E\u5907\u4EFD\u4E0E\u6062\u590D DSH \u6570\u636E\uFF1A\u5B9A\u65F6\u81EA\u52A8\u5907\u4EFD\u3001\u5B8C\u6574\u6027\u6821\u9A8C\u3001\u51ED\u636E\u9ED8\u8BA4\u8131\u654F\uFF08\u660E\u6587\u53EA\u5B58\u672C\u673A vault\uFF09\u3001\u8DE8\u673A\u6062\u590D\u9884\u68C0\u4E0E github pull \u62C9\u53D6\uFF0C\u9644 Settings \u53EF\u89C6\u9762\u677F\u3002",type:"module",packageManager:"pnpm@11.24.0",main:"lib/index.js",exports:{".":"./lib/index.js","./client":"./lib/client.js","./cordis.patch.yml":"./cordis.patch.yml","./package.json":"./package.json"},files:["lib","rescue","cordis.patch.yml","README.md","README.zh.md","LICENSE"],bin:{"dsh-rescue":"./rescue/rescue.mjs"},dsh:{bundle:{patch:"./cordis.patch.yml"},client:{platform:"web",inject:["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings"]}},keywords:["dsh","dsh-plugin","deepseek-harness","backup","\u5907\u4EFD","restore","\u6062\u590D","schedule","\u81EA\u52A8\u5907\u4EFD","cross-platform","rescue","doctor","upgrade-snapshot","\u6570\u636E\u5B89\u5168"],peerDependencies:{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-commands":"^0.1.1-rc.2 || ^0.1.2-rc.1","@deepseek-ai/dsh-fs":"^0.1.1-rc.2 || ^0.1.2-rc.1","@deepseek-ai/dsh-settings":"^0.1.1-rc.2 || ^0.1.2-rc.1","@deepseek-ai/dsh-subprocess":"^0.1.1-rc.2 || ^0.1.2-rc.1","@deepseek-ai/dsh-tools":"^0.1.1-rc.2 || ^0.1.2-rc.1","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2 || ^0.1.2-rc.1","@deepseek-ai/schemastery":"^3.18.1"},devDependencies:{esbuild:"^0.25.0",react:"^19.0.0","react-dom":"^19.0.0",zod:"^4.4.3"},engines:{node:">=20"},license:"MIT",repository:{type:"git",url:"git+https://github.com/xiaoyuyu6420/dsh-backup.git"},homepage:"https://github.com/xiaoyuyu6420/dsh-backup#readme",bugs:{url:"https://github.com/xiaoyuyu6420/dsh-backup/issues"},publishConfig:{access:"public"}};var Cn="settings.backupPanel",Ig=pm.name,jg=["slots","locale","remote"],Pg=y.object({destination:y.string(),dshHome:y.string(),keepDefault:y.number().int(),autoHours:y.number().int(),lastAuto:y.string().nullable(),backups:y.array(y.object({name:y.string(),size:y.number().int().nullable()})),typedBackups:y.array(y.object({name:y.string(),size:y.number().int().nullable(),types:y.array(y.string())})).optional()}),Ug=y.object({ok:y.boolean(),summary:y.string(),path:y.string(),sha:y.string(),stale:y.number().int(),keep:y.number().int(),types:y.array(y.string()).optional(),hasCredentials:y.boolean().optional()}),Dg=y.object({ok:y.boolean(),summary:y.string(),results:y.array(y.object({name:y.string(),ok:y.boolean(),note:y.string()}))}),Og=y.object({ok:y.boolean(),dryRun:y.boolean(),summary:y.string(),archive:y.string().nullable().optional(),files:y.number().int().nullable().optional(),aside:y.string().nullable().optional(),snapshotPath:y.string().nullable().optional(),sample:y.array(y.string()).optional(),preflight:y.array(y.string()).optional(),targetExists:y.boolean().nullable().optional(),merge:y.boolean().optional(),types:y.array(y.string()).optional(),willOverwrite:y.array(y.string()).optional(),restored:y.number().int().optional(),kept:y.array(y.string()).optional()}),Ng=y.object({ok:y.boolean(),hours:y.number().int(),summary:y.string()}),Zg=y.object({repoRaw:y.string().nullable(),repo:y.string().nullable(),tokenSet:y.boolean(),syncDir:y.string(),lastPush:y.string().nullable(),lastError:y.string().nullable()}),Tg=y.object({ok:y.boolean(),summary:y.string(),pushed:y.boolean(),tooBig:y.array(y.string())}),Eg=y.object({ok:y.boolean(),summary:y.string(),pulled:y.array(y.string()),corrupt:y.array(y.string()),total:y.number().int()}),Ag=y.object({ok:y.boolean(),summary:y.string()}),Lg=y.object({ok:y.boolean(),repo:y.string().nullable(),summary:y.string()}),Rg={name:"keep",wire:"keep",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#keep",schema:y.number().int().positive().optional()},acceptsUndefined:!0},Hu={name:"selector",wire:"selector",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#selector",schema:y.string().optional()},acceptsUndefined:!0},Cg={name:"dryRun",wire:"dryRun",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#dryRun",schema:y.boolean().optional()},acceptsUndefined:!0},Fg={name:"syncDeps",wire:"syncDeps",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#syncDeps",schema:y.boolean().optional()},acceptsUndefined:!0},Jg={name:"hours",wire:"hours",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#hours",schema:y.number().int().min(0).max(720)},acceptsUndefined:!0},Vg={name:"repo",wire:"repo",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#repo",schema:y.string().optional()},acceptsUndefined:!0},fm={name:"types",wire:"types",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#types",schema:y.array(y.string()).optional()},acceptsUndefined:!0};function de(t,r,i,o){return Object.freeze({id:`dsh-backup#backupPanel/${t}`,service:"backupPanel",namespace:"backupPanel",method:t,invocation:Object.freeze({kind:"direct"}),parameters:Object.freeze(r.map(e=>Object.freeze({...e,codec:Object.freeze(e.codec)}))),...o?{cancellation:Object.freeze({parameter:"signal"})}:{},result:Object.freeze({mode:"strict",typeSymbol:`dsh-backup/types#${t}Result`,schema:i})})}var gm=Object.freeze({package:"dsh-backup",descriptors:Object.freeze([de("status",[],Pg,!1),de("backup",[Rg,fm],Ug,!0),de("verify",[Hu],Dg,!0),de("restore",[Hu,Cg,fm,Fg],Og,!0),de("setAuto",[Jg],Ng,!1),de("githubStatus",[],Zg,!1),de("githubSyncNow",[],Tg,!0),de("githubPull",[],Eg,!0),de("removeEntry",[Hu],Ag,!0),de("setGithubRepo",[Vg],Lg,!1)])});function me(t){if(!t.ok){let r=t.error,i=r&&r.message?`${r.code}: ${r.message}`:"backupPanel \u8C03\u7528\u5931\u8D25";throw new Error(`\u64CD\u4F5C\u6CA1\u6709\u5B8C\u6210\uFF1A\u9762\u677F\u6682\u65F6\u8FDE\u4E0D\u4E0A\u540E\u53F0\uFF0C\u8BF7\u91CD\u8BD5\uFF1B\u82E5\u53CD\u590D\u51FA\u73B0\u8BF7\u91CD\u542F dsh web\uFF08\u6280\u672F\u7EC6\u8282: ${i}\uFF09`)}return t.value}function Mg(t){t.effect(()=>t.locale.register(Cn,{zh:lm,en:dm}),"dsh-backup: dictionaries"),t.effect(()=>mm(),"dsh-backup: stylesheet"),t.effect(()=>{let r=null,i=!0,o=!1;return(async()=>{try{r=await t.remote.$mount(gm)}catch(e){console.error("dsh-backup: backupPanel mount failed:",e)}i=!1,o&&r?.()})(),()=>{o=!0,i||r?.()}},"dsh-backup: remote contribution"),t.inject(["remote.backupPanel"],r=>{let i=r.locale.bind(Cn),o=()=>r.remote.backupPanel,e={status:async()=>me(await o().status()),backup:async(n,a)=>me(await o().backup(n,a)),verify:async n=>me(await o().verify(n)),restore:async(n,a,c,s)=>me(await o().restore(n,a,c,s)),setAuto:async n=>me(await o().setAuto(n)),githubStatus:async()=>me(await o().githubStatus()),githubSyncNow:async()=>me(await o().githubSyncNow()),githubPull:async()=>me(await o().githubPull()),removeEntry:async n=>me(await o().removeEntry(n)),setGithubRepo:async n=>me(await o().setGithubRepo(n))};r.slots.inject("settings.plugins.tab",()=>r.slots.register({name:"settings.plugins.tab",id:"backup",order:35,label:()=>i("tab"),locale:Cn,inject:()=>({panel:e})},sm))})}
454
454
  return module.exports; } });
package/lib/index.js CHANGED
@@ -51,7 +51,7 @@ import { fileURLToPath } from 'node:url';
51
51
  import * as zlib from 'node:zlib';
52
52
  import { defineTool } from '@deepseek-ai/dsh-tools';
53
53
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
54
- import { settingsNamespace, SettingsConflictError } from '@deepseek-ai/dsh-settings';
54
+ import { SettingsConflictError } from '@deepseek-ai/dsh-settings';
55
55
  import z from '@deepseek-ai/schemastery';
56
56
 
57
57
  export const name = 'dsh-backup';
@@ -266,8 +266,11 @@ function detectHostTrain() {
266
266
  return null;
267
267
  }
268
268
 
269
- /** Settings 命名空间:经 `ctx.settings` 提供(持久化到 $DSH_HOME/settings.yaml)。 */
270
- const NS = settingsNamespace('dsh-backup');
269
+ /** Settings 命名空间:经 `ctx.settings` 提供(持久化到 $DSH_HOME/settings.yaml)。
270
+ * 0.1.2-rc.1 起宿主移除了 settingsNamespace 帮助函数——它运行时本就只返回
271
+ * 这个字符串(纯 TS 类型校验),ctx.settings.register/update/replace/describe
272
+ * 吃的都是同一语法的字符串,直接写常量在两个列车上行为等价。 */
273
+ const NS = 'dsh-backup';
271
274
 
272
275
  /**
273
276
  * 设置默认值。SCHEMA 的 .default() 与 resolveBase 的初始值都引用这里,
@@ -1941,9 +1944,20 @@ export function apply(ctx, pluginConfig) {
1941
1944
  } catch {
1942
1945
  return `首行不是 JSON(${snippet(String(lines[0]))})`;
1943
1946
  }
1944
- if (!header || typeof header !== 'object' || header.type !== 'session' || typeof header.id !== 'string') {
1945
- return '首行不是有效的 SessionHeader(缺 type:"session" id)';
1946
- }
1947
+ if (!header || typeof header !== 'object') return '首行不是对象';
1948
+ // 行级 SessionHeader 校验对齐宿主 isHeaderLine(0.1.2-rc.1 是 0.1.1-rc.2 的严格
1949
+ // 超集——多查 seedLength;以严格者为准覆盖双列车)。宿主读端 isHeaderLine 通过后,
1950
+ // fromHeaderLine 还会拒绝退役字段 sandboxMode/approvalPolicy——两者合并即"能否加载",
1951
+ // 故 doctor 全检。字段语义取自 @deepseek-ai/dsh-session-persistence-jsonl format.ts。
1952
+ if (header.type !== 'session') return `首行 type 不是 "session"(${snippet(JSON.stringify(header.type) ?? String(header.type))})`;
1953
+ if (typeof header.version !== 'number') return `首行 version 不是 number(${snippet(typeof header.version)})`;
1954
+ if (typeof header.id !== 'string') return '首行 id 不是 string';
1955
+ if (typeof header.createdAt !== 'number' || !Number.isSafeInteger(header.createdAt) || header.createdAt < 0 || Object.is(header.createdAt, -0)) return `首行 createdAt 非法(须非负安全整数,实际 ${snippet(String(header.createdAt))})`;
1956
+ if (typeof header.delegationDepth !== 'number' || !Number.isSafeInteger(header.delegationDepth) || header.delegationDepth < 0 || Object.is(header.delegationDepth, -0)) return `首行 delegationDepth 非法(须非负安全整数,实际 ${snippet(String(header.delegationDepth))})`;
1957
+ if (header.seedLength !== undefined && (typeof header.seedLength !== 'number' || !Number.isSafeInteger(header.seedLength) || header.seedLength < 0 || Object.is(header.seedLength, -0))) return '首行 seedLength 非法(须 undefined 或非负安全整数)';
1958
+ if (header.origin !== undefined && header.origin !== 'subagent') return '首行 origin 非法(须 undefined 或 "subagent")';
1959
+ if (header.agentPreset !== undefined && typeof header.agentPreset !== 'string') return '首行 agentPreset 非法(须 undefined 或 string)';
1960
+ if (Object.hasOwn(header, 'sandboxMode') || Object.hasOwn(header, 'approvalPolicy')) return '首行含退役字段 sandboxMode/approvalPolicy——宿主读端拒绝';
1947
1961
  let nextSeq = 0;
1948
1962
  for (let i = 1; i < lines.length; i++) {
1949
1963
  let rec;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaoyuyu6420/dsh-backup",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Backup, restore, download and GitHub-sync DeepSeek Harness user data (~/.dsh): /backup, scheduled auto-backup that survives restarts, sha256 checksums, integrity verify, rotation, credential redaction with a local vault (plaintext never leaves the machine), cross-machine restore preflight with github pull, and a visual Settings panel. Cross-platform (macOS/Linux/Windows). 一键备份与恢复 DSH 数据:定时自动备份、完整性校验、凭据默认脱敏(明文只存本机 vault)、跨机恢复预检与 github pull 拉取,附 Settings 可视面板。",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.24.0",
@@ -53,12 +53,12 @@
53
53
  ],
54
54
  "peerDependencies": {
55
55
  "@deepseek-ai/cordis": "^4.0.1",
56
- "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
57
- "@deepseek-ai/dsh-fs": "^0.1.1-rc.2",
58
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
59
- "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2",
60
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
61
- "@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2",
56
+ "@deepseek-ai/dsh-commands": "^0.1.1-rc.2 || ^0.1.2-rc.1",
57
+ "@deepseek-ai/dsh-fs": "^0.1.1-rc.2 || ^0.1.2-rc.1",
58
+ "@deepseek-ai/dsh-settings": "^0.1.1-rc.2 || ^0.1.2-rc.1",
59
+ "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2 || ^0.1.2-rc.1",
60
+ "@deepseek-ai/dsh-tools": "^0.1.1-rc.2 || ^0.1.2-rc.1",
61
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2 || ^0.1.2-rc.1",
62
62
  "@deepseek-ai/schemastery": "^3.18.1"
63
63
  },
64
64
  "devDependencies": {
package/rescue/rescue.mjs CHANGED
@@ -283,9 +283,20 @@ function validateSessionLines(lines) {
283
283
  } catch {
284
284
  return `首行不是 JSON(${snippet(String(lines[0]))})`;
285
285
  }
286
- if (!header || typeof header !== 'object' || header.type !== 'session' || typeof header.id !== 'string') {
287
- return '首行不是有效的 SessionHeader(缺 type:"session" id)';
288
- }
286
+ if (!header || typeof header !== 'object') return '首行不是对象';
287
+ // 行级 SessionHeader 校验对齐宿主 isHeaderLine(0.1.2-rc.1 是 0.1.1-rc.2 的严格
288
+ // 超集——多查 seedLength;以严格者为准覆盖双列车)。宿主读端 isHeaderLine 通过后,
289
+ // fromHeaderLine 还会拒绝退役字段 sandboxMode/approvalPolicy——两者合并即"能否加载",
290
+ // 故 doctor 全检。字段语义取自 @deepseek-ai/dsh-session-persistence-jsonl format.ts。
291
+ if (header.type !== 'session') return `首行 type 不是 "session"(${snippet(JSON.stringify(header.type) ?? String(header.type))})`;
292
+ if (typeof header.version !== 'number') return `首行 version 不是 number(${snippet(typeof header.version)})`;
293
+ if (typeof header.id !== 'string') return '首行 id 不是 string';
294
+ if (typeof header.createdAt !== 'number' || !Number.isSafeInteger(header.createdAt) || header.createdAt < 0 || Object.is(header.createdAt, -0)) return `首行 createdAt 非法(须非负安全整数,实际 ${snippet(String(header.createdAt))})`;
295
+ if (typeof header.delegationDepth !== 'number' || !Number.isSafeInteger(header.delegationDepth) || header.delegationDepth < 0 || Object.is(header.delegationDepth, -0)) return `首行 delegationDepth 非法(须非负安全整数,实际 ${snippet(String(header.delegationDepth))})`;
296
+ if (header.seedLength !== undefined && (typeof header.seedLength !== 'number' || !Number.isSafeInteger(header.seedLength) || header.seedLength < 0 || Object.is(header.seedLength, -0))) return '首行 seedLength 非法(须 undefined 或非负安全整数)';
297
+ if (header.origin !== undefined && header.origin !== 'subagent') return '首行 origin 非法(须 undefined 或 "subagent")';
298
+ if (header.agentPreset !== undefined && typeof header.agentPreset !== 'string') return '首行 agentPreset 非法(须 undefined 或 string)';
299
+ if (Object.hasOwn(header, 'sandboxMode') || Object.hasOwn(header, 'approvalPolicy')) return '首行含退役字段 sandboxMode/approvalPolicy——宿主读端拒绝';
289
300
  let nextSeq = 0;
290
301
  for (let i = 1; i < lines.length; i++) {
291
302
  let rec;