dsh-rewind-plugin 0.14.0 → 0.15.0-beta.2
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/SECURITY.md +7 -7
- package/cordis.patch.yml +4 -7
- package/docs/README.md +2 -1
- package/docs/architecture.md +5 -25
- package/docs/compat/audit.md +21 -43
- package/docs/compat/diagnostics.md +6 -10
- package/docs/compat/diagnostics.zh.md +3 -4
- package/docs/compat/tracking-boundary.md +1 -4
- package/docs/compat/tracking-boundary.zh.md +2 -2
- package/docs/harness-reference.md +1 -8
- package/docs/release/release.md +8 -19
- package/docs/release/release.zh.md +2 -2
- package/docs/snapshot-auto-cleanup.md +18 -22
- package/docs/snapshot-auto-cleanup.zh.md +5 -10
- package/lib/client.js +124 -33
- package/lib/index.js +19 -9
- package/lib/types/client/candidates.d.ts +0 -11
- package/lib/types/client/hidden.d.ts +44 -22
- package/lib/types/client/index.d.ts +9 -21
- package/lib/types/client/log.d.ts +11 -19
- package/lib/types/client/pending.d.ts +19 -8
- package/lib/types/client/portals.d.ts +40 -18
- package/lib/types/client/settings-card.d.ts +0 -1
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/index.d.ts +3 -11
- package/lib/types/locales.d.ts +2 -0
- package/lib/types/marker.d.ts +3 -21
- package/lib/types/rewind.d.ts +12 -23
- package/lib/types/snapshot.d.ts +5 -34
- package/package.json +53 -55
package/SECURITY.md
CHANGED
|
@@ -80,13 +80,13 @@ whose store is **newer** than this build understands is not cleared by it (see
|
|
|
80
80
|
## Conversation integrity
|
|
81
81
|
|
|
82
82
|
The session log is **append-only** — the plugin never deletes or rewrites
|
|
83
|
-
recorded history. A rewind appends a single marker event (
|
|
84
|
-
`
|
|
85
|
-
The raw log (audit trail, search,
|
|
86
|
-
model-visible surface is cut, so the next
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
transcript.
|
|
83
|
+
recorded history. A rewind appends a single marker event (a `user/message` whose
|
|
84
|
+
content is the constant `(empty message)` placeholder) whose `surfaceOp`
|
|
85
|
+
replaces every surface node after the target. The raw log (audit trail, search,
|
|
86
|
+
`/export`) is untouched — only the model-visible surface is cut, so the next
|
|
87
|
+
request derives its context from the target onward. The marker's content is a
|
|
88
|
+
constant, so it carries no untrusted text into the model context; the client
|
|
89
|
+
hides the `[target, marker]` span from the rendered transcript.
|
|
90
90
|
|
|
91
91
|
## Filesystem containment
|
|
92
92
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
# dsh-rewind-plugin bundle patch: one row, dual-face
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# roster. The row name MUST equal the package name — the client-modules node
|
|
6
|
-
# half resolves `require.resolve('<row-name>/package.json')` to find the
|
|
7
|
-
# package and its dsh.client declaration.
|
|
1
|
+
# dsh-rewind-plugin bundle patch: one row, dual-face (node half = the package's
|
|
2
|
+
# default export, browser half = ./client via the `dsh.client` declaration).
|
|
3
|
+
# The row name MUST equal the package name — the client-modules node half
|
|
4
|
+
# resolves `require.resolve('<row-name>/package.json')` to find the package.
|
|
8
5
|
- insert:
|
|
9
6
|
- id: dsh-rewind-plugin
|
|
10
7
|
name: 'dsh-rewind-plugin'
|
package/docs/README.md
CHANGED
|
@@ -25,7 +25,8 @@ Repo-root docs outside `docs/`: `SECURITY.md` (security model) and
|
|
|
25
25
|
## Conventions
|
|
26
26
|
|
|
27
27
|
- Bilingual docs use the `.md` / `.zh.md` file split (e.g. `contract/client-contract.md`
|
|
28
|
-
+ `contract/client-contract.zh.md
|
|
28
|
+
+ `contract/client-contract.zh.md`); the root pair is the exception — `README.md` is
|
|
29
|
+
Chinese, `README.en.md` English.
|
|
29
30
|
- `compat/audit.md` is the single source of truth for compatibility conclusions;
|
|
30
31
|
other docs link to it instead of restating them.
|
|
31
32
|
- Cross-links are relative so the whole `docs/` directory stays relocatable — and it
|
package/docs/architecture.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
3
|
How dsh-rewind is built: module layering, the rewind pipeline, the checkpoint
|
|
4
|
-
pipeline, the compatibility strategy, and the roadmap. The module map
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
pipeline, the compatibility strategy, and the roadmap. The module map lives in
|
|
5
|
+
`AGENTS.md`; this document adds the wiring between the modules. The durable
|
|
6
|
+
on-disk format is specified separately in
|
|
7
7
|
`docs/format.md`, the security model in `SECURITY.md`.
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -15,25 +15,8 @@ credentials access.
|
|
|
15
15
|
|
|
16
16
|
## Module layering
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
├── index.ts host plugin: /rewind, /undo, /snapshot-auto-cleanup
|
|
21
|
-
│ commands + checkpoint pipeline
|
|
22
|
-
├── rewind.ts pure planning: target parsing, surface-range plan, candidate listing
|
|
23
|
-
├── snapshot.ts checkpoint store: disk before-backups, journaled restore,
|
|
24
|
-
│ reconcile / continue / rollback, bounded prune
|
|
25
|
-
├── snapshot-cleanup.ts cleanup policy + dsh-settings persistence + auto-sweep throttle
|
|
26
|
-
├── session-cwd.ts session working-directory resolution (fs-tools rule)
|
|
27
|
-
├── locales.ts host i18n (t() renderer, HostKey)
|
|
28
|
-
└── client/ browser half: per-message ↶ button (portal bridge),
|
|
29
|
-
mode popover, hidden-span computation, candidate parsing,
|
|
30
|
-
pending interaction, locales, styles
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
The old marker-update repair line (`/dsh-rewind-fix` and its `rewind-fix.ts` /
|
|
34
|
-
`rewind-marker-repair.ts` / `session-log-io.ts` modules) was a **temporary
|
|
35
|
-
migration tool** for the DSH `0.1.2-rc.1` → `0.1.3` transition: it shipped
|
|
36
|
-
through the `0.9.x` line and is **removed in the `0.10.x` line**.
|
|
18
|
+
The module map is the one in `AGENTS.md` (`Layout at a glance`); this document
|
|
19
|
+
adds the wiring between the modules and does not repeat it.
|
|
37
20
|
|
|
38
21
|
Two dependency rules keep the design testable:
|
|
39
22
|
|
|
@@ -156,9 +139,6 @@ Ideas under consideration, not commitments:
|
|
|
156
139
|
- **Multi-process identity/lock**: the current in-flight guard is
|
|
157
140
|
per-process; a cross-process exclusive lock (like the change-ledger
|
|
158
141
|
competitors) would cover multiple host processes on one worktree.
|
|
159
|
-
- **Lazy-commit UX**: an explicit confirm-then-apply step (a pending state)
|
|
160
|
-
to reduce mis-touch risk on in-window rewinds, which are inherently less
|
|
161
|
-
reversible than forked branches.
|
|
162
142
|
- **Locale expansion**: client/host copy is zh/en today; the copy layer
|
|
163
143
|
(`src/locales.ts`, `src/client/locales.ts`) is already keyed for more.
|
|
164
144
|
- **Composer re-send polish**: the target text is already refilled after a
|
package/docs/compat/audit.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
> compatibility invariants. A probe failure is a finding; it enters the
|
|
9
9
|
> fix/pin/record loop.
|
|
10
10
|
>
|
|
11
|
-
> Targeted version: npm `@deepseek-ai/*@0.
|
|
11
|
+
> Targeted version: npm `@deepseek-ai/*@0.2.0-rc.2` (the peers declare the matching range).
|
|
12
12
|
> Source reference: the upstream [github.com/deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
13
13
|
>
|
|
14
14
|
> Version alignment: one peer tuple per DSH line, declaring only what was verified — the
|
|
@@ -46,7 +46,7 @@ legacy branch).
|
|
|
46
46
|
| I6 tool pipeline | before-snapshot capture/commit/restore is correct (existing `snapshot.test.ts` + `verify-host` 4–8) for the tracked tools `write` / `edit` — `str_replace_editor` is an optional DSH package that stopped being a default tool in DSH 0.1.3, so it is not tracked; cancellation timing never hangs | `verify-host` 4–9 |
|
|
47
47
|
| I7 client ordering | A log carrying tool turns and rewind markers (a single `user/message` replace) satisfies the client builder ordering | `compat-interop` I7 |
|
|
48
48
|
| I8 runtime safety | `rewind`/`compact` combinations never leave a dangling step/turn frame | `verify-host` 13 |
|
|
49
|
-
| I9 tool-update projection | rc.2 folds mid-conversation tool additions from the whole log while a rewind cuts only the surface: after a withdrawal no `tool-addition`/`tool-removal` block reaches the provider and the current declarations stay complete | `compat-tool-updates` I9 |
|
|
49
|
+
| I9 tool-update projection | `0.1.7-rc.2` folds mid-conversation tool additions from the whole log while a rewind cuts only the surface: after a withdrawal no `tool-addition`/`tool-removal` block reaches the provider and the current declarations stay complete | `compat-tool-updates` I9 |
|
|
50
50
|
|
|
51
51
|
## Verified-compatible surfaces (probes pass)
|
|
52
52
|
|
|
@@ -58,13 +58,13 @@ legacy branch).
|
|
|
58
58
|
- **agent-loop cancellation**: `finally` guarantees step/turn closure; the rewind force-stop path leaves no dangling frame.
|
|
59
59
|
- **settings card (`0.1.7-alpha.1`)**: the card declares `configForms` as a module-level inject (the web profile always composes `ui-settings`), stages through the harness's own `SettingsFormModel` + `SettingsForm`, and registers into `plugins.bundle.config` keyed by the bundle package name; it reads that shared per-entry form's snapshot and writes through its revision-fenced `mutate`, disposing the model's subscription with the fiber. The host half declares the bundle's page policy (`configure({ auto: false }, ctx.fiber)` inside a `ctx.inject(['settings'])` child, per the dsh-settings README), opting the entry out of a client-built schema page. Pins: `verify:host` (`the bundle declares its own config page`), `tests/client-settings-card.test.ts` (staged plan, refusal, subscription release), `tests/client-lifecycle.test.ts`.
|
|
60
60
|
- **client session ownership (`0.1.6-alpha.2`)**: `SessionListState.current` / `currentAddress` are gone; main-view ownership is read from the row's `retainedBy.mainView` label — what `ui-workspace` retains the open session with. Pin: `tests/client-refill.test.ts`.
|
|
61
|
-
- **client pending input (`0.1.6-alpha.2`)**: `SessionSnapshot.queue` and the host `queue-mirror` are gone; pending steering rows come from the session's own `inbox` projection, and only USER-sourced `next-step` rows are retractable (the removed mapping was `source.kind === 'user' ? 'steering' : 'context'`). The rendered bubble also stays the client's own submission echo until the durable node arrives (`ChatView.pendingInputs` merges the Host occurrence into that echo by `rpcId`; `QueueDock` mirrors only `next-turn`), so the occurrence lands with NO DOM mutation — the portal refresh therefore follows the `inbox` face's own `subscribe` beside the DOM observer. Pins: `tests/pending.test.ts`, `tests/client-retract.test.ts`, `tests/client-portal-refresh.test.ts`.
|
|
61
|
+
- **client pending input (`0.1.6-alpha.2`)**: `SessionSnapshot.queue` and the host `queue-mirror` are gone; pending steering rows come from the session's own `inbox` projection, and only USER-sourced `next-step` rows are retractable (the removed mapping was `source.kind === 'user' ? 'steering' : 'context'`). The rendered bubble also stays the client's own submission echo until the durable node arrives (`ChatView.pendingInputs` merges the Host occurrence into that echo by `rpcId`; `QueueDock` mirrors only `next-turn`), so the occurrence lands with NO DOM mutation — the portal refresh therefore follows the `inbox` face's own `subscribe` beside the DOM observer. An attachment-bearing row is identified by its message-attachment block (`data-message-attachments`) and matched by block count, not by rendered text (the block renders a file name or an image's loading label, which no inbox row reproduces); a missing attribute degrades to "no button". Pins: `tests/pending.test.ts`, `tests/client-retract.test.ts`, `tests/client-portal-refresh.test.ts`, `tests/client-dom.test.ts`.
|
|
62
62
|
- **client settings slot (`0.1.6-alpha.2`)**: `settings.plugin.item` is gone; the configuration form registers into `plugins.bundle.config`, keyed by the bundle package name. Pin: `tests/client-contract.test.ts`.
|
|
63
63
|
- **`agent/created` lifecycle guard**: the session-format reconcile runs on the alpha line's `agent/created` (fire-and-forget); pin: `verify-host` 4e dispatches it.
|
|
64
64
|
- **marker vs `/compact`**: the checkpoint shape is unchanged on this line — a `user/message` replace (`surfaceOp {replace, startSeq, endSeq}` + `sourceEventSeqs`); `assistant/message` still cannot carry `sourceEventSeqs`.
|
|
65
65
|
- **`image/offload` projection**: the alpha line's first `SessionMessageProjection` changes derived content without touching surface node membership; candidate listing and target resolution tolerate it. Pin: `tests/image-offload-projection.test.ts`.
|
|
66
66
|
- **session-cwd**: the fs tools no longer canonicalize a parent-traversing cwd, so `src/session-cwd.ts` returns `header.cwd` verbatim. Pin: `tests/session-cwd.test.ts`.
|
|
67
|
-
- **startup admission (`0.1.7-rc.1`)**: the gate reads the manifest's own `@deepseek-ai/dsh-*` peers and requires each to satisfy the runtime with `includePrerelease`; it runs for a profile bundle and again for every row its patch inserts, and a denial skips the bundle or disables the row. This plugin's declarations all satisfy
|
|
67
|
+
- **startup admission (`0.1.7-rc.1`)**: the gate reads the manifest's own `@deepseek-ai/dsh-*` peers and requires each to satisfy the runtime with `includePrerelease`; it runs for a profile bundle and again for every row its patch inserts, and a denial skips the bundle or disables the row. This plugin's declarations all satisfy the targeted version above, so it is admitted with no exemption — a skipped bundle on a later line is a peer mismatch, not a load failure.
|
|
68
68
|
|
|
69
69
|
## Known behavior boundaries (deterministic differences, non-crash, documented)
|
|
70
70
|
|
|
@@ -112,26 +112,17 @@ the harness issue, its current status, and the plugin's stance, so a future main
|
|
|
112
112
|
|
|
113
113
|
### R-OPENSTEP (rewind part resolved): an unclosed `step` in the log breaks token-meter replay
|
|
114
114
|
|
|
115
|
-
> **
|
|
116
|
-
>
|
|
117
|
-
>
|
|
118
|
-
>
|
|
119
|
-
>
|
|
120
|
-
> `
|
|
121
|
-
> exactly one `append('step/start')` producer, `agent-loop/src/agent.ts:303`; an unclosed step
|
|
122
|
-
> otherwise comes from a third-party plugin appending `step/start` through the public
|
|
123
|
-
> `Session.append`, or from a hand-edited log. After a crash resume, `turn()` opens a new turn
|
|
124
|
-
> (`agent.ts:277-283`) without closing the leftover step, so continuing the conversation trips
|
|
125
|
-
> the same check — a rewind is **not** the only trigger.
|
|
126
|
-
>
|
|
127
|
-
> **Rewind's part**: the marker is a `user/message` and appends no `step/start`, so a rewind
|
|
128
|
-
> no longer introduces the first trip-wire and the R-OPENSTEP rewind amplifier is closed.
|
|
115
|
+
> **Status**: resolved upstream — DSH auto-closes crash-left step/turn/tool boundaries at load
|
|
116
|
+
> (`interruptedTurnClosers`, consumed by the agent-loop's `resumeWith` cold read). A leftover
|
|
117
|
+
> unclosed step can still come from a third-party plugin appending `step/start` through the public
|
|
118
|
+
> `Session.append`, or from a hand-edited log; when it does, replay rejects later step activity, so
|
|
119
|
+
> `/compact` fails and automatic compaction silently stays disabled. Rewind's part: the marker is a
|
|
120
|
+
> `user/message` and appends no `step/start`, so the rewind amplifier is closed.
|
|
129
121
|
>
|
|
130
122
|
> **Plugin stance**: no guard. A `hasOpenStep` + `planRewind` pre-refusal was implemented and
|
|
131
|
-
> misjudged on **real session logs** (normal rewinds refused, GUI verification broken), so it
|
|
132
|
-
>
|
|
133
|
-
>
|
|
134
|
-
> already abnormal.
|
|
123
|
+
> misjudged on **real session logs** (normal rewinds refused, GUI verification broken), so it was
|
|
124
|
+
> reverted — do not re-attempt a plugin-side pre-refusal. The fix direction is upstream (token-meter
|
|
125
|
+
> recovery for unclosed steps), and the residual risk is accepted: that log is already abnormal.
|
|
135
126
|
|
|
136
127
|
### R-PROMPTCARD (resolved on the 0.1.7 line): the repeated `System prompt` card is filtered out of chat
|
|
137
128
|
|
|
@@ -139,7 +130,8 @@ the harness issue, its current status, and the plugin's stance, so a future main
|
|
|
139
130
|
> (`packages/client/ui-chat/src/client/contract/chat-visibility.ts`) drops `system-prompt`
|
|
140
131
|
> nodes — and the `permission` command — from the visible chat rows before the row is built,
|
|
141
132
|
> so a rewind on this line adds no prompt row at all; the durable events and the trajectory
|
|
142
|
-
> inspection keep them. #22, #31 and
|
|
133
|
+
> inspection keep them. #22, #31 and the (now removed) repeated `System prompt` card known issue
|
|
134
|
+
> no longer reproduce.
|
|
143
135
|
>
|
|
144
136
|
> **Plugin stance**: still no compensation. The DOM row-hiding seam (`hiddenSeqsOf`) covers
|
|
145
137
|
> withdrawn messages, where hiding is essential, not cosmetic.
|
|
@@ -147,8 +139,9 @@ the harness issue, its current status, and the plugin's stance, so a future main
|
|
|
147
139
|
### R-PANELKEYS: the panel keyboard stays the plugin's own
|
|
148
140
|
|
|
149
141
|
> **Situation**: on Web, Escape, Tab, the four arrows, and Enter without Alt are
|
|
150
|
-
> platform-reserved
|
|
151
|
-
>
|
|
142
|
+
> platform-reserved. The predicate is exported (`bindingIssue` from
|
|
143
|
+
> `@deepseek-ai/dsh-client-shortcuts/protocol`), but a reserved binding is still refused, so
|
|
144
|
+
> neither a plugin nor a user may bind them. `Menu`
|
|
152
145
|
> is the dropdown primitive, while the harness's command-option panel (`ui-commands`'
|
|
153
146
|
> popupSelect) renders `MenuSurface` plus its own controller with `role="listbox"`/
|
|
154
147
|
> `role="option"`. `ui-commands`' `settle()` also calls `focusComposer()` unconditionally
|
|
@@ -172,21 +165,6 @@ the harness issue, its current status, and the plugin's stance, so a future main
|
|
|
172
165
|
- telemetry pipeline (`dsh-session-telemetry-otel`) and the attachment provider (`dsh-attachment-local`).
|
|
173
166
|
- Running workflow/jobs cancelled by a rewind: the tool contract requires observing `exec.signal` and settling (`packages/core/tools/src/index.ts`); a rewind triggers the harness's standard cancel, not plugin-specific — statically confirmed, real workflows untested.
|
|
174
167
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|
|
179
|
-
| Session core (append/surface/deriveMessages) | ✓ | ✓ | ✓ | — | ✓ | — | ✓ | ✓ |
|
|
180
|
-
| token-meter | ✓ | — | ✓ | — | ✓ | — | — | — |
|
|
181
|
-
| compaction (transaction/command/tool-pairing) | ✓ | — | — | — | ✓ | — | — | ✓ |
|
|
182
|
-
| session-stats / projection | — | — | ✓ | ✓ | — | — | — | — |
|
|
183
|
-
| session-title | — | — | — | ✓ | — | — | — | — |
|
|
184
|
-
| goal | — | — | — | ✓ | — | — | — | — |
|
|
185
|
-
| resume / session-query replay | ✓ | — | ✓ | — | — | — | ✓ | — |
|
|
186
|
-
| tool pipeline (snapshot/restore) | — | — | — | — | — | ✓ | — | ✓ |
|
|
187
|
-
| client ordering | — | — | ✓ | — | — | — | ✓ | — |
|
|
188
|
-
| plan-mode | ✓ | — | ✓ | — | — | — | — | ✓ (static) |
|
|
189
|
-
|
|
190
|
-
✓ = probe passes; — = not applicable. Statuses and stances for the named findings live in the
|
|
191
|
-
sections above; G1 (surface classification via `foldSurface`), G2 (projection checkpoint) and
|
|
192
|
-
G3 (the confirmed-non-defect usage anchor on token-meter) all pass in `compat-gaps.test.ts`.
|
|
168
|
+
Statuses and stances for the named findings live in the sections above; G1 (surface classification
|
|
169
|
+
via `foldSurface`), G2 (projection checkpoint) and G3 (the confirmed-non-defect usage anchor on
|
|
170
|
+
token-meter) all pass in `compat-gaps.test.ts`.
|
|
@@ -37,16 +37,14 @@ console filter:
|
|
|
37
37
|
| `portals` | Per-message button mount issues (e.g. no session binding) |
|
|
38
38
|
| `retract` | The pending-steering retract path (the remove lost the race, or the remove threw) |
|
|
39
39
|
| `settings` | The snapshot-cleanup settings card |
|
|
40
|
-
| `hiding` | **Reserved** — no active alert at present. If a future row-hiding diagnostic is added, it belongs in this region. |
|
|
41
40
|
|
|
42
41
|
## Verbose switch
|
|
43
42
|
|
|
44
43
|
The `info`/`debug` levels are gated by `localStorage['dsh-rewind.debug']`, read
|
|
45
|
-
once per call and filtered by namespace.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
it:
|
|
44
|
+
once per call and filtered by namespace. Two gated lines remain: the `boot`
|
|
45
|
+
startup identity line and the `retract` lost-race line. Both are deliberately
|
|
46
|
+
**off** by default (a normal user's console stays clean, and neither is an
|
|
47
|
+
anomaly), so a reporter enables the scope to see them:
|
|
50
48
|
|
|
51
49
|
```js
|
|
52
50
|
// Just the startup identity line.
|
|
@@ -63,14 +61,12 @@ delete localStorage['dsh-rewind.debug']
|
|
|
63
61
|
```
|
|
64
62
|
|
|
65
63
|
The `error`/`warn` anomaly alerts are **not** gated by this switch — they are
|
|
66
|
-
always printed.
|
|
67
|
-
hide-set, per-rewind lifecycle lines) has been withdrawn: it re-stated behavior
|
|
68
|
-
the user already sees and carried no attribution.
|
|
64
|
+
always printed.
|
|
69
65
|
|
|
70
66
|
## Capturing a report
|
|
71
67
|
|
|
72
68
|
1. Reproduce once on the affected page.
|
|
73
|
-
2. In DevTools, filter the Console for `
|
|
69
|
+
2. In DevTools, filter the Console for `dsh-rewind` and copy the output
|
|
74
70
|
(with the plugin version and the DSH/kernel version).
|
|
75
71
|
|
|
76
72
|
The `error`/`warn` anomaly alerts require no setup — they always print. To also
|
|
@@ -27,11 +27,10 @@
|
|
|
27
27
|
| `portals` | 每条消息按钮的挂载问题(如无会话绑定) |
|
|
28
28
|
| `retract` | 插话撤回路径(remove 竞争失败,或 remove 抛错) |
|
|
29
29
|
| `settings` | 快照清理设置卡片 |
|
|
30
|
-
| `hiding` | **保留区**——当前无活跃告警。若未来新增行隐藏诊断,应归属此区域。 |
|
|
31
30
|
|
|
32
31
|
## 详细输出开关
|
|
33
32
|
|
|
34
|
-
`info`/`debug` 级别受 `localStorage['dsh-rewind.debug']`
|
|
33
|
+
`info`/`debug` 级别受 `localStorage['dsh-rewind.debug']` 控制,每次调用读取并按命名空间过滤。仅剩两条受控行:`boot` 启动身份行与 `retract` 竞争失败行。两者**默认关闭**(普通用户控制台保持干净,且都不是异常),排查者需先开启对应作用域才能看到:
|
|
35
34
|
|
|
36
35
|
```js
|
|
37
36
|
// 仅启动身份行。
|
|
@@ -47,12 +46,12 @@ localStorage['dsh-rewind.debug'] = 'dsh-rewind*'
|
|
|
47
46
|
delete localStorage['dsh-rewind.debug']
|
|
48
47
|
```
|
|
49
48
|
|
|
50
|
-
`error`/`warn`
|
|
49
|
+
`error`/`warn` 异常告警**不受**该开关控制——它们总是打印。
|
|
51
50
|
|
|
52
51
|
## 采集一段报告
|
|
53
52
|
|
|
54
53
|
1. 在出问题的页面上复现一次。
|
|
55
|
-
2. 在 DevTools 里把 Console 按 `
|
|
54
|
+
2. 在 DevTools 里把 Console 按 `dsh-rewind` 过滤,复制输出(连同插件版本、DSH/内核版本)。
|
|
56
55
|
|
|
57
56
|
`error`/`warn` 异常告警无需任何设置——它们总是打印。若要同时采集启动身份行(`boot`,用于排除「旧 bundle / 宿主未重启」),请先开启详细输出开关(见上),再刷新。
|
|
58
57
|
|
|
@@ -212,9 +212,6 @@ What the two limitations buy is: lightweight, predictable, and **only ever writi
|
|
|
212
212
|
back content it actually backed up, never a guess**. For precise workspace-level
|
|
213
213
|
history, use Git.
|
|
214
214
|
|
|
215
|
-
##
|
|
215
|
+
## See also
|
|
216
216
|
|
|
217
|
-
This document was originally written for issue
|
|
218
|
-
[#5](https://github.com/SiriLee/dsh-rewind/issues/5) and completed for issue
|
|
219
|
-
[#39](https://github.com/SiriLee/dsh-rewind/issues/39). See also:
|
|
220
217
|
[SECURITY.md](../../SECURITY.md) · [Snapshot auto-cleanup](../snapshot-auto-cleanup.md)
|
|
@@ -126,6 +126,6 @@
|
|
|
126
126
|
|
|
127
127
|
两项限制换来的是:轻量、可预测,以及**只写它确实备份过的内容、绝不做任何猜测**。需要工作区级别的精确历史时,请使用 Git。
|
|
128
128
|
|
|
129
|
-
##
|
|
129
|
+
## 相关
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
[SECURITY.md](../../SECURITY.md) · [快照自动清理](../snapshot-auto-cleanup.zh.md)
|
|
@@ -22,7 +22,7 @@ Compatibility probes against these subsystems (test-driven investigation, the
|
|
|
22
22
|
`compat-invariants` / `compat-interop` vitest suites + the `verify-host` real
|
|
23
23
|
`/compact` chain): [compat/audit.md](compat/audit.md).
|
|
24
24
|
|
|
25
|
-
Also
|
|
25
|
+
Also in the harness repo's `docs/`: `persistence-catalog.md` (full
|
|
26
26
|
`SessionEventMap`), `tool-catalog.md` (tool inventory), `config-catalog.md`
|
|
27
27
|
(configuration inventory).
|
|
28
28
|
|
|
@@ -49,13 +49,6 @@ 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|/undo|/snapshot-auto-cleanup
|
|
53
|
-
+ checkpoint pipeline (tools/execute|post-execute)
|
|
54
|
-
src/rewind.ts pure planning: target resolution, surface range, candidate listing
|
|
55
|
-
src/snapshot.ts checkpoint store (disk before-backups, restore/preview, bounded prune)
|
|
56
|
-
src/snapshot-cleanup.ts cleanup policy + plugin-entry config persistence + auto-sweep throttle
|
|
57
|
-
src/session-cwd.ts session-cwd resolution (fs-tools rule)
|
|
58
|
-
src/locales.ts host i18n (t() renderer, HostKey)
|
|
59
52
|
src/client/index.ts client plugin: /rewind command decoration + per-message ↶ button portals;
|
|
60
53
|
re-exports the client contract (hiddenSeqsOf / targetSeqOfArgs / HiddenChat)
|
|
61
54
|
src/client/popover.ts mode-selection popover (both-mode impact confirm)
|
package/docs/release/release.md
CHANGED
|
@@ -73,7 +73,7 @@ Each release is `git push <branch>` followed by `git push <branch> --tags`.
|
|
|
73
73
|
|
|
74
74
|
DSH is still in rc; npm's prerelease matching rules require a peer range to
|
|
75
75
|
share the host version's `[major, minor, patch]` tuple. So `peerDependencies`
|
|
76
|
-
uses one peer tuple per DSH line (e.g. `^0.
|
|
76
|
+
uses one peer tuple per DSH line (e.g. `^0.2.0-rc.1`). The range is
|
|
77
77
|
conservative: it declares only what was verified, and guarantees nothing
|
|
78
78
|
outside it.
|
|
79
79
|
|
|
@@ -93,10 +93,10 @@ outside it.
|
|
|
93
93
|
- **After DSH goes final**: final releases are not bound by the prerelease
|
|
94
94
|
tuple rule, so the peers can converge to a single stable range (e.g.
|
|
95
95
|
`^0.1.x`); this section can then be deleted.
|
|
96
|
-
- **Declared minimum (`
|
|
97
|
-
release declares the DSH runtime floor under `
|
|
98
|
-
`>=0.
|
|
99
|
-
|
|
96
|
+
- **Declared minimum (`engines.dsh`)**: alongside the peer tuple, each
|
|
97
|
+
release declares the DSH runtime floor under `engines.dsh` (e.g.
|
|
98
|
+
`>=0.2.0-rc.1`). No runtime consumer reads it; its form and its alignment with
|
|
99
|
+
the peer tuple are pinned by `tests/package-layout.test.ts`. Bump it in
|
|
100
100
|
the same release that changes the peer range; never leave code raised while
|
|
101
101
|
the declared floor stays behind. Only the `>=X.Y.Z[-pre]` form is used.
|
|
102
102
|
- **The peers are enforced at startup (`0.1.7-rc.1`)**: DSH checks a profile
|
|
@@ -111,15 +111,9 @@ outside it.
|
|
|
111
111
|
independent of the host; a release declares its DSH line through the peer
|
|
112
112
|
constraint (a single companion tuple), never through the plugin version.
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| `0.8.x` | `0.1.2-rc.1` (single) | current line |
|
|
118
|
-
| `0.9.x` | `0.1.3` (single) | following line |
|
|
119
|
-
|
|
120
|
-
The rows are illustrative — the DSH line a release targets is the peer
|
|
121
|
-
constraint, and its npm dist-tag is derived from the version (see above), so
|
|
122
|
-
this model does not track the plugin's own version number.
|
|
114
|
+
The DSH line a release targets is the peer constraint, and its npm dist-tag is
|
|
115
|
+
derived from the version (see above), so this model does not track the plugin's
|
|
116
|
+
own version number.
|
|
123
117
|
|
|
124
118
|
**Versioning.** A DSH version-line break is a MAJOR bump (incompatible with the
|
|
125
119
|
prior DSH line). Within a line, MINOR/PATCH remain compatible.
|
|
@@ -130,11 +124,6 @@ and is always releasable. The currently-shipped stable is cut into a short-lived
|
|
|
130
124
|
receives backported fixes while `main` advances to the next line. The prior
|
|
131
125
|
(broad-compat) line is frozen as a tag, with no branch.
|
|
132
126
|
|
|
133
|
-
**dist-tag routing.** The release workflow derives the npm dist-tag from the
|
|
134
|
-
version: a stable version publishes to `latest`; a pre-release publishes to the
|
|
135
|
-
dist-tag named by its pre-release identifier (`0.9.0-alpha.1` → `alpha`,
|
|
136
|
-
`0.9.0-rc.1` → `rc`). A pre-release never occupies `latest`.
|
|
137
|
-
|
|
138
127
|
**Support window / EOL.** A DSH line is supported within a declared window. By
|
|
139
128
|
default the window runs until the next DSH line ships as `latest`; after that
|
|
140
129
|
the line is EOL, frozen, and receives no further patches.
|
|
@@ -81,8 +81,8 @@ DSH 仍在 rc 阶段,npm 的 prerelease 匹配规则要求 peer 范围与宿
|
|
|
81
81
|
范围 → `npm install` → `npm run check` → 发版。
|
|
82
82
|
- **正式版后收敛**:DSH 发布 final 版本后,正式版不受 prerelease 元组规则
|
|
83
83
|
限制,peer 可收敛为稳定的 `^0.1.x` 单范围,此节即可删除。
|
|
84
|
-
- **声明的最低运行时(`
|
|
85
|
-
`
|
|
84
|
+
- **声明的最低运行时(`engines.dsh`)**:与 peer 元组一起,每个发布在
|
|
85
|
+
`engines.dsh` 声明 DSH 运行时下限(如 `>=0.1.2-rc.1`)。当前线上还没有
|
|
86
86
|
任何读取方,因此它只是前置声明、尚未被强制执行。**与 peer 范围持平的同一发布里
|
|
87
87
|
一并 bump**;不可只升代码、声明下限停留在旧值。仅使用 `>=X.Y.Z[-pre]` 形式。
|
|
88
88
|
- **peer 在启动时会被强制执行(`0.1.7-rc.1`)**:DSH 会拿 bundle 自身的
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Snapshot cleanup
|
|
2
2
|
|
|
3
|
-
<!-- docs-scope: applies to DSH <= 0.1.6, where the policy is a dsh-settings document namespace. DSH 0.1.7 stores it as the plugin entry's own live configuration; the 0.1.7 seam is recorded in docs/compat/audit.md and docs/format.md. -->
|
|
4
|
-
|
|
5
3
|
The plugin saves a backup of each file before it's edited, so you can rewind your
|
|
6
4
|
code to an earlier point. These backups are called **snapshots**, and they're
|
|
7
5
|
grouped by message and stored per session.
|
|
@@ -17,14 +15,8 @@ you've stopped using, and now and then remove their snapshots to keep disk usage
|
|
|
17
15
|
down. It never touches your active session, and it never touches your
|
|
18
16
|
conversation.
|
|
19
17
|
|
|
20
|
-
**Manual**: even with automatic cleanup off, you can run the cleanup yourself
|
|
21
|
-
|
|
22
|
-
- `/snapshot-auto-cleanup run [--apply]` — preview, then actually remove the
|
|
23
|
-
snapshots of sessions you haven't used for a while.
|
|
24
|
-
- `/snapshot-auto-cleanup run --current [--apply]` — preview, then actually
|
|
25
|
-
clear the **current** session's snapshots. This resets its rewind history to
|
|
26
|
-
"from now on" (your conversation is unaffected). If a turn is currently
|
|
27
|
-
running, the plugin pauses it first, then clears.
|
|
18
|
+
**Manual**: even with automatic cleanup off, you can run the cleanup yourself —
|
|
19
|
+
see [Commands](#commands) below.
|
|
28
20
|
|
|
29
21
|
## Commands
|
|
30
22
|
|
|
@@ -43,12 +35,14 @@ whether or not automatic cleanup is on.
|
|
|
43
35
|
|
|
44
36
|
## Settings
|
|
45
37
|
|
|
46
|
-
The auto-cleanup switch and the idle-day cutoff
|
|
38
|
+
The auto-cleanup switch and the idle-day cutoff are this plugin entry's own
|
|
39
|
+
configuration. View and edit them on the **Plugins** page, in this plugin's
|
|
40
|
+
configuration card, or with the `/snapshot-auto-cleanup` command:
|
|
47
41
|
|
|
48
42
|
<img src="../assets/screenshots/cleanup-setting.png" alt="Plugin configuration card: auto cleanup and idle time (days)" width="600">
|
|
49
43
|
|
|
50
|
-
- `
|
|
51
|
-
- `
|
|
44
|
+
- `autoCleanupEnabled` — whether automatic cleanup runs (default `false`).
|
|
45
|
+
- `autoCleanupMaxAgeDays` — how many idle days before a session's snapshots are removed (default `30`). Only positive integers are accepted, so a broken setting can never delete everything.
|
|
52
46
|
|
|
53
47
|
## When automatic cleanup runs
|
|
54
48
|
|
|
@@ -67,16 +61,18 @@ can't make it run early. To clean up right now instead of waiting, use
|
|
|
67
61
|
session history.
|
|
68
62
|
- Automatic cleanup never removes your **active** session's snapshots — only
|
|
69
63
|
sessions that have been idle past the cutoff.
|
|
70
|
-
- `run --current` clears the current session's snapshots
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
- `run --current` clears the current session's snapshots; if a turn is currently
|
|
65
|
+
running, the plugin pauses it first, then clears. This is one-way for that
|
|
66
|
+
session's file-rewind history: you can't rewind code to before the clear, but
|
|
67
|
+
your conversation stays intact, and the session starts recording fresh
|
|
73
68
|
snapshots from now on.
|
|
74
69
|
|
|
75
70
|
## Known limitation
|
|
76
71
|
|
|
77
|
-
The plugin keeps the most recent **100
|
|
78
|
-
rewind or compact a lot in one long session,
|
|
79
|
-
messages that are no longer reachable, so you
|
|
80
|
-
back as you'd like. (Claude Code behaves the
|
|
81
|
-
|
|
82
|
-
session and
|
|
72
|
+
The plugin keeps the most recent **100 anchor groups'** snapshots per session (one
|
|
73
|
+
group per user message). If you rewind or compact a lot in one long session,
|
|
74
|
+
those 100 slots can be taken up by messages that are no longer reachable, so you
|
|
75
|
+
may find you can't rewind as far back as you'd like. (Claude Code behaves the
|
|
76
|
+
same way.) To get back to a clean state, run
|
|
77
|
+
`/snapshot-auto-cleanup run --current --apply` to clear the current session and
|
|
78
|
+
start fresh.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# 快照清理
|
|
2
2
|
|
|
3
|
-
<!-- docs-scope: 适用于 DSH <= 0.1.6,此时策略存放在 dsh-settings 文档的命名空间;DSH 0.1.7 起改为本插件条目自身的实时配置,0.1.7 的接缝记录在 docs/compat/audit.md 与 docs/format.md。 -->
|
|
4
|
-
|
|
5
3
|
插件会在每次修改文件前保存一份备份,方便你把代码回退到之前的状态。这些备份叫**快照**,按消息分组、按会话存放。
|
|
6
4
|
|
|
7
5
|
`/snapshot-auto-cleanup` 帮你管理这些快照——既可以回收旧会话占用的磁盘,也可以清空**当前**会话、让它从"现在"重新开始记录回退历史。
|
|
@@ -10,10 +8,7 @@
|
|
|
10
8
|
|
|
11
9
|
**自动清理**(默认关闭):插件会记住哪些会话你已不再使用,并定期移除它们的快照以节省磁盘。它**绝不**触碰你当前活跃的会话,也**绝不**触碰你的对话。
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- `/snapshot-auto-cleanup run [--apply]` — 先预演,再真正移除你已有一阵子没用的会话的快照。
|
|
16
|
-
- `/snapshot-auto-cleanup run --current [--apply]` — 先预演,再真正清空**当前**会话的快照。这会让它从"现在"重新开始记录回退历史(你的对话不受影响)。若此刻有正在进行中的回合,插件会先暂停它,再清空。
|
|
11
|
+
**手动**:即使自动清理是关闭的,你也可以自己执行清理——见下[命令](#命令)。
|
|
17
12
|
|
|
18
13
|
## 命令
|
|
19
14
|
|
|
@@ -35,8 +30,8 @@
|
|
|
35
30
|
|
|
36
31
|
<img src="../assets/screenshots/cleanup-setting.png" alt="插件配置卡片:自动清理与不活跃时间(天)" width="600">
|
|
37
32
|
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
33
|
+
- `autoCleanupEnabled` — 是否运行自动清理(默认 `false`)。
|
|
34
|
+
- `autoCleanupMaxAgeDays` — 会话失活多少天后移除其快照(默认 `30`)。只接受正整数,因此一个损坏的设置永远不可能"删掉一切"。
|
|
40
35
|
|
|
41
36
|
## 自动清理何时运行
|
|
42
37
|
|
|
@@ -46,8 +41,8 @@
|
|
|
46
41
|
|
|
47
42
|
- 只会移除回退用的**快照**:一个会话的快照目录里只有写前文件备份及其附属记录(暂存副本、救援副本、还原日志),清理也只动这些。你的对话绝不会被动到,插件也绝不改写或删除你的会话历史。
|
|
48
43
|
- 自动清理**永不**移除你**当前活跃**会话的快照——只清理已失活超过阈值的会话。
|
|
49
|
-
- `run --current`
|
|
44
|
+
- `run --current` 会清空当前会话的快照;若此刻有正在进行中的回合,插件会先暂停它再清空。这对该会话的文件回退历史是**不可逆**的:你无法回退到清空之前的代码状态,但你的对话保持完整,会话会从"现在"开始重新记录快照。
|
|
50
45
|
|
|
51
46
|
## 已知限制
|
|
52
47
|
|
|
53
|
-
插件每个会话只保留**最近 100
|
|
48
|
+
插件每个会话只保留**最近 100 组锚点**的快照(每条用户消息一组)。若你在一个很长的会话里多次回退或压缩,这 100 个名额常会被"已经无法再回退到"的消息占满,你可能无法回退到想要的位置。(Claude Code 也是同样行为。)想恢复到一个干净状态,运行 `/snapshot-auto-cleanup run --current --apply` 清空当前会话、重新开始。
|