@anionex/dsh-turn-rewind 0.1.2 → 0.2.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.md +19 -6
- package/README.zh.md +19 -6
- package/SECURITY.md +3 -1
- package/docs/assets/turn-rewind-dialog.png +0 -0
- package/lib/client.js +289 -22
- package/lib/client.js.map +1 -1
- package/lib/engine.js +140 -3
- package/lib/index.js +17 -1
- package/lib/rewind-host.js +131 -19
- package/lib/settings.js +58 -0
- package/lib/store.js +90 -23
- package/lib/types/client/index.d.ts +74 -7
- package/lib/types/engine.d.ts +21 -2
- package/lib/types/index.d.ts +7 -0
- package/lib/types/rewind-host.d.ts +5 -0
- package/lib/types/settings.d.ts +44 -0
- package/lib/types/store.d.ts +20 -0
- package/lib/types/types.d.ts +19 -0
- package/package.json +19 -3
- package/src/client/index.tsx +534 -42
- package/src/engine.ts +154 -3
- package/src/index.ts +20 -1
- package/src/rewind-host.ts +144 -20
- package/src/settings.ts +93 -0
- package/src/store.ts +109 -23
- package/src/types.ts +21 -0
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Rewind appears as an icon-only third action under each user message, after its t
|
|
|
32
32
|
|
|
33
33
|

|
|
34
34
|
|
|
35
|
-
Opening it shows the affected files and offers
|
|
35
|
+
Opening it shows the affected files and offers three choices: restore the files and restart from before that message, restore only the files, or rewind only the messages and leave the files untouched:
|
|
36
36
|
|
|
37
37
|

