@xiaoyuyu6420/dsh-backup 0.7.0 → 0.7.1

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
@@ -7,198 +7,188 @@
7
7
 
8
8
  English | [简体中文](README.zh.md)
9
9
 
10
- One-command backup **and restore** for DeepSeek Harness user data sessions,
11
- settings, credentials, skills, and plugin config under `~/.dsh`, excluding
12
- reinstallable `node_modules` — with sha256 checksums, integrity verification,
13
- automatic rotation, and scheduled auto-backup that survives restarts.
14
- **Credentials are redacted by default**: plaintext never enters an archive or
15
- the GitHub sync, only a local vault, and is restored automatically. Cross-machine
16
- restores get preflight hints and a one-command `github pull`. Works on macOS,
17
- Linux, and Windows.
10
+ **dsh-backup is a DeepSeek Harness (DSH) plugin that backs up and restores `~/.dsh` with a single command.**
11
+
12
+ Everything you have in DSH sessions, settings, skills, and plugin config — lives in one folder: `~/.dsh`. Delete it by accident, break a config, or move to a new machine: with a backup, you get it all back.
13
+
14
+ What you get:
15
+
16
+ - **One command to back up, one to restore** every archive ships with a checksum so you can tell if it's corrupted, and old backups rotate out automatically.
17
+ - **Scheduled backups** — set an interval and forget it. It keeps the schedule across restarts.
18
+ - **Credentials never enter an archive** — plaintext stays in a local `vault/` folder and is restored automatically (details below).
19
+ - **New machine, no panic** — backups sync to your private GitHub repo; pull them down on the new machine and restore.
20
+ - **A web panel** — prefer clicking? There's a visual UI for everything.
21
+
22
+ Works on macOS, Linux, and Windows.
23
+
24
+ ## Install
25
+
26
+ ```sh
27
+ dsh plugin --profile web add @xiaoyuyu6420/dsh-backup
28
+ # or from GitHub:
29
+ dsh plugin --profile web add github:xiaoyuyu6420/dsh-backup
30
+ ```
31
+
32
+ Then restart `dsh web`.
33
+
34
+ > ⚠️ **Don't install the wrong package**: the correct name is `@xiaoyuyu6420/dsh-backup`, with the scope. The unscoped `dsh-backup` on npm is an unrelated third-party package.
35
+
36
+ ## Quickstart
37
+
38
+ About 30 seconds:
39
+
40
+ 1. Install (above) and restart `dsh web`
41
+ 2. Run `/backup`
42
+ 3. Done — the archive lands in `~/Desktop/dsh-backups/`, named with a timestamp
43
+
44
+ That one command covers day-to-day use. Want it to run on a schedule? See below.
18
45
 
19
46
  ## Scenario cheat sheet
20
47
 
21
- | Scenario | What to run |
48
+ | Situation | What to do |
22
49
  |---|---|
23
- | Everyday backup | `/backup` (or Settings Plugins Backup → Back up now) |
24
- | Don't trust yourself to remember | `/backup auto 12` — scheduled, survives restarts |
25
- | Broke a config / bad plugin install | `/backup restore latest --dry-run`, then drop the flag |
26
- | `~/.dsh` is gone entirely | `/backup restore latest` — no existing data means no snapshot, straight to restore |
27
- | New machine | Install the plugin, set the same `githubRepo` → `/backup github pull` → `/backup restore latest --sync-deps` |
50
+ | Routine backup | `/backup` (or "Back up now" in the panel) |
51
+ | Afraid you'll forget | `/backup auto 12` — every 12 hours, keeps going across restarts |
52
+ | Broke a config or a plugin install | `/backup restore latest --dry-run` to preview, then drop the flag to do it |
53
+ | `~/.dsh` is gone entirely | `/backup restore latest` |
54
+ | New machine | See "New machine" below |
28
55
  | Suspect a corrupt archive | `/backup verify all` |
29
- | Cloud copy | `/backup github repo name/dsh-backups` (private repo); every backup pushes afterwards |
56
+ | Keep a copy in the cloud | `/backup github repo name/dsh-backups` every backup pushes from then on (use a private repo) |
30
57
 
31
58
  ## Commands
32
59
 
33
- - **`/backup`** immediately back up `~/.dsh` to `~/Desktop/dsh-backups/dsh-<timestamp>.tar.gz`
34
- - **`/backup list`** — list existing backups (name + size) and auto-backup status
35
- - **`/backup verify [prefix|all]`** validate archive checksums (default: the newest)
36
- - **`/backup restore <prefix|latest> [--dry-run] [--sync-deps]`** restore `~/.dsh` from an archive (`--sync-deps` reinstalls per-profile plugin dependencies afterwards)
37
- - **`/backup auto <N>|off|status`** auto-backup every N hours (1–720; retains 3 copies below 24h, 7 otherwise, unless `config.keep` overrides; persisted across restarts)
38
- - **`/backup --keep N`** override the rotation count (default 7)
39
- - **`/backup github status|sync|pull [--restore <prefix|latest>]|repo <address|off>`** — sync status / push now / pull backups from the repo / set the sync repository
40
- - **`/backup delete|rm <prefix|latest>`** delete a backup and its sidecars
41
- - **`backup_dsh` tool** same capability for the model (`mode=backup|list|verify|restore|auto`; restore accepts `syncDeps`)
42
-
43
- ## Credential redaction & the local vault
44
-
45
- Credential files (by default `.credentials.yaml`, `.env`, `qq-bridge/config.json`;
46
- extend or disable via `config.redact`) **never enter an archive**:
47
-
48
- - On backup, plaintext copies are mirrored into `vault/` under the backup
49
- directory (POSIX mode 700/600); archives and the GitHub sync carry only
50
- redacted data.
51
- - Restoring on the same machine copies the credentials back from the vault —
52
- full fidelity.
53
- - Restoring on a new machine (no vault) lists the missing credential files and
54
- tells you to re-enter them.
55
- - Each archive ships with `.redacted.json` (the redaction list) and
56
- `.meta.json` (host / home / timestamp) sidecars; restore preflight uses them
57
- to flag cross-machine path risks and credentials to re-enter.
58
- - `config.redact: false` restores the v0.6.x plaintext behavior (not recommended).
59
-
60
- ## GitHub sync
61
-
62
- With `config.githubRepo` set, every backup (manual, automatic, or panel) is
63
- also pushed to a Git repository — archives, checksum sidecars, and rotation
64
- deletions stay in sync:
60
+ | Command | What it does |
61
+ |---|---|
62
+ | `/backup` | Back up now |
63
+ | `/backup list` | List backups (name, size) and the auto-backup status |
64
+ | `/backup verify [prefix\|all]` | Check that archives are intact (default: newest only) |
65
+ | `/backup restore <prefix\|latest>` | Restore; `--dry-run` previews, `--sync-deps` reinstalls plugin dependencies afterwards |
66
+ | `/backup auto <hours>\|off\|status` | Start / stop / check scheduled backups |
67
+ | `/backup --keep N` | Override how many copies to keep (default 7) |
68
+ | `/backup github …` | Cloud sync see "GitHub sync" |
69
+ | `/backup delete <prefix\|latest>` | Delete a backup and its sidecar files |
70
+
71
+ The model can call the same operations directly via the `backup_dsh` tool (`mode=backup|list|verify|restore|auto`; restore accepts `syncDeps`).
72
+
73
+ ## Scheduled backups
65
74
 
