dsh-rewind-plugin 0.6.3 → 0.7.0

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.en.md CHANGED
@@ -66,10 +66,13 @@ clears the file backups (chat rewinds are unaffected) and the plugin rebuilds th
66
66
  automatically.
67
67
 
68
68
  A **global auto-cleanup** (off by default) removes the snapshot directories of
69
- **long-inactive** sessions, leaving the active session and chat log untouched. Use
70
- `/snapshot-auto-cleanup` to **view, configure, and run** it; the settings live in
71
- `<dsh home>/snapshot-cleanup.json` and the last-sweep time in
72
- `<dsh home>/snapshot-cleanup-last-sweep.json`. See: [Snapshot cleanup](docs/snapshot-auto-cleanup.md).
69
+ long-inactive sessions, leaving the active session and chat log untouched. Configure
70
+ and review it in the **Settings &gt; Plugins &gt; Plugin configuration &gt; Snapshot
71
+ cleanup** panel (the auto-cleanup switch and the idle-day cutoff), or use the
72
+ `/snapshot-auto-cleanup` command to **view, configure, and run** it. See:
73
+ [Snapshot cleanup](docs/snapshot-auto-cleanup.md).
74
+
75
+ <img src="assets/screenshots/cleanup-setting.png" alt="Snapshot cleanup settings: auto-cleanup and idle days" width="600">
73
76
 
74
77
  ## Why it stands out
75
78
 
@@ -98,14 +101,15 @@ The whole design rests on two principles, simple but deliberate: **the conversat
98
101
 
99
102
  ### 2. File restore: lightweight checkpointing, "back up before the change"
100
103
 
101
- The file half follows Claude Code's checkpoint semantics — **per-file before-backups plus a re-scan of tracked files at each message**, not a whole-tree snapshot. This trade-off saves space, and it's actually more complete:
104
+ The file half follows Claude Code's checkpoint semantics — **partial tracking + before-write backup, plus a re-scan of tracked files at each message**, not a whole-tree snapshot. This trade-off saves space, and it's actually more complete:
102
105
 
103
- - **Before-backup**: tracks the write-class tools (`write`, `edit`, `str_replace_editor`) and stores the original content **before** each write. Timing is the key it captures after any approval gate lets the call through: an approval short-circuit can't skip the backup, and a denied call never records; a read failure only warns, never blocks the write. Backups are grouped by conversation turn and **persist on disk** across restarts.
104
- - **External changes count too**: at every user-message boundary the plugin re-checks all tracked files — edits or deletions made outside the write tools are recorded as well and restored by a later rewind. "Lightweight" but not "incomplete".
105
- - **Reconcile against the real disk before restoring**: the most interesting decision. At rewind time the plugin reads each file's current content and compares it to the target state **only files that actually differ are touched**: modified files are written back to their earliest backup, files created after the target are deleted, files already matching are skipped. Repeated rewinds are therefore **idempotent with zero side effects** and never produce "ghost impact".
106
+ - **Before-write backup**: tracks only the write-class tools (`write`, `edit`, `str_replace_editor`) backs up the original content before a write and records/tracks the files it touches; it never backs up the whole workspace, so it's lightweight.
107
+ - **External changes count too**: at every user-message boundary the plugin re-checks all tracked files — external changes such as a command run or a manual edit are recorded as well and restored by a later rewind. "Lightweight" but not "incomplete".
108
+ - **Unchanged-not-recorded, identical-content-as-link**: an entry is written only when something changed at the message-boundary re-check, an unchanged file is never backed up (no record); at before-write time, when the new content matches the path's prior record, only a **link to it** (`ref`) is stored instead of a copy. Repeated writes cost almost nothing, and a link is materialized before its group is evicted never left dangling.
109
+ - **Reconcile against the real disk before restoring**: restore takes each path's **earliest** record, then reads the live file and compares — **only files that actually differ are touched**: modified files are written back to the earliest backup, files created after the target are deleted, already-matching files are skipped. Repeated rewinds are therefore **idempotent with zero side effects** and never produce "ghost impact".
106
110
  - **Safety boundary**: symlinks / hard links are skipped so one restore can't clobber another name of the same file; paths are sanitized so nothing ever escapes the backup root; a per-file failure never aborts the pass.
107
111
 
108
- > **Design highlight**: **"reconcile against the real disk before acting"** is the most insightful decision in this checkpoint design — it never assumes blindly; it trusts the disk, doing what must be done and skipping what must not.
112
+ > **Design highlight**: this checkpoint's light footprint comes from **recording only what was actually touched and really changed**before-write backup makes it restorable, unchanged-not-recorded and content-as-link drop the repetition; which files to touch is decided against the real disk at restore time.
109
113
 
