dsh-rewind-plugin 0.2.7 → 0.2.9
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 +74 -181
- package/README.zh.md +73 -168
- package/docs/harness-reference.md +23 -0
- package/docs/release.md +90 -0
- package/docs/troubleshooting.md +39 -0
- package/docs/troubleshooting.zh.md +31 -0
- package/lib/client.js +219 -148
- package/lib/types/client/index.d.ts +14 -18
- package/lib/types/client/portals.d.ts +66 -0
- package/lib/types/client/styles.d.ts +0 -2
- package/package.json +7 -2
package/README.zh.md
CHANGED
|
@@ -1,46 +1,26 @@
|
|
|
1
1
|
# dsh-rewind
|
|
2
2
|
|
|
3
|
-
[English](README.md)
|
|
4
|
-
|
|
5
3
|
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件:**同一会话窗口的 in-place 对话回退**(Claude Code `/rewind` 语义)——把模型上下文剪回更早的一条用户消息,并可基于**落盘的写前备份**还原工作区文件。
|
|
6
4
|
|
|
7
|
-
> **状态**:已发布 npm(`dsh-rewind-plugin`,v0.2.7),经 GitHub Actions Trusted Publishing + Sigstore provenance 构建发布。目标为 web 配置档(`dsh --profile web`)。交互以 Claude Code 的 rewind 为参考,并贴合 dsh Web 实际 UI。
|
|
8
|
-
>
|
|
9
|
-
> **v0.2.7 要点**:输入框回填改为事件驱动(重开会话不再复活已撤回文本);子代理编辑不跟踪(对齐 Claude Code);并发回退有防护;「回退代码」选项仅在存在跟踪变更时显示(兼容新旧 host/client 混合版本)。
|
|
10
|
-
|
|
11
5
|
[](https://www.npmjs.com/package/dsh-rewind-plugin)
|
|
12
6
|
[](https://github.com/SiriLee/dsh-rewind/blob/main/LICENSE)
|
|
13
7
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| 特性 | 说明 |
|
|
32
|
-
| --- | --- |
|
|
33
|
-
| 同窗口原地回退 | 在**任意**用户消息旁点 ↶ 按钮:该消息及之后全部内容(agent 回复、工具调用)从模型上下文**与**渲染对话中撤回——不新建会话、不切换窗口 |
|
|
34
|
-
| 时间回溯语义 | 回退到某消息会**连同撤回该消息本身**;其文本自动填入输入框,可修改后重发 |
|
|
35
|
-
| Claude Code 式文件还原 | 写类编辑在执行**前**被备份并落盘;「回退对话和代码」把文件还原到编辑前内容、删除目标之后新建的文件 |
|
|
36
|
-
| 影响清单确认 | 「回退对话和代码」先展示要还原/删除的文件清单再确认(目标之后无跟踪变更时不显示该选项,对齐 Claude Code 的 code-restore 可见性) |
|
|
37
|
-
| 与审批类插件共存 | 捕获在 `tools/execute`(around-dispatch 阶段):其他插件的 pre-execute 审批短路(如 dsh-edit-approval)无法跳过备份,被拒绝的调用也不会记录 |
|
|
38
|
-
| 路径按会话 cwd 解析 | 相对路径按 fs-tools 的 session-cwd 规则解析到**真实文件**,记录解析后的 display path |
|
|
39
|
-
| 还原直写真实文件 | 还原走纯 `node:fs` 直接落盘;符号链接与硬链接跳过并警告(不通过共享 inode 误伤) |
|
|
40
|
-
| 重启后仍可还原 | 备份落在磁盘 `~/.dsh/rewind-snapshots/<会话>/<锚点 seq>/`,每会话保留最近 100 组 |
|
|
41
|
-
| 本地化 | `zh` / `en` 文案,注册进 dsh 的 locale 体系 |
|
|
42
|
-
|
|
43
|
-
## 📸 截图
|
|
8
|
+
> [English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
刻意保持聚焦,只做一件事:**就地回退到任意更早的用户消息**。
|
|
11
|
+
|
|
12
|
+
| 模式 | 对话 | 工作区文件 |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| **仅回退对话** | 剪回目标消息之前 | 不动 |
|
|
15
|
+
| **回退对话和代码** | 剪回目标消息之前 | 还原到目标之前的 state(改过的文件写回、之后新建的文件删除) |
|
|
16
|
+
|
|
17
|
+
回退即**时间回溯**:目标消息及其之后全部内容(agent 回复、工具调用)从模型上下文**与**渲染对话中撤回——不新建会话、不切换窗口——目标消息的文本会回填输入框,可修改后重发。
|
|
18
|
+
|
|
19
|
+
插件从不改写 append-only 会话日志,从不触碰你的 git 仓库。
|
|
20
|
+
|
|
21
|
+
## 效果预览
|
|
22
|
+
|
|
23
|
+
每条用户消息的操作行上多出一个 **↶ 回退** 按钮。点击后弹出模式选择浮层;「回退对话和代码」会先展示待还原/删除的文件清单再确认(目标之后无跟踪变更时不显示该选项,对齐 Claude Code 的 code-restore 可见性)。
|
|
44
24
|
|
|
45
25
|
<table>
|
|
46
26
|
<tr>
|
|
@@ -53,123 +33,71 @@
|
|
|
53
33
|
</tr>
|
|
54
34
|
</table>
|
|
55
35
|
|
|
56
|
-
|
|
36
|
+
在输入框手动输入 `/rewind`(含裸命令)会被**拦截**——提交时弹出临时提示,指向消息旁的 ↶ 按钮。
|
|
57
37
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
### 1. 对话回退
|
|
61
|
-
|
|
62
|
-
插件向会话日志追加一条**空内容标记** `assistant/message`,其 `surfaceOp: { op: 'replace', start, end }` 把目标消息之后的全部 surface 节点替换为标记本身:
|
|
63
|
-
|
|
64
|
-
- 标记携带 `sourceEventSeqs` 覆盖所有被遮蔽节点,`Session.append` 的 surface 规则校验切割合法性(仅限当前 surface 上的连续区间)。
|
|
65
|
-
- 因为标记**内容为空**,harness 会将其派生为 `null`——永不进入模型上下文、也永不渲染成对话内容。agent 与用户看到的对话都回到目标消息当时的样子。
|
|
66
|
-
- 标记的 **turn 号复用最后一个已开始的回合**(`markerTurnOf`),而不是「最后回合 + 1」:harness 的 agent loop 恰好用 `最后 turn/start + 1` 编号下一条真实回合。若标记也取这个数,日志里就会出现同一 turn 的 `assistant/message` 先于 `turn/start` 的乱序,客户端 conversation 构建器会以 `conversation Context …:turn-tail… received an update before its start Match` 拒绝重放——历史加载失败、整个对话从界面消失(0.2.4 及之前的真实缺陷,已在 0.2.5 修复)。复用已消费的 turn 号则标记只是上一个已完成回合尾部的一次无害追加,永不与新回合冲突。
|
|
67
|
-
- append-only 日志**不被改写**——审计轨迹完整保留每条被撤回的事件,只有模型可见的 surface 被剪掉,下一条请求从目标消息起派生上下文。
|
|
68
|
-
|
|
69
|
-
若 agent 正在运行(LLM 思考/流式输出),会先强制停止(`cancel({ kind: 'user' })`)并等待 quiescence 再回退;停不下来则中止并报错。
|
|
70
|
-
|
|
71
|
-
### 2. Checkpoint 文件还原
|
|
72
|
-
|
|
73
|
-
插件跟踪写类工具:`write`、`edit`、`str_replace_editor`(变更子命令 `create` / `str_replace` / `insert`):
|
|
74
|
-
|
|
75
|
-
1. **写前备份**(`tools/execute`,around-dispatch 阶段):读取目标文件,把解析后的路径与内容放入 pending 表。此阶段只在任何 pre-execute 审批门放行之后运行——所以审批 `ask` 短路(dsh-edit-approval)**无法跳过**备份,被拒绝的调用也不会记录。
|
|
76
|
-
2. **落盘提交**(`tools/post-execute`):备份按当前轮**锚点消息 seq** 写入 `~/.dsh/rewind-snapshots/<会话>/<锚点 seq>/<callId>.json`。
|
|
77
|
-
3. **还原**(`/rewind @<seq> both`):锚点 ≥ 目标的每条备份生效——被修改的文件写回其**最早一次**捕获的 before 内容,目标之后新建的文件被删除,符号/硬链接跳过。写入走纯 `node:fs`,不经 fs 服务。
|
|
78
|
-
4. 工具体**抛异常**会跳过 `tools/post-execute`;`tools/result` 兜底清掉 pending,避免内存泄漏。
|
|
79
|
-
|
|
80
|
-
备份跨 host 重启持久化,每会话有界保留最近 100 组锚点。
|
|
81
|
-
|
|
82
|
-
## 🔧 故障修复:历史加载失败(`…turn-tail… received an update before its start Match`)
|
|
83
|
-
|
|
84
|
-
0.2.4 及之前版本在回退**之后继续对话**的场景下会损坏会话的客户端重放:标记的 turn 号
|
|
85
|
-
与下一条真实回合的 `turn/start` 编号冲突,重新打开会话时界面报
|
|
86
|
-
`历史加载失败:conversation Context …:turn-tail… received an update before its start Match(internal)`,
|
|
87
|
-
历史整段消失。0.2.5 起新的回退不再产生该冲突;但**已损坏的会话需要离线修复**(日志是
|
|
88
|
-
append-only 的,不能在内存中改写)。
|
|
89
|
-
|
|
90
|
-
修复工具**已随 npm 包发布**(`dsh-rewind-repair`)——无需下载源码:
|
|
38
|
+
## 安装
|
|
91
39
|
|
|
92
40
|
```sh
|
|
93
|
-
|
|
94
|
-
# 2. 运行离线修复(扫描 ~/.dsh/sessions 下所有会话,把标记 turn 改回最后一个已开始的回合)
|
|
95
|
-
npm exec --yes --package=dsh-rewind-plugin -- dsh-rewind-repair
|
|
96
|
-
npm exec --yes --package=dsh-rewind-plugin -- dsh-rewind-repair -- --dry-run # 只预览不写盘
|
|
97
|
-
# 3. 重启 dsh web,损坏的会话即可正常加载历史
|
|
41
|
+
dsh plugin --profile web add dsh-rewind-plugin
|
|
98
42
|
```
|
|
99
43
|
|
|
100
|
-
|
|
101
|
-
源码方式为 `node scripts/repair-markers.mjs`(参数相同)。
|
|
102
|
-
|
|
103
|
-
工具只改写 `dsh-rewind` 空标记事件的 `data.turn` 字段(保持 seq / 顺序 / zstd 帧结构不变),
|
|
104
|
-
改前自动备份原文件为 `session.jsonl.zstd.bak-<时间戳>`;不改动任何其它事件,可安全重复运行。
|
|
44
|
+
装完重启 `dsh web`(`--profile web`)。
|
|
105
45
|
|
|
106
|
-
|
|
46
|
+
> ⚠️ npm 上的 `dsh-rewind` 属于其他作者,请用 `dsh-rewind-plugin` 安装。
|
|
107
47
|
|
|
108
|
-
|
|
48
|
+
给贡献者:可从本地 checkout 或 pin 的 commit 安装——`dsh plugin --profile web add /path/to/dsh-rewind` 或 `dsh plugin --profile web add github:SiriLee/dsh-rewind#<sha>`。git 安装首次会失败:pnpm 默认禁止 git 依赖执行构建脚本,需先在 profile 的 `pnpm-workspace.yaml` 加 `allowBuilds`;之后 pnpm 会执行插件的 `prepare`(完整构建)并装入 profile。
|
|
109
49
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
### 方式 A:registry(推荐)
|
|
50
|
+
## 使用
|
|
113
51
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
52
|
+
1. **hover** 任意你发送过的用户消息——操作行出现 **↶ 回退** 按钮。
|
|
53
|
+
2. **点击它。** 目标即这条消息;小浮层提供两种模式(目标之后没有跟踪的变更时,「回退对话和代码」不显示)。
|
|
54
|
+
3. 回退以一条会话内命令执行;结果消息确认,被撤回消息的文本自动填入输入框,可编辑后重发。
|
|
117
55
|
|
|
118
|
-
|
|
56
|
+
↶ 按钮只出现在**当前会话视图**渲染的用户消息行上——回退其他会话前先切换到该会话。回退本身可再回退(标记进入日志),但文件还原动作不再记录新备份。
|
|
119
57
|
|
|
120
|
-
|
|
121
|
-
cd dsh-rewind
|
|
122
|
-
npm install # devDeps 来自 npm registry,无需 harness checkout
|
|
123
|
-
npm run build # 完整构建:lib/(host ESM + client bundle + .d.ts)
|
|
124
|
-
dsh plugin --profile web add /path/to/dsh-rewind # link 安装
|
|
125
|
-
```
|
|
58
|
+
## 原理
|
|
126
59
|
|
|
127
|
-
###
|
|
60
|
+
### 1. 对话回退(同窗口就地)
|
|
128
61
|
|
|
129
|
-
|
|
130
|
-
dsh plugin --profile web add github:SiriLee/dsh-rewind#<commit-sha>
|
|
131
|
-
```
|
|
62
|
+
插件向会话日志追加一条**空内容标记** `assistant/message`,其 `surfaceOp: { op: 'replace', start, end }` 把目标消息之后的全部 surface 节点替换为标记本身:
|
|
132
63
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
`
|
|
64
|
+
- 标记携带 `sourceEventSeqs` 覆盖所有被遮蔽节点,`Session.append` 的 surface 规则校验切割合法性(仅限当前 surface 上的连续区间)。
|
|
65
|
+
- 因为标记**内容为空**,harness 会将其派生为 `null`——永不进入模型上下文、也永不渲染成对话内容。agent 与用户看到的对话都回到目标消息当时的样子。
|
|
66
|
+
- 标记的 **turn 号复用最后一个已开始的回合**(`markerTurnOf`),而不是「最后回合 + 1」:harness 恰好用 `最后 turn/start + 1` 编号下一条真实回合。若标记也取这个数,日志里就会出现同一 turn 的 `assistant/message` 先于 `turn/start` 的乱序,客户端 conversation 构建器会以 `conversation Context …:turn-tail… received an update before its start Match` 拒绝重放——历史加载失败、整个对话从界面消失。复用已消费的 turn 号则标记只是上一个已完成回合尾部的一次无害追加,永不与新回合冲突。
|
|
67
|
+
- append-only 日志**不被改写**——审计轨迹完整保留每条被撤回的事件,只有模型可见的 surface 被剪掉,下一条请求从目标消息起派生上下文。
|
|
136
68
|
|
|
137
|
-
|
|
69
|
+
若 agent 正在运行(LLM 思考/流式输出),会先强制停止(`cancel({ kind: 'user' })`)并等待 quiescence 再回退;停不下来则中止并报错。
|
|
138
70
|
|
|
139
|
-
###
|
|
71
|
+
### 2. Checkpoint 文件还原
|
|
140
72
|
|
|
141
|
-
|
|
142
|
-
2. **点击它。** 目标即这条消息(第一步完成)。弹出小浮层(第二步):
|
|
143
|
-
- **仅回退对话** —— 把模型上下文剪回这条消息之前;工作区文件不动。
|
|
144
|
-
- **回退对话和代码** —— 同样的上下文裁剪,并把工作区文件还原到该消息之前的状态。先显示影响清单(待还原/删除的文件),确认后执行。
|
|
145
|
-
- 目标之后**没有**跟踪的文件变更时,该选项**不显示**(对齐 Claude Code 行为)。
|
|
146
|
-
3. 回退以一条会话内命令执行;结果消息确认(如「已撤回 seq N 及之后内容;还原 M 个文件」),被撤回消息的文本自动填入输入框,可编辑后重发。
|
|
73
|
+
插件跟踪写类工具:`write`、`edit`、`str_replace_editor`(变更子命令 `create` / `str_replace` / `insert`):
|
|
147
74
|
|
|
148
|
-
|
|
75
|
+
1. **写前备份**(`tools/execute`,around-dispatch 阶段):读取目标文件,把解析后的路径与内容放入 pending 表。此阶段只在任何 pre-execute 审批门放行之后运行——审批 `ask` 短路(dsh-edit-approval)**无法跳过**备份,被拒绝的调用也不会记录。若读取失败(如权限错误),该次变更直接不入备份——插件只在日志中警告,**不会阻塞写操作**。
|
|
76
|
+
2. **落盘提交**(`tools/post-execute`):备份按当前轮**锚点消息 seq** 写入 `~/.dsh/rewind-snapshots/<会话>/<锚点 seq>/<callId>.json`。
|
|
77
|
+
3. **还原**(`/rewind @<seq> both`):锚点 ≥ 目标的每条备份生效——被修改的文件写回其**最早一次**捕获的 before 内容,目标之后新建的文件被删除,符号/硬链接跳过(它们与另一名字共享 inode,透过一个还原会误伤两个)。写入走纯 `node:fs`,不经 fs 服务——sandbox / 远程 backend 下路径解析可能受限。
|
|
78
|
+
4. 工具体**抛异常**会跳过 `tools/post-execute`;`tools/result` 兜底清掉 pending,避免内存泄漏。
|
|
149
79
|
|
|
150
|
-
|
|
80
|
+
备份跨 host 重启持久化,每会话有界保留最近 100 组锚点。
|
|
151
81
|
|
|
152
|
-
|
|
82
|
+
## 明确不做的事
|
|
153
83
|
|
|
154
|
-
|
|
84
|
+
- **整树 / git-first 快照**——只备份写类工具编辑。`bash`、其他工具与外部程序的修改不在备份内、无法还原:与 Claude Code 相同,官方同样不覆盖,此类回退交由用户 git 处理。
|
|
85
|
+
- **子代理(subagent)的编辑**——不跟踪(同 Claude Code):子代理运行在自己的会话里,其备份无法被父会话的回退还原。
|
|
86
|
+
- **fork / 分支回退与 `/compact`**——harness 已内置(「在新对话中分支」、compact)。
|
|
87
|
+
- **快捷键**(esc+esc 打开回退菜单)——规划中的后续项。
|
|
155
88
|
|
|
156
|
-
##
|
|
89
|
+
## 与同类项目对比
|
|
157
90
|
|
|
158
|
-
|
|
159
|
-
- **子代理(subagent)的编辑不跟踪**——与 Claude Code 相同。子代理运行在自己的会话里,其备份无法被父会话的回退还原;插件直接跳过捕获,而不是记录到永远读不到的位置。
|
|
160
|
-
- 写前备份读取失败时(如权限错误)该次变更不会入备份,`both` 回退无法还原它——插件会在日志中警告,但**不会阻塞写操作**。
|
|
161
|
-
- 文件还原/删除直写**真实本地文件系统**;sandbox / 远程 backend 下路径解析可能受限。
|
|
162
|
-
- 符号链接与硬链接不写入(它们与另一名字共享 inode,还原会互相污染)——跳过并在结果中提示。
|
|
163
|
-
- 回退本身可再回退(标记进入日志),但文件还原动作不再记录新备份。
|
|
164
|
-
- ↶ 按钮只出现在**当前会话视图**渲染的用户消息行上;回退其他会话前先切换到该会话。
|
|
165
|
-
- 目标之后没有跟踪的文件变更时,模式浮层只显示「仅回退对话」(Claude Code 同样隐藏 code-restore 选项)。
|
|
91
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 还有 [Anionex/dsh-turn-rewind](https://github.com/Anionex/dsh-turn-rewind)——同样是回退插件,用户面想法相同(每条消息下挂一个动作,回退对话并还原工作区文件),但路线不同:
|
|
166
92
|
|
|
167
|
-
|
|
93
|
+
| 维度 | dsh-rewind(本项目) | Anionex dsh-turn-rewind |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| 对话回退 | **同窗口就地**——把模型可见 surface 剪回目标;append-only 日志原封不动 | 在上一 `turn/end` 处**派生新 Session**;原会话永远保留 |
|
|
96
|
+
| 文件还原引擎 | **轻量写前备份**,只跟踪写类工具,纯 `node:fs` 还原 | **Change Ledger**——持久化还原点引擎,带 Git 围栏、审批门、救援点与崩溃对账 |
|
|
97
|
+
| 跟踪范围 | 仅写类工具编辑(同 Claude Code) | 任意 Git 管理文件(要求 Git worktree) |
|
|
98
|
+
| 公共服务 API | 无——聚焦单用途插件 | 有——`ctx.changeLedger` 服务 + `/turn-rewind` HTTP 端点 |
|
|
168
99
|
|
|
169
|
-
-
|
|
170
|
-
- `/compact` —— harness 已内置。
|
|
171
|
-
- fork / 分支回退 —— harness 内置的「在新对话中分支」。
|
|
172
|
-
- 整树 / git-first 快照(覆盖 bash 与外部修改)——**明确不做**,与 Claude Code 原生 rewind 保持一致(官方同样不覆盖,把此类回退交给用户 git)。
|
|
100
|
+
本质区别:dsh-turn-rewind 因保持日志不可变而必须派生新会话;本插件用空标记**就地剪掉**模型可见 surface,于是原对话在同一个窗口继续——这段并不平凡的实现(见[已知问题](#已知问题))正是 dsh-turn-rewind 绕开的部分。
|
|
173
101
|
|
|
174
102
|
## 兼容性
|
|
175
103
|
|
|
@@ -180,63 +108,40 @@ dsh plugin --profile web add github:SiriLee/dsh-rewind#<commit-sha>
|
|
|
180
108
|
> 本项目与 DeepSeek Harness 均处于开发者预览阶段。可复现环境请 pin 精确版本,
|
|
181
109
|
> 并阅读上述行为说明。
|
|
182
110
|
|
|
111
|
+
## 已知问题
|
|
112
|
+
|
|
113
|
+
`v0.2.4` 及之前版本创建的回退在随后继续对话时可能损坏客户端重放(标记 turn 与下一个 `turn/start` 撞号)。离线修复工具**已随 npm 包内置**(`dsh-rewind-repair`)。只影响升级前就已存在的旧会话——全新安装永不触发。
|
|
114
|
+
|
|
115
|
+
完整步骤见:[docs/troubleshooting.zh.md](docs/troubleshooting.zh.md)
|
|
116
|
+
|
|
117
|
+
## 安全
|
|
118
|
+
|
|
119
|
+
本插件只向会话日志追加回退标记事件,从不删除或改写已记录的历史。文件写入仅在你选择「回退对话和代码」时发生,备份与还原都限定在 `~/.dsh/rewind-snapshots/` 内。不触碰你的 git 仓库,无网络请求,不访问任何凭据。
|
|
120
|
+
|
|
183
121
|
## 开发
|
|
184
122
|
|
|
185
123
|
```sh
|
|
186
124
|
npm install # devDeps 来自 npm registry
|
|
187
125
|
npm run typecheck # tsc 双面编译(host + client)
|
|
188
|
-
npm test # vitest:rewind / snapshot / hidden / session-cwd /
|
|
126
|
+
npm test # vitest:rewind / snapshot / hidden / session-cwd / 集成
|
|
189
127
|
npm run build # esbuild:lib/index.js(host ESM)+ lib/client.js(loader 闭包)+ .d.ts
|
|
190
128
|
node scripts/verify-host.mjs # 端到端验证构建产物(18 项检查)
|
|
191
129
|
```
|
|
192
130
|
|
|
193
|
-
`prepare` 执行完整构建,所以 git 安装与 `npm pack` / `npm publish` 总会产出完整的
|
|
194
|
-
`lib/` 与 `LICENSE`。
|
|
131
|
+
`prepare` 执行完整构建,所以 git 安装与 `npm pack` / `npm publish` 总会产出完整的 `lib/` 与 `LICENSE`。
|
|
195
132
|
|
|
196
|
-
|
|
197
|
-
Harness 接口文档(子系统文档 + 关键源码索引)。
|
|
133
|
+
维护者:模块地图与 harness 接口参考见 [docs/harness-reference.md](docs/harness-reference.md);发布步骤见 [docs/release.md](docs/release.md)。
|
|
198
134
|
|
|
199
135
|
## 发布
|
|
200
136
|
|
|
201
|
-
通过 GitHub Actions Trusted Publishing(OIDC,无存储 `NPM_TOKEN
|
|
137
|
+
通过 GitHub Actions Trusted Publishing(OIDC,无存储 `NPM_TOKEN`)发布:推送 `v<版本>` tag,CI 即带 Sigstore provenance 发布。
|
|
202
138
|
|
|
203
139
|
```sh
|
|
204
|
-
npm version patch && git push origin main --tags
|
|
140
|
+
npm version patch && git push origin main --tags
|
|
205
141
|
```
|
|
206
142
|
|
|
207
|
-
|
|
208
|
-
产物验证,以 `--provenance`(Sigstore)发布,并创建 GitHub Release。**幂等**——
|
|
209
|
-
已发布的版本会跳过。CI(`.github/workflows/ci.yml`)在每次 push / PR 跑相同检查,
|
|
210
|
-
外加 `npm pack --dry-run` 校验 tarball 含 `lib/` 与 `LICENSE`。
|
|
211
|
-
- 一次性 npm 侧配置(仓库内无法代做):打开
|
|
212
|
-
[dsh-rewind-plugin](https://www.npmjs.com/package/dsh-rewind-plugin) →
|
|
213
|
-
**settings → Trusted Publisher → Add**,Provider **GitHub Actions** ·
|
|
214
|
-
Organization or user **`SiriLee`** · Repository **`dsh-rewind`**(GitHub 仓库名,
|
|
215
|
-
与 npm 包名可不同)· Workflow filename **`publish.yml`** · Environment
|
|
216
|
-
**留空** · Allowed actions **`npm publish`**。配置好后 push `v<version>` tag
|
|
217
|
-
即自动发布。
|
|
218
|
-
|
|
219
|
-
## 目录结构
|
|
220
|
-
|
|
221
|
-
```
|
|
222
|
-
src/index.ts host 插件:/rewind 命令 + checkpoint 流水线(tools/execute|post-execute)
|
|
223
|
-
src/rewind.ts 纯函数规划:目标解析、surface 范围、候选列表
|
|
224
|
-
src/snapshot.ts checkpoint 存储(磁盘写前备份、还原/preview、有界清理)
|
|
225
|
-
src/session-cwd.ts session-cwd 解析(fs-tools 规则)
|
|
226
|
-
src/client/index.ts client 插件:消息行 ↶ 按钮 + 手动 /rewind 拦截
|
|
227
|
-
src/client/popover.ts 模式选择浮层(both 模式影响清单确认)
|
|
228
|
-
src/client/hidden.ts 被撤回区间计算(hiddenSeqsOf),纯函数
|
|
229
|
-
src/client/locales.ts zh / en 文案(LocaleNamespaceMap)
|
|
230
|
-
src/client/styles.ts 注入样式(dsh 设计 token)
|
|
231
|
-
scripts/build.mjs esbuild:lib/index.js(host ESM)+ lib/client.js(loader 闭包)+ .d.ts
|
|
232
|
-
scripts/verify-host.mjs 端到端验证构建产物(18 项检查)
|
|
233
|
-
tests/ vitest 套件(rewind / snapshot / hidden / session-cwd / 集成,46 例)
|
|
234
|
-
docs/harness-reference.md 维护者文档:DeepSeek Harness 接口参考
|
|
235
|
-
assets/screenshots/ 界面截图
|
|
236
|
-
cordis.patch.yml bundle patch(挂载双面插件行)
|
|
237
|
-
package.json dsh.bundle + dsh.client 声明、optional peerDependencies
|
|
238
|
-
```
|
|
143
|
+
一次性 npm 侧配置与完整流程:见 [docs/release.md](docs/release.md)。
|
|
239
144
|
|
|
240
|
-
##
|
|
145
|
+
## 许可
|
|
241
146
|
|
|
242
147
|
[MIT](LICENSE)
|
|
@@ -32,3 +32,26 @@ Also under `docs/` at the repo root: `persistence-catalog.md` (full
|
|
|
32
32
|
| User bubble rendering | [packages/client/ui-conversation/src/client/chat/MessageItem.tsx](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/client/ui-conversation/src/client/chat/MessageItem.tsx) |
|
|
33
33
|
| Client `SessionFace` (`command` / `cancel`) | [packages/client/runtime/src/client/contract/session.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/client/runtime/src/client/contract/session.ts) |
|
|
34
34
|
| Client `PendingWait` (`respond`) | [packages/client/runtime/src/client/sessions/pending.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/client/runtime/src/client/sessions/pending.ts) |
|
|
35
|
+
|
|
36
|
+
## Plugin source layout
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
src/index.ts host plugin: /rewind command + checkpoint pipeline (tools/execute|post-execute)
|
|
40
|
+
src/rewind.ts pure planning: target resolution, surface range, candidate listing
|
|
41
|
+
src/snapshot.ts checkpoint store (disk before-backups, restore/preview, bounded prune)
|
|
42
|
+
src/session-cwd.ts session-cwd resolution (fs-tools rule)
|
|
43
|
+
src/client/index.ts client plugin: per-message ↶ button + manual /rewind guard
|
|
44
|
+
src/client/popover.ts mode-selection popover (both-mode impact confirm)
|
|
45
|
+
src/client/hidden.ts withdrawn-span computation (hiddenSeqsOf), pure
|
|
46
|
+
src/client/locales.ts zh / en copy (LocaleNamespaceMap)
|
|
47
|
+
src/client/styles.ts injected styles (dsh design tokens)
|
|
48
|
+
scripts/build.mjs esbuild: lib/index.js (host ESM) + lib/client.js (loader closure) + .d.ts
|
|
49
|
+
scripts/verify-host.mjs end-to-end host verification (18 checks)
|
|
50
|
+
scripts/repair-markers.mjs offline marker-turn repair tool (ships as `dsh-rewind-repair`)
|
|
51
|
+
tests/ vitest suites (rewind / snapshot / hidden / session-cwd / integration)
|
|
52
|
+
docs/ maintainer docs: harness reference, troubleshooting, release steps
|
|
53
|
+
assets/screenshots/ UI screenshots
|
|
54
|
+
cordis.patch.yml bundle patch (mounts the dual-face plugin row)
|
|
55
|
+
package.json dsh.bundle + dsh.client manifests, optional peerDependencies
|
|
56
|
+
```
|
|
57
|
+
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Release
|
|
2
|
+
|
|
3
|
+
## First release (manual, one-time)
|
|
4
|
+
|
|
5
|
+
Trusted Publisher can only be configured once the package exists, so the first
|
|
6
|
+
version is published locally:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm login
|
|
10
|
+
npm publish --access public
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- If prompted for `EOTP`: complete the browser auth link the CLI prints, or
|
|
14
|
+
retry with a 6-digit code — `npm publish --otp=<code>`.
|
|
15
|
+
- The first version carries no provenance (local path) — acceptable; every CI
|
|
16
|
+
release after that publishes with Sigstore/SLSA provenance automatically.
|
|
17
|
+
|
|
18
|
+
## Configure Trusted Publisher (npmjs.com, one-time)
|
|
19
|
+
|
|
20
|
+
Open `https://www.npmjs.com/package/dsh-rewind-plugin` → package **settings** →
|
|
21
|
+
**Trusted Publisher**:
|
|
22
|
+
|
|
23
|
+
| Field | Value |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Provider | GitHub Actions |
|
|
26
|
+
| Organization or user | `SiriLee` |
|
|
27
|
+
| Repository | `dsh-rewind` (the GitHub repo, not the npm name) |
|
|
28
|
+
| Workflow filename | `publish.yml` |
|
|
29
|
+
| Environment | empty |
|
|
30
|
+
| Allowed actions | `npm publish` |
|
|
31
|
+
|
|
32
|
+
## Subsequent releases (CI, automatic)
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm version patch
|
|
36
|
+
git push origin main --tags # triggers .github/workflows/publish.yml
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- The workflow verifies the tag matches `package.json`, runs typecheck + tests +
|
|
40
|
+
a full build + artifact verification, publishes with `--provenance`
|
|
41
|
+
(Sigstore), and creates a GitHub Release. It is **idempotent** — an already
|
|
42
|
+
published version is skipped.
|
|
43
|
+
- CI (`.github/workflows/ci.yml`) runs the same checks on every push / PR, plus
|
|
44
|
+
a `npm pack --dry-run` sanity check that the tarball carries `lib/` and
|
|
45
|
+
`LICENSE`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
# 发布流程
|
|
50
|
+
|
|
51
|
+
## 首次发布(手动,一次性)
|
|
52
|
+
|
|
53
|
+
Trusted Publisher 要求**包已存在**才能配置,因此首个版本走本地发布:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npm login
|
|
57
|
+
npm publish --access public
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- 若提示 `EOTP`(一次性密码):按 CLI 输出的浏览器认证链接完成认证,或用
|
|
61
|
+
authenticator 的 6 位码 `npm publish --otp=<code>` 重试。
|
|
62
|
+
- 首个版本无 provenance(本地路径),合规;之后每次 CI 发布自动带
|
|
63
|
+
Sigstore/SLSA provenance。
|
|
64
|
+
|
|
65
|
+
## 配置 Trusted Publisher(npmjs.com,一次性)
|
|
66
|
+
|
|
67
|
+
打开 `https://www.npmjs.com/package/dsh-rewind-plugin` → 包右上角 **settings**
|
|
68
|
+
→ **Trusted Publisher**:
|
|
69
|
+
|
|
70
|
+
| 字段 | 值 |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| Provider | GitHub Actions |
|
|
73
|
+
| Organization or user | `SiriLee` |
|
|
74
|
+
| Repository | `dsh-rewind`(GitHub 仓库名,与 npm 包名可不同) |
|
|
75
|
+
| Workflow filename | `publish.yml` |
|
|
76
|
+
| Environment | 留空 |
|
|
77
|
+
| Allowed actions | `npm publish` |
|
|
78
|
+
|
|
79
|
+
## 后续发布(CI 自动)
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
npm version patch
|
|
83
|
+
git push origin main --tags # 触发 .github/workflows/publish.yml
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- workflow 校验 tag 与 `package.json` 版本一致,跑 typecheck + 测试 + 完整
|
|
87
|
+
构建 + 产物验证,以 `--provenance`(Sigstore)发布并创建 GitHub Release。
|
|
88
|
+
**幂等**——已发布的版本会跳过。
|
|
89
|
+
- CI(`.github/workflows/ci.yml`)在每次 push / PR 跑相同检查,外加
|
|
90
|
+
`npm pack --dry-run` 校验 tarball 含 `lib/` 与 `LICENSE`。
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
[简体中文](troubleshooting.zh.md)
|
|
4
|
+
|
|
5
|
+
## History load failure: `…turn-tail… received an update before its start Match`
|
|
6
|
+
|
|
7
|
+
Versions `≤ 0.2.4` corrupted client replay when a rewind was **followed by further
|
|
8
|
+
conversation**: the marker's turn number collided with the next real turn's
|
|
9
|
+
`turn/start`, so reopening the session showed
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Failed to load history: conversation Context …:turn-tail… received an update before its start Match (internal)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
and the history vanished. Rewinds created from `0.2.5` on no longer produce the
|
|
16
|
+
collision, but **already-corrupted sessions need an offline repair** (the log is
|
|
17
|
+
append-only — it cannot be rewritten in memory).
|
|
18
|
+
|
|
19
|
+
The repair tool ships **inside the npm package** (`dsh-rewind-repair`) — no
|
|
20
|
+
source checkout needed:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
# 1. Fully quit dsh web / host first (while a session is resident in memory,
|
|
24
|
+
# a disk repair is overwritten by the next checkpoint)
|
|
25
|
+
# 2. Run the offline repair (scans every session under ~/.dsh/sessions,
|
|
26
|
+
# rewriting each marker's turn back to the last started turn)
|
|
27
|
+
npm exec --yes --package=dsh-rewind-plugin -- dsh-rewind-repair
|
|
28
|
+
npm exec --yes --package=dsh-rewind-plugin -- dsh-rewind-repair -- --dry-run # preview only
|
|
29
|
+
# 3. Restart dsh web — the repaired sessions load their history again
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or install it globally once (`npm i -g dsh-rewind-plugin`) and run
|
|
33
|
+
`dsh-rewind-repair` directly; from a source checkout the same tool is
|
|
34
|
+
`node scripts/repair-markers.mjs` (identical flags).
|
|
35
|
+
|
|
36
|
+
The tool only rewrites the `data.turn` of `dsh-rewind` empty-marker events
|
|
37
|
+
(keeping seqs, order, and the zstd frame structure intact), backs up the original
|
|
38
|
+
file to `session.jsonl.zstd.bak-<timestamp>` before writing, and never touches
|
|
39
|
+
any other event — safe to run repeatedly.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 故障修复
|
|
2
|
+
|
|
3
|
+
[English](troubleshooting.md)
|
|
4
|
+
|
|
5
|
+
## 历史加载失败:`…turn-tail… received an update before its start Match`
|
|
6
|
+
|
|
7
|
+
0.2.4 及之前版本在回退**之后继续对话**的场景下会损坏会话的客户端重放:标记的 turn 号
|
|
8
|
+
与下一条真实回合的 `turn/start` 编号冲突,重新打开会话时界面报
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
历史加载失败:conversation Context …:turn-tail… received an update before its start Match(internal)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
历史整段消失。0.2.5 起新的回退不再产生该冲突;但**已损坏的会话需要离线修复**(日志是
|
|
15
|
+
append-only 的,不能在内存中改写)。
|
|
16
|
+
|
|
17
|
+
修复工具**已随 npm 包发布**(`dsh-rewind-repair`)——无需下载源码:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
# 1. 先完全退出 dsh web / host(会话处于驻留内存时,磁盘修复会被下次 checkpoint 覆盖)
|
|
21
|
+
# 2. 运行离线修复(扫描 ~/.dsh/sessions 下所有会话,把标记 turn 改回最后一个已开始的回合)
|
|
22
|
+
npm exec --yes --package=dsh-rewind-plugin -- dsh-rewind-repair
|
|
23
|
+
npm exec --yes --package=dsh-rewind-plugin -- dsh-rewind-repair -- --dry-run # 只预览不写盘
|
|
24
|
+
# 3. 重启 dsh web,损坏的会话即可正常加载历史
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
也可以全局安装一次(`npm i -g dsh-rewind-plugin`)后直接运行 `dsh-rewind-repair`;
|
|
28
|
+
源码方式为 `node scripts/repair-markers.mjs`(参数相同)。
|
|
29
|
+
|
|
30
|
+
工具只改写 `dsh-rewind` 空标记事件的 `data.turn` 字段(保持 seq / 顺序 / zstd 帧结构不变),
|
|
31
|
+
改前自动备份原文件为 `session.jsonl.zstd.bak-<时间戳>`;不改动任何其它事件,可安全重复运行。
|