dsh-rewind-plugin 0.8.0-alpha.1 → 0.9.0-alpha.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.en.md +12 -10
- package/README.md +12 -10
- package/SECURITY.md +6 -7
- package/docs/README.md +2 -1
- package/docs/architecture.md +34 -17
- package/docs/compat/audit.md +9 -9
- package/docs/format.md +11 -8
- package/docs/harness-reference.md +15 -2
- package/docs/release/release.md +10 -8
- package/docs/release/release.zh.md +9 -7
- package/docs/rewind-fix.md +80 -0
- package/docs/rewind-fix.zh.md +80 -0
- package/lib/client.js +1 -1
- package/lib/index.js +519 -47
- package/lib/types/index.d.ts +11 -5
- package/lib/types/locales.d.ts +19 -0
- package/lib/types/rewind-fix.d.ts +109 -0
- package/lib/types/rewind-marker-repair.d.ts +83 -0
- package/lib/types/rewind.d.ts +14 -57
- package/lib/types/session-log-io.d.ts +57 -0
- package/package.json +1 -1
- package/docs/compat/troubleshooting.md +0 -41
- package/docs/compat/troubleshooting.zh.md +0 -29
package/README.en.md
CHANGED
|
@@ -8,6 +8,9 @@ Conversation rewind for DeepSeek Harness: **rewind the conversation to any earli
|
|
|
8
8
|
|
|
9
9
|
> English | [中文](README.md)
|
|
10
10
|
|
|
11
|
+
> [!WARNING]
|
|
12
|
+
> For the upcoming DSH line (v0.1.3), users who want the latest DSH should move to the new plugin (`>=0.9.0-alpha.1`) and update their session logs — see the [update guide](docs/rewind-fix.md).
|
|
13
|
+
|
|
11
14
|
A deliberately focused plugin with one job: **rewind to any user message, no matter how far back, in place** — and conveniently **restore the files it changed** along the way.
|
|
12
15
|
|
|
13
16
|
- **Rewinding is time-travel** — the target message and everything after it (agent replies, tool calls) are withdrawn from the model context *and* the rendered transcript at once, with no new session and no window switch; the target's text is offered back in the composer so you can edit and re-send it — **truly seamless and convenient by design**.
|
|
@@ -91,13 +94,13 @@ The whole design rests on two principles, simple but deliberate: **the conversat
|
|
|
91
94
|
|
|
92
95
|
### 1. Conversation rewind: a single "mask", not a delete
|
|
93
96
|
|
|
94
|
-
`append-only` is a hard rule: the session log only grows and is never rewritten — the foundation of auditability and privacy. A rewind never touches history; it makes a single move: append **one empty
|
|
97
|
+
`append-only` is a hard rule: the session log only grows and is never rewritten — the foundation of auditability and privacy. A rewind never touches history; it makes a single move: append **one content-empty marker message** to the end of the log and use it to "mask + replace" everything after the target message, so the model and the UI see only the part before it.
|
|
95
98
|
|
|
96
|
-
- The marker is **
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
+
- The marker is **canonical** — the plugin **replicates** `/compact`'s "hide + replace": `/compact` compresses a span of history into a summary, while `/rewind` swaps in an empty user message. Because it's canonical, the harness's own log replay, `/compact` compaction, and resume preflight all recognize it and never mistake it for a real message.
|
|
100
|
+
- The replacement is **empty** — the model fully ignores the empty message, with no effect (verified theoretically and empirically). Together with the plugin's UI handling, what you and the model see is exactly how the conversation looked at the target — truly "in place".
|
|
101
|
+
- Because this is **masking, not deleting**, every withdrawn event stays in the log — auditable, traceable, viewable, and in principle manually recoverable.
|
|
99
102
|
|
|
100
|
-
> **Design highlight**: the entire conversation rewind is **a single append**. It's deterministic, auditable, and — because the log was never broken — a "clean" time-travel. Minimal action, complete semantics. The compatibility subtleties with the harness (
|
|
103
|
+
> **Design highlight**: the entire conversation rewind is **a single append**. It's deterministic, auditable, and — because the log was never broken — a "clean" time-travel. Minimal action, complete semantics. The compatibility subtleties with the harness (replicating `/compact`, the empty-message mask) are where this plugin is genuinely professional — each is pinned by a dedicated probe test.
|
|
101
104
|
|
|
102
105
|
### 2. File restore: lightweight checkpointing, "back up before the change"
|
|
103
106
|
|
|
@@ -121,7 +124,7 @@ The file half follows Claude Code's checkpoint semantics — **partial tracking
|
|
|
121
124
|
| Identical content stored as a link (dedup) | Hundreds of repeated writes cost almost nothing; links are materialized before their group is evicted, never left dangling |
|
|
122
125
|
| Session-level auto-cleanup | Removes only long-inactive sessions' snapshots; the active session and the chat log are never touched |
|
|
123
126
|
| Reconcile against the real disk before restoring | Idempotent, zero side effects, no collateral damage |
|
|
124
|
-
|
|
|
127
|
+
| Empty-message mask + replicating `/compact` | Deeply compatible with the host, pinned by probe tests |
|
|
125
128
|
| Crash safety (atomic writes + restore journal) | Continue or roll back cleanly after a crash |
|
|
126
129
|
| Pure-function planning + probed store | Fully unit-testable without a host; test-driven |
|
|
127
130
|
|
|
@@ -154,10 +157,9 @@ withdrew should consume the stable, locale-independent helpers exported from
|
|
|
154
157
|
|
|
155
158
|
1. **Exported logs are complete** — a rewind only removes messages from the model context and the view; the exported session log (`/export`) still contains **withdrawn messages**. This plugin cannot alter exports.
|
|
156
159
|
2. **Lightweight file rewind has a cost** — in specific cases not all changes can be rewound. Consistent with Claude Code. See: [File-rewind tracking boundary](docs/compat/tracking-boundary.md).
|
|
157
|
-
3. **
|
|
158
|
-
4. **
|
|
159
|
-
5. **
|
|
160
|
-
6. **The system prompt is re-displayed after a rewind** — in DSH `v0.1.2`, rewinding and resending a message shows the "System prompt" component again, just like `/compact`. Only a display difference; no functional impact.
|
|
160
|
+
3. **The turn-rail shows rewound turns** — the right-side rail added in DSH `v0.1.2` keeps ticks for withdrawn messages, and hovering shows the withdrawn text. Only a display difference; no functional impact.
|
|
161
|
+
4. **The system prompt is re-displayed after a rewind** — in DSH `v0.1.2`, rewinding and resending a message shows the "System prompt" component again, just like `/compact`. Only a display difference; no functional impact.
|
|
162
|
+
5. **Old rewind markers are no longer compatible** — DSH `v0.1.3` rejects the rewind markers from the old plugin (≤ 0.8.0). The new version resolves this and provides an in-session update. See the [update guide](docs/rewind-fix.md).
|
|
161
163
|
|
|
162
164
|
> [!NOTE]
|
|
163
165
|
> Browser diagnostics are available; see [Browser diagnostics](docs/compat/diagnostics.md).
|
package/README.md
CHANGED
|
@@ -8,6 +8,9 @@ DeepSeek Harness 插件:**一键就地回退对话到任意更早的用户消
|
|
|
8
8
|
|
|
9
9
|
> [English](README.en.md) | 中文
|
|
10
10
|
|
|
11
|
+
> [!WARNING]
|
|
12
|
+
> 为了适配未来版本(DSH v0.1.3),期望使用最新版 DSH 的用户,请尽早使用新版插件(`>=0.9.0-alpha.1`)。并更新你的会话日志,详见:[更新指南](docs/rewind-fix.zh.md)
|
|
13
|
+
|
|
11
14
|
刻意聚焦、保持极简,只做一件事:**就地回退到任意远的用户消息**,还能**顺手还原改过的文件**。
|
|
12
15
|
|
|
13
16
|
- **回退 = 时间回溯**——目标消息及其之后的全部内容(agent 回复、工具调用)同时从**模型上下文**和**渲染对话**中撤回,不新建会话、不切换窗口;目标消息文本会回填输入框,改完可重发。**在原理上就真正无感、便捷**。
|
|
@@ -81,13 +84,13 @@ dsh plugin --profile web add dsh-rewind-plugin
|
|
|
81
84
|
|
|
82
85
|
### 1. 对话回退:一次「遮蔽」,而不是「删除」
|
|
83
86
|
|
|
84
|
-
`append-only`
|
|
87
|
+
`append-only` 是铁律:会话日志只追加、从不改写——这是可审计与信息安全的地基。回退从不动历史,它只做一步:往日志末尾追加一条**内容为空的标记消息**,把目标消息之后的全部内容「遮蔽 + 替换」掉,让模型和界面都只看得到目标之前的部分。
|
|
85
88
|
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
+
- **标记是规范的**——插件复刻 `/compact` 标准的「隐藏 + 替换」:`/compact` 把一段历史压缩成摘要,`/rewind` 则换成一条空用户消息。由于其规范性,harness 的日志重放、`/compact` 压缩、续接检查都能正确识别它,绝不会把它误认为真实对话;
|
|
90
|
+
- **替换内容是空的**——模型对空消息完全忽略、无感(理论 + 实测验证)。配合插件对界面显示的处理,模型和你看到的对话就是目标消息当时的样子,真正的「就地」;
|
|
91
|
+
- 因为是「遮蔽」而非「删除」,**被撤回的每一条事件都完整留在日志里**,可审计、可追溯、可查看,原则上也随时能手动恢复。
|
|
89
92
|
|
|
90
|
-
> **设计点睛**:整个对话回退就是**一条**追加。它确定、可审计,且因为日志从未被破坏,回溯是「干净的」——用最小的动作,实现最完整的语义。那些与 harness
|
|
93
|
+
> **设计点睛**:整个对话回退就是**一条**追加。它确定、可审计,且因为日志从未被破坏,回溯是「干净的」——用最小的动作,实现最完整的语义。那些与 harness 内部的兼容细节(对 `/compact` 的复刻、空消息的遮蔽)正是插件的专业所在,每一条都由专门的探针测试固化。
|
|
91
94
|
|
|
92
95
|
### 2. 文件还原:轻量检查点,「改前备份」
|
|
93
96
|
|
|
@@ -111,7 +114,7 @@ dsh plugin --profile web add dsh-rewind-plugin
|
|
|
111
114
|
| 同内容存为链接(去重) | 上百次重复写入几乎不占空间;淘汰组前先落地链接,绝不悬空 |
|
|
112
115
|
| 会话级自动清理 | 只移除长期不活跃会话的快照,活动会话与对话日志永不触及 |
|
|
113
116
|
| 对照真实磁盘再还原 | 幂等、零副作用、不误伤 |
|
|
114
|
-
|
|
|
117
|
+
| 空消息遮蔽 + 对 `/compact` 的复刻 | 与宿主深度兼容,且被探针测试固化 |
|
|
115
118
|
| 崩溃安全(原子写 + 还原日志) | 断电/崩溃后仍可续做或回滚 |
|
|
116
119
|
| 纯函数规划 + 注入探针的存储 | 无需宿主即可单测,测试驱动 |
|
|
117
120
|
|
|
@@ -141,10 +144,9 @@ dsh plugin --profile web add dsh-rewind-plugin
|
|
|
141
144
|
|
|
142
145
|
1. **导出的日志是完整内容**——回退只是把消息从模型上下文和视图中移除,`/export` 导出的会话日志包含**已撤回的消息**。本插件无法改动导出。
|
|
143
146
|
2. **轻量文件回退存在代价**——特定情况可能无法回退所有修改。行为与 Claude Code 一致。详见:[文件回退的追踪边界](docs/compat/tracking-boundary.zh.md)。
|
|
144
|
-
3.
|
|
145
|
-
4.
|
|
146
|
-
5.
|
|
147
|
-
6. **回退重显系统提示词**——DSH `v0.1.2` 回退重发消息时,与 `/compact` 一样重显“系统提示词”组件。仅显示差异,无功能影响。
|
|
147
|
+
3. **导轨显示已回退轮次**——DSH `v0.1.2` 新增右侧导轨,为已撤回消息保留刻度,悬浮显示已撤回正文。仅显示差异,无功能影响。
|
|
148
|
+
4. **回退重显系统提示词**——DSH `v0.1.2` 回退重发消息时,与 `/compact` 一样重显“系统提示词”组件。仅显示差异,无功能影响。
|
|
149
|
+
5. **旧回退标记不再兼容**——DSH `v0.1.3` 拒绝旧版插件(≤ 0.8.0)的回退标记。新版本已解决,并提供会话更新功能。详见:[更新指南](docs/rewind-fix.zh.md)。
|
|
148
150
|
|
|
149
151
|
> [!NOTE]
|
|
150
152
|
> 本插件提供浏览器端诊断输出;详见 [浏览器诊断](docs/compat/diagnostics.zh.md)。
|
package/SECURITY.md
CHANGED
|
@@ -70,14 +70,13 @@ runs.
|
|
|
70
70
|
## Conversation integrity
|
|
71
71
|
|
|
72
72
|
The session log is **append-only** — the plugin never deletes or rewrites
|
|
73
|
-
recorded history. A rewind appends a single marker event
|
|
74
|
-
`
|
|
75
|
-
|
|
73
|
+
recorded history. A rewind appends a single marker event (an **empty**
|
|
74
|
+
`user/message`) whose `surfaceOp` replaces every surface node after the target.
|
|
75
|
+
The raw log (audit trail, search, `/export`) is untouched — only the
|
|
76
76
|
model-visible surface is cut, so the next request derives its context from the
|
|
77
|
-
target onward. The marker
|
|
78
|
-
the
|
|
79
|
-
|
|
80
|
-
and is repaired offline (see `docs/compat/troubleshooting.md`).
|
|
77
|
+
target onward. The marker is empty, so it carries no untrusted text into the
|
|
78
|
+
model context; the client hides the `[target, marker]` span from the rendered
|
|
79
|
+
transcript.
|
|
81
80
|
|
|
82
81
|
## Filesystem containment
|
|
83
82
|
|
package/docs/README.md
CHANGED
|
@@ -12,9 +12,10 @@ index/navigation entry point.
|
|
|
12
12
|
| `format.md` | Durable on-disk format spec (checkpoint entries + restore journals) | maintainers |
|
|
13
13
|
| `harness-reference.md` | DeepSeek Harness interface reference + plugin source layout | maintainers |
|
|
14
14
|
| `snapshot-auto-cleanup.md` | Global snapshot auto-cleanup policy and command (`.zh` mirror) | users / maintainers |
|
|
15
|
+
| `rewind-fix.md` | Migrate old rewind markers (A/B→C) with `/dsh-rewind-fix` (`.zh` mirror) | users / maintainers |
|
|
15
16
|
| `contract/client-contract.md` | Rewind visibility contract for third-party DOM plugins (`.zh` mirror) | integrators |
|
|
16
17
|
| `compat/audit.md` | Compatibility audit: verified surfaces, recorded findings, probe matrix | maintainers |
|
|
17
|
-
| `compat/
|
|
18
|
+
| `compat/tracking-boundary.md` | Which files a rewind restores: the tracking boundary (`.zh` mirror) | users / maintainers |
|
|
18
19
|
| `compat/diagnostics.md` | Browser diagnostics (anomaly alerts; verbose switch gates the startup identity line) (`.zh` mirror) | users / maintainers |
|
|
19
20
|
| `release/release.md` | Release workflow & DSH peer-version alignment (`.zh` mirror) | maintainers |
|
|
20
21
|
|
package/docs/architecture.md
CHANGED
|
@@ -17,15 +17,20 @@ credentials access.
|
|
|
17
17
|
|
|
18
18
|
```
|
|
19
19
|
src/
|
|
20
|
-
├── index.ts host plugin: /rewind
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
├── index.ts host plugin: /rewind, /undo, /snapshot-auto-cleanup,
|
|
21
|
+
│ /dsh-rewind-fix commands + checkpoint pipeline
|
|
22
|
+
├── rewind.ts pure planning: target parsing, surface-range plan, candidate listing
|
|
23
|
+
├── rewind-fix.ts /dsh-rewind-fix orchestration (repair pipeline, locks, rollback)
|
|
24
|
+
├── rewind-marker-repair.ts pure legacy-marker transform (A/B → C)
|
|
25
|
+
├── session-log-io.ts session-log zstd codec + lossless re-encoder (rewind-fix write-back)
|
|
23
26
|
├── snapshot.ts checkpoint store: disk before-backups, journaled restore,
|
|
24
27
|
│ reconcile / continue / rollback, bounded prune
|
|
28
|
+
├── snapshot-cleanup.ts cleanup policy + dsh-settings persistence + auto-sweep throttle
|
|
25
29
|
├── session-cwd.ts session working-directory resolution (fs-tools rule)
|
|
30
|
+
├── locales.ts host i18n (t() renderer, HostKey)
|
|
26
31
|
└── client/ browser half: per-message ↶ button (portal bridge),
|
|
27
32
|
mode popover, hidden-span computation, candidate parsing,
|
|
28
|
-
locales, styles
|
|
33
|
+
pending interaction, locales, styles
|
|
29
34
|
```
|
|
30
35
|
|
|
31
36
|
Two dependency rules keep the design testable:
|
|
@@ -48,11 +53,9 @@ machine channels (see [Compatibility strategy](#compatibility-strategy)).
|
|
|
48
53
|
user/message currently on the surface)
|
|
49
54
|
→ agent.cancel({ keepInbox: true }) if running; waitForAgentIdle
|
|
50
55
|
→ dropPendingSteering (next-step inbox only; queued messages untouched)
|
|
51
|
-
→ append
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
surfaceOp { op: 'replace', start, end } over every surface node
|
|
55
|
-
after the target (+ sourceEventSeqs = shadowed seqs)
|
|
56
|
+
→ append the rewind marker = an empty user/message with surfaceOp
|
|
57
|
+
{ op: 'replace', start, end } over every surface node after the
|
|
58
|
+
target (+ sourceEventSeqs = shadowed seqs) [a single event]
|
|
56
59
|
→ if mode 'both': store.restoreAfter(targetSeq) + syncRestoreObservations
|
|
57
60
|
→ result text carries machine tokens (impact=<n>, restore:/delete: lines)
|
|
58
61
|
→ client: hides withdrawn rows (data-dsh-rewind-hidden), refills composer
|
|
@@ -63,18 +66,32 @@ Key invariants:
|
|
|
63
66
|
|
|
64
67
|
- **The log is append-only.** The marker is the *only* mutation: it cuts the
|
|
65
68
|
model-visible surface, never the raw history (search/export still see it).
|
|
66
|
-
- **The marker is empty** (`content: []
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
- **The marker is empty** (`content: []`) and carries the dsh-rewind plugin
|
|
70
|
+
source. It is a `user/message`, the only surface type that can cite the
|
|
71
|
+
shadowed seqs (`sourceEventSeqs`) — `assistant/message` can no longer carry
|
|
72
|
+
them (v2). It derives to itself, so it stays as a present-but-empty user
|
|
73
|
+
turn at the surface tail rather than entering model context as content.
|
|
74
|
+
- **No ghost step frame is needed**: the token-meter step machine ignores
|
|
75
|
+
`user/message`, and the session invariant imposes no open-turn requirement
|
|
76
|
+
on it, so the marker is appended while idle, outside any turn, as one event.
|
|
74
77
|
- **Restore is reconciled against the live disk** (`planRestore`), so repeated
|
|
75
78
|
rewinds are idempotent and a rewind whose target state already matches is a
|
|
76
79
|
no-op.
|
|
77
80
|
|
|
81
|
+
### Marker format history
|
|
82
|
+
|
|
83
|
+
The rewind marker is written as form C (an empty `user/message` with a
|
|
84
|
+
`surfaceOp.replace` over the shadowed range and `sourceEventSeqs`). Earlier
|
|
85
|
+
plugin versions wrote shapes a newer harness no longer accepts:
|
|
86
|
+
|
|
87
|
+
- **form A** — a bare `assistant/message(turn=N, step=0)` with no frame.
|
|
88
|
+
- **form B** — a ghost turn frame: `[step/start][assistant/message][step/end]`
|
|
89
|
+
inside a closed turn.
|
|
90
|
+
|
|
91
|
+
A/B became unreadable once v2 reserved surface `replace` to a node that cites
|
|
92
|
+
`sourceEventSeqs` (`assistant/message` can no longer carry them). `/dsh-rewind-fix`
|
|
93
|
+
rewrites form A/B in closed sessions to form C so a newer harness accepts the log.
|
|
94
|
+
|
|
78
95
|
## Checkpoint pipeline (Claude Code before-backup model)
|
|
79
96
|
|
|
80
97
|
```
|
package/docs/compat/audit.md
CHANGED
|
@@ -41,30 +41,30 @@ legacy branch).
|
|
|
41
41
|
|---|---|---|
|
|
42
42
|
| I1 log replayability | A rewound log passes token-meter replay and `Session.create` (the resume-preflight validation) without throwing | `compat-invariants` I1, `verify-host` 12/13 |
|
|
43
43
|
| I2 surface consistency | After a cut, the surface has no duplicate nodes, every node exists in the log, the withdrawn target never returns to the surface, and `deriveMessages()` is legal | `compat-invariants` I2 |
|
|
44
|
-
| I3 step/turn structure | Client turn-tail ordering, unique `step/start
|
|
44
|
+
| I3 step/turn structure | Client turn-tail ordering, unique `step/start` (real turns), no ghost turns; the `user/message` rewind marker adds no step frame | `compat-invariants` I3, `helpers.assertTurnTailOrdering` |
|
|
45
45
|
| I4 fold-service safety | stats / title / goal / projection fold a marker-bearing log without throwing, with predictable values | `compat-invariants` I4 |
|
|
46
46
|
| I5 compact interop | A tool-call orphaned by a cancelled turn is pair-balanced once shadowed by a rewind; a rewind across a compaction checkpoint is explicitly refused; a rewind-then-compact transaction stays legal | `compat-interop` I5, `verify-host` 12/14 |
|
|
47
47
|
| I6 tool pipeline | before-snapshot capture/commit/restore is correct (existing `snapshot.test.ts` + `verify-host` 4–8); cancellation timing never hangs | `verify-host` 4–8, 15 |
|
|
48
|
-
| I7 client ordering | A log carrying tool turns
|
|
48
|
+
| I7 client ordering | A log carrying tool turns and rewind markers (a single `user/message` replace) satisfies the client builder ordering | `compat-interop` I7 |
|
|
49
49
|
| I8 runtime safety | `rewind`/`compact` combinations never leave a dangling step/turn frame | `verify-host` 15 |
|
|
50
50
|
|
|
51
51
|
## Verified-compatible surfaces (probes pass)
|
|
52
52
|
|
|
53
|
-
- **token-meter replay** (
|
|
53
|
+
- **token-meter replay** (the empty `user/message` marker + multiple rewinds + interleaved real turns + compact stacking).
|
|
54
54
|
- **compaction transactions**: `toolPairingBalancedBefore/After` stays balanced after a marker cut; the real `/compact` command (`command-compact` + `compaction-basic`, stub summarizer) can land `compaction/start…end` on top of a rewind marker and stay replayable; `/compact` is a legal no-op on a small surface.
|
|
55
55
|
- **resume replay**: `Session.create(id, events)` replays a rewind/compact-bearing log.
|
|
56
|
-
- **session-stats**:
|
|
56
|
+
- **session-stats**: the `user/message` marker adds no step (the step count stays at the real turns' steps), no phantom turn.
|
|
57
57
|
- **session-title / goal fold**: a marker does not disturb `foldSessionTitle` / `foldGoal`.
|
|
58
58
|
- **client ordering**: turn-tail ordering + `step/start` uniqueness hold for tool turns + marker logs.
|
|
59
59
|
- **rewind across a compact checkpoint**: `RewindError('not-on-surface')` refuses cleanly, no crash.
|
|
60
|
-
- **plan-mode**:
|
|
60
|
+
- **plan-mode**: the marker is a turn-less `user/message` (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`).
|
|
61
61
|
- **agent-loop cancellation**: `finally` guarantees step/turn closure; the rewind force-stop path leaves no dangling frame.
|
|
62
62
|
- **settings-card registration**: the Snapshot cleanup card must be registered through a **nested** `ctx.inject(['settingsScope'], …)` — naming `settingsScope` in the module-level inject would keep the whole client plugin unmounted on a host without that service (card and rewind button would disappear). It reads `getSnapshot().value` + `set`, never the `mutate` write API.
|
|
63
63
|
|
|
64
64
|
## Known behavior boundaries (deterministic differences, non-crash, documented)
|
|
65
65
|
|
|
66
|
-
- **session-stats / session-telemetry fold the full log**: post-rewind stats do **not** rewind — `turns`/`steps`/`llmMs` still include withdrawn content;
|
|
67
|
-
- **token-meter usage anchor
|
|
66
|
+
- **session-stats / session-telemetry fold the full log**: post-rewind stats do **not** rewind — `turns`/`steps`/`llmMs` still include withdrawn content; the empty `user/message` marker is folded as a present-but-empty user turn (it adds no step). This is the intended "fold the full log" semantics, pinned by probe.
|
|
67
|
+
- **token-meter usage anchor stays stable** (G3): the empty `user/message` marker carries no usage, but because it is not an `assistant/message`, the baseline anchor does not drop to a heuristic estimate — it stays `usage` across a rewind. Pinned by `compat-gaps` G3.
|
|
68
68
|
- **Withdrawn content stays searchable/exportable**: session-query full-text and `/export` read the raw log; a rewind cuts only the surface, so withdrawn messages remain (declared in the README).
|
|
69
69
|
- **Session title auto-regeneration**: the title derives from the surface, so an automatically-derived title may change after a rewind.
|
|
70
70
|
- **Files written but uncommitted in a cancelled turn**: a `both` rewind cannot restore them (tool side-effect timing; same as Claude Code).
|
|
@@ -101,7 +101,7 @@ The plugin treats these as harness-side defects it does not compensate for. Each
|
|
|
101
101
|
strings, e.g. `/goal` — so this behavior is consistent with the ecosystem, not a plugin
|
|
102
102
|
deviation.)
|
|
103
103
|
|
|
104
|
-
### R-OPENSTEP: an unclosed `step` in the log
|
|
104
|
+
### R-OPENSTEP (rewind part resolved): an unclosed `step` in the log breaks token-meter replay; the rewind no longer compounds it
|
|
105
105
|
|
|
106
106
|
> **Root cause (harness-side)**: an unclosed step left by a crash makes token-meter replay
|
|
107
107
|
> reject any later step activity. DSH `0.1.1-rc.2` now auto-closes crash-left step/turn/tool
|
|
@@ -135,7 +135,7 @@ new turn at `phase.turn + 1` (`agent.ts:251-255`) **without closing the leftover
|
|
|
135
135
|
- **The conversation itself is unaffected** (the request path does not call `tokenMeter.measure`; only compaction-basic does tree-wide).
|
|
136
136
|
- **Manual `/compact` fails permanently** (`compactNow`'s first `measure()` throws the raw error).
|
|
137
137
|
- **Automatic compaction silently stays disabled** (the `agent/pre-step` hook catches and warns; the conversation continues).
|
|
138
|
-
- **rewind's role**:
|
|
138
|
+
- **rewind's role (resolved)**: the v2 `user/message` rewind marker appends no `step/start`, so a rewind no longer introduces the first trip-wire and the R-OPENSTEP rewind amplifier is closed. The harness-side root cause (an unclosed step after a crash, tripped by continuing the conversation) remains.
|
|
139
139
|
|
|
140
140
|
## Uncovered boundaries (need an additional e2e layer; non-blocking)
|
|
141
141
|
|
package/docs/format.md
CHANGED
|
@@ -103,9 +103,11 @@ interface RestoreJournalAction {
|
|
|
103
103
|
}
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
States: `running` and `rollback-running` are non-terminal;
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
States: `running` and `rollback-running` are non-terminal; `completed` /
|
|
107
|
+
`rolled-back` are terminal. A restart never rewrites the journal — a
|
|
108
|
+
reconciliation *reports* a still non-terminal op as `interrupted` (or
|
|
109
|
+
`recovery-required` when the journal is corrupt or a rollback could not
|
|
110
|
+
complete), while the journal itself stays `running` / `rollback-running`.
|
|
109
111
|
|
|
110
112
|
## Write guarantees
|
|
111
113
|
|
|
@@ -144,11 +146,12 @@ a rollback could not complete). `completed` / `rolled-back` are terminal.
|
|
|
144
146
|
|
|
145
147
|
## Versioning policy
|
|
146
148
|
|
|
147
|
-
The journal schema is `version: 1
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
The journal schema is `version: 1` (currently descriptive — `isRestoreJournal`
|
|
150
|
+
validates shape, not version). Checkpoint entries carry no version field. A
|
|
151
|
+
future incompatible format should either make readers reject an unknown
|
|
152
|
+
`version` (there is no best-effort fallback or legacy coercion) or move the
|
|
153
|
+
state root (e.g. `rewind-snapshots/v2`) and ship an explicit migration tool.
|
|
154
|
+
Old-format data is never silently re-interpreted.
|
|
152
155
|
|
|
153
156
|
## Cleanup policy persistence
|
|
154
157
|
|
|
@@ -49,16 +49,29 @@ the canonical source; this block only adds the finer-grained client-side files
|
|
|
49
49
|
and packaging entries.
|
|
50
50
|
|
|
51
51
|
```
|
|
52
|
-
src/index.ts host plugin: /rewind
|
|
52
|
+
src/index.ts host plugin: /rewind|/undo|/snapshot-auto-cleanup|/dsh-rewind-fix
|
|
53
|
+
+ checkpoint pipeline (tools/execute|post-execute)
|
|
53
54
|
src/rewind.ts pure planning: target resolution, surface range, candidate listing
|
|
55
|
+
src/rewind-fix.ts /dsh-rewind-fix orchestration (repair pipeline, locks, rollback)
|
|
56
|
+
src/rewind-marker-repair.ts pure legacy-marker transform (A/B → C)
|
|
57
|
+
src/session-log-io.ts session-log zstd codec + lossless re-encoder (rewind-fix write-back)
|
|
54
58
|
src/snapshot.ts checkpoint store (disk before-backups, restore/preview, bounded prune)
|
|
59
|
+
src/snapshot-cleanup.ts cleanup policy + dsh-settings persistence + auto-sweep throttle
|
|
55
60
|
src/session-cwd.ts session-cwd resolution (fs-tools rule)
|
|
56
|
-
src/
|
|
61
|
+
src/locales.ts host i18n (t() renderer, HostKey)
|
|
62
|
+
src/client/index.ts client plugin: /rewind command decoration + per-message ↶ button portals;
|
|
63
|
+
re-exports the client contract (hiddenSeqsOf / targetSeqOfArgs / HiddenChat)
|
|
57
64
|
src/client/popover.ts mode-selection popover (both-mode impact confirm)
|
|
58
65
|
src/client/hidden.ts withdrawn-span computation (hiddenSeqsOf), pure
|
|
66
|
+
src/client/candidates.ts rewind candidate listing (rewindCandidatesOf), pure
|
|
67
|
+
src/client/pending.ts pending-steering bubble ↔ queue-mirror matching, pure
|
|
59
68
|
src/client/locales.ts zh / en copy (LocaleNamespaceMap)
|
|
60
69
|
src/client/styles.ts injected styles (dsh design tokens)
|
|
70
|
+
src/client/build-info.ts client build identity (__DSH_REWIND_VERSION__ / __DSH_REWIND_BUILD__)
|
|
71
|
+
src/client/log.ts client logger (namespaced, dsh-rewind.debug-gated)
|
|
61
72
|
scripts/build.mjs esbuild: lib/index.js (host ESM) + lib/client.js (loader closure) + .d.ts
|
|
73
|
+
scripts/check-dsh-version.mjs DSH peer-tuple check (latest dist-tag vs peers)
|
|
74
|
+
scripts/update-badge.mjs regenerate the tests badge (CI only)
|
|
62
75
|
scripts/verify-host.mjs end-to-end host verification (full check suite)
|
|
63
76
|
tests/ vitest suites (rewind / snapshot / hidden / session-cwd / integration)
|
|
64
77
|
docs/ maintainer docs: contract/, compat/, release/ subdirectories
|
package/docs/release/release.md
CHANGED
|
@@ -49,11 +49,9 @@ The line being released determines the branch and the bump:
|
|
|
49
49
|
|
|
50
50
|
Each release is `git push <branch>` followed by `git push <branch> --tags`.
|
|
51
51
|
|
|
52
|
-
- The
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
an unpushed version bump leaves the tag on the wrong commit and the
|
|
56
|
-
tag/version match check fails.
|
|
52
|
+
- The release commit is **`chore: release vX.Y.Z`**; the **lightweight `vX.Y.Z`
|
|
53
|
+
tag** sits on it. Do **not** create tag/release first with `gh release create
|
|
54
|
+
<tag>` (it tags the remote `main` head and breaks the tag/version match).
|
|
57
55
|
- **Before bumping, manually confirm there is no newer DSH version the plugin
|
|
58
56
|
has not been verified against** (a pre-release can ship in DSH Desktop
|
|
59
57
|
without being on npm; see docs/compat/audit.md).
|
|
@@ -100,11 +98,15 @@ appended) when DSH releases a new tuple.
|
|
|
100
98
|
independent of the host; a release declares its DSH line through the peer
|
|
101
99
|
constraint (a single companion tuple), never through the plugin version.
|
|
102
100
|
|
|
103
|
-
| Plugin version | DSH line |
|
|
101
|
+
| Plugin version | DSH line | Role (example) |
|
|
104
102
|
| --- | --- | --- |
|
|
105
103
|
| `0.7.x` | `0.1.1` + `0.1.2` (broad) | frozen / EOL |
|
|
106
|
-
| `0.8.x` | `0.1.2-rc.1` (single) | current
|
|
107
|
-
| `0.9.x` | `0.1.3` (single) |
|
|
104
|
+
| `0.8.x` | `0.1.2-rc.1` (single) | current line |
|
|
105
|
+
| `0.9.x` | `0.1.3` (single) | following line |
|
|
106
|
+
|
|
107
|
+
The rows are illustrative — the DSH line a release targets is the peer
|
|
108
|
+
constraint, and its npm dist-tag is derived from the version (see above), so
|
|
109
|
+
this model does not track the plugin's own version number.
|
|
108
110
|
|
|
109
111
|
**Versioning.** A DSH version-line break is a MAJOR bump (incompatible with the
|
|
110
112
|
prior DSH line). Within a line, MINOR/PATCH remain compatible.
|
|
@@ -46,10 +46,9 @@ npm publish --access public
|
|
|
46
46
|
|
|
47
47
|
每次发布为 `git push <分支>`,再 `git push <分支> --tags`。
|
|
48
48
|
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
就会落在错误提交上,导致 tag/版本一致性校验失败。
|
|
49
|
+
- 发布提交为 **`chore: release vX.Y.Z`**,**轻量 `vX.Y.Z` tag** 落在该提交上。
|
|
50
|
+
**不要**用 `gh release create <tag>` 事先建 tag/release(会打到远端 `main`
|
|
51
|
+
HEAD,导致 tag/版本校验失败)。
|
|
53
52
|
- **升版前手动确认**:确认无插件未针对其验证过的更新 DSH 版本(pre-release
|
|
54
53
|
可能只随 Desktop 捆绑、而不发到 npm;见 docs/compat/audit.md)。
|
|
55
54
|
- workflow 校验 tag 与 `package.json` 版本一致,跑 typecheck + 测试 + 完整
|
|
@@ -86,11 +85,14 @@ DSH 仍在 rc 阶段,npm 的 prerelease 匹配规则要求 peer 范围与宿
|
|
|
86
85
|
**一个发布对准一条 DSH 版本线。** 插件自身版本号与宿主解耦;某发布所对准的
|
|
87
86
|
DSH 线由 peer 约束(单一 companion 元组)声明,而非插件版本号。
|
|
88
87
|
|
|
89
|
-
| 插件版本 | DSH 线 |
|
|
88
|
+
| 插件版本 | DSH 线 | 角色(示例) |
|
|
90
89
|
| --- | --- | --- |
|
|
91
90
|
| `0.7.x` | `0.1.1` + `0.1.2`(广兼容) | 冻结 / EOL |
|
|
92
|
-
| `0.8.x` | `0.1.2-rc.1`(单线) |
|
|
93
|
-
| `0.9.x` | `0.1.3`(单线) |
|
|
91
|
+
| `0.8.x` | `0.1.2-rc.1`(单线) | 当前线 |
|
|
92
|
+
| `0.9.x` | `0.1.3`(单线) | 后续线 |
|
|
93
|
+
|
|
94
|
+
各行仅为示例——某个发布对准的 DSH 线由 peer 约束声明,其 npm dist-tag 按版本号
|
|
95
|
+
派生(见上文),因此本模型不跟随插件自身版本号变化。
|
|
94
96
|
|
|
95
97
|
**版本号。** DSH 版本线破坏性变更 = MAJOR 升版(与更早 DSH 线向后不兼容)。
|
|
96
98
|
同一线内 MINOR/PATCH 保持向后兼容。
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Rewind-marker update guide
|
|
2
|
+
|
|
3
|
+
> English | [中文](rewind-fix.zh.md)
|
|
4
|
+
|
|
5
|
+
## Applies to
|
|
6
|
+
|
|
7
|
+
- **DSH**: `0.1.2-rc.1`
|
|
8
|
+
- **dsh-rewind**: `0.9.0-alpha.1`
|
|
9
|
+
|
|
10
|
+
## Background
|
|
11
|
+
|
|
12
|
+
`/rewind` appends a **marker** to the session log, telling DSH "everything from this screen onward is withdrawn". Aged plugin versions used a "ghost step frame" for this; the current version uses a more canonical, functionally-equivalent shape — a content-empty `user/message` that replaces the content after the target (see the [README](../README.en.md), the "How it works" section).
|
|
13
|
+
|
|
14
|
+
The next DSH line (`v0.1.3`) will reject the old shape, so **sessions rewound by an older plugin may fail to open after an upgrade**. That's why the plugin ships `/dsh-rewind-fix`: it translates those old markers into the new shape and makes the sessions usable again. The new shape is also fully compatible with older DSH versions.
|
|
15
|
+
|
|
16
|
+
## Warnings
|
|
17
|
+
|
|
18
|
+
1. **It directly edits the session log** — it rewrites old rewind markers into the new format. The design already handles the common cases safely (**multiple web windows**, **exit / restart**, **switching sessions**, **power loss**): it only touches **closed** sessions, locks and **backs up** each one before writing, **rolls back** on failure, and is **idempotent** (safe to re-run). It changes the marker only — it deletes no conversation content and **loses no information**.
|
|
19
|
+
|
|
20
|
+
2. **It resets the matching snapshot backups** — the format update renumbers event seqs, so a session that was **updated** has its snapshot backups (the lightweight backups used to **restore files** for "conversation and code") no longer match, and the plugin **clears** them. This only affects **file restore** (those sessions can't use snapshots to restore files); backups start recording fresh. Sessions that weren't updated keep their snapshots.
|
|
21
|
+
|
|
22
|
+
## Steps
|
|
23
|
+
|
|
24
|
+
### Step 1 · Confirm your versions
|
|
25
|
+
|
|
26
|
+
First confirm your DSH and plugin versions are in the "Applies to" range — it's a prerequisite. If either is out of range, the tool may be unavailable or behave differently. You can just ask the AI for your current DSH and dsh-rewind plugin versions and check they're in range.
|
|
27
|
+
|
|
28
|
+
### Step 2 · Back up manually (optional)
|
|
29
|
+
|
|
30
|
+
The command rewrites session files and clears some snapshots, so a backup is a good idea. The default data directory is `~/.dsh` (if you've set `$DSH_HOME`, use its value):
|
|
31
|
+
```sh
|
|
32
|
+
cp -r ~/.dsh/sessions ~/.dsh/sessions.backup
|
|
33
|
+
cp -r ~/.dsh/rewind-snapshots ~/.dsh/rewind-snapshots.backup
|
|
34
|
+
```
|
|
35
|
+
Or copy them anywhere convenient.
|
|
36
|
+
|
|
37
|
+
### Step 3 · Start a new session, or pick one that was never rewound
|
|
38
|
+
|
|
39
|
+
The command only handles **closed** sessions, and it can't run on itself. So:
|
|
40
|
+
- **Start a new session** — ideally send any message first to initialize the window so you can see the command's progress and output.
|
|
41
|
+
- Or pick a session that was **never rewound** (one that needs no update).
|
|
42
|
+
|
|
43
|
+
Then run the command **in this new session**, and it will update the old sessions that need it.
|
|
44
|
+
|
|
45
|
+
> ⚠️ Don't run it in a session that itself needs updating and is currently open — the command skips this session, and any other currently-open/in-use session.
|
|
46
|
+
|
|
47
|
+
### Step 4 · Preview the update scope
|
|
48
|
+
|
|
49
|
+
Type `/dsh-rewind-fix` in the composer and send it. It only scans, doesn't write — it reports how many sessions were scanned, how many will be updated, how many skipped, and how many failed. Confirm those are what you expect before moving on.
|
|
50
|
+
```
|
|
51
|
+
/dsh-rewind-fix
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Step 5 · Execute
|
|
55
|
+
|
|
56
|
+
Once you're sure, re-enter the command with `--apply` to actually run it:
|
|
57
|
+
```
|
|
58
|
+
/dsh-rewind-fix --apply
|
|
59
|
+
```
|
|
60
|
+
This really rewrites the session logs and updates the old markers, and **may take a few minutes**. Please let it finish — **don't switch to another session window or close DSH** while it runs: a session you switch to is **safely skipped** (no corruption, but it won't be updated this pass and you'll need to re-run). A session that fails stays as it was, unharmed, and can be updated again later. Sessions that are updated also get their matching **snapshot backups cleared**, so file restore to earlier messages is no longer available for them.
|
|
61
|
+
|
|
62
|
+
### Step 6 · Restart DSH and preview again (optional)
|
|
63
|
+
|
|
64
|
+
After the run, restart DSH, then **preview once more**:
|
|
65
|
+
```
|
|
66
|
+
/dsh-rewind-fix
|
|
67
|
+
```
|
|
68
|
+
If it says there are no more sessions to update, the markers are all current and the old sessions will open normally.
|
|
69
|
+
|
|
70
|
+
### Step 7 · Delete the backup after confirming (optional)
|
|
71
|
+
|
|
72
|
+
Use it for a while, and once everything works, delete the backup from step 2:
|
|
73
|
+
```sh
|
|
74
|
+
rm -rf ~/.dsh/sessions.backup ~/.dsh/rewind-snapshots.backup
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Notes
|
|
78
|
+
|
|
79
|
+
- The session logs are still v0 format; when DSH's later `v0 → v1 → v2` migration (in `v0.1.3`) arrives, if you've completed the `rewind` marker update, the markers themselves won't block it.
|
|
80
|
+
- Some sessions may still be blocked by an **unclosed turn** (a turn that was interrupted/cancelled and never wrote `turn/end`). Per the empirical analysis these are widespread and **unrelated to rewind** — they're a DSH-side issue and this tool doesn't handle them. **So updating the markers doesn't guarantee you can upgrade to the next DSH line.**
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 回退标记更新指南
|
|
2
|
+
|
|
3
|
+
> [English](rewind-fix.md) | 中文
|
|
4
|
+
|
|
5
|
+
## 适配
|
|
6
|
+
|
|
7
|
+
- **DSH**:`0.1.2-rc.1`
|
|
8
|
+
- **dsh-rewind**:`0.9.0-alpha.1`
|
|
9
|
+
|
|
10
|
+
## 背景
|
|
11
|
+
|
|
12
|
+
`/rewind` 回退会往会话日志追加一条**标记**,告诉 DSH 从某一屏往后都算「已撤回」。旧版插件用的是「幽灵步骤框架」写法;新版本已换成更规范且功能一致的形态——一条内容为空的 `user/message`,把目标之后的内容整体替换掉(原理见 [README](../README.md) 的「原理」一节)。
|
|
13
|
+
|
|
14
|
+
新一代 DSH(`v0.1.3`)会拒绝旧写法,所以**用旧版插件回退过的会话,升级后可能打不开**。因此本插件提供了 `/dsh-rewind-fix` 便捷命令,把这些旧标记「翻译」成新格式,让会话重新可用。新格式同样对旧版本 DSH 完全兼容。
|
|
15
|
+
|
|
16
|
+
## 警告
|
|
17
|
+
|
|
18
|
+
1. **会直接编辑会话日志** —— 把旧回退标记更新为新格式。设计上对**多个网页窗口、退出重启、切换会话、关机断电**等场景都已做安全处理:只处理**已关闭**的会话,写前加锁+备份、失败自动回滚、可重复运行(**幂等**);只动标记本身,不删任何对话内容、**无信息丢失**。
|
|
19
|
+
|
|
20
|
+
2. **会重置对应的快照备份** —— 格式更新会改变事件序号,**被更新过的会话**,其用于「回退对话和代码」时**还原文件**的对应快照备份将不再匹配,因此会被插件**清除**。这只影响**文件还原**,备份会重新开始记录;没被更新的会话快照不变。
|
|
21
|
+
|
|
22
|
+
## 操作步骤
|
|
23
|
+
|
|
24
|
+
### 第一步 · 确认版本
|
|
25
|
+
|
|
26
|
+
先确认你当前的 DSH 与插件版本落在「适配」范围里——这是前提。版本不符时,工具可能不可用或行为不符。你可以直接问 AI「当前的 DSH 与 dsh-rewind 插件版本」,并确认是否在「适配」范围内。
|
|
27
|
+
|
|
28
|
+
### 第二步 · 手动备份(可选)
|
|
29
|
+
|
|
30
|
+
命令会改写会话文件、删掉部分快照,稳妥起见先备份一下。默认数据目录是 `~/.dsh`(若你设置了 `$DSH_HOME`,请用它的值):
|
|
31
|
+
```sh
|
|
32
|
+
cp -r ~/.dsh/sessions ~/.dsh/sessions.backup
|
|
33
|
+
cp -r ~/.dsh/rewind-snapshots ~/.dsh/rewind-snapshots.backup
|
|
34
|
+
```
|
|
35
|
+
或者复制到任意合适的位置。
|
|
36
|
+
|
|
37
|
+
### 第三步 · 新建会话,或选一个从未回退过的会话
|
|
38
|
+
|
|
39
|
+
命令只处理已关闭的会话,而且不能在自己身上运行——建议你:
|
|
40
|
+
- **新建一个会话**,先随便发一条消息初始化窗口,确保能看到命令执行过程和结果
|
|
41
|
+
- 选择一个**从未回退过**(不需要更新)的会话
|
|
42
|
+
|
|
43
|
+
然后在**这个新会话窗口里**运行命令,去更新那些需要处理的旧会话。
|
|
44
|
+
|
|
45
|
+
> ⚠️ 别在「本身就需要更新、且正开着」的会话里运行——命令会跳过本会话,以及任何正被打开/使用的会话。
|
|
46
|
+
|
|
47
|
+
### 第四步 · 预览更新范围
|
|
48
|
+
|
|
49
|
+
在编辑区域输入 `/dsh-rewind-fix` 并发送。它只扫描、不写盘,会告诉你:扫描了几个会话、其中几个将被更新、几个跳过、几个失败。确认是你预期的那几项,再进下一步。
|
|
50
|
+
```
|
|
51
|
+
/dsh-rewind-fix
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 第五步 · 执行
|
|
55
|
+
|
|
56
|
+
确认无误后,重新输入命令并加 `--apply` 真正执行:
|
|
57
|
+
```
|
|
58
|
+
/dsh-rewind-fix --apply
|
|
59
|
+
```
|
|
60
|
+
这一步会真的改动会话日志、把旧标记更新成新格式,**可能需要几分钟**。请耐心等它跑完,**不要中途切换会话窗口**或关闭 DSH——被切到的会话会被**安全地跳过**(不损坏,但这次不会更新,需重新执行)。更新失败的会话保持原状态不变、无破坏,可重新进行更新。被更新的会话会同时**清掉对应的文件快照备份**,更早消息回退时文件还原不可用。
|
|
61
|
+
|
|
62
|
+
### 第六步 · 重启 DSH,再预览确认(可选)
|
|
63
|
+
|
|
64
|
+
执行完后重启一下 DSH,然后**再跑一次预览**:
|
|
65
|
+
```
|
|
66
|
+
/dsh-rewind-fix
|
|
67
|
+
```
|
|
68
|
+
如果提示已经没有待更新的会话,说明标记已全部更新到位,旧会话就能正常打开了。
|
|
69
|
+
|
|
70
|
+
### 第七步 · 确认正常后删除备份(可选)
|
|
71
|
+
|
|
72
|
+
继续使用一段时间,确认一切功能正常后,删掉第二步拷贝的备份即可:
|
|
73
|
+
```sh
|
|
74
|
+
rm -rf ~/.dsh/sessions.backup ~/.dsh/rewind-snapshots.backup
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 补充说明
|
|
78
|
+
|
|
79
|
+
- 当前会话日志仍为 v0 格式;DSH 后续(`v0.1.3`)的 `v0 → v1 → v2` 迁移到来时,如果你完成了 `rewind` 标记更新,标记本身就不会阻断它。
|
|
80
|
+
- 个别会话还可能因**未闭合的 turn**(某次回合被打断/取消、没写 `turn/end`)等问题而卡住迁移——根据实测分析,这些问题普遍存在,**与 rewind 无关**,属 DSH 侧自身问题,本工具不处理。**所以更新完标记并不保证一定能升到下一 DSH 线。**
|
package/lib/client.js
CHANGED
|
@@ -1333,7 +1333,7 @@ function createRewindBridge(deps) {
|
|
|
1333
1333
|
}
|
|
1334
1334
|
|
|
1335
1335
|
// src/client/build-info.ts
|
|
1336
|
-
var PLUGIN_VERSION = true ? "0.
|
|
1336
|
+
var PLUGIN_VERSION = true ? "0.9.0-alpha.1" : "dev";
|
|
1337
1337
|
var BUILD_HASH = true ? "ca24fc4e" : "dev";
|
|
1338
1338
|
|
|
1339
1339
|
// src/client/locales.ts
|