110
114
  ### Design highlights
111
115
 
@@ -132,7 +136,7 @@ This plugin deliberately stays lightweight and focused on one thing — "convers
132
136
  ## Compatibility
133
137
 
134
138
  - Node.js `^22.19.0 || >=24.0.0`.
135
- - DeepSeek Harness web profile (`dsh --profile web`); peer `@deepseek-ai/*` packages are resolved by the harness at runtime.
139
+ - Compatibility definition, verification method, and version alignment: see [docs/compat/audit.md](docs/compat/audit.md); supported DSH versions are declared by `package.json` `peerDependencies`.
136
140
 
137
141
  > [!WARNING]
138
142
  > This project and DeepSeek Harness are both in developer preview. Pin exact
package/README.md CHANGED
@@ -60,7 +60,9 @@ dsh plugin --profile web add dsh-rewind-plugin
60
60
 
61
61
  快照(写前备份)存储于 `<dsh home>/rewind-snapshots/`(未设 `$DSH_HOME` 时即 `~/.dsh/rewind-snapshots/`)。插件对**同一会话**的快照做内容去重(内容未变则存为链接)并保留最近 100 组锚点;**手动删除该目录**仅清除文件备份(对话回退不受影响),插件会自动重建。
62
62
 
63
- 另提供**全局自动清理**(默认关闭):把**长期不活跃**的会话快照整目录移除,不影响活动会话与对话日志。用 `/snapshot-auto-cleanup` 命令**查看、设置和运行**,配置写入 `<dsh home>/snapshot-cleanup.json`;最近一次自动清扫的时间记录在 `<dsh home>/snapshot-cleanup-last-sweep.json`。详见:[快照自动清理](docs/snapshot-auto-cleanup.zh.md)。
63
+ 另提供**全局自动清理**(默认关闭):把长期不活跃的会话快照整目录移除,不影响活动会话与对话日志。可在 `设置→插件→插件配置→快照清理` 面板查看与配置(自动清理开关、失活天数),也可用 `/snapshot-auto-cleanup` 命令查看、设置和运行。详见:[快照自动清理](docs/snapshot-auto-cleanup.zh.md)。
64
+
65
+ <img src="assets/screenshots/cleanup-setting.png" alt="快照清理设置:自动清理与失活天数" width="600">
64
66
 
65
67
  ## 本插件的优势
66
68
 
@@ -89,14 +91,15 @@ dsh plugin --profile web add dsh-rewind-plugin
89
91
 
90
92
  ### 2. 文件还原:轻量检查点,「改前备份」
91
93
 
92
- 文件部分对齐 Claude Code 的检查点语义——**逐文件、写前备份 + 每条消息重扫已跟踪文件**,而不是整树快照。这项取舍既省空间,又更完整:
94
+ 文件部分对齐 Claude Code 的检查点语义——**局部追踪、写前备份 + 每条消息重扫已跟踪文件**,而不是整树快照。这项取舍既省空间,又更完整:
93
95
 
94
- - **改前备份**:追踪写类工具(`write`、`edit`、`str_replace_editor`),在**每次写文件之前**先把原内容存下来。关键在时机——在审批门放行之后捕获:审批短路不会漏备份,被拒绝的调用也不会留下记录;读取失败只警告、从不阻塞写操作。备份按对话轮次分组锚定,**落盘持久化**,重启也还在。
95
- - **外部变更也追**:每条用户消息边界,插件重新检查所有已跟踪文件——那些从没经过写工具、被外部改过或删掉的文件,同样被记录,回退时一并还原。这让「轻量」却不「残缺」。
96
- - **还原前对照真实磁盘**:这是最值得说的一点。回退时插件实时读取文件当前内容,与目标状态逐一比对——**只操作真正不一致的文件**:改过的写回最早备份、目标之后新建的删除、已经一致的跳过。重复回退因此**零副作用、幂等**,绝不会出现「幽灵影响」。
96
+ - **写前备份**:只追踪写类工具(`write`、`edit`、`str_replace_editor`),写前**备份原内容**,并**记录、追踪**被处理的文件——从不备份整个工作区,因此轻量。
97
+ - **外部变更也追**:每条用户消息边界,插件重新检查所有已跟踪文件——命令执行、手动修改等外部变更同样被记录,回退时一并还原。这让「轻量」却不「残缺」。
98
+ - **不变不存、同内容存链接**:记录只在有变化时发生——消息边界重扫时无变更的不备份(不留记录);写前备份时若与前一条记录一致,只存**指向它的链接**(`ref`)而非复制内容。重复写入几乎不占空间,链接也先落地、绝不悬空。
99
+ - **还原时对照真实磁盘**:先取每条路径的**最早**记录,再实时读取文件当前内容与之比对——**只操作真正不一致的文件**:改过的写回最早期内容、目标之后新建的删除、已经一致的跳过。重复回退因此**零副作用、幂等**,不会出现「幽灵影响」。
97
100
  - **安全边界**:符号/硬链接跳过,避免透过一个还原误伤另一个名字;路径经安全化处理,**绝不越出备份根目录**;单个文件失败绝不中止整轮还原。