66
- ```yaml
67
- - id: dsh-backup
68
- name: 'dsh-backup'
69
- config:
70
- githubRepo: 'your-name/dsh-backups' # owner/repo, full URL, or a local path
75
+ ```
76
+ /backup auto 12
71
77
  ```
72
78
 
73
- Use a **private** repository archives are redacted but still contain session
74
- content. For an `https` remote, set the token in the environment
75
- (`DSH_BACKUP_GITHUB_TOKEN` or `GITHUB_TOKEN`); it is only written into the sync
76
- worktree's credential file (never process args). Push is `HEAD:main
77
- --force-with-lease`; archives over 90 MB are skipped with a notice. State (last
78
- push, last error) lives in `<destination>/auto.json` and shows in the panel and
79
- `/backup github status`.
80
-
81
- **Restoring on a new machine**: install the plugin, configure the same
82
- `githubRepo`, then run `/backup github pull` — it fetches every remote backup
83
- (each one sha256-verified; corrupt archives are skipped and reported), then
84
- `/backup restore latest --sync-deps` restores and reinstalls plugin
85
- dependencies. The restore report reads `.meta.json` to flag the cross-machine
86
- restore (absolute-path risks) and lists the credentials to re-enter.
87
- `--restore <prefix|latest>` restores a specific archive right after pulling.
88
-
89
- ## Settings panel (Web)
90
-
91
- The same controls have a visual entry: a **Backup** tab inside Settings → Plugins
92
- (`dsh web`). It shows the destination, auto-backup state, GitHub sync status, and
93
- every archive with its size, and offers one-click back-up-now, per-archive
94
- verify, download, restore with a dry-run preview plus explicit confirmation,
95
- and **pull from GitHub** (the first step of a new-machine restore).
96
- Downloads stream from the loopback-only route `GET /backup-download/<name>`.
97
- The tab talks to the host through the `backupPanel` Typert Remote namespace
98
- (`/api` RPC); the browser bundle ships prebuilt in `lib/client.js` — no build
99
- step at install time.
79
+ From then on, a backup runs every 12 hours (any interval from 1 to 720).
100
80
 
101
- ## How restore works
81
+ - `/backup auto off` — stop
82
+ - `/backup auto status` — check
102
83
 
103
- Restore is safe by construction:
84
+ State lives in `auto.json` inside the backup folder. After a restart, the schedule resumes from the last run instead of restarting the clock. Retention: intervals under 24 hours keep 3 copies by default, longer ones keep 7 (override with `config.keep`).
104
85
 
105
- 1. The archive's sha256 is verified first — a corrupt archive never touches existing data.
106
- 2. Entries are listed and any path outside the backup root rejects the restore (tar path-traversal guard).
107
- 3. Preflight: `.meta.json` flags a backup from another machine/home (absolute-path risks); redacted archives note that credentials come back from the local vault (or must be re-entered cross-machine).
108
- 4. The current `~/.dsh` is snapshotted, then moved aside to `~/.dsh.pre-restore-<timestamp>` — restore replaces rather than merges. A missing `~/.dsh` (data gone / first restore on a new machine) skips the snapshot and extracts directly.
109
- 5. The archive is extracted; redacted archives then restore credentials from the vault; `--sync-deps` runs `pnpm install` per profile (node_modules never travel inside archives).
110
- 6. Restart `dsh` afterwards so restored sessions and settings take effect.
86
+ ## New machine
111
87
 
112
- `--dry-run` shows the archive summary and preflight hints without writing anything.
88
+ Prerequisite: the old machine had GitHub sync configured (next section).
113
89
 
114
- ## Configuration (optional)
90
+ 1. Install the plugin on the new machine and set the same `githubRepo`
91
+ 2. `/backup github pull` — fetches every remote backup (each one checksum-verified; corrupt copies are skipped and reported)
92
+ 3. `/backup restore latest --sync-deps` — restore, then reinstall plugin dependencies per profile
93
+ 4. Restart `dsh`
115
94
 
116
- Plugin `config` in the active cordis profile:
95
+ The restore report tells you two things: the backup came from another machine (watch for absolute paths in configs), and which credential files you need to re-enter (they're not in the archive see next section). To save a step, `/backup github pull --restore latest` restores right after pulling.
96
+
97
+ ## Credentials (passwords, tokens)
98
+
99
+ Files like `.credentials.yaml`, `.env`, and `qq-bridge/config.json` never enter an archive, by default:
100
+
101
+ - On backup: plaintext copies go into a `vault/` folder under the backup directory, locked to your user (mode 700/600). The archive and the GitHub sync carry only redacted copies.
102
+ - Restoring on the same machine: credentials are copied back from the vault automatically.
103
+ - Restoring on a new machine: there's no vault, so the report lists the missing files — re-enter them once.
104
+ - To change the list, edit `config.redact`; `redact: false` turns the whole mechanism off (not recommended — that's the pre-v0.7 plaintext behavior).
105
+
106
+ Each archive also carries two small metadata files: `.meta.json` (which machine, which home directory, when) and `.redacted.json` (what was redacted). Restore preflight reads them and warns about cross-machine restores.
107
+
108
+ Archives and checksum files are chmod 600 on macOS/Linux; Windows relies on per-user profile ACLs.
109
+
110
+ ## GitHub sync (optional)
111
+
112
+ Set `githubRepo` in the plugin config, and every backup (manual, scheduled, or from the panel) is pushed to that Git repository. Deletions sync too:
117
113
 
118
114
  ```yaml
119
115
  - id: dsh-backup
120
116
  name: 'dsh-backup'
121
117
  config:
122
- destination: '~/Backups/dsh' # default ~/Desktop/dsh-backups
123
- keep: 10 # manual rotation count (default 7); when set, also the auto-backup retention — auto keeps 3 copies below 24h, 7 otherwise by default
124
- exclude: # extra tar --exclude patterns
125
- - '*cache*'
126
- redact: # extra redacted files (relative to ~/.dsh); false/'off' disables redaction
127
- - 'some-plugin/token.json'
128
- githubRepo: 'name/dsh-backups' # optional GitHub sync (see below)
118
+ githubRepo: 'your-name/dsh-backups' # owner/repo, a full URL, or a local path
129
119
  ```
130
120
 
131
- Auto-backup state lives in `<destination>/auto.json` and resumes after restart — the next run is scheduled from the last auto-backup time, never reset by the restart.
121
+ Things to know:
132
122
 
133
- ## Security note
123
+ - **Use a private repository.** Archives carry no plaintext credentials, but they do contain your session content.
124
+ - For https remotes, provide a token via `DSH_BACKUP_GITHUB_TOKEN` or `GITHUB_TOKEN`. It's written only to the sync worktree's credential file, never into process args.
125
+ - The push is `HEAD:main --force-with-lease` — the remote's main is aligned with your local backup folder, so don't put anything else in that repo.
126
+ - Archives over 90 MB are skipped from sync, with a notice.
127
+ - Sync state (last push, last error) shows in `/backup github status` and the panel; `/backup github sync` pushes immediately instead of waiting for the next backup.
134
128
 
135
- Credential files are redacted by default (see above): archives and the GitHub
136
- sync carry no plaintext credentials — plaintext lives only in the local
137
- `vault/` under the backup directory (POSIX 700/600). Archives may still contain
138
- sensitive session content, so keep the sync repository private. Archives and
139
- checksum sidecars are chmod 600 on POSIX (Windows relies on per-user profile
140
- ACLs).
129
+ ## Web panel
141
130
 
142
- Storage note: the plugin writes its own data (archives, checksum sidecars,
143
- `auto.json`, `vault/`) directly through `node:fs`, the same pattern as DSH's
144
- own session persistence — the `ctx.fs` capability is the model-facing sandboxed
145
- surface and does not apply to host-owned storage.
131
+ Open **Settings Plugins Backup** in `dsh web`: see every archive with its size, the auto-backup and sync status, and run back-up-now, per-archive verify, **download**, restore (dry-run preview plus confirmation), and **pull from GitHub** (the first step of a new-machine restore). Downloads go through a loopback-only route, never exposed externally.
146
132
 
147
- ## Install
133
+ ## How restore works
148
134
 
149
- ```sh
150
- dsh plugin --profile web add @xiaoyuyu6420/dsh-backup
151
- # or from git:
152
- dsh plugin --profile web add github:xiaoyuyu6420/dsh-backup
153
- ```
135
+ Restore touches your live data, so every step is guarded:
154
136
 
155
- > ⚠️ The npm package name is the **scoped** `@xiaoyuyu6420/dsh-backup`. The
156
- > unscoped `dsh-backup` on npm is an unrelated third-party package don't
157
- > install it.
137
+ 1. **Verify first**: a corrupt archive aborts the restore before anything is touched.
138
+ 2. **Path check**: any entry escaping the backup root (tar path traversal) rejects the restore.
139
+ 3. **Preflight**: a backup from another machine/home triggers an absolute-path warning; redacted archives explain that credentials come back from the local vault (or must be re-entered, cross-machine).
140
+ 4. **Keep an escape hatch**: the current `~/.dsh` is snapshotted, then moved aside to `~/.dsh.pre-restore-<timestamp>`. Restore replaces rather than merges, so stale files can't linger. If `~/.dsh` no longer exists (data lost, or first restore on a new machine), extraction proceeds directly.
141
+ 5. **Extract**: the archive is unpacked; credentials return from the vault; `--sync-deps` runs `pnpm install` per profile (node_modules never travel inside archives).
142
+ 6. **Restart `dsh`** and the restored sessions and settings take effect.
158
143
 
159
- ## Quickstart
144
+ `--dry-run` shows the summary and preflight hints without writing anything. When in doubt, dry-run first.
160
145
 
161
- Your first backup is about 30 seconds away:
146
+ ## Configuration (optional)
162
147
 
163
- 1. Install the plugin `dsh plugin --profile web add @xiaoyuyu6420/dsh-backup`
164
- 2. Restart `dsh web` — plugin discovery is cached per process.
165
- 3. Run `/backup` — the archive and its sha256 sidecar land in `~/Desktop/dsh-backups/`.
148
+ Defaults work out of the box. To adjust, add `config` to the plugin in your active cordis profile:
166
149
 
167
- Prefer clicking? The same flow lives in Settings → Plugins → Backup.
150
+ ```yaml
151
+ - id: dsh-backup
152
+ name: 'dsh-backup'
153
+ config:
154
+ destination: '~/Backups/dsh' # where backups go (default ~/Desktop/dsh-backups)
155
+ keep: 10 # copies to keep for manual backups (default 7); also applies to scheduled ones when set
156
+ exclude: # extra tar --exclude patterns
157
+ - '*cache*'
158
+ redact: # extra credential files (relative to ~/.dsh); false/'off' disables redaction
159
+ - 'some-plugin/token.json'
160
+ githubRepo: 'name/dsh-backups' # GitHub sync (optional)
161
+ ```
168
162
 
169
163
  ## Requirements
170
164
 
171
- - macOS, Linux, or Windows 10+ with `tar` in PATH (Windows ships bsdtar in
172
- System32; Git Bash's GNU tar also works checksums prefer `sha256sum`/`shasum`
173
- and fall back to an in-process hash on Windows)
165
+ - macOS, Linux, or Windows 10+, with `tar` in PATH (Windows ships it)
166
+ - Checksums prefer `sha256sum`/`shasum` and fall back to a built-in hash when absent (that's the norm on Windows)
174
167
  - DSH `0.1.0-rc.6` or compatible
175
168
 
176
169
  ## Troubleshooting
177
170
 
178
- - **Plugin fails to load with `client api: method "backupPanel/remove" conflicts with its namespace service`** you are on v0.5.0, whose delete-endpoint method name collided with a reserved name in the DSH client (issues [#2](https://github.com/xiaoyuyu6420/dsh-backup/issues/2), [#5](https://github.com/xiaoyuyu6420/dsh-backup/issues/5)). v0.5.1 renamed the method to `removeEntry`; upgrade with `dsh plugin --profile web add @xiaoyuyu6420/dsh-backup@latest` and restart `dsh web`.
179
- - **Which `tar` on Windows?** Either one works Windows ships bsdtar in System32, and Git Bash provides GNU tar. Checksums prefer `sha256sum`/`shasum` when present and fall back to an in-process hash, so `/backup verify` works in both shells.
180
- - **Installed the wrong package** — the npm package is the **scoped** `@xiaoyuyu6420/dsh-backup`; the unscoped `dsh-backup` is an unrelated third-party package. Check your profile's plugin list and reinstall with the scoped name.
171
+ - **Installed the wrong package** — the correct one is `@xiaoyuyu6420/dsh-backup` (scoped). The unscoped `dsh-backup` on npm is an unrelated third-party package. Check your profile's plugin list and reinstall with the scoped name.
172
+ - **Plugin fails to load with `client api: method "backupPanel/remove" conflicts with its namespace service`** you're on v0.5.0 (see [#2](https://github.com/xiaoyuyu6420/dsh-backup/issues/2), [#5](https://github.com/xiaoyuyu6420/dsh-backup/issues/5)). Fixed in v0.5.1: run `dsh plugin --profile web add @xiaoyuyu6420/dsh-backup@latest` to upgrade, then restart `dsh web`.
173
+ - **Which `tar` on Windows?** Either. System32 ships bsdtar and Git Bash provides GNU tar; verification works in both shells.
181
174
 
182
175
  ## Development
183
176
 
184
- Zero runtime dependencies — the host plugin is `lib/index.js`. The browser half
185
- lives in `src/` and is bundled (zod inlined, React/Cordis external) into
186
- `lib/client.js`, which is committed so git installs never build:
177
+ Zero runtime dependencies — the host plugin is `lib/index.js`. The browser half lives in `src/` and its bundle (`lib/client.js`, zod inlined, React/Cordis external) is committed, so git installs never build. The panel talks to the host through the `backupPanel` namespace (`/api` RPC); downloads use the loopback-only route `GET /backup-download/<name>`.
178
+
179
+ Storage note: the plugin writes its own data (archives, checksum sidecars, `auto.json`, `vault/`) directly through `node:fs`, the same pattern as DSH's own session persistence — `ctx.fs` is the model-facing sandboxed surface and doesn't apply to host-owned storage.
187
180
 
188
181
  ```sh
