dsh-rewind-plugin 0.13.0-alpha.1 → 0.14.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/CONTRIBUTING.md +1 -1
- package/SECURITY.md +4 -4
- package/assets/icon.svg +24 -0
- package/docs/README.md +1 -1
- package/docs/architecture.md +3 -3
- package/docs/compat/audit.md +80 -44
- package/docs/compat/diagnostics.md +1 -0
- package/docs/compat/diagnostics.zh.md +1 -0
- package/docs/contract/client-contract.md +4 -2
- package/docs/contract/client-contract.zh.md +1 -1
- package/docs/format.md +10 -9
- package/docs/harness-reference.md +6 -3
- package/docs/release/release.md +9 -9
- package/docs/release/release.zh.md +10 -10
- package/docs/rewind-fix.md +1 -1
- package/docs/rewind-fix.zh.md +1 -1
- package/docs/snapshot-auto-cleanup.md +2 -0
- package/docs/snapshot-auto-cleanup.zh.md +2 -0
- package/lib/client.js +236 -474
- package/lib/index.js +110 -41
- package/lib/types/client/build-info.d.ts +6 -0
- package/lib/types/client/candidates.d.ts +0 -2
- package/lib/types/client/hidden.d.ts +11 -7
- package/lib/types/client/index.d.ts +6 -1
- package/lib/types/client/locales.d.ts +6 -14
- package/lib/types/client/pending.d.ts +57 -15
- package/lib/types/client/popover.d.ts +1 -1
- package/lib/types/client/portals.d.ts +93 -29
- package/lib/types/client/settings-card.d.ts +101 -60
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/index.d.ts +43 -4
- package/lib/types/locales.d.ts +26 -9
- package/lib/types/marker.d.ts +39 -0
- package/lib/types/rewind.d.ts +5 -23
- package/lib/types/snapshot-cleanup.d.ts +44 -41
- package/lib/types/snapshot.d.ts +1 -8
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +69 -54
package/CONTRIBUTING.md
CHANGED
|
@@ -8,7 +8,7 @@ first), and the docs live under `docs/` with an index in `docs/README.md`.
|
|
|
8
8
|
|
|
9
9
|
- **Focused on purpose** — one thing: in-window rewind to any earlier user
|
|
10
10
|
message, never forking a session.
|
|
11
|
-
- **Security first** — session logs are append-only; file restores
|
|
11
|
+
- **Security first** — session logs are append-only; file restores draw only from
|
|
12
12
|
the plugin's own backup directory. See `SECURITY.md`.
|
|
13
13
|
- **Minimal** — avoid over-abstraction; keep the plugin light and maintainable.
|
|
14
14
|
|
package/SECURITY.md
CHANGED
|
@@ -90,7 +90,7 @@ transcript.
|
|
|
90
90
|
|
|
91
91
|
## Filesystem containment
|
|
92
92
|
|
|
93
|
-
- **Store root**: `<
|
|
93
|
+
- **Store root**: `<dsh home>/rewind-snapshots/` by default (resolved via
|
|
94
94
|
`resolveDshHome`, so `~/.dsh/...` when `DSH_HOME` is unset); the `snapshotDir`
|
|
95
95
|
config, then `DSH_REWIND_SNAPSHOT_DIR` env, override it. Deleting it only
|
|
96
96
|
removes file backups and the store rebuilds from scratch.
|
|
@@ -128,9 +128,9 @@ transcript.
|
|
|
128
128
|
bounded by the cap plus the number of unresolved journals (the exact cap is
|
|
129
129
|
pinned in `docs/format.md`). Across sessions, the opt-in `pruneStale` sweep
|
|
130
130
|
removes whole **long-inactive** session directories (measured by the newest
|
|
131
|
-
member being idle past `
|
|
132
|
-
skips dot-prefixed temp files, and never
|
|
133
|
-
(`keepActiveId`).
|
|
131
|
+
member being idle past the configured `autoCleanupMaxAgeDays`); it uses
|
|
132
|
+
`lstat` (no symlink following), skips dot-prefixed temp files, and never
|
|
133
|
+
targets the active session (`keepActiveId`).
|
|
134
134
|
|
|
135
135
|
## Crash safety
|
|
136
136
|
|
package/assets/icon.svg
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Layout follows the terminal card glyph (packages/client/ui-sidebar-terminal):
|
|
3
|
+
a rounded tile inset from the canvas (28/36 here, 22/28 there) with a
|
|
4
|
+
white round-capped prompt. The fill follows the Subagent plugin artwork
|
|
5
|
+
(packages/client/ui-primitives/src/plugin-artwork.tsx), whose blue square
|
|
6
|
+
carries the same vertical light-to-dark gradient: #69B9FF at the top,
|
|
7
|
+
#324DE2 at the bottom.
|
|
8
|
+
The rewind mark is the in-app back-arrow (src/client/styles.ts, 16-unit
|
|
9
|
+
grid) scaled 1.4x. Its ink box including the 0.75 stroke reaches
|
|
10
|
+
(1.75,1.75)-(14.25,12.75) on that grid, so the translate lands its centre
|
|
11
|
+
on the tile centre (18,18), and the ink spans 62.5% of the tile width —
|
|
12
|
+
the terminal glyph's own ratio. -->
|
|
13
|
+
<rect x="4" y="4" width="28" height="28" rx="8" fill="url(#rewind_blue)" />
|
|
14
|
+
<g transform="translate(6.8 7.85) scale(1.4)" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
15
|
+
<path d="M6.5 2.5 2.5 6.5l4 4" />
|
|
16
|
+
<path d="M2.5 6.5h7a4 4 0 0 1 4 4v1.5" />
|
|
17
|
+
</g>
|
|
18
|
+
<defs>
|
|
19
|
+
<linearGradient id="rewind_blue" x1="18" y1="4" x2="18" y2="32" gradientUnits="userSpaceOnUse">
|
|
20
|
+
<stop stop-color="#69B9FF" />
|
|
21
|
+
<stop offset="1" stop-color="#324DE2" />
|
|
22
|
+
</linearGradient>
|
|
23
|
+
</defs>
|
|
24
|
+
</svg>
|
package/docs/README.md
CHANGED
|
@@ -12,7 +12,7 @@ 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` |
|
|
15
|
+
| `rewind-fix.md` | Historical guide for the removed `/dsh-rewind-fix` (`.zh` mirror) | users / maintainers |
|
|
16
16
|
| `contract/client-contract.md` | Rewind visibility contract for third-party DOM plugins (`.zh` mirror) | integrators |
|
|
17
17
|
| `compat/audit.md` | Compatibility audit: verified surfaces, recorded findings, probe matrix | maintainers |
|
|
18
18
|
| `compat/tracking-boundary.md` | Which files a rewind restores: the tracking boundary (`.zh` mirror) | users / maintainers |
|
package/docs/architecture.md
CHANGED
|
@@ -134,13 +134,13 @@ pruneStale cross-session auto-cleanup (default off): whole
|
|
|
134
134
|
|
|
135
135
|
## Compatibility strategy
|
|
136
136
|
|
|
137
|
-
- **Peer ranges as one tuple per DSH line** (`^0.1.
|
|
137
|
+
- **Peer ranges as one tuple per DSH line** (`^0.1.6-alpha.2`): npm's prerelease
|
|
138
138
|
rules require the peer range to share the host's `[major, minor, patch]`
|
|
139
139
|
tuple, so a new DSH tuple replaces the peer tuple (the single-line model);
|
|
140
140
|
`scripts/check-dsh-version.mjs` flags when a new tuple arrives. See
|
|
141
141
|
`docs/release/release.md`.
|
|
142
|
-
- **Test-driven investigation**: `tests/compat-invariants.ts` /
|
|
143
|
-
`compat-interop` / `compat-gaps` probe harness behavior and pin findings in
|
|
142
|
+
- **Test-driven investigation**: `tests/compat-invariants.test.ts` /
|
|
143
|
+
`compat-interop.test.ts` / `compat-gaps.test.ts` probe harness behavior and pin findings in
|
|
144
144
|
`docs/compat/audit.md`; `scripts/verify-host.mjs` runs a real end-to-end
|
|
145
145
|
rewind + `/compact` chain (the full check suite).
|
|
146
146
|
- **Stable machine channels for third parties**: `dsh-rewind-plugin/client`
|
package/docs/compat/audit.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
> compatibility invariants. A probe failure is a finding; it enters the
|
|
8
8
|
> fix/pin/record loop.
|
|
9
9
|
>
|
|
10
|
-
> Targeted version: npm `@deepseek-ai/*@0.1.
|
|
10
|
+
> Targeted version: npm `@deepseek-ai/*@0.1.7-alpha.1` (the range the peers and `dsh.engines.dsh` declare).
|
|
11
11
|
> Source reference: the upstream [github.com/deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
12
12
|
>
|
|
13
13
|
> Version alignment: `peerDependencies` use one tuple per DSH line
|
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
> share the range comparator's `[major, minor, patch]` tuple, so a new DSH tuple
|
|
16
16
|
> replaces the peer tuple (single-line model). The range is conservative — it
|
|
17
17
|
> declares only what was verified, so a release already inside it changes
|
|
18
|
-
> nothing
|
|
18
|
+
> nothing — unless it changes interfaces inside the tuple: `0.1.6-alpha.2`
|
|
19
|
+
> removed the client session-ownership and queue-mirror APIs, and
|
|
20
|
+
> `0.1.7-alpha.1` moved the session writer to format v4 (producer-owned message
|
|
21
|
+
> sources, tool-role results, `developer/message`) and replaced the settings
|
|
22
|
+
> namespace registry with each entry's volatile `Config`, so the peer floor and
|
|
23
|
+
> both plugin seams moved with them. Signal: `npm view @deepseek-ai/dsh dist-tags`;
|
|
19
24
|
> flow: `scripts/check-dsh-version.mjs` (it reads the `latest` dist-tag only; a
|
|
20
25
|
> prerelease published under another tag is a manual pre-release check).
|
|
21
26
|
>
|
|
@@ -33,7 +38,7 @@ legacy branch).
|
|
|
33
38
|
| Host session log | `session.snapshotEvents()` |
|
|
34
39
|
| Client chat snapshot | `uiConversation` `chat` view (`chatSnapshotOf`) |
|
|
35
40
|
| Client composer refill | `conversation.input.setDraft` facade |
|
|
36
|
-
| Client settings card |
|
|
41
|
+
| Client settings card | entry form via `ctx.configForms.get(entryId)` (`plugins.bundle.config`) |
|
|
37
42
|
| Client seat-button DOM | structural locate of the copy-`<button>` container (`actionsContainerOf`) |
|
|
38
43
|
|
|
39
44
|
## Definition of "fully compatible" (invariants)
|
|
@@ -45,9 +50,9 @@ legacy branch).
|
|
|
45
50
|
| 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` |
|
|
46
51
|
| I4 fold-service safety | stats / title / goal / projection fold a marker-bearing log without throwing, with predictable values | `compat-invariants` I4 |
|
|
47
52
|
| 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 |
|
|
48
|
-
| 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–
|
|
53
|
+
| 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 |
|
|
49
54
|
| I7 client ordering | A log carrying tool turns and rewind markers (a single `user/message` replace) satisfies the client builder ordering | `compat-interop` I7 |
|
|
50
|
-
| I8 runtime safety | `rewind`/`compact` combinations never leave a dangling step/turn frame | `verify-host`
|
|
55
|
+
| I8 runtime safety | `rewind`/`compact` combinations never leave a dangling step/turn frame | `verify-host` 13 |
|
|
51
56
|
|
|
52
57
|
## Verified-compatible surfaces (probes pass)
|
|
53
58
|
|
|
@@ -60,7 +65,11 @@ legacy branch).
|
|
|
60
65
|
- **rewind across a compact checkpoint**: `RewindError('not-on-surface')` refuses cleanly, no crash.
|
|
61
66
|
- **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`).
|
|
62
67
|
- **agent-loop cancellation**: `finally` guarantees step/turn closure; the rewind force-stop path leaves no dangling frame.
|
|
63
|
-
- **settings-card registration**: the
|
|
68
|
+
- **settings-card registration (`0.1.7-alpha.1`)**: `settingsScope` is gone with the namespace registry. 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 the entry's form snapshot and writes through its revision-fenced `mutate`, and disposes the model's subscription with the fiber.
|
|
69
|
+
- **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`.
|
|
70
|
+
- **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'`). Pins: `tests/pending.test.ts`, `tests/client-retract.test.ts`.
|
|
71
|
+
- **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`.
|
|
72
|
+
- **client settings form (`0.1.7-alpha.1`)**: the same release retired the `settingsScope` bind (namespace registry) in favour of the shared per-entry form; the card now reads that form's snapshot and stages edits through `mutate`. Pin: `tests/client-settings-card.test.ts` (staged plan, refusal, and the fiber releasing the model's subscription), `tests/client-lifecycle.test.ts`.
|
|
64
73
|
|
|
65
74
|
- **`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.
|
|
66
75
|
- **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`.
|
|
@@ -71,13 +80,14 @@ legacy branch).
|
|
|
71
80
|
|
|
72
81
|
- **session-stats / session-telemetry fold the full log**: post-rewind stats do **not** rewind — `turns`/`steps`/`llmMs` still include withdrawn content; the `user/message` marker is folded as a present user turn (it adds no step). This is the intended "fold the full log" semantics, pinned by probe.
|
|
73
82
|
- **token-meter usage anchor stays stable** (G3): the `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.
|
|
74
|
-
- **marker content is the constant `(empty message)` placeholder**: never empty, because the session log is immutable but the model serving a session may change later — a strict OpenAI-compatible gateway rejects an empty user message (HTTP 400, Issue #21). The marker is a small visible user turn in derived history. Pin: `verify-host` (`marker is a user/message with the dsh-rewind
|
|
75
|
-
- **marker shape (
|
|
83
|
+
- **marker content is the constant `(empty message)` placeholder**: never empty, because the session log is immutable but the model serving a session may change later — a strict OpenAI-compatible gateway rejects an empty user message (HTTP 400, Issue #21). The marker is a small visible user turn in derived history. Pin: `verify-host` (`marker is a user/message with the dsh-rewind producer source and the (empty message) placeholder`).
|
|
84
|
+
- **marker shape (v4)**: the replace `surfaceOp` is `{ op: 'replace', startSeq, endSeq }` (renamed from `start`/`end` in session-format v3); the dsh-rewind source is the single producer-owned kind `{ kind: 'dsh-rewind' }`, declared by merging `MessageSourceMap` (v4 removed the catch-all `plugin` kind and rejects it on write). Two older shapes stay readable, because a stored marker is immutable: the released v3 wrapper `{ kind: 'plugin', plugin: 'dsh-rewind' }`, and the `plugin:dsh-rewind` form the v3→v4 conversion gives a producer its rename table does not know. The `user/message` + `sourceEventSeqs` shape and the `(empty message)` content are unchanged.
|
|
76
85
|
- **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).
|
|
77
86
|
- **Session title auto-regeneration**: the title derives from the surface, so an automatically-derived title may change after a rewind.
|
|
78
87
|
- **Files written but uncommitted in a cancelled turn**: a `both` rewind cannot restore them (tool side-effect timing; same as Claude Code).
|
|
79
88
|
- **Attachment files left after a message is shadowed**: attachment storage is not cleaned with the surface (`dsh-attachment-local` not installed, not automatically verified).
|
|
80
89
|
- **Rewind leaves plan mode untouched**: `/plan text` is two independent actions (enter plan mode + steer the message). Rewinding the message undoes only the message — the log-only `plan/mode` state stays active, and the user leaves plan mode with `/plan off`, which still commits after a rewind (the marker creates no open turn). Pin: `verify-host` plan checks (`plan rewind leaves plan mode active`, `/plan off after rewind turns plan mode off`), `tests/hidden.test.ts` `messageTextAt`.
|
|
90
|
+
- **Bundle card metadata is declared by the plugin, not by the manager (`0.1.7-alpha.1`)**: the manager still titles a bundle with `shortName(pkg.name)` and its raw `package.json` description when nothing else is declared, but it now reads plugin-owned resources first — `locale/<lang>.json` (`meta.title`/`meta.description`) through the package exports map, and an `icon` file relative to the manifest. This plugin declares both, so its card shows an icon and copy that follows the active language; only the fallback description remains mixed-language. Pin: `tests/package-layout.test.ts` (icon path/media/size and both dictionaries).
|
|
81
91
|
|
|
82
92
|
- **Synchronous Session history reads are deprecated** on this line (`snapshotEvents` / `eventAt` / `ownEvents`): existing calls may remain, new calls are prohibited. The plugin keeps its existing reads (turn anchor + candidate listing); the migration path is a `ctx.sessionProjections` projection unit or the async paged history read this line has not shipped yet — not a plugin-side index. Not migrated in this release.
|
|
83
93
|
|
|
@@ -85,46 +95,43 @@ legacy branch).
|
|
|
85
95
|
|
|
86
96
|
The plugin treats these as harness-side defects it does not compensate for. Each entry records the harness issue, its current status, and the plugin's stance, so a future maintainer does not "fix the wrong direction."
|
|
87
97
|
|
|
88
|
-
### RU-I18N
|
|
98
|
+
### RU-I18N (resolved on the 0.1.7 line): host command copy follows the user's language
|
|
89
99
|
|
|
90
|
-
- **
|
|
91
|
-
`ctx.inject(['settings'])` callback that
|
|
92
|
-
**once, with no retry** (`src/index.ts`)
|
|
93
|
-
|
|
100
|
+
- **History (0.1.2–0.1.6 lines)**: the plugin resolved `activeLocale` in an
|
|
101
|
+
`ctx.inject(['settings'])` callback that read `settings.get('locale').preference`
|
|
102
|
+
**once, with no retry** (`src/index.ts`), while `dsh-client-locale`'s host half registered that
|
|
103
|
+
`locale` settings section through its own `ctx.inject(['settings'])`
|
|
94
104
|
(`packages/client/locale/src/index.ts`). Both callbacks wait only on `settings` and are
|
|
95
|
-
independent of each other, so cordis
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- **
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
third-party description, this plugin's included, passes through verbatim.)
|
|
113
|
-
- **Client-side command-description i18n is first-party-only**: DSH also localizes host command
|
|
105
|
+
independent of each other, so cordis made **no ordering guarantee** between the section
|
|
106
|
+
registration and the plugin's read. The plugin's own command descriptors were registered
|
|
107
|
+
**synchronously** in the same `apply`, i.e. before that microtask ran, so their `description`
|
|
108
|
+
strings were baked in the neutral English default — the defect reported as #28 — while the
|
|
109
|
+
runtime output, evaluated later at command execution from the then-updated `activeLocale`, did
|
|
110
|
+
follow the stored preference. A preference changed *after* the mount reached the output only on
|
|
111
|
+
the next mount, because the read was one-shot.
|
|
112
|
+
- **Resolution (0.1.7)**: the section is gone — the locale host half now only calls
|
|
113
|
+
`settings.configure({ auto: false })`, and the preference lives in the `locale` entry's own
|
|
114
|
+
Config. The plugin reads that same value through the settings service's descriptor read
|
|
115
|
+
(`readHostLocale` in `src/index.ts` calls `settings.describe({ redactSecrets: true })`, the route
|
|
116
|
+
the settings UI and the client's own locale runtime take): at mount, which is what the
|
|
117
|
+
once-registered command descriptions carry, and again before each command renders, so the output
|
|
118
|
+
follows a language switch without a remount (the descriptors keep the mount-time language until
|
|
119
|
+
the plugin remounts). The read is best-effort: a missing method, a missing entry, or a
|
|
120
|
+
throwing read stays on the neutral English default.
|
|
121
|
+
- **Client-side command-description i18n is still first-party-only**: DSH localizes host command
|
|
114
122
|
descriptions through the client `locale` binding (`ui-commands`), but the description keys come
|
|
115
|
-
from a **closed allowlist** (`
|
|
123
|
+
from a **closed allowlist** (`HOST_FACES`: compact, export, feedback, goal,
|
|
116
124
|
permission, plan). A command outside that set — every third-party plugin — is passed through
|
|
117
|
-
verbatim, never translated (`
|
|
118
|
-
first-party English copy)
|
|
119
|
-
|
|
120
|
-
runtime copy above.
|
|
125
|
+
verbatim, never translated (`builtinRowFace` only rewrites a description that equals the
|
|
126
|
+
first-party English copy), and no host command *output* is localized by the harness for anyone.
|
|
127
|
+
This plugin's host dictionary is what carries both, in the language read above.
|
|
121
128
|
|
|
122
129
|
### R-OPENSTEP (rewind part resolved): an unclosed `step` in the log breaks token-meter replay; the rewind no longer compounds it
|
|
123
130
|
|
|
124
131
|
> **Root cause (harness-side)**: an unclosed step left by a crash makes token-meter replay
|
|
125
132
|
> reject any later step activity. DSH `0.1.1-rc.2` now auto-closes crash-left step/turn/tool
|
|
126
133
|
> boundaries at load via `interruptedTurnClosers` (`dsh-session`, consumed by
|
|
127
|
-
> `
|
|
134
|
+
> `packages/core/agent-loop/src/index.ts:907`) — **the crash path is fixed**.
|
|
128
135
|
>
|
|
129
136
|
> **Plugin guard (attempted and reverted)**: a `hasOpenStep` + `planRewind` pre-refusal was
|
|
130
137
|
> implemented (`open-step`) but misjudged on **real session logs** (normal rewinds refused, GUI
|
|
@@ -135,19 +142,19 @@ The plugin treats these as harness-side defects it does not compensate for. Each
|
|
|
135
142
|
|
|
136
143
|
#### Concrete `step/start` trigger paths (source-confirmed)
|
|
137
144
|
|
|
138
|
-
The tree has exactly **one** `append('step/start')` producer: `packages/core/agent-loop/src/agent.ts:
|
|
145
|
+
The tree has exactly **one** `append('step/start')` producer: `packages/core/agent-loop/src/agent.ts:303`
|
|
139
146
|
(no other producer inside the official packages; `session/end-seed` etc. only truncate torn writes,
|
|
140
147
|
not logically-unclosed steps).
|
|
141
148
|
|
|
142
149
|
| # | Trigger path | Plausibility | Basis |
|
|
143
150
|
|---|---|---|---|
|
|
144
|
-
| P1 | **Abnormal process termination**: `step/start` is batched to disk (write-behind, `maxDelayMs` per batch) → the step is mid-execution (LLM stream/tool, seconds to minutes) → SIGKILL / OOM-kill / power loss / WSL hard-close → `step/end` (in `finally`, only runs while the process is alive) is never persisted | **Most realistic** | `agent.ts:
|
|
151
|
+
| P1 | **Abnormal process termination**: `step/start` is batched to disk (write-behind, `maxDelayMs` per batch) → the step is mid-execution (LLM stream/tool, seconds to minutes) → SIGKILL / OOM-kill / power loss / WSL hard-close → `step/end` (in `finally`, only runs while the process is alive) is never persisted | **Most realistic** | `agent.ts:313` finally; write-behind batching; torn-write fix truncates only a half-written line |
|
|
145
152
|
| P2 | **Third-party plugin bug**: only the official agent-loop produces one, but external plugins may `session.append('step/start', …)` and never close it | possible | public `Session.append` |
|
|
146
153
|
| P3 | **Manual session-file editing**: edit `~/.dsh/…/session.jsonl[.zstd]` (zstd needs decompress/recompress; plaintext config edits directly) | possible but laborious | `persistence-jsonl/format.ts` (`JsonlCompression = 'zstd' \| 'none'`) |
|
|
147
|
-
| P4 | **append itself failing**: `append('step/end')` in `finally` throws (payload is plain numbers, nearly impossible) | theoretical | `agent.ts:
|
|
154
|
+
| P4 | **append itself failing**: `append('step/end')` in `finally` throws (payload is plain numbers, nearly impossible) | theoretical | `agent.ts:313` |
|
|
148
155
|
|
|
149
156
|
**Amplifier (rewind is not the only trigger)**: after a crash resume, agent-loop `turn()` opens a
|
|
150
|
-
new turn at `phase.turn + 1` (`agent.ts:
|
|
157
|
+
new turn at `phase.turn + 1` (`agent.ts:277-283`) **without closing the leftover step** — so
|
|
151
158
|
"continue the conversation" (a new `step/start`) trips the same token-meter check. Scope:
|
|
152
159
|
|
|
153
160
|
- **The conversation itself is unaffected** (the request path does not call `tokenMeter.measure`; only compaction-basic does tree-wide).
|
|
@@ -155,6 +162,34 @@ new turn at `phase.turn + 1` (`agent.ts:251-255`) **without closing the leftover
|
|
|
155
162
|
- **Automatic compaction silently stays disabled** (the `agent/pre-step` hook catches and warns; the conversation continues).
|
|
156
163
|
- **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.
|
|
157
164
|
|
|
165
|
+
### R-PROMPTCARD (resolved on the 0.1.7 line): the repeated `System prompt` card is filtered out of chat
|
|
166
|
+
|
|
167
|
+
> **History (0.1.2–0.1.6 lines)**: Chat rendered a collapsed `System prompt`
|
|
168
|
+
> card at every request-series start. Any surface mutation bumps `contentGeneration` (a positional
|
|
169
|
+
> `replace` — rewind, `/compact` — or a `SessionMessageProjection`, e.g. image offload), so the next
|
|
170
|
+
> request logs `request/header { reason: 'series' }`; a process restart logs `'resume'`. The client
|
|
171
|
+
> shows the card for every reason except `'change'`. The effective prompt is unchanged — only the
|
|
172
|
+
> card repeats. Triggers beyond rewind: `/compact`, restart/resume, projections, explicit
|
|
173
|
+
> `startsSeries`.
|
|
174
|
+
>
|
|
175
|
+
> **Upstream decision (deliberate, twice)**: `6ad01cbd8d` suppressed the repeat on `resume` (note
|
|
176
|
+
> `2026-09-03-resume-headers-do-not-repeat-system-prompts.md`, rejecting the card as a "lifecycle
|
|
177
|
+
> marker" that "incorrectly implies another prompt injection"); three days later `77b6b10c21`
|
|
178
|
+
> restored it — a resume/series header starts a visible request series. Locked by the `ui-chat` test
|
|
179
|
+
> `repeats an unchanged system prompt after a surface rewrite…`.
|
|
180
|
+
>
|
|
181
|
+
> **Resolution (0.1.7)**: upstream stopped rendering the card in chat at all. `isVisibleChatNode`
|
|
182
|
+
> (`packages/client/ui-chat/src/client/contract/chat-visibility.ts`, added by `b6f99fad55`
|
|
183
|
+
> "feat(ui-chat): filter system prompts and permission commands") drops `system-prompt` nodes — and
|
|
184
|
+
> the `permission` command — from the visible chat rows, while the durable events and the trajectory
|
|
185
|
+
> inspection keep them. The `showsPrompt` computation is unchanged and no longer matters: the node is
|
|
186
|
+
> filtered before the row is built, so a rewind on this line adds no prompt row at all. #22, #31 and
|
|
187
|
+
> README known issue #4 no longer reproduce.
|
|
188
|
+
>
|
|
189
|
+
> **Plugin stance**: still no compensation. The DOM row-hiding seam (`hiddenSeqsOf`) covers withdrawn
|
|
190
|
+
> messages, where hiding is essential, not cosmetic; nothing was added for the card, and the
|
|
191
|
+
> display-layer workup above stays valid history.
|
|
192
|
+
|
|
158
193
|
## Uncovered boundaries (need an additional e2e layer; non-blocking)
|
|
159
194
|
|
|
160
195
|
- Real LLM streaming and auto title generation (L2 stubbed).
|
|
@@ -180,7 +215,8 @@ new turn at `phase.turn + 1` (`agent.ts:251-255`) **without closing the leftover
|
|
|
180
215
|
| client ordering | — | — | ✓ | — | — | — | ✓ | — |
|
|
181
216
|
| plan-mode | ✓ | — | ✓ | — | — | — | — | ✓ (static) |
|
|
182
217
|
|
|
183
|
-
✓ = probe passes; — = not applicable. RU-I18N and R-
|
|
184
|
-
|
|
218
|
+
✓ = probe passes; — = not applicable. RU-I18N and R-PROMPTCARD are resolved on the 0.1.7 line (see
|
|
219
|
+
above); R-OPENSTEP is an upstream issue the
|
|
220
|
+
plugin does not compensate for (see above); G3 is a confirmed-non-defect behavior pinned in
|
|
185
221
|
`compat-gaps.test.ts` (G1 surface classification via `foldSurface` and G2 projection checkpoint
|
|
186
222
|
both pass).
|
|
@@ -35,6 +35,7 @@ console filter:
|
|
|
35
35
|
| `refill` | The composer refill after a rewind (command/wait/refill throws, a rejected or unmatched command, an outcome that never settles) |
|
|
36
36
|
| `preview` | The `/rewind preview` impact probe behind the mode popover (command rejected/unmatched/threw, an outcome that never settles) |
|
|
37
37
|
| `portals` | Per-message button mount issues (e.g. no session binding) |
|
|
38
|
+
| `retract` | The pending-steering retract path (the remove lost the race, or the remove threw) |
|
|
38
39
|
| `settings` | The snapshot-cleanup settings card |
|
|
39
40
|
| `hiding` | **Reserved** — no active alert at present. If a future row-hiding diagnostic is added, it belongs in this region. |
|
|
40
41
|
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
| `refill` | 回退后的输入框回填(命令/等待/回填抛出异常、命令被拒绝或未匹配、等待的结果始终未落定) |
|
|
26
26
|
| `preview` | 模式气泡背后的 `/rewind preview` 影响探测(命令被拒绝/未匹配/抛出异常、等待的结果始终未落定) |
|
|
27
27
|
| `portals` | 每条消息按钮的挂载问题(如无会话绑定) |
|
|
28
|
+
| `retract` | 插话撤回路径(remove 竞争失败,或 remove 抛错) |
|
|
28
29
|
| `settings` | 快照清理设置卡片 |
|
|
29
30
|
| `hiding` | **保留区**——当前无活跃告警。若未来新增行隐藏诊断,应归属此区域。 |
|
|
30
31
|
|
|
@@ -21,7 +21,7 @@ the plugin itself uses (it never reads the DOM or host copy):
|
|
|
21
21
|
```ts
|
|
22
22
|
import { hiddenSeqsOf, type HiddenChat } from 'dsh-rewind-plugin/client'
|
|
23
23
|
|
|
24
|
-
const chat = uiConversation.binding(sessionId).target('chat')?.getSnapshot() // the
|
|
24
|
+
const chat = uiConversation.binding(sessionId).target('chat')?.getSnapshot() // the `uiConversation` "chat" view
|
|
25
25
|
const hidden = hiddenSeqsOf(chat as HiddenChat) // Set<number> of anchor seqs
|
|
26
26
|
```
|
|
27
27
|
|
|
@@ -35,7 +35,9 @@ dsh-chat-timeline#6).
|
|
|
35
35
|
## DOM attribute
|
|
36
36
|
|
|
37
37
|
Each withdrawn row carries `data-dsh-rewind-hidden="true"` while hidden,
|
|
38
|
-
removed on un-hide.
|
|
38
|
+
removed on un-hide. The same attribute also lands on a step/process GROUP shell
|
|
39
|
+
— the view container around a turn's process rows, which is not itself a message
|
|
40
|
+
— when every member it holds is withdrawn. Contract:
|
|
39
41
|
|
|
40
42
|
- The **attribute name** is stable; treat the value as opaque.
|
|
41
43
|
- It is **observational only** — rewind hides via `style.display`; the
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
```ts
|
|
21
21
|
import { hiddenSeqsOf, type HiddenChat } from 'dsh-rewind-plugin/client'
|
|
22
22
|
|
|
23
|
-
const chat = uiConversation.binding(sessionId).target('chat')?.getSnapshot() //
|
|
23
|
+
const chat = uiConversation.binding(sessionId).target('chat')?.getSnapshot() // `uiConversation` 的 "chat" 视图
|
|
24
24
|
const hidden = hiddenSeqsOf(chat as HiddenChat) // 被隐藏的 anchor seq 集合
|
|
25
25
|
```
|
|
26
26
|
|
package/docs/format.md
CHANGED
|
@@ -7,7 +7,7 @@ and this spec disagree, the code wins and this spec is a bug.
|
|
|
7
7
|
|
|
8
8
|
## State root
|
|
9
9
|
|
|
10
|
-
The store root defaults to `<
|
|
10
|
+
The store root defaults to `<dsh home>/rewind-snapshots/` — the dsh data
|
|
11
11
|
directory (`~/.dsh/rewind-snapshots/` when `DSH_HOME` is unset) — overridable in
|
|
12
12
|
order by the `snapshotDir` plugin config, then the `DSH_REWIND_SNAPSHOT_DIR`
|
|
13
13
|
environment variable. It is a sibling of the workspace, never a subtree of it.
|
|
@@ -46,7 +46,7 @@ Deleting the root only removes file backups; the store rebuilds from scratch.
|
|
|
46
46
|
- `store` is the session's store-format marker (a decimal version, written
|
|
47
47
|
atomically); a missing marker means the released v1 string format. `format` is
|
|
48
48
|
the DSH **session**-format marker the snapshots were anchored under (see
|
|
49
|
-
`
|
|
49
|
+
`SECURITY.md`) — the two are independent.
|
|
50
50
|
|
|
51
51
|
## Checkpoint entry
|
|
52
52
|
|
|
@@ -261,10 +261,11 @@ migration tool. Old-format data is never silently re-interpreted.
|
|
|
261
261
|
|
|
262
262
|
## Cleanup policy persistence
|
|
263
263
|
|
|
264
|
-
The snapshot auto-cleanup policy (the `
|
|
265
|
-
idle cutoff) is no longer a file: it
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
`<dsh home>/snapshot-cleanup.json` file; that
|
|
269
|
-
startup migration have been removed. The last-sweep
|
|
270
|
-
`<dsh home>/snapshot-cleanup-last-sweep.json` state file,
|
|
264
|
+
The snapshot auto-cleanup policy (the `autoCleanupEnabled` switch and the
|
|
265
|
+
`autoCleanupMaxAgeDays` idle cutoff) is no longer a file: it is this plugin
|
|
266
|
+
entry's own live configuration (both fields declared `.volatile()`, validated by
|
|
267
|
+
the entry's schemastery `Config` schema, defaults on the schema). The policy was
|
|
268
|
+
previously persisted in a legacy `<dsh home>/snapshot-cleanup.json` file; that
|
|
269
|
+
file store and its one-time startup migration have been removed. The last-sweep
|
|
270
|
+
clock stays in its own `<dsh home>/snapshot-cleanup-last-sweep.json` state file,
|
|
271
|
+
which is unchanged.
|
|
@@ -37,8 +37,8 @@ Also under `docs/` at the repo root: `persistence-catalog.md` (full
|
|
|
37
37
|
| `CommandDefinition`, `CommandInvocation` | [packages/interaction/commands/src/index.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/interaction/commands/src/index.ts) |
|
|
38
38
|
| `Agent` (`status` / `session`) | [packages/core/agent/src/runtime-types.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/core/agent/src/runtime-types.ts) |
|
|
39
39
|
| `tools/pre-execute` / `execute` / `post-execute` | [packages/core/tools/src/index.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/core/tools/src/index.ts) |
|
|
40
|
-
| Client DOM anchors (`data-chat-flow-kind` / `data-chat-anchor-key`) | [packages/client/ui-
|
|
41
|
-
| User bubble rendering | [packages/client/ui-
|
|
40
|
+
| Client DOM anchors (`data-chat-flow-kind` / `data-chat-anchor-key`) | [packages/client/ui-chat/src/client/chat/ChatNodeSeat.tsx](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/client/ui-chat/src/client/chat/ChatNodeSeat.tsx) |
|
|
41
|
+
| User bubble rendering | [packages/client/ui-chat/src/client/chat/MessageItem.tsx](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/client/ui-chat/src/client/chat/MessageItem.tsx) |
|
|
42
42
|
| Client `SessionFace` (`command` / `cancel`) | [packages/api/session-controller/src/client/contract/session.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/api/session-controller/src/client/contract/session.ts) |
|
|
43
43
|
| Client pending interaction (SessionPendingInteraction) | [packages/client/ui-session/src/client/index.ts](https://github.com/deepseek-ai/deepseek-harness/blob/main/packages/client/ui-session/src/client/index.ts) |
|
|
44
44
|
|
|
@@ -61,7 +61,9 @@ src/client/index.ts client plugin: /rewind command decoration + per-message
|
|
|
61
61
|
src/client/popover.ts mode-selection popover (both-mode impact confirm)
|
|
62
62
|
src/client/hidden.ts withdrawn-span computation (hiddenSeqsOf), pure
|
|
63
63
|
src/client/candidates.ts rewind candidate listing (rewindCandidatesOf), pure
|
|
64
|
-
src/client/pending.ts pending-steering bubble ↔
|
|
64
|
+
src/client/pending.ts pending-steering bubble ↔ inbox next-step (user-sourced) matching, pure
|
|
65
|
+
src/client/portals.tsx per-user-message ↶ button portals (React bridge into the actions row)
|
|
66
|
+
src/client/settings-card.tsx snapshot-cleanup form on the bundle page (plugins.bundle.config)
|
|
65
67
|
src/client/locales.ts zh / en copy (LocaleNamespaceMap)
|
|
66
68
|
src/client/styles.ts injected styles (dsh design tokens)
|
|
67
69
|
src/client/build-info.ts client build identity (__DSH_REWIND_VERSION__ / __DSH_REWIND_BUILD__)
|
|
@@ -70,6 +72,7 @@ scripts/build.mjs esbuild: lib/index.js (host ESM) + lib/client.js (loader
|
|
|
70
72
|
scripts/check-dsh-version.mjs DSH peer-tuple check (latest dist-tag vs peers)
|
|
71
73
|
scripts/update-badge.mjs regenerate the tests badge (CI only)
|
|
72
74
|
scripts/verify-host.mjs end-to-end host verification (full check suite)
|
|
75
|
+
scripts/session-decode.mjs / session-encode.mjs `.jsonl.zstd` codec (test fixtures)
|
|
73
76
|
tests/ vitest suites (rewind / snapshot / hidden / session-cwd / integration)
|
|
74
77
|
docs/ maintainer docs: contract/, compat/, release/ subdirectories
|
|
75
78
|
assets/screenshots/ UI screenshots
|
package/docs/release/release.md
CHANGED
|
@@ -43,9 +43,9 @@ The line being released determines the branch and the bump:
|
|
|
43
43
|
|
|
44
44
|
| Release | Branch | Bump | dist-tag |
|
|
45
45
|
| --- | --- | --- | --- |
|
|
46
|
-
| Stable patch (current line) | `release
|
|
46
|
+
| Stable patch (current line) | `release/<line>.x` | `npm version patch` | `latest` |
|
|
47
47
|
| Pre-release (next line) | `main` | `npm version prerelease --preid=alpha` | `alpha` |
|
|
48
|
-
| Stable (next line) | `main` | `npm version
|
|
48
|
+
| Stable (next line) | `main` | `npm version <next>` | `latest` |
|
|
49
49
|
|
|
50
50
|
Each release is `git push <branch>` followed by `git push <branch> --tags`.
|
|
51
51
|
|
|
@@ -79,7 +79,9 @@ outside it.
|
|
|
79
79
|
|
|
80
80
|
- **When to update**: when the verified range changes — a new DSH tuple, or a
|
|
81
81
|
deliberate narrowing (e.g. dropping the internal `alpha` series); a release
|
|
82
|
-
already inside the range changes nothing
|
|
82
|
+
already inside the range changes nothing **unless it changes interfaces inside
|
|
83
|
+
the tuple** (`0.1.6-alpha.2` removed the client session-ownership and
|
|
84
|
+
queue-mirror APIs, so the floor moved with it). All `@deepseek-ai/*` packages
|
|
83
85
|
release together; `npm view @deepseek-ai/dsh dist-tags` is the signal.
|
|
84
86
|
- **Published-tuple check (optional)**: `node scripts/check-dsh-version.mjs`
|
|
85
87
|
compares the `latest` dist-tag version against the tuple the peers cover
|
|
@@ -93,11 +95,10 @@ outside it.
|
|
|
93
95
|
`^0.1.x`); this section can then be deleted.
|
|
94
96
|
- **Declared minimum (`dsh.engines.dsh`)**: alongside the peer tuple, each
|
|
95
97
|
release declares the DSH runtime floor under `dsh.engines.dsh` (e.g.
|
|
96
|
-
`>=0.1.2-rc.1`)
|
|
98
|
+
`>=0.1.2-rc.1`). Nothing reads it on the current line yet, so it is a
|
|
99
|
+
forward-looking declaration rather than an enforced guard. Bump it in
|
|
97
100
|
the same release that changes the peer range; never leave code raised while
|
|
98
|
-
the declared floor stays behind. Only the `>=X.Y.Z[-pre]` form is
|
|
99
|
-
supported (`^`/`~`/multi-range are treated as "cannot verify" and
|
|
100
|
-
fail closed).
|
|
101
|
+
the declared floor stays behind. Only the `>=X.Y.Z[-pre]` form is used.
|
|
101
102
|
|
|
102
103
|
## Versioned-line release model
|
|
103
104
|
|
|
@@ -131,8 +132,7 @@ dist-tag named by its pre-release identifier (`0.9.0-alpha.1` → `alpha`,
|
|
|
131
132
|
|
|
132
133
|
**Support window / EOL.** A DSH line is supported within a declared window. By
|
|
133
134
|
default the window runs until the next DSH line ships as `latest`; after that
|
|
134
|
-
the line is EOL, frozen, and receives no further patches.
|
|
135
|
-
(`0.1.2-rc.1`) is supported until `0.9.x` (`0.1.3`) ships as `latest`.
|
|
135
|
+
the line is EOL, frozen, and receives no further patches.
|
|
136
136
|
|
|
137
137
|
**Bug-fix flow (forward-fix then backport).** A fix affecting multiple supported
|
|
138
138
|
lines is applied on `main` first, then backported to each still-supported
|
|
@@ -40,9 +40,9 @@ npm publish --access public
|
|
|
40
40
|
|
|
41
41
|
| 发布类型 | 分支 | 版本步进 | dist-tag |
|
|
42
42
|
| --- | --- | --- | --- |
|
|
43
|
-
| 当前线稳定补丁 | `release
|
|
43
|
+
| 当前线稳定补丁 | `release/<line>.x` | `npm version patch` | `latest` |
|
|
44
44
|
| 下一线 pre-release | `main` | `npm version prerelease --preid=alpha` | `alpha` |
|
|
45
|
-
| 下一线正式版 | `main` | `npm version
|
|
45
|
+
| 下一线正式版 | `main` | `npm version <next>` | `latest` |
|
|
46
46
|
|
|
47
47
|
每次发布为 `git push <分支>`,再 `git push <分支> --tags`。
|
|
48
48
|
|
|
@@ -69,8 +69,10 @@ DSH 仍在 rc 阶段,npm 的 prerelease 匹配规则要求 peer 范围与宿
|
|
|
69
69
|
**每一条 DSH 线一个 peer 元组**(如 `^0.1.2-rc.1`);范围是保守的,只声明实际验证过的内容。
|
|
70
70
|
|
|
71
71
|
- **何时需要更新**:**已验证范围**变化时——DSH 发新元组,或主动收窄(例如不再
|
|
72
|
-
声明内测的 DSH `alpha`
|
|
73
|
-
|
|
72
|
+
声明内测的 DSH `alpha` 系列);落在已声明范围内的发布不改变任何东西,**除非它在
|
|
73
|
+
同一元组内改变了接口**(`0.1.6-alpha.2` 删除了客户端会话所有权与 queue 镜像
|
|
74
|
+
API,下限随之移动)。DSH 所有包同版本发布;信号是
|
|
75
|
+
`npm view @deepseek-ai/dsh dist-tags`。
|
|
74
76
|
- **已发布元组检查(可选)**:`node scripts/check-dsh-version.mjs` 用 npm `latest`
|
|
75
77
|
dist-tag 版本对比 peer 覆盖的元组(exit 0 无需动作,exit 1 需要)。它**只读
|
|
76
78
|
`latest` tag**;发布在其它 tag 的 pre-release 走**手动发布前检查**
|
|
@@ -80,10 +82,9 @@ DSH 仍在 rc 阶段,npm 的 prerelease 匹配规则要求 peer 范围与宿
|
|
|
80
82
|
- **正式版后收敛**:DSH 发布 final 版本后,正式版不受 prerelease 元组规则
|
|
81
83
|
限制,peer 可收敛为稳定的 `^0.1.x` 单范围,此节即可删除。
|
|
82
84
|
- **声明的最低运行时(`dsh.engines.dsh`)**:与 peer 元组一起,每个发布在
|
|
83
|
-
`dsh.engines.dsh` 声明 DSH 运行时下限(如 `>=0.1.2-rc.1
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
「无法校验」而 fail-closed)。
|
|
85
|
+
`dsh.engines.dsh` 声明 DSH 运行时下限(如 `>=0.1.2-rc.1`)。当前线上还没有
|
|
86
|
+
任何读取方,因此它只是前置声明、尚未被强制执行。**与 peer 范围持平的同一发布里
|
|
87
|
+
一并 bump**;不可只升代码、声明下限停留在旧值。仅使用 `>=X.Y.Z[-pre]` 形式。
|
|
87
88
|
|
|
88
89
|
## 发布版本线模型
|
|
89
90
|
|
|
@@ -111,8 +112,7 @@ pre-release 发到与其 pre-release 标识符同名的 dist-tag(`0.9.0-alpha.
|
|
|
111
112
|
`alpha`、`0.9.0-rc.1` → `rc`)。pre-release 不占据 `latest`。
|
|
112
113
|
|
|
113
114
|
**支持窗口 / EOL。** 一条 DSH 线仅在声明的窗口内受支持。默认窗口到下一
|
|
114
|
-
DSH 线作为 `latest` 发布为止;此后该线 EOL
|
|
115
|
-
(`0.1.2-rc.1`)支持到 `0.9.x`(`0.1.3`)作为 `latest` 发布为止。
|
|
115
|
+
DSH 线作为 `latest` 发布为止;此后该线 EOL、冻结、不再发补丁。
|
|
116
116
|
|
|
117
117
|
**Bug 修复流程(先向前修,再回迁)。** 跨多条支持线的修复,先在 `main` 上
|
|
118
118
|
修复,再回迁到各仍受支持的 release 分支。仅特定线的修复,只在对应线修复。
|
package/docs/rewind-fix.md
CHANGED
|
@@ -18,7 +18,7 @@ The plugin is prepared in two parts, both shipped in the new version:
|
|
|
18
18
|
|
|
19
19
|
1. **New rewind markers use the new shape** (forward) — this is a **correct, low-risk**, long-term change aligned with the official `/compact` design (see the [README](../README.en.md), the "How it works" section), and the new shape is fully compatible with **both old and new** DSH.
|
|
20
20
|
|
|
21
|
-
2. **The `/dsh-rewind-fix` command** (backward) — for **already-existing** old sessions, the plugin
|
|
21
|
+
2. **The `/dsh-rewind-fix` command** (backward) — for **already-existing** old sessions, the plugin shipped an update command (removed in plugin `0.10.x`) that translated those old markers into the new shape so the sessions were usable again.
|
|
22
22
|
|
|
23
23
|
This document covers mainly the **update command**.
|
|
24
24
|
|
package/docs/rewind-fix.zh.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
1. **新产生的 rewind 标记换成新格式**(向前)——这一步是**正确、低风险**的长期改动(对标官方 `/compact` 设计,见 [README](../README.md)「原理」一节),新格式对**新旧版本** DSH 均完全兼容。
|
|
20
20
|
|
|
21
|
-
2. **提供 `/dsh-rewind-fix`
|
|
21
|
+
2. **提供 `/dsh-rewind-fix` 命令**(向后)——对于**已经存在**的旧会话,本插件曾提供便捷更新命令(已在插件 `0.10.x` 移除),把旧标记「翻译」成新格式,让会话重新可用。
|
|
22
22
|
|
|
23
23
|
本文档主要讲解**更新命令**的使用方法。
|
|
24
24
|
|
|
@@ -1,5 +1,7 @@
|
|
|
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
|
+
|
|
3
5
|
The plugin saves a backup of each file before it's edited, so you can rewind your
|
|
4
6
|
code to an earlier point. These backups are called **snapshots**, and they're
|
|
5
7
|
grouped by message and stored per session.
|
|
@@ -1,5 +1,7 @@
|
|
|
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
|
+
|
|
3
5
|
插件会在每次修改文件前保存一份备份,方便你把代码回退到之前的状态。这些备份叫**快照**,按消息分组、按会话存放。
|
|
4
6
|
|
|
5
7
|
`/snapshot-auto-cleanup` 帮你管理这些快照——既可以回收旧会话占用的磁盘,也可以清空**当前**会话、让它从"现在"重新开始记录回退历史。
|