98
101
 
99
- > **设计点睛**:**「对照真实磁盘再动手」** 是这套检查点里最有洞察力的决定——它从不盲目假设,而是以磁盘为准,该做的做、不该做的跳过。
102
+ > **设计点睛**:这套检查点的「轻」,来自**只记录被工具动过、且确实变化的文件**——写前备份保证可还原,不变不存与存链接压掉重复;还原时再对照真实磁盘,只动不一致的文件。
100
103
 
101
104
  ### 设计亮点一览
102
105
 
@@ -123,7 +126,7 @@ dsh plugin --profile web add dsh-rewind-plugin
123
126
  ## 兼容性
124
127
 
125
128
  - Node.js `^22.19.0 || >=24.0.0`。
126
- - DeepSeek Harness web 配置档(`dsh --profile web`);peer `@deepseek-ai/*` 包由 harness 运行时解析。
129
+ - 兼容性定义、验证方法与版本对齐详见 [docs/compat/audit.md](docs/compat/audit.md);支持的 DSH 版本由 `package.json` `peerDependencies` 声明。
127
130
 
128
131
  > [!WARNING]
129
132
  > 本项目与 DeepSeek Harness 均处于开发者预览阶段。可复现环境请 pin 精确版本,
@@ -20,6 +20,10 @@
20
20
  > `-alpha` prerelease published under another tag, e.g. `0.1.2-alpha.2` under
21
21
  > `alpha`, is a manual pre-release check).
22
22
  >
23
+ > `0.1.2-alpha.1` was never published to npm, so the peer OR-union is declared only from `0.1.2-alpha.2`; the plugin code still supports the `alpha.1`+ client.
24
+ >
25
+ > `0.1.2-alpha.3` verified-compatible (`v0.6.3` runs without issues); `rc.2` (`latest`) remains the primary baseline.
26
+ >
23
27
  > Client channel (harness `0.1.2-alpha.x`; `0.1.2-alpha.2` is published to npm
24
28
  > under the `alpha` dist-tag while `latest` stays `0.1.1-rc.2`): the plugin reads
25
29
  > the session chat through `uiConversation` whenever the DSH client exposes it.
@@ -67,6 +71,7 @@
67
71
  - **rewind across a compact checkpoint**: `RewindError('not-on-surface')` refuses cleanly, no crash.
68
72
  - **plan-mode**: a marker reuses the last started turn (no phantom turn); a rewind never touches the log-only `plan/mode` state (plan mode stays active; the user leaves it with `/plan off`) and the log stays replayable (`compat-invariants` I1/I3 marker + `plan/mode` probe, `verify-host`).
69
73
  - **agent-loop cancellation**: `finally` guarantees step/turn closure; the rewind force-stop path leaves no dangling frame.
74
+ - **settings-card cross-version reach**: the Snapshot cleanup card must be registered through a **nested** `ctx.inject(['settingsScope'], …)` — naming `settingsScope` in the module-level inject unmounts the whole client plugin on rc.2 (card and rewind button disappear). It uses only the rc.2↔alpha-common scope subset (`getSnapshot().value` + `set`), never the alpha-only `mutate`.
70
75
 
71
76
  ## Known behavior boundaries (deterministic differences, non-crash, documented)
72
77
 
package/docs/format.md CHANGED
@@ -149,3 +149,14 @@ version field. A future incompatible format must either bump the journal
149
149
  `version` (readers reject unknown values — there is no best-effort fallback or
150
150
  legacy coercion) or move the state root (e.g. `rewind-snapshots/v2`) and ship
151
151
  an explicit migration tool. Old-format data is never silently re-interpreted.