189
182
  node scripts/build-client.mjs # rebuild the client bundle after editing src/
190
183
  node scripts/smoke.mjs # host smoke suite (real temp dir, mocked DSH services)
191
- node scripts/smoke-client.mjs # client bundle: handshake, schemas, tab registration, SSR
184
+ node scripts/smoke-client.mjs # client bundle smoke: handshake, schemas, tab registration, SSR
192
185
  ```
193
186
 
194
187
  ## Acknowledgements
195
188
 
196
- - [@beastrobin](https://github.com/beastrobin) — the reserved-method-name root
197
- cause analysis in #1 that directly led to the v0.5.1 fix
198
- - [@mlosun](https://github.com/mlosun) — the thorough reproduction and root
199
- cause report in #2
200
- - [@Choi-Peng](https://github.com/Choi-Peng) — triage help pointing affected
201
- users to the fix in #5
189
+ - [@beastrobin](https://github.com/beastrobin) — the reserved-method-name root cause analysis in #1 that directly led to the v0.5.1 fix
190
+ - [@mlosun](https://github.com/mlosun) the thorough reproduction and root cause report in #2
191
+ - [@Choi-Peng](https://github.com/Choi-Peng) — triage help pointing affected users to the fix in #5
202
192
 
203
193
  ## License
204
194
 
package/README.zh.md CHANGED
@@ -7,173 +7,181 @@
7
7
 
8
8
  [English](README.md) | 简体中文
9
9
 
10
- 一键备份**与恢复** DeepSeek Harness 用户数据——`~/.dsh` 下的会话、设置、
11
- 技能与插件配置(排除可重装的 node_modules),自动生成 sha256 校验和、完整性
12
- 校验、自动轮换,定时自动备份状态落盘、重启续跑。**凭据默认脱敏**:明文绝不
13
- 进归档、不进 GitHub 同步,只存本机 vault,恢复时自动还原。跨机恢复有预检
14
- 提示与 `github pull` 一键拉取。支持 macOS / Linux / Windows。
10
+ **dsh-backup DeepSeek Harness(DSH)的备份插件:一条命令备份 `~/.dsh`,一条命令恢复。**
11
+
12
+ 你在 DSH 里的会话记录、设置、技能、插件配置,全都在 `~/.dsh` 这一个目录里。误删了、改坏了、换电脑了——只要有过备份,就能找回来。
13
+
14
+ 它能做到:
15
+
16
+ - **一键备份、一键恢复** —— 每份备份自动附带校验文件,随时能检查备份有没有损坏;旧备份自动清理,不会越积越多。
17
+ - **定时自动备份** —— 设好间隔就不用管了,重启 DSH 后照常继续。
18
+ - **密码等敏感文件不进备份包** —— 明文只留在本机的 `vault/` 目录里,恢复时自动放回原处(详见下文)。
19
+ - **换电脑不慌** —— 备份可以自动同步到你的 GitHub 私有仓库,新电脑拉回来就能恢复。
20
+ - **有图形界面** —— 不想敲命令,网页设置里有可视化面板。
21
+
22
+ 支持 macOS、Linux、Windows。
23
+
24
+ ## 安装
25
+
26
+ ```sh
27
+ dsh plugin --profile web add @xiaoyuyu6420/dsh-backup
28
+ # 或者从 GitHub 安装:
29
+ dsh plugin --profile web add github:xiaoyuyu6420/dsh-backup
30
+ ```
31
+
32
+ 装完重启 `dsh web`。
33
+
34
+ > ⚠️ **别装错包**:正确的包名是 `@xiaoyuyu6420/dsh-backup`,带前缀。npm 上另有一个不带前缀的 `dsh-backup`,那是无关的第三方项目,请勿安装。
35
+
36
+ ## 快速上手
37
+
38
+ 大约 30 秒:
39
+
40
+ 1. 按上面装好插件,重启 `dsh web`
41
+ 2. 输入 `/backup`
42
+ 3. 搞定 —— 备份文件出现在 `~/Desktop/dsh-backups/`,文件名带时间戳
43
+
44
+ 之后日常最常用的就是这一条命令。想定时自动备份?看下文。
15
45
 
16
46
  ## 场景速查
17
47
 
18
- | 场景 | 怎么做 |
48
+ | 遇到什么情况 | 怎么办 |
19
49
  |---|---|
20
- | 日常备份 | `/backup`(或 Settings → Plugins → 备份 → 立即备份) |
21
- | 担心忘备份 | `/backup auto 12` —— 定时备份,重启续跑 |
22
- | 改坏了配置/装坏了插件 | `/backup restore latest --dry-run` 预览确认后去掉 `--dry-run` |
23
- | `~/.dsh` 整个没了 | `/backup restore latest` —— 无现有数据时跳过快照直接恢复 |
24
- | 换新电脑 | 新机装好插件并配置同一 `githubRepo` → `/backup github pull` 拉回备份 → `/backup restore latest --sync-deps` |
25
- | 怀疑备份损坏 | `/backup verify all` |
26
- | 归档同步到云端 | `/backup github repo 账号/dsh-backups`(私有仓库),此后每次备份自动推送 |
27
-
28
- ## 命令
29
-
30
- - **`/backup`** —— 立即备份 `~/.dsh` 到 `~/Desktop/dsh-backups/dsh-<时间戳>.tar.gz`
31
- - **`/backup list`** —— 列出已有备份(名称 + 大小)与自动备份状态
32
- - **`/backup verify [前缀|all]`** —— 校验归档完整性(缺省校验最新一份)
33
- - **`/backup restore <前缀|latest> [--dry-run] [--sync-deps]`** —— 从归档恢复 `~/.dsh`(`--sync-deps` 恢复后对各 profile 重装插件依赖)
34
- - **`/backup auto <N小时>|off|status`** —— 每 N 小时自动备份(1~720;保留份数默认 <24h 3 份、否则 7 份,config.keep 可覆盖;状态持久化,重启续跑)
35
- - **`/backup --keep N`** —— 覆盖轮换保留份数(默认 7)
36
- - **`/backup github status|sync|pull [--restore <前缀|latest>]|repo <地址|off>`** —— 同步状态 / 立即推送 / 从仓库拉取备份到本地 / 设置同步仓库
37
- - **`/backup delete|rm <前缀|latest>`** —— 删除指定备份(归档 + 全部边车)
38
- - **`backup_dsh` 工具** —— 模型可调用同一能力(`mode=backup|list|verify|restore|auto`,restore 支持 `syncDeps`)
39
-
40
- ## 凭据脱敏与本机 vault
41
-
42
- 凭据文件(默认 `.credentials.yaml`、`.env`、`qq-bridge/config.json`,
43
- `config.redact` 可增删)**不进归档**:
44
-
45
- - 备份时,敏感文件的明文副本镜像到备份目录下的 `vault/`(POSIX 上目录 700、
46
- 文件 600),归档与 GitHub 同步只含脱敏后的数据。
47
- - 本机恢复时,凭据自动从 vault 拷回 `~/.dsh`,完整还原。
48
- - 跨机恢复(新机没有 vault)时,恢复报告会列出缺失的凭据文件清单,提示重填。
49
- - 归档附带的 `.redacted.json`(脱敏清单)与 `.meta.json`(主机/家目录/时间)
50
- 边车随归档走,恢复预检据此提示跨机路径风险与需重填的凭据。
51
- - `config.redact: false` 可回到 v0.6.x 的明文行为(不推荐)。
52
-
53
- ## GitHub 同步
54
-
55
- 配置 `config.githubRepo` 后,每次备份(手动 / 定时 / 面板)都会把归档、校验
56
- 边车与轮换删除一并推送到 Git 仓库:
50
+ | 日常备份一次 | `/backup`(或在面板里点「立即备份」) |
51
+ | 怕自己忘备份 | `/backup auto 12`(每 12 小时一次,重启不中断) |
52
+ | 配置改坏了、插件装坏了 | `/backup restore latest --dry-run` 先预览,确认后去掉 `--dry-run` 真正恢复 |
53
+ | `~/.dsh` 整个没了 | `/backup restore latest` |
54
+ | 换新电脑 | 见「换新电脑」一节 |
55
+ | 怀疑备份文件坏了 | `/backup verify all` |
56
+ | 想把备份放云端 | `/backup github repo 账号/dsh-backups`,之后每次备份自动推送(务必用私有仓库) |
57
+
58
+ ## 命令一览
59
+
60
+ | 命令 | 作用 |
61
+ |---|---|
62
+ | `/backup` | 立即备份 |
63
+ | `/backup list` | 列出所有备份(名称、大小)和自动备份状态 |
64
+ | `/backup verify [前缀\|all]` | 校验备份是否完好,默认只查最新一份 |
65
+ | `/backup restore <前缀\|latest>` | 恢复,支持 `--dry-run`(只预览不动手)和 `--sync-deps`(恢复后重装插件依赖) |
66
+ | `/backup auto <小时数>\|off\|status` | 定时备份的开启、关闭、状态 |
67
+ | `/backup --keep N` | 覆盖保留份数(默认 7) |
68
+ | `/backup github …` | 云同步相关,见「GitHub 同步」 |
69
+ | `/backup delete <前缀\|latest>` | 删除某份备份及其附属文件 |
70
+
71
+ 以上能力模型也能直接调用(工具 `backup_dsh`,`mode=backup|list|verify|restore|auto`,restore 支持 `syncDeps`)。
72
+
73
+ ## 定时自动备份
57
74
 
58
- ```yaml
59
- - id: dsh-backup
60
- name: 'dsh-backup'
61
- config:
62
- githubRepo: '你的账号/dsh-backups' # owner/repo、完整 URL 或本地路径
75
+ ```
76
+ /backup auto 12
63
77
  ```