|
|
38
38
|
|
|
@@ -107,22 +107,25 @@ When the profile also provides the DSH Agent service, the plugin captures a hidd
|
|
|
107
107
|
|
|
108
108
|
## User flow
|
|
109
109
|
|
|
110
|
-
In the Web profile, each direct user message gains a compact, icon-only **Rewind** action after its timestamp and native Copy control. The tooltip reads “Return to before sending this message.” Opening Rewind checks the saved file state, shows a concise preview with a “view all files” action, and offers
|
|
110
|
+
In the Web profile, each direct user message gains a compact, icon-only **Rewind** action after its timestamp and native Copy control. The tooltip reads “Return to before sending this message.” Opening Rewind checks the saved file state, shows a concise preview with a “view all files” action, and offers three modes:
|
|
111
111
|
|
|
112
112
|
| Mode | Code | Conversation |
|
|
113
113
|
| --- | --- | --- |
|
|
114
|
-
| **Restore files and restart** (default) | Restores the project files after automatically backing up their current state. | Creates and opens a Session ending before the selected message, then puts that message's text back in the composer. |
|
|
114
|
+
| **Restore files and restart** (default when files changed) | Restores the project files after automatically backing up their current state. | Creates and opens a Session ending before the selected message, then puts that message's text back in the composer. |
|
|
115
115
|
| **Restore files only** | Restores the project files after automatically backing up their current state. | Leaves the current Session open and unchanged. |
|
|
116
|
+
| **Rewind messages only** (default when no checkpoint or no file changes) | Leaves the project files exactly as they are. | Creates and opens a Session ending before the selected message, then puts that message's text back in the composer. |
|
|
116
117
|
|
|
117
|
-
The dialog itself is the confirmation: there is no duplicate checkbox. It describes each file as restoring an earlier version, finding a deleted file, removing a later-added file, or restoring permissions/type.
|
|
118
|
+
The dialog itself is the confirmation: there is no duplicate checkbox. It describes each file as restoring an earlier version, finding a deleted file, removing a later-added file, or restoring permissions/type. **Rewind messages only** is always available — including when the checkpoint for that message is missing, was skipped (for example after disabling automatic checkpoints), or the project files already match the saved state — because it never touches the worktree. It is not blocked by other running Agents in the same worktree.
|
|
118
119
|
|
|
119
120
|
Before mutation, Turn Rewind rechecks the selected files and repository state, then creates an automatic backup. Changes made after preview invalidate the operation. Any running Agent using the same worktree, including the source Session, blocks restoration; idle Sessions do not block. A reviewed HEAD or branch difference does not block restoration: commits, refs, branch, and index remain unchanged, so restored content may appear as ordinary uncommitted changes against the current HEAD. An in-progress Git operation still blocks. If child creation fails after “restore and restart,” Change Ledger automatically restores the pre-operation files from the backup.
|
|
120
121
|
|
|
121
|
-
DSH Session logs are append-only, so “restart” creates a new Session instead of truncating the original. For the first message, the Host creates a blank Session in the same working directory; for later messages, it forks at the previous completed `turn/end`. A child may reuse an ancestor's prompt checkpoint only while both the selected `user/message` and its exact `turn/start` remain inside every durable `seedLength` fence. Direct child checkpoints take priority and sibling checkpoints never mix. **
|
|
122
|
+
DSH Session logs are append-only, so “restart” creates a new Session instead of truncating the original. For the first message, the Host creates a blank Session in the same working directory; for later messages, it forks at the previous completed `turn/end`. A child may reuse an ancestor's prompt checkpoint only while both the selected `user/message` and its exact `turn/start` remain inside every durable `seedLength` fence. Direct child checkpoints take priority and sibling checkpoints never mix. **Turn Rewind** always treats the two dimensions independently: the two restore modes change project files (optionally followed by a new conversation), while **Rewind messages only** reuses the same fork lifecycle without touching files. The original Session is always retained.
|
|
122
123
|
|
|
123
124
|
## Configuration
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
Runtime-tunable options are editable in the DSH web settings page under **Plugins → Turn Rewind** (`turn-rewind` settings namespace). Changes apply live to the next capture, restore, or deletion; they persist in the host's `settings.yaml` and override the profile patch values below. `storageDir` is deliberately not editable there: the storage root must not move while the engine holds locks and journals, so it stays a patch-layer field.
|
|
127
|
+
|
|
128
|
+
Override the composition base (and `storageDir`) in the profile patch layer:
|
|
126
129
|
|
|
127
130
|
```yaml
|
|
128
131
|
- id: turn-rewind
|
|
@@ -135,10 +138,20 @@ Override configuration in the profile patch layer:
|
|
|
135
138
|
maxSnapshotBytes: 536870912
|
|
136
139
|
planTtlMs: 900000
|
|
137
140
|
staleLockMs: 30000
|
|
141
|
+
turnCheckpointMode: legacy # off | git-native | legacy; "off" stops creating file checkpoints
|
|
142
|
+
turnCheckpointTimeoutMs: 5000
|
|
143
|
+
turnCheckpointMaxNewBytes: 33554432
|
|
144
|
+
turnCheckpointTrust: fast # fast | strict
|
|
138
145
|
```
|
|
139
146
|
|
|
147
|
+
Setting `turnCheckpointMode: off` (in the patch or in the settings card) stops automatic file checkpoints; every turn records a durable skip instead, and the rewind dialog still offers **Rewind messages only** for those messages.
|
|
148
|
+
|
|
140
149
|
All size and user-point retention limits fail loudly. Automatic turn checkpoints have a separate per-session retention window and prune only their own oldest checkpoints; user and rescue restore points are never silently pruned. When omitted, `storageDir` resolves to `$DSH_HOME/change-ledger/v1` and falls back to `~/.dsh/change-ledger/v1`; it must not overlap the managed worktree.
|
|
141
150
|
|
|
151
|
+
## Checkpoint management
|
|
152
|
+
|
|
153
|
+
The same settings card includes a storage manager backed by the same-origin `/turn-rewind/manage` endpoint. It lists every workspace this storage root has ever tracked — including projects whose directory no longer exists — grouped with checkpoint counts, approximate sizes, and pending-recovery badges. Per checkpoint, per workspace, or globally (**Clear all**), it deletes unprotected restore points and garbage-collects unreferenced blobs. Restore points still referenced by an incomplete recovery journal, a running restore, or an unfinished Git-native publish are retained and reported. Git-native (v2) checkpoints live in the repository's Git object database, so their disk space is reclaimed by normal Git garbage collection; the displayed sizes are logical values.
|
|
154
|
+
|
|
142
155
|
## Recovery
|
|
143
156
|
|
|
144
157
|
Before writing any path, a restore creates a rescue point and a durable operation journal. If DSH stops with a non-terminal journal, the next plugin startup marks it `interrupted` unless another live DSH process still owns that workspace lock.
|
package/README.zh.md
CHANGED
|
@@ -32,7 +32,7 @@ Agent / 用户 / 外部程序修改工作树
|
|
|
32
32
|
|
|
33
33
|

|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
打开后会先展示受影响文件,可选择“恢复文件并从这里继续”“只恢复文件”或“只回溯消息(不动文件)”:
|
|
36
36
|
|
|
37
37
|