152
+
153
+ ## Cleanup policy persistence
154
+
155
+ The snapshot auto-cleanup policy (the `enabled` switch and the `maxAgeDays`
156
+ idle cutoff) is no longer a file: it lives in the **dsh-settings document** under
157
+ the `dsh-rewind-snapshot-cleanup` namespace (validated by a schemastery schema;
158
+ defaults are the `base` layer). On first run after this change, a legacy
159
+ `<dsh home>/snapshot-cleanup.json` is imported into the document **once** and
160
+ then deleted (an absent file is a no-op; an invalid file imports the safe
161
+ default and is dropped). The last-sweep clock stays in its own
162
+ `<dsh home>/snapshot-cleanup-last-sweep.json` state file, which is unchanged.
@@ -15,7 +15,7 @@ you've stopped using, and now and then remove their snapshots to keep disk usage
15
15
  down. It never touches your active session, and it never touches your
16
16
  conversation.
17
17
 
18
- **Manual:** even with automatic cleanup off, you can run the cleanup yourself:
18
+ **Manual**: even with automatic cleanup off, you can run the cleanup yourself:
19
19
 
20
20
  - `/snapshot-auto-cleanup run [--apply]` — preview, then actually remove the
21
21
  snapshots of sessions you haven't used for a while.
@@ -41,20 +41,12 @@ whether or not automatic cleanup is on.
41
41
 
42
42
  ## Settings
43
43
 
44
- The settings live in `<dsh home>/snapshot-cleanup.json`:
44
+ The auto-cleanup switch and the idle-day cutoff live in the **dsh-settings configuration document**. View and edit them in the **Settings &gt; Plugins &gt; Plugin configuration &gt; Snapshot cleanup** panel (the auto-cleanup switch and the idle days), or view and set them with the `/snapshot-auto-cleanup` command:
45
45
 
46
- ```json
47
- { "enabled": false, "maxAgeDays": 30 }
48
- ```
46
+ <img src="../assets/screenshots/cleanup-setting.png" alt="Snapshot cleanup settings: auto-cleanup and idle days" width="600">
49
47
 
50
48
  - `enabled` — whether automatic cleanup runs (default `false`).
51
- - `maxAgeDays` — how many idle days before a session's snapshots are removed
52
- (default `30`). Only positive numbers are accepted, so a broken setting can
53
- never delete everything.
54
-
55
- You can point the plugin at a different file with the `DSH_SNAPSHOT_CLEANUP_CONFIG`
56
- environment variable. The file is changed only when you turn cleanup on/off or
57
- set `max-age`; a missing file reads as the safe default (off).
49
+ - `maxAgeDays` — how many idle days before a session's snapshots are removed (default `30`). Only positive integers are accepted, so a broken setting can never delete everything.
58
50
 
59
51
  ## When automatic cleanup runs
60
52
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  **自动清理**(默认关闭):插件会记住哪些会话你已不再使用,并定期移除它们的快照以节省磁盘。它**绝不**触碰你当前活跃的会话,也**绝不**触碰你的对话。
10
10
 
11
- **手动:**即使自动清理是关闭的,你也可以自己执行清理:
11
+ **手动**:即使自动清理是关闭的,你也可以自己执行清理:
12
12
 
13
13
  - `/snapshot-auto-cleanup run [--apply]` — 先预演,再真正移除你已有一阵子没用的会话的快照。
14
14
  - `/snapshot-auto-cleanup run --current [--apply]` — 先预演,再真正清空**当前**会话的快照。这会让它从"现在"重新开始记录回退历史(你的对话不受影响)。若此刻有正在进行中的回合,插件会先暂停它,再清空。
@@ -29,16 +29,12 @@
29
29
 
30
30
  ## 设置
31
31
 
32
- 设置保存在 `<dsh home>/snapshot-cleanup.json`:
32
+ 自动清理开关与失活天数保存在 **dsh-settings 配置文档**。可在 **设置→插件→插件配置→快照清理** 面板查看与修改(自动清理开关、失活天数),也可用 `/snapshot-auto-cleanup` 命令查看和设置:
33
33
 
34
- ```json
35
- { "enabled": false, "maxAgeDays": 30 }
36
- ```
34
+ <img src="../assets/screenshots/cleanup-setting.png" alt="快照清理设置:自动清理与失活天数" width="600">
37
35
 
38
36
  - `enabled` — 是否运行自动清理(默认 `false`)。
39
- - `maxAgeDays` — 会话失活多少天后移除其快照(默认 `30`)。只接受正数,因此一个损坏的设置永远不可能"删掉一切"。
40
-
41
- 你可以用环境变量 `DSH_SNAPSHOT_CLEANUP_CONFIG` 指向别的文件。该文件只在运行 `/snapshot-auto-cleanup` 时写入;文件缺失按安全默认值(关闭)处理。
37
+ - `maxAgeDays` — 会话失活多少天后移除其快照(默认 `30`)。只接受正整数,因此一个损坏的设置永远不可能"删掉一切"。
42
38
 
43
39
  ## 自动清理何时运行
44
40