dsh-recall-plugin 1.7.0 → 2.0.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/CHANGELOG.md +23 -0
- package/README.en.md +21 -18
- package/README.md +28 -19
- package/lib/client.js +284 -108
- package/lib/config.js +43 -2
- package/lib/index.js +153 -24
- package/lib/maintenance.js +263 -145
- package/lib/snapshots.js +73 -50
- package/package.json +15 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
本文件格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## [2.0.0] - 2026-08-26
|
|
6
|
+
|
|
7
|
+
从 v1.7.1 以来的首个大版本:P0 防线(撤回防护/时效校验)、P1 工程化(单测/探针/CI)、设置页体验改造与新增四项配置、转向指令消息撤回修复。发版前活体冒烟(浏览器自动化 + 真实 dsh web)通过。
|
|
8
|
+
|
|
9
|
+
### 新增
|
|
10
|
+
|
|
11
|
+
- **运行中撤回防护**(P0-1):目标工作区 agent 正在运行时拒绝发起撤回(preview/execute 均拦截,同会话优先、快照存在时叠加跨会话同工作区检查)——避免用户确认时文件被 agent 改动,预览清单与实际回退内容脱节。拦截依赖 `inject` 声明 `agents` 服务(cordis 4 门禁,冒烟实证:漏声明时静默 fail-open,防护等于没有)。
|
|
12
|
+
- **回退时效校验**(P0-3):preview 之后、execute 之前若该消息又出现了新快照(`previewTotal` 与当前 `recall.total` 不一致),强制重新预览并提示,防止按旧清单回退。
|
|
13
|
+
- **工程化基建**(P1):vitest 单元测试(104 例)+ 官方 API 字段探针(`npm run test:probe`,dsh 升级后本地必跑)+ GitHub Actions CI;快照失败反馈持久化(设置页可回溯最近错误);per-workspace 快照条数硬上限(超出先清最旧)。
|
|
14
|
+
- **新增配置项**:快照总开关 `snapshotEnabled`(关闭只冻结新建、存量快照仍可撤回)、撤回后归档开关 `archiveOriginal`(关闭时原会话保留在侧栏)、按时间保留 `retentionDays`(0 关闭;超期快照自动清理,与条数上限独立触发)。
|
|
15
|
+
- **配置一键恢复默认**:设置页「恢复默认」走官方 `settings.replace` reset 通道(`section: {}` 重置为组合默认并清 user 覆盖层),老版本服务无该 RPC 时降级写默认值。
|
|
16
|
+
- **设置页体验改造**:文件大小上限改 MB 单位输入;快照树「加载更多」与计数修复(缓存全量数组、按 limit 切片);存储健康状态行;快照搜索框;危险操作分级(全删/清空折叠 + 二次确认);操作成功即时反馈;空态引导;「最近错误」可一键清空。
|
|
17
|
+
|
|
18
|
+
### 修复
|
|
19
|
+
|
|
20
|
+
- **转向指令消息缺撤回按钮**:agent 运行中插入的用户输入在 UI 投影层为 `kind=steering`(存储层 `role` 恒 user、无差异),不命中 keyed `user` 渲染器而落到官方默认气泡——keyed 注册扩展为 `['user','steering']`(冒烟实测复现并验证)。
|
|
21
|
+
|
|
22
|
+
## [1.7.1] - 2026-08-25
|
|
23
|
+
|
|
24
|
+
### 修复
|
|
25
|
+
|
|
26
|
+
- 历史会话中用户消息图片从未渲染([#9](https://github.com/limbo947/dsh-recall-plugin/issues/9)):插件渲染器读取的 `props.loadImage` 在官方 `conversation.chat.node` slot 契约中**从不存在**(实际入口是 `props.renderMessageImages`),自研加载链在守卫处直接 return——v1.6.2 的重试链、v1.7.0 的失败按钮全部从未执行,图片永久无声空白(v1.6.2/#8 的修复因此「修了却无效」)。用户消息图片改走官方 `renderMessageImages` 管线(自带鉴权、缓存、失败重试与灯箱预览),布局对齐官方(图片在上、气泡在下);自研 `ImageBox`/`useImageSrc` 及对应 CSS 作为死代码移除。
|
|
27
|
+
|
|
5
28
|
## [1.7.0] - 2026-08-25
|
|
6
29
|
|
|
7
30
|
### 新增
|
package/README.en.md
CHANGED
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|

|
|
20
20
|
|
|
21
21
|
---
|
|
22
|
-
| Confirmation panel · file change list | |
|
|
22
|
+
| Confirmation panel · file change list | Confirmation panel · rollback scope |
|
|
23
23
|
| --- | --- |
|
|
24
|
-
|  |  |
|
|
24
|
+
|  |  |
|
|
25
25
|
|
|
26
|
-
- After a recall, the message text is auto-refilled into the input box for quick editing and resending (can be disabled in the settings card)
|
|
26
|
+
- After a recall, the message text is auto-refilled into the input box for quick editing and resending (can be disabled in the settings card)
|
|
27
27
|
- Settings · plugin config card (thresholds / exclusions / snapshot manager, saved changes apply live)
|
|
28
28
|
|
|
29
29
|
| Settings | Settings |
|
|
@@ -41,8 +41,11 @@
|
|
|
41
41
|
- **Keeps your project directory clean**: snapshots always live under `$DSH_HOME`, nothing is ever dropped into your project — regardless of the session's sandbox permission (workspace-write / read-only sessions snapshot and recall as usual). Only when home itself is unwritable (e.g. pointed at a read-only drive) does it fall back to an in-project `.dsh-recall-snapshots` directory (the page shows a notice when degraded); once home is writable again, data migrates back and the fallback directory is cleaned up.
|
|
42
42
|
- **Change your mind as many times as you like**: as long as the session still exists (including archived ones), snapshots are fully retained and never pruned. After one recall you can recall again to an even earlier point; files overwritten during a recall always remain recoverable. Once a session is permanently deleted, its snapshots are cleaned up accordingly (see below).
|
|
43
43
|
- **See the list before you act**: clicking recall first shows the list of files that will change (modified / restored / deleted); nothing is overwritten until you confirm.
|
|
44
|
-
- **Disk-friendly**: snapshots use git delta compression — incremental, not full-directory copies. Files larger than 100MB are skipped automatically.
|
|
45
|
-
- **Automatic housekeeping**: periodic `git gc` packs loose objects (lossless — not a single snapshot is lost); snapshots of deleted sessions are cleaned up automatically; build artifacts can be excluded globally via `exclude.txt` (see below).
|
|
44
|
+
- **Disk-friendly**: snapshots use git delta compression — incremental, not full-directory copies. Files larger than 100MB are skipped automatically (the threshold is configurable in the settings card).
|
|
45
|
+
- **Automatic housekeeping**: periodic `git gc` packs loose objects (lossless — not a single snapshot is lost); snapshots of deleted sessions are cleaned up automatically; build artifacts can be excluded globally via `exclude.txt` (see below).
|
|
46
|
+
- **Failures speak up** (1.7.0+): snapshot failures, skipped paths, and circuit-breaker pauses all surface as a toast at the top of the page (the same fault only bothers you once per 10 minutes) — nothing fails silently; the failure reason lands in the "Recent errors" section of the settings card.
|
|
47
|
+
- **Self-healing on failure** (1.7.0+): after a snapshot fails, leftover objects are pruned automatically; 3 consecutive failures trigger an exponential-backoff circuit breaker (auto-retry after the cooldown); the failure path also sweeps stray git processes and stale locks — the disk never bloats from failed retries, and a single hiccup can't wedge the pipeline.
|
|
48
|
+
- **Unindexable paths are skipped, not fatal** (1.7.0+): embedded git repositories, unreadable files, and other paths that can't be indexed no longer fail the whole snapshot — the snapshot is still taken, and skipped paths are reported via toast (on recall they are neither restored nor deleted, same semantics as exclusions).
|
|
46
49
|
- **Tree-view snapshot manager**: the "Snapshot Manager" on the settings page shows a **workspace → session → snapshot** three-level tree with expand/collapse support; each level has a delete button on its right, so you can clear all snapshots of a workspace or a session at once. Leaves show a summary of the message content the snapshot corresponds to, making it easy to locate "what this message changed back then".
|
|
47
50
|
|
|
48
51
|
## Known Limitations
|
|
@@ -50,7 +53,7 @@
|
|
|
50
53
|
- Snapshots are created **when a message is sent**; messages from before the plugin was enabled have no snapshot and show no recall button.
|
|
51
54
|
- The first user message of a session cannot roll back the conversation (files only), because fork requires an earlier turn boundary.
|
|
52
55
|
- Supports Windows (PowerShell 5.1/7 + git CLI) and Linux/macOS (bash + git CLI). Windows is thoroughly verified on real machines; Linux has been fully tested on WSL2 (Ubuntu 26.04, bash 5.3 + git 2.53), including Chinese paths, home fallback, session cleanup, and gc; the macOS side is written to be bash 3.2 compatible but has not been tested on real hardware yet.
|
|
53
|
-
- Nested git repositories inside the workspace (subdirectories with their own `.git`)
|
|
56
|
+
- Nested git repositories inside the workspace (subdirectories with their own `.git`) cannot be indexed: the snapshot proceeds for everything else (fail-open, with a toast listing the skipped paths), but their contents do not participate in recalls.
|
|
54
57
|
- Extreme cases like filenames containing newlines/TAB are beyond the diff list's parsing capability (negligible probability).
|
|
55
58
|
|
|
56
59
|
## Installation
|
|
@@ -61,7 +64,7 @@ Prerequisites: git CLI (without it the recall button won't appear and a notice s
|
|
|
61
64
|
```powershell
|
|
62
65
|
dsh plugin --profile web add dsh-recall-plugin
|
|
63
66
|
```
|
|
64
|
-
- Or install directly from git
|
|
67
|
+
- Or install directly from git:
|
|
65
68
|
```powershell
|
|
66
69
|
dsh plugin --profile web add github:limbo947/dsh-recall-plugin
|
|
67
70
|
```
|
|
@@ -96,7 +99,7 @@ Snapshots are fully retained as long as "the session might still be recoverable"
|
|
|
96
99
|
*.log
|
|
97
100
|
```
|
|
98
101
|
|
|
99
|
-
This applies to all projects (when home is unwritable and a workspace falls back to in-project storage, it gets its own independent exclusion config, listed as a separate card in the settings tab). New exclusions only affect future snapshots; **when recalling to an earlier snapshot, files that weren't excluded at that time are still restored** (returning to the state as it was — that's exactly what recall means). To fully purge a directory that already made it into snapshots, manually delete the corresponding hash directory under `dsh-recall-snapshots/` in home. The settings card requires DSH's built-in settings page (all 0.1.0-rc.x releases have it); on very old versions without the tab, editing the file directly is equivalent.
|
|
102
|
+
This applies to all projects (when home is unwritable and a workspace falls back to in-project storage, it gets its own independent exclusion config, listed as a separate card in the settings tab). New exclusions only affect future snapshots; **when recalling to an earlier snapshot, files that weren't excluded at that time are still restored** (returning to the state as it was — that's exactly what recall means). To fully purge a directory that already made it into snapshots, manually delete the corresponding hash directory under `dsh-recall-snapshots/` in home. The settings card requires DSH's built-in settings page (all 0.1.0-rc.x releases have it); on very old versions without the tab, editing the file directly is equivalent.
|
|
100
103
|
- **Tree-view snapshot manager**: open "**Settings → Plugins → Recall Plugin → Snapshot Manager**" to see the tree list — first level workspace (folder name), second level session (session title), third level snapshot (time + message content summary, hover to see the full content). Workspace and session nodes support expand/collapse; every level has a delete button on its right, with an inline confirmation before deletion. Deleting a workspace = clearing all snapshots of that workspace; deleting a session = clearing all snapshots of that session within that workspace; deleting a leaf = removing just that single snapshot.
|
|
101
104
|
|
|
102
105
|
## How It Works
|
|
@@ -111,21 +114,21 @@ When each user message is sent (before the agent touches any files), the workspa
|
|
|
111
114
|
git --git-dir="<store>\git\.git" ls-tree -r --name-only snap-<messageID>
|
|
112
115
|
```
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
|
|
116
117
|
## Local Development (without publishing)
|
|
117
118
|
|
|
119
|
+
Point the profile's dependency for this package at your clone via `link:`, and changes take effect after restarting DSH (the workspace `lib/` IS the running code — no copying or publishing needed):
|
|
120
|
+
|
|
118
121
|
```powershell
|
|
119
|
-
#
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
#
|
|
126
|
-
# then restart DSH and hard-refresh the page
|
|
122
|
+
# 1. Edit $env:USERPROFILE\.dsh\profiles\web\package.json:
|
|
123
|
+
# in "dependencies", set "dsh-recall-plugin": "link:<path-to-your-clone>\dsh-recall-plugin"
|
|
124
|
+
# "dsh.profile.bundles" should already contain "dsh-recall-plugin" (run the official install command once)
|
|
125
|
+
# 2. Install in the profile directory and restart
|
|
126
|
+
cd $env:USERPROFILE\.dsh\profiles\web
|
|
127
|
+
pnpm install
|
|
128
|
+
# 3. Restart DSH and hard-refresh the page (Ctrl+Shift+R)
|
|
127
129
|
```
|
|
128
130
|
|
|
131
|
+
|
|
129
132
|
## License
|
|
130
133
|
|
|
131
134
|
MIT
|
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# dsh-recall-plugin
|
|
2
2
|
|
|
3
|
-
> 撤回一条消息,项目文件也一起回去。
|
|
4
|
-
|
|
5
3
|
简体中文 | [English](README.en.md)
|
|
6
4
|
|
|
7
5
|

|
|
8
6
|

|
|
9
7
|

|
|
10
|
-

|
|
11
8
|

|
|
12
9
|
|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
13
|
---
|
|
14
|
-
**在任意一条你发过的消息下方**,**点「↶ 撤回」**,**工作区文件和对话历史一起回到那条消息发出之前的状态**。
|
|
14
|
+
**在任意一条你发过的消息下方**,**点「↶ 撤回」**,**工作区文件和对话历史一起回到那条消息发出之前的状态**。(dsh-0.1.1-rc.2)
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
[更新日志](CHANGELOG.md)
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|

|
|
23
23
|
|
|
24
24
|
---
|
|
25
|
-
| 确认面板 ·
|
|
25
|
+
| 确认面板 · 变更文件清单 | 确认面板 · 回退范围说明 |
|
|
26
26
|
| --- | --- |
|
|
27
|
-
|  |  |
|
|
27
|
+
|  |  |
|
|
28
28
|
|
|
29
29
|
- 撤回后自动把消息文本回填到输入框,方便修改后重发(可在设置卡片关闭)
|
|
30
30
|
- 设置页 · 插件配置卡片(阈值 / 排除表 / 快照管理,保存即热生效)
|
|
@@ -39,8 +39,11 @@
|
|
|
39
39
|
- **项目目录保持干净**:快照始终存在 `$DSH_HOME` 下,不会往项目里塞任何东西;与会话的沙箱权限无关(workspace-write / read-only 会话照常快照与回退),仅当 home 本身不可写(如指到只读盘)才降级到项目内 `.dsh-recall-snapshots`(降级时页面会提示),home 恢复后自动迁走、清理干净。
|
|
40
40
|
- **可以反复后悔**:只要会话还在(含归档),快照全量保留、不修剪。撤回一次后还能再撤到更早;撤回时被覆盖的文件也一直找得回来。会话被彻底删除后,其快照随之清理(见下)。
|
|
41
41
|
- **先看清单再动手**:点撤回先弹出将变更的文件清单(修改 / 恢复 / 删除),确认后才执行,不会稀里糊涂覆盖。
|
|
42
|
-
- **磁盘友好**:快照走 git delta 压缩,是增量不是整目录拷贝;超过 100MB
|
|
42
|
+
- **磁盘友好**:快照走 git delta 压缩,是增量不是整目录拷贝;超过 100MB 的大文件自动跳过(阈值可在设置卡片改)。
|
|
43
43
|
- **自动瘦身**:定期 `git gc` 把 loose 对象压 pack(无损,快照一个不丢);会话删除后其快照自动清理;构建产物可经 `exclude.txt` 全局排除(见下)。
|
|
44
|
+
- **失败了会说话**(1.7.0+):快照失败、跳过路径、连续失败熔断都会在页面顶部 toast 提示(同类故障 10 分钟只打扰一次),不会无声失效;失败原因进设置卡片「最近错误」。
|
|
45
|
+
- **故障自愈**(1.7.0+):快照失败后自动清理残骸对象、连续 3 次失败起指数退避熔断(冷却后自动重试),失败路径还会清扫漏网的 git 进程与残留锁——磁盘不会被失败重试撑爆,也不会被一次异常卡死。
|
|
46
|
+
- **个别路径进不去就跳过**(1.7.0+):嵌入式 git 仓库、无读权限等无法索引的路径不再让整条快照失败——快照照常落盘,被跳过的路径 toast 告知(撤回时既不恢复也不删它们,与排除表语义一致)。
|
|
44
47
|
- **树形快照管理**:设置页「快照管理」按 **工作区 → 会话 → 快照** 三级树形展示,支持展开/折叠;每级右侧都有删除按钮,可一次清掉整个工作区或某个会话的全部快照,叶子显示该快照对应的消息内容摘要,方便定位“这条消息当时改了什么”。
|
|
45
48
|
|
|
46
49
|
## 已知限制
|
|
@@ -48,7 +51,7 @@
|
|
|
48
51
|
- 快照在**消息发送时**创建,插件启用前的历史消息没有快照,不显示撤回按钮。
|
|
49
52
|
- 会话第一条用户消息无法回退对话(仅文件回退),因为 fork 需要更早的 turn 边界。
|
|
50
53
|
- 支持 Windows(PowerShell 5.1/7 + git CLI)与 Linux/macOS(bash + git CLI)。Windows 真机验证充分;Linux 已在 WSL2(Ubuntu 26.04,bash 5.3 + git 2.53)实测全流程(含中文路径、home 降级、会话清理、gc);macOS 侧脚本按 bash 3.2 兼容编写,尚未真机实测。
|
|
51
|
-
- 工作区内嵌套的其他 git 仓库(子目录自带 `.git
|
|
54
|
+
- 工作区内嵌套的其他 git 仓库(子目录自带 `.git`)无法索引:快照对其余部分照常(fail-open,页面会提示跳过了哪些路径),但其内容不参与回退。
|
|
52
55
|
- 文件名含换行/TAB 的极端情形不在 diff 清单的解析能力内(概率可忽略)。
|
|
53
56
|
|
|
54
57
|
## 安装
|
|
@@ -60,7 +63,7 @@
|
|
|
60
63
|
```powershell
|
|
61
64
|
dsh plugin --profile web add dsh-recall-plugin
|
|
62
65
|
```
|
|
63
|
-
- 也可从 git
|
|
66
|
+
- 也可从 git 直接安装:
|
|
64
67
|
```powershell
|
|
65
68
|
dsh plugin --profile web add github:limbo947/dsh-recall-plugin
|
|
66
69
|
```
|
|
@@ -110,21 +113,27 @@ pm2 restart <你的dsh进程名> # 若用 pm2 托管
|
|
|
110
113
|
git --git-dir="<store>\git\.git" ls-tree -r --name-only snap-<消息ID>
|
|
111
114
|
```
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
|
|
115
116
|
## 本地开发(无需发布)
|
|
116
117
|
|
|
118
|
+
把 profile 对本包的依赖改成 `link:` 指向克隆目录,改完代码重启 DSH 即生效(工作区 `lib/` 即运行代码,无需复制或发布):
|
|
119
|
+
|
|
117
120
|
```powershell
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
#
|
|
125
|
-
# 然后重启 DSH 并硬刷新页面
|
|
121
|
+
# 1. 编辑 $env:USERPROFILE\.dsh\profiles\web\package.json:
|
|
122
|
+
# "dependencies" 里 "dsh-recall-plugin": "link:<你的克隆路径>\dsh-recall-plugin"
|
|
123
|
+
# "dsh.profile.bundles" 已含 "dsh-recall-plugin"(官方命令装过一次即可)
|
|
124
|
+
# 2. 在 profile 目录安装并重启
|
|
125
|
+
cd $env:USERPROFILE\.dsh\profiles\web
|
|
126
|
+
pnpm install
|
|
127
|
+
# 3. 重启 DSH + 硬刷新页面(Ctrl+Shift+R)
|
|
126
128
|
```
|
|
127
129
|
|
|
130
|
+
|
|
131
|
+
### 测试
|
|
132
|
+
|
|
133
|
+
- `npm test`:纯逻辑单测(vitest,无 DSH 依赖,CI 与本地同跑)——配置解析、快照解析器、脚本模板同名导出契约、客户端纯函数、发布包内容布局、快照索引持久化、存储总量上限;
|
|
134
|
+
- `npm run test:probe`:官方 API 字段探针(依赖本机 dsh 安装;dsh 升级后本地必跑)——钉住 `renderMessageImages`/`node`/`cwd`、`sessions.fork` 的 `atSeq`/`increaseTitle`、`listSessions` 记录结构、`AgentRegistry` 等字段,违反即红(合规清单 #8 的机器化)。
|
|
135
|
+
- CI(GitHub Actions)跑 `npm ci --legacy-peer-deps` + `npm test`(探针只在有 dsh 的机器跑)。
|
|
136
|
+
|
|
128
137
|
## License
|
|
129
138
|
|
|
130
139
|
MIT
|