|
|
38
38
|
|
|
@@ -105,22 +105,25 @@ dsh --profile web --dump-config | grep turn-rewind
|
|
|
105
105
|
|
|
106
106
|
## 使用流程
|
|
107
107
|
|
|
108
|
-
在 Web Profile
|
|
108
|
+
在 Web Profile 中,每条用户消息下方都会在时间和原生“复制”之后显示一个紧凑、无文字的**回退**图标,提示是“恢复到发送这条消息之前”。图标使用明确的向后/撤销箭头,而不是“重试”圆形箭头。打开后会检查保存的文件状态,先显示简洁预览,需要时可“查看全部文件”,并提供三种模式:
|
|
109
109
|
|
|
110
110
|
| 模式 | 代码 | 对话 |
|
|
111
111
|
| --- | --- | --- |
|
|
112
|
-
|
|
|
112
|
+
| **恢复文件并从这里继续**(文件有变化时的默认) | 自动备份当前状态后恢复项目文件。 | 创建一个从这里开始的新会话(当前对话会保留)。 |
|
|
113
113
|
| **只恢复文件** | 自动备份当前状态后恢复项目文件。 | 当前 Session 保持原位且内容不变。 |
|
|
114
|
+
| **只回溯消息(不动文件)**(无检查点或文件无变化时的默认) | 项目文件保持当前状态,不做任何修改。 | 创建一个从这里开始的新会话,并把原消息文字填入输入框。 |
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
弹窗和最终主按钮就是确认流程,不再要求重复勾选。文件会按实际结果显示为“恢复之前的版本”“找回文件”“移除后来新增的文件”“恢复文件权限”或“恢复之前的文件类型”。**只回溯消息**始终可用——即使该消息没有保存检查点、检查点被跳过(例如在设置里关闭了自动检查点),或项目文件已经与保存状态一致——因为它完全不触碰工作区,也不会被同一工作区中其他运行中的 Agent 阻止。
|
|
116
117
|
|
|
117
118
|
真正修改前,Turn Rewind 会再次检查所选文件和项目版本状态,并先创建自动备份。预览后出现的新变化会让本次恢复失效。同一工作树只要还有正在运行的 Agent(包括当前来源 Session),恢复就会被阻止;仅处于空闲状态的 Session 不会阻止恢复。已经审阅过的 HEAD 或分支变化不会阻止恢复:commit、分支、HEAD 和 index 都保持不变,恢复后的内容可能表现为当前 HEAD 上的未提交修改。Git 正在合并、变基等操作时仍会阻止。如果“恢复文件并从这里继续”在创建新对话时失败,Change Ledger 会自动从备份恢复操作前的文件。
|
|
118
119
|
|
|
119
|
-
DSH Session
|
|
120
|
+
DSH Session 日志只追加不改写,因此“恢复文件并从这里继续”和“只回溯消息”都会创建新 Session,而不是截断原对话。选中第一条消息时,Host 会在同一目录创建空 Session;选中后续消息时,会在上一轮 `turn/end` 处分叉。只有所选 `user/message` 和对应的精确 `turn/start` 都低于每一层持久 `seedLength` 时,子 Session 才能复用祖先保存的状态;子 Session 自己的状态优先,兄弟分支绝不混用。**Turn Rewind** 的两个维度彼此独立:两个“恢复文件”模式会修改项目文件(可选随后创建新对话),而**只回溯消息**复用同一分叉生命周期但完全不碰文件。原 Session 始终保留。
|
|
120
121
|
|
|
121
122
|
## 配置
|
|
122
123
|
|
|
123
|
-
|
|
124
|
+
运行时可调选项可以直接在 DSH Web 设置页的**插件 → Turn Rewind**卡片(`turn-rewind` 设置命名空间)中修改,修改对下一次捕获、恢复或删除即时生效,并持久化到宿主 `settings.yaml`,优先级高于下方 patch 层配置。`storageDir` 刻意不在此处暴露:存储根目录在引擎持有锁与 journal 时不可移动,只能通过 patch 层配置。
|
|
125
|
+
|
|
126
|
+
在 Profile 的 patch 层覆盖组合基线(以及 `storageDir`):
|
|
124
127
|
|
|
125
128
|
```yaml
|
|
126
129
|
- id: turn-rewind
|
|
@@ -133,10 +136,20 @@ DSH Session 日志只追加不改写,因此“恢复文件并从这里继续
|
|
|
133
136
|
maxSnapshotBytes: 536870912
|
|
134
137
|
planTtlMs: 900000
|
|
135
138
|
staleLockMs: 30000
|
|
139
|
+
turnCheckpointMode: legacy # off | git-native | legacy;off 表示不创建文件检查点
|
|
140
|
+
turnCheckpointTimeoutMs: 5000
|
|
141
|
+
turnCheckpointMaxNewBytes: 33554432
|
|
142
|
+
turnCheckpointTrust: fast # fast | strict
|
|
136
143
|
```
|
|
137
144
|
|
|
145
|
+
把 `turnCheckpointMode` 设为 `off`(patch 层或设置卡均可)后,插件不再为每条消息自动创建文件检查点,而是记录持久跳过标记;回退弹窗对这些消息仍然提供**只回溯消息**。
|
|
146
|
+
|
|
138
147
|
所有容量与用户恢复点数量限制都采用 fail loud。自动 Turn 检查点使用独立的每会话保留窗口,并且只清理自己最旧的检查点;用户和救援恢复点永远不会被静默删除。未配置时,`storageDir` 使用 `$DSH_HOME/change-ledger/v1`,未设置 `DSH_HOME` 时回退到 `~/.dsh/change-ledger/v1`;它不得与被管理 worktree 重叠。
|
|
139
148
|
|
|
149
|
+
## 检查点管理
|
|
150
|
+
|
|
151
|
+
同一张设置卡内置存储管理器,由同源 `/turn-rewind/manage` 端点支撑。它列出该存储根下跟踪过的所有工作区——包括目录已被删除的项目——并按项目分组显示检查点数量、近似占用和待处理恢复徽标。支持按单个检查点、按项目或全局(一键清空)删除未受保护的恢复点并回收不再引用的 blob。仍被未完成的恢复 journal、进行中的恢复或未完成的 Git-native publish 引用的恢复点会被保留并明确报告。Git-native(v2)检查点内容存放在仓库的 Git 对象库中,其磁盘空间由 Git 自身的垃圾回收释放;界面显示的大小为逻辑值。
|
|
152
|
+
|
|
140
153
|
## 故障恢复
|
|
141
154
|
|
|
142
155
|
任何路径写入前,插件都会先创建救援点和持久 operation journal。如果 DSH 在非终态操作期间退出,下次启动会把该操作标记为 `interrupted`;如果另一个仍存活的 DSH 进程持有工作树锁,则不会误判其操作。
|
package/SECURITY.md
CHANGED
|
@@ -16,7 +16,9 @@ Workspace restoration requires all of the following:
|
|
|
16
16
|
6. still-fresh selected-path hashes and the exact reviewed HEAD/branch/operation fence under the workspace lock;
|
|
17
17
|
7. a durable rescue point and operation journal.
|
|
18
18
|
|
|
19
|
-
The Web rewind adapter obtains the same session-bound plan and exact confirmation from a same-origin preview request, then sends both only after the user reviews the affected files and presses the final restore button. Direct mutation requests without that live plan pair fail closed.
|
|
19
|
+
The Web rewind adapter obtains the same session-bound plan and exact confirmation from a same-origin preview request, then sends both only after the user reviews the affected files and presses the final restore button. Direct mutation requests without that live plan pair fail closed. Message-only rewind (`mode: "messages"`) deliberately requires no restore plan: it never mutates the worktree, so there is nothing to gate or rescue. It re-resolves the selected message boundary server-side, revalidates the exact `turn/start` and previous `turn/end` against the live session, and fails closed with `PLAN_STALE` when the boundary no longer matches.
|
|
20
|
+
|
|
21
|
+
The storage-management endpoint (`/turn-rewind/manage`, same-origin like the rewind endpoint) only deletes the plugin's own durable state: manifest deletion runs under the workspace lock when the recorded repository still exists, skips every restore point referenced by an incomplete recovery journal, a running restore, or an unfinished Git-native publish, and garbage-collects only blobs no remaining manifest references. It never touches worktree content and never requires a worktree to exist on disk.
|
|
20
22
|
|
|
21
23
|
Restore-and-restart verifies that the durable checkpoint still names the exact `turn/start` before the selected `user/message`. A forked Session may resolve that checkpoint through its parent lineage only while both event sequences remain below every durable `seedLength` and every ancestor contains the same message and turn boundary. A direct checkpoint wins over an inherited checkpoint, sibling checkpoints are isolated, and malformed or missing lineage fails closed. The first message restarts through Host `session.create`; later messages fork at the previous completed `turn/end`. The Host owns seed creation, model-target inheritance, persistence, and Workspace attachment. The original append-only Session remains intact.
|
|
22
24
|
|
|
Binary file
|