64
78
 
65
- **请使用私有仓库**——归档虽已脱敏,但仍含会话内容等敏感数据。https 远端需要
66
- 环境变量 token(`DSH_BACKUP_GITHUB_TOKEN` 或 `GITHUB_TOKEN`),token 只写入
67
- 同步工作树的 credential 文件(不进进程参数)。推送为 `HEAD:main
68
- --force-with-lease`;超过 90MB 的归档会跳过并提示。同步状态(上次推送 / 错误)
69
- 存于 `<destination>/auto.json`,面板与 `/backup github status` 可见。
79
+ 从现在起每 12 小时自动备份一次(间隔可设 1~720 小时)。
70
80
 
71
- **换新机器恢复**:新机装好插件、配好同一 `githubRepo` 后执行
72
- `/backup github pull` —— 拉回远端全部备份(逐份 sha256 校验,损坏即跳过并
73
- 报告),再 `/backup restore latest --sync-deps` 恢复并重装插件依赖;恢复报告
74
- 会按 `.meta.json` 提示这是跨机恢复(绝对路径风险)并列出需重填的凭据清单。
75
- 加 `--restore <前缀|latest>` 可在拉取后直接恢复指定备份。
81
+ - `/backup auto off` —— 关闭
82
+ - `/backup auto status` —— 查看状态
76
83
 
77
- ## Settings 可视面板(Web)
84
+ 状态记录在备份目录的 `auto.json` 里。重启 DSH 后会接着上次的节奏排期,不会重新计时。保留份数:间隔不足 24 小时的默认留 3 份,更长的留 7 份(可用配置 `keep` 覆盖)。
78
85
 
79
- 同样的能力在 `dsh web` 的 **Settings → Plugins → 备份** 标签页有可视化入口:
80
- 显示备份目录、自动备份状态、GitHub 同步状态和每份归档的大小,支持一键立即
81
- 备份、逐份校验、**下载**、带 dry-run 预览与二次确认的恢复,以及**从 GitHub
82
- 拉取**备份(新机恢复第一步)。下载走仅限本机的
83
- `GET /backup-download/<归档名>` 路由。面板经 `backupPanel` Typert Remote
84
- 命名空间(`/api` RPC)与宿主通信;浏览器 bundle 预构建在 `lib/client.js`,
85
- 安装时无需构建。
86
+ ## 换新电脑
86
87
 
87
- ## 恢复的工作方式
88
+ 前提:旧电脑已经配置了 GitHub 同步(见下一节)。
88
89
 
89
- 恢复安全性是设计出来的:
90
+ 1. 新电脑装好插件,配置里填同一个 `githubRepo`
91
+ 2. `/backup github pull` —— 把云端备份全部拉回本地(每份都做校验,损坏的自动跳过并报告)
92
+ 3. `/backup restore latest --sync-deps` —— 恢复数据,并重装各 profile 的插件依赖
93
+ 4. 重启 `dsh`
90
94
 
91
- 1. 先校验归档 sha256——损坏的归档绝不触碰现有数据。
92
- 2. 列出归档条目,任何超出备份根目录的路径都会拒绝恢复(tar 路径穿越防护)。
93
- 3. 预检:`.meta.json` 显示备份来自另一台机器/用户目录时提示绝对路径风险;
94
- 脱敏归档提示凭据将从本机 vault 还原(跨机则提示重填)。
95
- 4. 当前 `~/.dsh` 先自动快照,再移动到 `~/.dsh.pre-restore-<时间戳>`——恢复是
96
- 替换而不是合并;`~/.dsh` 已不存在(数据全失/新机首恢复)时跳过快照直接解压。
97
- 5. 解压归档;脱敏归档随后从 vault 还原凭据文件;`--sync-deps` 对各 profile
98
- 执行 `pnpm install` 重装插件依赖(node_modules 不随归档走)。
99
- 6. 重启 `dsh`,恢复的会话与配置即生效。
95
+ 恢复报告会提示两件事:这份备份来自另一台电脑(留意配置里的绝对路径),以及哪些敏感文件需要重新填(它们不在备份包里,见下节)。想省一步,可以用 `/backup github pull --restore latest` 拉取后直接恢复。
100
96
 
101
- `--dry-run` 只显示归档概要与预检提示,不写入任何内容。
97
+ ## 敏感文件的处理(密码、token)
102
98
 
