@xiaoyuyu6420/dsh-backup 0.11.1 → 0.11.3

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
@@ -5,6 +5,7 @@
5
5
  [![Downloads](https://img.shields.io/npm/dw/@xiaoyuyu6420/dsh-backup)](https://www.npmjs.com/package/@xiaoyuyu6420/dsh-backup)
6
6
  [![Publish to npm](https://github.com/xiaoyuyu6420/dsh-backup/actions/workflows/publish.yml/badge.svg)](https://github.com/xiaoyuyu6420/dsh-backup/actions/workflows/publish.yml)
7
7
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+ [![Listed on DSH Directory](https://dsh.directory/badges/listed.svg)](https://dsh.directory/plugins/xiaoyuyu6420/dsh-backup)
8
9
 
9
10
  English | [简体中文](README.zh.md)
10
11
 
@@ -45,7 +46,7 @@ Prefer clicking? There's a visual panel in `dsh web` → Settings → Plugins
45
46
 
46
47
  ## Install
47
48
 
48
- Requires macOS / Linux / Windows 10+ (ships `tar`) and DSH `0.1.1-rc.2` or compatible.
49
+ Requires macOS / Linux / Windows 10+ (ships `tar`) and DSH `0.1.1-rc.2`+ (the 0.1.1 / 0.1.2 / 0.1.5 trains are all tested; verified up to `0.1.5-rc.2`).
49
50
 
50
51
  ```sh
51
52
  dsh plugin --profile web add @xiaoyuyu6420/dsh-backup
@@ -131,6 +132,8 @@ Tried it? Tell us what broke, what's missing, what you liked — it directly sha
131
132
  <details>
132
133
  <summary>Recent releases</summary>
133
134
 
135
+ - **0.11.3** — Follow the dsh `0.1.5` train: peerDependencies now include `^0.1.5-rc.1` (0.11.2 raised peer warnings on 0.1.5 hosts). Verified against host `0.1.5-rc.2`: real-host e2e 32/32; all six node-side peer packages are **byte-identical** between rc.1 and rc.2 (tarball diff) and the client train hasn't moved — zero adaptation surface this time; a cross-train in-place upgrade e2e (rc.1 host + 0.11.2 → rc.2 host + 0.11.3) passed 14/14 with settings and archives intact. Also fixed a latent bug in the upgrade e2e itself: the expected new version is now derived from the tarball instead of hardcoded.
136
+ - **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.
134
137
  - **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).
135
138
  - **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.
136
139
  - **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.
package/README.zh.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Downloads](https://img.shields.io/npm/dw/@xiaoyuyu6420/dsh-backup)](https://www.npmjs.com/package/@xiaoyuyu6420/dsh-backup)
6
6
  [![Publish to npm](https://github.com/xiaoyuyu6420/dsh-backup/actions/workflows/publish.yml/badge.svg)](https://github.com/xiaoyuyu6420/dsh-backup/actions/workflows/publish.yml)
7
7
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+ [![Listed on DSH Directory](https://dsh.directory/badges/listed.svg)](https://dsh.directory/plugins/xiaoyuyu6420/dsh-backup)
8
9
 
9
10
  [English](README.md) | 简体中文
10
11
 
@@ -45,7 +46,7 @@ sha256: 8f9ae6322ef782d21554981cf4547220d5bb3e64d7964a883317415ad54e3cbb
45
46
 
46
47
  ## 安装
47
48
 
48
- 要求:macOS / Linux / Windows 10+(自带 `tar`),DSH `0.1.1-rc.2` 或兼容版本。
49
+ 要求:macOS / Linux / Windows 10+(自带 `tar`),DSH `0.1.1-rc.2`+(0.1.1 / 0.1.2 / 0.1.5 列车均已实测,最新验证至 `0.1.5-rc.2`)。
49
50
 
50
51
  ```sh
51
52
  dsh plugin --profile web add @xiaoyuyu6420/dsh-backup
@@ -131,6 +132,8 @@ dsh plugin --profile web add github:xiaoyuyu6420/dsh-backup
131
132
  <details>
132
133
  <summary>最近的版本</summary>
133
134
 
135
+ - **0.11.3** —— 跟进 dsh `0.1.5` 列车:peerDependencies 追加 `^0.1.5-rc.1`(0.11.2 在 0.1.5 宿主上会报 peer 警告)。兼容实测:宿主 `0.1.5-rc.2` 真机 e2e 32/32;六个 node 侧 peer 包 rc.1↔rc.2 **逐字节相同**(tarball diff),client 包列车未动——本次升列车零适配面;跨列车原地升级 e2e(rc.1 宿主 + 0.11.2 → rc.2 宿主 + 0.11.3)14/14,设置与归档无损。顺带修了升级 e2e 脚本自身的一个坑:新版期望版本从写死改为从 tarball 动态推导,换版本对不再改脚本。
136
+ - **0.11.2** —— doctor 行级 SessionHeader 校验对齐宿主 `isHeaderLine`(闭环 0.11.0 已知遗留):补 `version`/`createdAt`/`delegationDepth` 类型与非负安全整数三连(含 `-0` 拒绝)、`seedLength`/`origin`/`agentPreset` 可选分支、退役字段 `sandboxMode`/`approvalPolicy`——宿主拒载的 header 不再被误报健康。对照双列车宿主编译产物逐字段验证(rc.1 为严格超集),独立复核结论 ALIGN;测试套新增 11 种坏 header 负样本 + 修复往返。
134
137
  - **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 原地升级测试(设置保留、旧归档可恢复)。
135
138
  - **0.11.0** —— doctor 容器契约校验:首帧必须解出「恰好一行 header、单个换行结尾」(字节精确,对齐宿主读端)。单帧重写、首帧多余空行、缺行尾、skippable 帧现在都会判损坏(此前报健康但宿主拒载);救援台同步。来自 deepseek-harness 官方讨论区 #1047 的社区审计。
136
139
  - **0.10.0** —— 分类型备份:只备份需要的部分(`/backup --types skills,sessions`),按类型 merge 恢复(`/backup restore <归档> --types skills`);类型归档独立轮换不挤全量配额。含凭据的类型归档永不进 GitHub 同步,跨机护栏不变。
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.1",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))})}
453
+ `;var pm={name:"@xiaoyuyu6420/dsh-backup",version:"0.11.3",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 || ^0.1.5-rc.1","@deepseek-ai/dsh-fs":"^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1","@deepseek-ai/dsh-settings":"^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1","@deepseek-ai/dsh-subprocess":"^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1","@deepseek-ai/dsh-tools":"^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-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
@@ -1944,9 +1944,20 @@ export function apply(ctx, pluginConfig) {
1944
1944
  } catch {
1945
1945
  return `首行不是 JSON(${snippet(String(lines[0]))})`;
1946
1946
  }
1947
- if (!header || typeof header !== 'object' || header.type !== 'session' || typeof header.id !== 'string') {
1948
- return '首行不是有效的 SessionHeader(缺 type:"session" id)';
1949
- }
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——宿主读端拒绝';
1950
1961
  let nextSeq = 0;
1951
1962
  for (let i = 1; i < lines.length; i++) {
1952
1963
  let rec;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaoyuyu6420/dsh-backup",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
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 || ^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",
56
+ "@deepseek-ai/dsh-commands": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
57
+ "@deepseek-ai/dsh-fs": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
58
+ "@deepseek-ai/dsh-settings": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
59
+ "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
60
+ "@deepseek-ai/dsh-tools": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
61
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.5-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;