103
- ## 配置(可选)
99
+ `.credentials.yaml`、`.env`、`qq-bridge/config.json` 这类存凭据的文件,默认**不打进备份包**:
100
+
101
+ - 备份时:明文复制到备份目录下的 `vault/` 文件夹,权限收紧到只有你能读(目录 700、文件 600)。备份包和云端同步的都是脱敏后的版本。
102
+ - 同一台电脑恢复:凭据自动从 `vault/` 放回原位,不用你动手。
103
+ - 新电脑恢复:本机没有 `vault/`,恢复报告会列出缺了哪些文件,重新填一遍即可。
104
+ - 想增减敏感文件:改配置里的 `redact` 列表;`redact: false` 可整个关闭这个机制(不推荐,等于回到 v0.7 之前的明文行为)。
105
+
106
+ 每个备份还附带两个信息文件:`.meta.json`(备份来自哪台机器、哪个用户目录、什么时间)和 `.redacted.json`(哪些文件被脱敏了)。恢复前的预检会读取它们,跨机器恢复时提前给出提醒。
107
+
108
+ 备份文件和校验文件在 macOS / Linux 上权限都是 600(只有你能读);Windows 靠用户目录的访问控制。
104
109
 
105
- 在生效的 cordis profile 中为插件声明 `config`:
110
+ ## GitHub 同步(可选)
111
+
112
+ 在插件配置里填上 `githubRepo`,之后每次备份(手动、定时、面板点的)都会自动推送到这个 Git 仓库,删除旧备份也会一并同步:
106
113
 
107
114
  ```yaml
108
115
  - id: dsh-backup
109
116
  name: 'dsh-backup'
110
117
  config:
111
- destination: '~/Backups/dsh' # 默认 ~/Desktop/dsh-backups
112
- keep: 10 # 手动备份轮换份数(默认 7);配置后同时作为自动备份保留份数(未配置时 auto 默认 <24h 3 份 / 否则 7 份)
113
- exclude: # 额外的 tar --exclude 模式
114
- - '*cache*'
115
- redact: # 追加脱敏文件(相对 ~/.dsh);false/'off' 关闭脱敏
116
- - 'some-plugin/token.json'
117
- githubRepo: '账号/dsh-backups' # 可选 GitHub 同步(见下文)
118
+ githubRepo: '你的账号/dsh-backups' # 支持 owner/repo、完整 URL 或本地路径
118
119
  ```
119
120
 
120
- 自动备份状态保存在 `<destination>/auto.json`,重启后按上次自动执行时间推算下次触发(不重置节奏)。
121
+ 几个要点:
121
122
 
122
- ## 安全说明
123
+ - **务必用私有仓库** —— 备份虽然不含密码明文,但有你的会话内容。
124
+ - 走 https 需要 token:环境变量 `DSH_BACKUP_GITHUB_TOKEN` 或 `GITHUB_TOKEN`。token 只写进同步工作树的凭据文件,不会出现在进程参数里。
125
+ - 推送方式是 `HEAD:main --force-with-lease`,也就是远端 main 会被对齐成本地备份目录的状态——别往这个仓库里手动放别的东西。
126
+ - 单个备份超过 90MB 会跳过推送并提示。
127
+ - 同步状态(上次推送、最近错误)在 `/backup github status` 和面板里都能看到;`/backup github sync` 可以不等下一次备份,立即推送一次。
123
128
 
124
- 凭据文件默认脱敏(见上文「凭据脱敏与本机 vault」):归档与 GitHub 同步不含
125
- 明文凭据,明文只存备份目录下的本机 `vault/`(POSIX 700/600)。归档仍可能含
126
- 会话中的敏感内容,请使用私有同步仓库。归档与校验文件在 POSIX 上为
127
- `chmod 600`(Windows 依赖用户目录 ACL)。
129
+ ## 可视化面板
128
130
 
129
- 存储说明:插件自有数据(归档、校验和、`auto.json`、`vault/`)直接经
130
- `node:fs` 写入,与 DSH 自身的会话持久化同一模式——`ctx.fs` 能力是模型面的
131
- 沙箱 surface,不适用于宿主插件的自有存储。
131
+ 打开 `dsh web` 的 **Settings → Plugins → 备份** 标签页:查看备份列表与大小、自动备份状态、GitHub 同步状态,支持一键备份、逐份校验、**下载**备份、恢复(先预览再二次确认),以及**从 GitHub 拉取**备份(新电脑恢复的第一步)。下载只走本机回环地址的接口,不对外暴露。
132
132
 
133
- ## 安装
133
+ ## 恢复是怎么工作的
134
134
 
135
- ```sh
136
- dsh plugin --profile web add @xiaoyuyu6420/dsh-backup
137
- # 或从 git 安装:
138
- dsh plugin --profile web add github:xiaoyuyu6420/dsh-backup
139
- ```
135
+ 恢复动的是你现有的数据,所以每一步都有保护:
140
136
 
141
- > ⚠️ npm 包名是 **scoped** 的 `@xiaoyuyu6420/dsh-backup`。npm 上不带 scope
142
- > `dsh-backup` 是无关的第三方包,请勿安装。
137
+ 1. **先校验**:备份文件损坏就直接中止,绝不碰现有数据。
138
+ 2. **路径检查**:备份包里出现越界路径(tar 路径穿越)就拒绝恢复。
139
+ 3. **预检提醒**:备份来自别的机器或用户目录时,提示绝对路径风险;脱敏备份则说明凭据会从本机 vault 还原(跨机恢复会列出要重填的)。
140
+ 4. **先留后路**:现有的 `~/.dsh` 先自动快照,再移到 `~/.dsh.pre-restore-<时间戳>`。恢复是整体替换,不是合并,不会被旧文件搅浑;如果 `~/.dsh` 已经不存在(数据已经丢了,或新机首次恢复),跳过快照直接解压。
141
+ 5. **解压还原**:解压备份;凭据从 vault 放回;`--sync-deps` 给各 profile 跑 `pnpm install`(node_modules 不进备份包,靠这步重装)。
142
+ 6. **重启生效**:重启 `dsh`,会话和配置就回来了。
143
143
 
144
- ## 快速上手
144
+ `--dry-run` 只显示概览和预检提示,不写入任何东西。拿不准就先 dry-run 一次。
145
145
 
146
- 30 秒拿到第一个备份:
146
+ ## 配置(可选)
147
147
 
148
- 1. 安装插件 —— `dsh plugin --profile web add @xiaoyuyu6420/dsh-backup`
149
- 2. 重启 `dsh web` —— 插件发现按进程缓存。
150
- 3. 跑 `/backup` —— 归档连同 sha256 校验文件落到 `~/Desktop/dsh-backups/`。
148
+ 默认开箱即用,以下都可不配。想调整时,在生效的 cordis profile 里给插件加 `config`:
151
149
 
152
- 更喜欢点鼠标?同一套流程在 Settings → Plugins → 备份 标签页。
150
+ ```yaml
151
+ - id: dsh-backup
152
+ name: 'dsh-backup'
153
+ config:
154
+ destination: '~/Backups/dsh' # 备份存放位置(默认 ~/Desktop/dsh-backups)
155
+ keep: 10 # 手动备份保留几份(默认 7);设了以后定时备份也按这个数
156
+ exclude: # 额外排除的内容(tar --exclude 语法)
157
+ - '*cache*'
158
+ redact: # 追加敏感文件(相对 ~/.dsh 的路径);false 或 'off' 关闭脱敏
159
+ - 'some-plugin/token.json'
160
+ githubRepo: '账号/dsh-backups' # GitHub 同步,见上文
161
+ ```
153
162
 
154
- ## 依赖
163
+ ## 系统要求
155
164
 
156
- - macOS、Linux 或 Windows 10+,PATH 中有 `tar`(Windows 自带 System32 的
157
- bsdtar,Git Bash GNU tar 也可以;校验和优先 `sha256sum`/`shasum`,
158
- Windows 上回退进程内哈希)
165
+ - macOS、Linux 或 Windows 10+,PATH 里有 `tar`(Windows 自带)
166
+ - 校验优先用 `sha256sum` / `shasum`,没有就自动改用内置哈希(Windows 上就是这样)
159
167
  - DSH `0.1.0-rc.6` 或兼容版本
160
168
 
161
169
  ## 故障排查
162
170
 
163
- - **插件加载失败,报 `client api: method "backupPanel/remove" conflicts with its namespace service`** —— 你装的是 v0.5.0:删除接口的方法名撞上了 DSH 客户端的保留方法名(见 [#2](https://github.com/xiaoyuyu6420/dsh-backup/issues/2)、[#5](https://github.com/xiaoyuyu6420/dsh-backup/issues/5))。v0.5.1 已将方法改名 `removeEntry` 修复;执行 `dsh plugin --profile web add @xiaoyuyu6420/dsh-backup@latest` 升级后重启 `dsh web` 即可。
164
- - **Windows 上用哪个 `tar`?** 都可以——Windows 自带 System32 里的 bsdtar,Git Bash 里则是 GNU tar。校验和优先用 `sha256sum`/`shasum`,缺失时自动回退进程内哈希,两种 shell `/backup verify` 都能正常工作。
165
- - **装错了包** —— npm 包名是 **scoped** `@xiaoyuyu6420/dsh-backup`;不带 scope `dsh-backup` 是无关的第三方包。检查 profile 的插件列表,改用 scoped 名重装。
171
+ - **装错了包** —— 正确的包名是 `@xiaoyuyu6420/dsh-backup`(带前缀)。不带前缀的 `dsh-backup` 是无关的第三方包。检查 profile 的插件列表,用正确名字重装。
172
+ - **插件加载失败,报 `client api: method "backupPanel/remove" conflicts with its namespace service`** —— 你装的是 v0.5.0 旧版(详见 [#2](https://github.com/xiaoyuyu6420/dsh-backup/issues/2)、[#5](https://github.com/xiaoyuyu6420/dsh-backup/issues/5))。v0.5.1 已修复:执行 `dsh plugin --profile web add @xiaoyuyu6420/dsh-backup@latest` 升级,重启 `dsh web` 即可。
173
+ - **Windows 上用哪个 `tar`?** 都行。系统自带 System32 里的 bsdtar,Git Bash 里是 GNU tar,校验功能在两种 shell 下都能正常工作。
166
174
 
167
175
  ## 开发
168
176
 
169
- 运行时零依赖——宿主插件就是 `lib/index.js`。浏览器半边源码在 `src/`,
170
- 打包(zod 内联、React/Cordis 保持 external)产物 `lib/client.js` 提交进仓库,
171
- git 安装无需构建:
177
+ 运行时零依赖,宿主插件就是 `lib/index.js`。浏览器端源码在 `src/`,打包产物 `lib/client.js` 直接提交进仓库(zod 内联,React / Cordis 保持 external),从 git 安装不需要构建。面板通过 `backupPanel` 命名空间(`/api` RPC)与宿主通信;下载走仅限本机的 `GET /backup-download/<归档名>` 路由。
178
+
179
+ 存储说明:插件自有数据(归档、校验文件、`auto.json`、`vault/`)直接用 `node:fs` 写入,与 DSH 自身的会话持久化同一模式;`ctx.fs` 是模型侧的沙箱接口,不适用于宿主插件的自有存储。
172
180
 
173
181
  ```sh
174
182
  node scripts/build-client.mjs # 改 src/ 后重新打包客户端
175
- node scripts/smoke.mjs # 宿主冒烟(真实临时目录 + 模拟 DSH 服务)
176
- node scripts/smoke-client.mjs # 客户端 bundle:握手/schema/标签页注册/SSR
183
+ node scripts/smoke.mjs # 宿主冒烟测试(真实临时目录 + 模拟 DSH 服务)
184
+ node scripts/smoke-client.mjs # 客户端 bundle 冒烟(握手 / schema / 标签页注册 / SSR
177
185
  ```
178
186
 
179
187
  ## 致谢
package/lib/client.js CHANGED
@@ -330,5 +330,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
330
330
  max-height: 10em;
331
331
  overflow: auto;
332
332
  }
333
- `;var Ld={name:"@xiaoyuyu6420/dsh-backup",version:"0.7.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",main:"lib/index.js",exports:{".":"./lib/index.js","./client":"./lib/client.js","./cordis.patch.yml":"./cordis.patch.yml","./package.json":"./package.json"},files:["lib","cordis.patch.yml","README.md","README.zh.md","LICENSE"],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"],peerDependencies:{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-commands":"^0.1.0-rc.6","@deepseek-ai/dsh-fs":"^0.1.0-rc.6","@deepseek-ai/dsh-subprocess":"^0.1.0-rc.6","@deepseek-ai/dsh-tools":"^0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"^0.1.0-rc.6"},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 jn="settings.backupPanel",Xf=Ld.name,qf=["slots","locale","remote"],Hf=x.object({destination:x.string(),dshHome:x.string(),keepDefault:x.number().int(),autoHours:x.number().int(),lastAuto:x.string().nullable(),backups:x.array(x.object({name:x.string(),size:x.number().int().nullable()}))}),Yf=x.object({ok:x.boolean(),summary:x.string(),path:x.string(),sha:x.string(),stale:x.number().int(),keep:x.number().int()}),Qf=x.object({ok:x.boolean(),summary:x.string(),results:x.array(x.object({name:x.string(),ok:x.boolean(),note:x.string()}))}),eg=x.object({ok:x.boolean(),dryRun:x.boolean(),summary:x.string(),archive:x.string().nullable().optional(),files:x.number().int().nullable().optional(),aside:x.string().nullable().optional(),snapshotPath:x.string().nullable().optional(),sample:x.array(x.string()).optional()}),tg=x.object({ok:x.boolean(),hours:x.number().int(),summary:x.string()}),rg=x.object({repoRaw:x.string().nullable(),repo:x.string().nullable(),tokenSet:x.boolean(),syncDir:x.string(),lastPush:x.string().nullable(),lastError:x.string().nullable()}),ng=x.object({ok:x.boolean(),summary:x.string(),pushed:x.boolean(),tooBig:x.array(x.string())}),ig=x.object({ok:x.boolean(),summary:x.string(),pulled:x.array(x.string()),corrupt:x.array(x.string()),total:x.number().int()}),og=x.object({ok:x.boolean(),summary:x.string()}),ag=x.object({ok:x.boolean(),repo:x.string().nullable(),summary:x.string()}),cg={name:"keep",wire:"keep",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#keep",schema:x.number().int().positive().optional()},acceptsUndefined:!0},Nu={name:"selector",wire:"selector",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#selector",schema:x.string().optional()},acceptsUndefined:!0},ug={name:"dryRun",wire:"dryRun",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#dryRun",schema:x.boolean().optional()},acceptsUndefined:!0},sg={name:"hours",wire:"hours",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#hours",schema:x.number().int().min(0).max(720)},acceptsUndefined:!0},lg={name:"repo",wire:"repo",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#repo",schema:x.string().optional()},acceptsUndefined:!0};function ce(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 Cd=Object.freeze({package:"dsh-backup",descriptors:Object.freeze([ce("status",[],Hf,!1),ce("backup",[cg],Yf,!0),ce("verify",[Nu],Qf,!0),ce("restore",[Nu,ug],eg,!0),ce("setAuto",[sg],tg,!1),ce("githubStatus",[],rg,!1),ce("githubSyncNow",[],ng,!0),ce("githubPull",[],ig,!0),ce("removeEntry",[Nu],og,!0),ce("setGithubRepo",[lg],ag,!1)])});function ue(t){if(!t.ok){let r=t.error;throw new Error(r&&r.message?`${r.code}: ${r.message}`:"backupPanel \u8C03\u7528\u5931\u8D25")}return t.value}function dg(t){t.effect(()=>t.locale.register(jn,{zh:Ed,en:Ad}),"dsh-backup: dictionaries"),t.effect(()=>Rd(),"dsh-backup: stylesheet"),t.effect(()=>{let r=null,i=!0,o=!1;return(async()=>{try{r=await t.remote.$mount(Cd)}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(jn),o=()=>r.remote.backupPanel,e={status:async()=>ue(await o().status()),backup:async n=>ue(await o().backup(n)),verify:async n=>ue(await o().verify(n)),restore:async(n,a)=>ue(await o().restore(n,a)),setAuto:async n=>ue(await o().setAuto(n)),githubStatus:async()=>ue(await o().githubStatus()),githubSyncNow:async()=>ue(await o().githubSyncNow()),githubPull:async()=>ue(await o().githubPull()),removeEntry:async n=>ue(await o().removeEntry(n)),setGithubRepo:async n=>ue(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:jn,inject:()=>({panel:e})},Td))})}
333
+ `;var Ld={name:"@xiaoyuyu6420/dsh-backup",version:"0.7.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",main:"lib/index.js",exports:{".":"./lib/index.js","./client":"./lib/client.js","./cordis.patch.yml":"./cordis.patch.yml","./package.json":"./package.json"},files:["lib","cordis.patch.yml","README.md","README.zh.md","LICENSE"],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"],peerDependencies:{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-commands":"^0.1.0-rc.6","@deepseek-ai/dsh-fs":"^0.1.0-rc.6","@deepseek-ai/dsh-subprocess":"^0.1.0-rc.6","@deepseek-ai/dsh-tools":"^0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"^0.1.0-rc.6"},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 jn="settings.backupPanel",Xf=Ld.name,qf=["slots","locale","remote"],Hf=x.object({destination:x.string(),dshHome:x.string(),keepDefault:x.number().int(),autoHours:x.number().int(),lastAuto:x.string().nullable(),backups:x.array(x.object({name:x.string(),size:x.number().int().nullable()}))}),Yf=x.object({ok:x.boolean(),summary:x.string(),path:x.string(),sha:x.string(),stale:x.number().int(),keep:x.number().int()}),Qf=x.object({ok:x.boolean(),summary:x.string(),results:x.array(x.object({name:x.string(),ok:x.boolean(),note:x.string()}))}),eg=x.object({ok:x.boolean(),dryRun:x.boolean(),summary:x.string(),archive:x.string().nullable().optional(),files:x.number().int().nullable().optional(),aside:x.string().nullable().optional(),snapshotPath:x.string().nullable().optional(),sample:x.array(x.string()).optional()}),tg=x.object({ok:x.boolean(),hours:x.number().int(),summary:x.string()}),rg=x.object({repoRaw:x.string().nullable(),repo:x.string().nullable(),tokenSet:x.boolean(),syncDir:x.string(),lastPush:x.string().nullable(),lastError:x.string().nullable()}),ng=x.object({ok:x.boolean(),summary:x.string(),pushed:x.boolean(),tooBig:x.array(x.string())}),ig=x.object({ok:x.boolean(),summary:x.string(),pulled:x.array(x.string()),corrupt:x.array(x.string()),total:x.number().int()}),og=x.object({ok:x.boolean(),summary:x.string()}),ag=x.object({ok:x.boolean(),repo:x.string().nullable(),summary:x.string()}),cg={name:"keep",wire:"keep",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#keep",schema:x.number().int().positive().optional()},acceptsUndefined:!0},Nu={name:"selector",wire:"selector",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#selector",schema:x.string().optional()},acceptsUndefined:!0},ug={name:"dryRun",wire:"dryRun",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#dryRun",schema:x.boolean().optional()},acceptsUndefined:!0},sg={name:"hours",wire:"hours",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#hours",schema:x.number().int().min(0).max(720)},acceptsUndefined:!0},lg={name:"repo",wire:"repo",source:"json",codec:{mode:"strict",typeSymbol:"dsh-backup/types#repo",schema:x.string().optional()},acceptsUndefined:!0};function ce(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 Cd=Object.freeze({package:"dsh-backup",descriptors:Object.freeze([ce("status",[],Hf,!1),ce("backup",[cg],Yf,!0),ce("verify",[Nu],Qf,!0),ce("restore",[Nu,ug],eg,!0),ce("setAuto",[sg],tg,!1),ce("githubStatus",[],rg,!1),ce("githubSyncNow",[],ng,!0),ce("githubPull",[],ig,!0),ce("removeEntry",[Nu],og,!0),ce("setGithubRepo",[lg],ag,!1)])});function ue(t){if(!t.ok){let r=t.error;throw new Error(r&&r.message?`${r.code}: ${r.message}`:"backupPanel \u8C03\u7528\u5931\u8D25")}return t.value}function dg(t){t.effect(()=>t.locale.register(jn,{zh:Ed,en:Ad}),"dsh-backup: dictionaries"),t.effect(()=>Rd(),"dsh-backup: stylesheet"),t.effect(()=>{let r=null,i=!0,o=!1;return(async()=>{try{r=await t.remote.$mount(Cd)}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(jn),o=()=>r.remote.backupPanel,e={status:async()=>ue(await o().status()),backup:async n=>ue(await o().backup(n)),verify:async n=>ue(await o().verify(n)),restore:async(n,a)=>ue(await o().restore(n,a)),setAuto:async n=>ue(await o().setAuto(n)),githubStatus:async()=>ue(await o().githubStatus()),githubSyncNow:async()=>ue(await o().githubSyncNow()),githubPull:async()=>ue(await o().githubPull()),removeEntry:async n=>ue(await o().removeEntry(n)),setGithubRepo:async n=>ue(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:jn,inject:()=>({panel:e})},Td))})}
334
334
  return module.exports; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaoyuyu6420/dsh-backup",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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
  "main": "lib/index.js",