dsh-rewind-plugin 0.7.5 → 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 -9
- package/README.md +12 -9
- package/SECURITY.md +6 -7
- package/docs/README.md +2 -1
- package/docs/architecture.md +39 -21
- package/docs/compat/audit.md +32 -34
- package/docs/contract/client-contract.md +1 -1
- package/docs/contract/client-contract.zh.md +1 -1
- package/docs/format.md +11 -8
- package/docs/harness-reference.md +17 -4
- package/docs/release/release.md +82 -24
- package/docs/release/release.zh.md +63 -16
- package/docs/rewind-fix.md +80 -0
- package/docs/rewind-fix.zh.md +80 -0
- package/lib/client.js +15 -41
- package/lib/index.js +531 -73
- package/lib/types/client/hidden.d.ts +26 -35
- package/lib/types/client/index.d.ts +19 -1
- package/lib/types/client/popover.d.ts +8 -9
- package/lib/types/client/portals.d.ts +25 -40
- package/lib/types/client/settings-card.d.ts +3 -4
- package/lib/types/client/styles.d.ts +1 -1
- 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/lib/types/snapshot-cleanup.d.ts +3 -3
- package/package.json +44 -41
- package/docs/compat/troubleshooting.md +0 -41
- package/docs/compat/troubleshooting.zh.md +0 -29
- package/lib/types/session-events.d.ts +0 -37
- package/lib/types/settings-locale.d.ts +0 -33
package/lib/types/rewind.d.ts
CHANGED
|
@@ -9,23 +9,22 @@
|
|
|
9
9
|
* transcript) is untouched; only the model-visible surface is cut, so the
|
|
10
10
|
* next request derives its context from the target message onward.
|
|
11
11
|
*
|
|
12
|
-
* Marker shape (v0.3
|
|
13
|
-
* replace `surfaceOp
|
|
12
|
+
* Marker shape (v0.1.3/v2): the marker is an EMPTY `user/message` carrying a
|
|
13
|
+
* replace `surfaceOp` — a single event:
|
|
14
14
|
*
|
|
15
|
-
*
|
|
15
|
+
* user/message (marker, empty content) → { surfaceOp {replace, start, end} }
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `(
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* never collide with a future real step.
|
|
17
|
+
* v2 reserves surface `replace` to a node that cites every shadowed seq via
|
|
18
|
+
* `sourceEventSeqs`, and `assistant/message` can no longer carry
|
|
19
|
+
* `sourceEventSeqs` (it now embeds its provider stream instead) — so the
|
|
20
|
+
* replacement node must be a `user/message`, exactly as /compact's checkpoint
|
|
21
|
+
* is. No ghost `step/start`…`step/end` frame is needed: the token-meter's
|
|
22
|
+
* step state machine ignores `user/message`, and the session invariant
|
|
23
|
+
* (`invariant.ts`) imposes no open-turn requirement on it, so the marker is
|
|
24
|
+
* appended while idle, outside any turn. The empty content means the marker
|
|
25
|
+
* carries no language; it sits at the surface tail as the model-visible
|
|
26
|
+
* "cut point" (an empty `user/message` derives to itself, so it remains a
|
|
27
|
+
* present-but-empty user turn in derived history).
|
|
29
28
|
*
|
|
30
29
|
* @module dsh-rewind/rewind
|
|
31
30
|
*/
|
|
@@ -85,48 +84,6 @@ export declare const CANDIDATE_PREVIEW_CHARS = 80;
|
|
|
85
84
|
* still pass an explicit `limit`.
|
|
86
85
|
*/
|
|
87
86
|
export declare const DEFAULT_CANDIDATE_LIMIT = 100;
|
|
88
|
-
/**
|
|
89
|
-
* Turn number for the rewind marker.
|
|
90
|
-
*
|
|
91
|
-
* The marker MUST NOT reuse the harness's next-turn number. The agent loop
|
|
92
|
-
* numbers its next real turn `lastTurn/start + 1` (dsh-agent-loop), so a
|
|
93
|
-
* marker numbered `maxTurn + 1` collides: the log then holds an
|
|
94
|
-
* `assistant/message` (the marker) BEFORE the `turn/start` of the same turn,
|
|
95
|
-
* and the client conversation-context builder rejects that ordering with
|
|
96
|
-
* `conversation Context …:turn-tail… received an update before its start
|
|
97
|
-
* Match` — history load fails and the whole conversation disappears from the
|
|
98
|
-
* UI (reproduced across real sessions).
|
|
99
|
-
*
|
|
100
|
-
* The marker therefore reuses the LAST STARTED turn's number: the harness has
|
|
101
|
-
* already consumed it (its next turn is strictly larger), so it can never be
|
|
102
|
-
* reused by a future `turn/start`, and the marker lands as a harmless
|
|
103
|
-
* trailing update on that turn's already-closed tail context (its `turn/end`
|
|
104
|
-
* is already matched) — no new context, no reordering, nothing rendered, and
|
|
105
|
-
* the empty content still derives to `null` in the model context.
|
|
106
|
-
*
|
|
107
|
-
* @param events - the full session event log.
|
|
108
|
-
* @returns a turn number the harness can never reuse for a future `turn/start`.
|
|
109
|
-
*/
|
|
110
|
-
export declare function markerTurnOf(events: readonly SessionEvent[]): number;
|
|
111
|
-
/**
|
|
112
|
-
* Step number for the rewind marker's ghost step frame.
|
|
113
|
-
*
|
|
114
|
-
* The marker's `assistant/message` must be wrapped in `step/start` …
|
|
115
|
-
* `step/end` of the SAME `(turn, step)` so the harness token-meter replay
|
|
116
|
-
* accepts it (see the module doc). The step number MUST be a step this turn
|
|
117
|
-
* has never started: the client conversation assembler treats `step/start`
|
|
118
|
-
* as the start of an `assistant-step` context keyed `turn:step`, so reusing
|
|
119
|
-
* an already-started step number makes the log replay throw "received more
|
|
120
|
-
* than one start Match" and the history disappears from the UI. Reusing
|
|
121
|
-
* `lastStep + 1` is always safe: the harness numbers a turn's steps from
|
|
122
|
-
* memory (each new turn restarts at 1), so the ghost step can never collide
|
|
123
|
-
* with a future real step of this turn.
|
|
124
|
-
*
|
|
125
|
-
* @param events - the full session event log.
|
|
126
|
-
* @param turn - the marker's turn (normally `markerTurnOf(events)`).
|
|
127
|
-
* @returns the smallest step number this turn has never started (≥ 1).
|
|
128
|
-
*/
|
|
129
|
-
export declare function markerStepOf(events: readonly SessionEvent[], turn: number): number;
|
|
130
87
|
/** Narrow an event to a user message. */
|
|
131
88
|
export declare function isUserMessageEvent(event: SessionEvent): event is SessionEvent<'user/message'>;
|
|
132
89
|
/**
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type SessionEvent } from '@deepseek-ai/dsh-session';
|
|
2
|
+
/** A complete frame's byte range within a buffer. */
|
|
3
|
+
export interface ZstdFrameRange {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
}
|
|
7
|
+
/** Result of scanning a buffer for complete zstd frames. */
|
|
8
|
+
export interface ZstdFrameScan {
|
|
9
|
+
frames: ZstdFrameRange[];
|
|
10
|
+
/** Offset of an incomplete trailing frame, or undefined when the buffer is whole. */
|
|
11
|
+
tornStart?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Scan a buffer for structurally complete Zstandard frames (mirrors DSH
|
|
15
|
+
* `scanZstdFrames`). A trailing incomplete frame is reported as `tornStart`
|
|
16
|
+
* and omitted from `frames`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function scanZstdFrames(buffer: Buffer): ZstdFrameScan;
|
|
19
|
+
/**
|
|
20
|
+
* Compress one independently decodable, checksummed Zstandard frame (mirrors DSH
|
|
21
|
+
* `compressZstdFrame`). Async so it runs on libuv's threadpool and does not
|
|
22
|
+
* block the event loop, letting a concurrency pool overlap compression across
|
|
23
|
+
* sessions.
|
|
24
|
+
*/
|
|
25
|
+
export declare function compressZstdFrame(input: Buffer | string): Promise<Buffer>;
|
|
26
|
+
/** Decompress one complete Zstandard frame (validates its checksum). Async (threadpool). */
|
|
27
|
+
export declare function decompressZstdFrame(input: Buffer): Promise<Buffer>;
|
|
28
|
+
/** Decode a concatenated multi-frame zstd buffer to plaintext (async, threadpool). Frames are
|
|
29
|
+
* decoded in bounded parallel batches (a large log can have tens of thousands of frames). */
|
|
30
|
+
export declare function decodeZstd(buffer: Buffer): Promise<string>;
|
|
31
|
+
/** One complete session plaintext split into its header line and event body. */
|
|
32
|
+
export interface SplitSession {
|
|
33
|
+
/** The first line (a `type:'session'` record) WITHOUT its trailing newline. */
|
|
34
|
+
headerLine: string;
|
|
35
|
+
/** Every event row, newline-separated, after the header line. */
|
|
36
|
+
body: string;
|
|
37
|
+
}
|
|
38
|
+
/** Split a session plaintext into an independent header line and the event body. */
|
|
39
|
+
export declare function splitSession(plaintext: string): SplitSession;
|
|
40
|
+
/**
|
|
41
|
+
* Decode a JSONL event body into logical {@link SessionEvent}s. Layout-blind:
|
|
42
|
+
* packed chunk rows and per-line rows both decode; range-encoded provenance is
|
|
43
|
+
* expanded. This is the read-side counterpart that consumes the body that
|
|
44
|
+
* `sessionPersistence.readRaw(id)` produced.
|
|
45
|
+
*/
|
|
46
|
+
export declare function decodeEventBody(body: string): SessionEvent[];
|
|
47
|
+
export interface EncodeOptions {
|
|
48
|
+
/** Pack delta-chunk runs into storage rows (lossless, ~60% smaller). Default true. */
|
|
49
|
+
readonly packChunks?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Encode a header line + events into a 2-frame Zstandard buffer (mirrors DSH
|
|
53
|
+
* `encodePhysicalJsonl`): the header is its OWN frame, the body its own.
|
|
54
|
+
* @param headerLine - the header JSON text, no trailing newline.
|
|
55
|
+
* @param events - the repaired event list in log order.
|
|
56
|
+
*/
|
|
57
|
+
export declare function encodeSessionLog(headerLine: string, events: readonly SessionEvent[], options?: EncodeOptions): Promise<Buffer>;
|
|
@@ -46,9 +46,9 @@ export declare const CleanupConfigSchema: z<CleanupConfig>;
|
|
|
46
46
|
/**
|
|
47
47
|
* Structural face of the settings scope the host needs for the policy: a
|
|
48
48
|
* resolved read and a validated write. Kept local (never imports the settings
|
|
49
|
-
* contract) so the host bundle
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* contract) so the host bundle does not type-couple on the client settings
|
|
50
|
+
* API (0.1.2 adds `mutate`; it is unused here), and the seam the host passes
|
|
51
|
+
* in isolates the drift to this module.
|
|
52
52
|
*/
|
|
53
53
|
export interface CleanupSettingsScope {
|
|
54
54
|
/** The resolved policy: schema defaults, then base, then the user layer. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-rewind-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-alpha.1",
|
|
4
4
|
"description": "DSH 插件:真正便捷无感的同窗口内对话回退,从不新建分支;自带轻量工作区备份,可一并还原文件(完整 Claude Code /rewind 语义)。 · DSH plugin: genuinely effortless in-window conversation rewind — never forking a new session; ships a lightweight workspace backup that restores files together with the rewind (full Claude Code /rewind semantics).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"client": {
|
|
53
53
|
"inject": [
|
|
54
54
|
"@deepseek-ai/dsh-client-locale",
|
|
55
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
56
55
|
"@deepseek-ai/dsh-client-ui-commands",
|
|
57
56
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
58
57
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
@@ -74,19 +73,18 @@
|
|
|
74
73
|
"peerDependencies": {
|
|
75
74
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
76
75
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
77
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.
|
|
78
|
-
"@deepseek-ai/dsh-client-
|
|
79
|
-
"@deepseek-ai/dsh-client-ui-
|
|
80
|
-
"@deepseek-ai/dsh-client-ui-
|
|
81
|
-
"@deepseek-ai/dsh-
|
|
82
|
-
"@deepseek-ai/dsh-
|
|
83
|
-
"@deepseek-ai/dsh-
|
|
84
|
-
"@deepseek-ai/dsh-
|
|
85
|
-
"@deepseek-ai/dsh-
|
|
86
|
-
"@deepseek-ai/dsh-
|
|
87
|
-
"@deepseek-ai/dsh-
|
|
88
|
-
"@deepseek-ai/dsh-
|
|
89
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-rc.2 || ^0.1.2-alpha.2"
|
|
76
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
|
|
77
|
+
"@deepseek-ai/dsh-client-ui-commands": "^0.1.2-rc.1",
|
|
78
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
|
|
79
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
|
|
80
|
+
"@deepseek-ai/dsh-commands": "^0.1.2-rc.1",
|
|
81
|
+
"@deepseek-ai/dsh-fs": "^0.1.2-rc.1",
|
|
82
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.2-rc.1",
|
|
83
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
|
|
84
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1",
|
|
85
|
+
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
|
86
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
|
|
87
|
+
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1"
|
|
90
88
|
},
|
|
91
89
|
"peerDependenciesMeta": {
|
|
92
90
|
"@deepseek-ai/cordis": {
|
|
@@ -98,9 +96,6 @@
|
|
|
98
96
|
"@deepseek-ai/dsh-client-locale": {
|
|
99
97
|
"optional": true
|
|
100
98
|
},
|
|
101
|
-
"@deepseek-ai/dsh-client-runtime": {
|
|
102
|
-
"optional": true
|
|
103
|
-
},
|
|
104
99
|
"@deepseek-ai/dsh-client-ui-commands": {
|
|
105
100
|
"optional": true
|
|
106
101
|
},
|
|
@@ -138,29 +133,37 @@
|
|
|
138
133
|
"devDependencies": {
|
|
139
134
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
140
135
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
141
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
142
|
-
"@deepseek-ai/dsh-
|
|
143
|
-
"@deepseek-ai/dsh-client-
|
|
144
|
-
"@deepseek-ai/dsh-client-
|
|
145
|
-
"@deepseek-ai/dsh-client-
|
|
146
|
-
"@deepseek-ai/dsh-client-ui-
|
|
147
|
-
"@deepseek-ai/dsh-
|
|
148
|
-
"@deepseek-ai/dsh-
|
|
149
|
-
"@deepseek-ai/dsh-
|
|
150
|
-
"@deepseek-ai/dsh-
|
|
151
|
-
"@deepseek-ai/dsh-
|
|
152
|
-
"@deepseek-ai/dsh-
|
|
153
|
-
"@deepseek-ai/dsh-
|
|
154
|
-
"@deepseek-ai/dsh-
|
|
155
|
-
"@deepseek-ai/dsh-
|
|
156
|
-
"@deepseek-ai/dsh-
|
|
157
|
-
"@deepseek-ai/dsh-
|
|
158
|
-
"@deepseek-ai/dsh-
|
|
159
|
-
"@deepseek-ai/dsh-
|
|
160
|
-
"@deepseek-ai/dsh-
|
|
161
|
-
"@deepseek-ai/dsh-
|
|
162
|
-
"@deepseek-ai/dsh-
|
|
163
|
-
"@deepseek-ai/dsh-
|
|
136
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
|
|
137
|
+
"@deepseek-ai/dsh-attachment": "^0.1.2-rc.1",
|
|
138
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
|
|
139
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.2-rc.1",
|
|
140
|
+
"@deepseek-ai/dsh-client-store": "^0.1.2-rc.1",
|
|
141
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
|
|
142
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.2-rc.1",
|
|
143
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
|
|
144
|
+
"@deepseek-ai/dsh-scope": "^0.1.2-rc.1",
|
|
145
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1",
|
|
146
|
+
"@deepseek-ai/dsh-user-questions": "^0.1.2-rc.1",
|
|
147
|
+
"@deepseek-ai/dsh-client-ui-commands": "^0.1.2-rc.1",
|
|
148
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.2-rc.1",
|
|
149
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
|
|
150
|
+
"@deepseek-ai/dsh-command-compact": "^0.1.2-rc.1",
|
|
151
|
+
"@deepseek-ai/dsh-commands": "^0.1.2-rc.1",
|
|
152
|
+
"@deepseek-ai/dsh-compaction": "^0.1.2-rc.1",
|
|
153
|
+
"@deepseek-ai/dsh-compaction-basic": "^0.1.2-rc.1",
|
|
154
|
+
"@deepseek-ai/dsh-fs": "^0.1.2-rc.1",
|
|
155
|
+
"@deepseek-ai/dsh-goal": "^0.1.2-rc.1",
|
|
156
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.2-rc.1",
|
|
157
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
|
|
158
|
+
"@deepseek-ai/dsh-plan-mode": "^0.1.2-rc.1",
|
|
159
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1",
|
|
160
|
+
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
|
161
|
+
"@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1",
|
|
162
|
+
"@deepseek-ai/dsh-session-stats": "^0.1.2-rc.1",
|
|
163
|
+
"@deepseek-ai/dsh-session-title": "^0.1.2-rc.1",
|
|
164
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
|
|
165
|
+
"@deepseek-ai/dsh-token-meter": "^0.1.2-rc.1",
|
|
166
|
+
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
|
|
164
167
|
"@types/node": "^24.0.0",
|
|
165
168
|
"@types/react": "^18.3.31",
|
|
166
169
|
"@types/react-dom": "^18.3.7",
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Troubleshooting
|
|
2
|
-
|
|
3
|
-
[简体中文](troubleshooting.zh.md)
|
|
4
|
-
|
|
5
|
-
## History load failure: `…turn-tail… received an update before its start Match`
|
|
6
|
-
|
|
7
|
-
Rewinds from `≤ 0.2.4` collided with the next real turn's `turn/start`, so reopening the session showed
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Failed to load history: conversation Context …:turn-tail… received an update before its start Match (internal)
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
and the history vanished. Rewinds from `0.2.5` on no longer collide; already-corrupted sessions need an offline repair (the log is append-only). The repair tool (`dsh-rewind-repair`) is no longer shipped from v0.4.0 — install a pre-v0.4.0 release to get it (fully quit dsh web / host first, then):
|
|
14
|
-
|
|
15
|
-
```sh
|
|
16
|
-
npm exec --yes --package=dsh-rewind-plugin@0.3.3 -- dsh-rewind-repair
|
|
17
|
-
npm exec --yes --package=dsh-rewind-plugin@0.3.3 -- dsh-rewind-repair -- --dry-run # preview only
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
It only rewrites the marker events' `data.turn` (seqs, order, and zstd frame structure intact) and backs up the original file before writing — safe to run repeatedly. From a source checkout of a pre-v0.4.0 tag: `node scripts/repair-markers.mjs` (identical flags).
|
|
21
|
-
|
|
22
|
-
## Known compatibility boundaries
|
|
23
|
-
|
|
24
|
-
Behavioral notes — none of these is a crash — verified by the compatibility
|
|
25
|
-
probe suites; the audit [audit.md](audit.md) is the source of truth and lists
|
|
26
|
-
the probes that pin each one:
|
|
27
|
-
|
|
28
|
-
- Session stats / telemetry do **not** roll back with a rewind.
|
|
29
|
-
- Withdrawn messages stay **searchable and exported** (`/export` and full-text
|
|
30
|
-
search read the raw log).
|
|
31
|
-
- Session titles may **regenerate** (title derives from the current surface).
|
|
32
|
-
- Files written by a **cancelled tool call** (write happened, no snapshot
|
|
33
|
-
commit) cannot be restored by "conversation and code".
|
|
34
|
-
|
|
35
|
-
**R-OPENSTEP** (harness-side, plugin does not guard): a session log carrying an
|
|
36
|
-
*unclosed* `step/start` (a crash before the agent loop's `finally` closed the
|
|
37
|
-
step) makes later step activity break token-meter replay, so `/compact` can
|
|
38
|
-
fail after a rewind. Harness `0.1.1-rc.2` fixes the crash path on load
|
|
39
|
-
(`interruptedTurnClosers`); a plugin-side up-front rejection was tried and
|
|
40
|
-
**reverted** (`177ec14`, false positives on real logs). Deep analysis:
|
|
41
|
-
[audit.md](audit.md) → R-OPENSTEP.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# 故障修复
|
|
2
|
-
|
|
3
|
-
[English](troubleshooting.md)
|
|
4
|
-
|
|
5
|
-
## 历史加载失败:`…turn-tail… received an update before its start Match`
|
|
6
|
-
|
|
7
|
-
0.2.4 及之前版本的回退与下一条真实回合的 `turn/start` 撞号,重开会话时历史整段消失。0.2.5 起的新回退不再产生该冲突;**已损坏的旧会话需离线修复**(日志是 append-only 的)。修复工具(`dsh-rewind-repair`)v0.4.0 起不再随包提供——安装 v0.4.0 之前的版本即可获取(先完全退出 dsh web / host,然后):
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
npm exec --yes --package=dsh-rewind-plugin@0.3.3 -- dsh-rewind-repair
|
|
11
|
-
npm exec --yes --package=dsh-rewind-plugin@0.3.3 -- dsh-rewind-repair -- --dry-run # 只预览不写盘
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
工具只改写标记事件的 `data.turn`(保持 seq / 顺序 / zstd 帧结构不变),改前自动备份原文件——可安全重复运行。源码方式:v0.4.0 之前的 tag 下 `node scripts/repair-markers.mjs`(参数相同)。
|
|
15
|
-
|
|
16
|
-
## 已知兼容边界
|
|
17
|
-
|
|
18
|
-
以下均为**预期行为而非崩溃**(探针钉住,完整依据见 [audit.md](audit.md) 事实源):
|
|
19
|
-
|
|
20
|
-
- 会话统计 / 遥测**不回退**(折叠的是完整日志);
|
|
21
|
-
- 被撤回的消息**仍可搜索、可导出**(`/export` 与全文搜索基于原始日志);
|
|
22
|
-
- 会话标题可能**重新生成**(标题由当前 surface 派生);
|
|
23
|
-
- 被**取消的工具调用**写入的文件(无快照提交)无法由「回退对话和代码」恢复。
|
|
24
|
-
|
|
25
|
-
**R-OPENSTEP**(harness 侧,插件不设守卫):日志中存在*未闭合* `step/start`
|
|
26
|
-
(agent 循环的 `finally` 闭合 step 前崩溃)时,后续 step 活动会破坏 token-meter
|
|
27
|
-
重放,回退后 `/compact` 可能报错。harness `0.1.1-rc.2` 已在加载时自动闭合
|
|
28
|
-
(`interruptedTurnClosers`);插件曾实现前置拒绝但已回退(`177ec14`,真实日志
|
|
29
|
-
误判)。深入分析:[audit.md](audit.md) → R-OPENSTEP。
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-channel session event-log reader.
|
|
3
|
-
*
|
|
4
|
-
* This is a "0.1.1-rc.2 ↔ 0.1.2-rc.1" dual-channel reader. Harness 0.1.1-rc.2
|
|
5
|
-
* exposes the full log as `Session.events` (`get events(): readonly
|
|
6
|
-
* SessionEvent[]`); the 0.1.2 line (alpha.4+, now 0.1.2-rc.1) removed that
|
|
7
|
-
* member and replaced it with the on-demand APIs `snapshotEvents(from?, to?)`
|
|
8
|
-
* (half-open range, internally cached), `eventAt(seq)`, `ownEvents()` and
|
|
9
|
-
* `seq`. This module reads the full log through whichever channel the host
|
|
10
|
-
* exposes, so the plugin keeps one code path across both endpoints.
|
|
11
|
-
*
|
|
12
|
-
* `snapshotEvents()` is deliberately preferred over `ownEvents()`:
|
|
13
|
-
* `snapshotEvents()` defaults to the whole log (including any fork-inherited
|
|
14
|
-
* prefix), which is exactly what `Session.events` returned on 0.1.1-rc.2 — the
|
|
15
|
-
* rewind semantics are preserved for fork-seeded sessions. `ownEvents()`
|
|
16
|
-
* would drop the inherited prefix and change behaviour.
|
|
17
|
-
*
|
|
18
|
-
* @module dsh-rewind/session-events
|
|
19
|
-
*/
|
|
20
|
-
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session';
|
|
21
|
-
/**
|
|
22
|
-
* Read the full event log of a session, transparently across harness channels:
|
|
23
|
-
* - 0.1.1-rc.2 (`Session.events`): the live immutable log array.
|
|
24
|
-
* - 0.1.2-rc.1 (`Session.snapshotEvents()`): a deep-frozen snapshot, cached
|
|
25
|
-
* by the session until the next append. This is the single 0.1.2-line
|
|
26
|
-
* channel (alpha.2/3 still exposed `events` and thus fall into the
|
|
27
|
-
* 0.1.1-rc.2 branch below).
|
|
28
|
-
*
|
|
29
|
-
* Falls back to an empty log when the session exposes neither member (a future
|
|
30
|
-
* harness shape) rather than throwing — callers already treat the empty log as
|
|
31
|
-
* "no candidates".
|
|
32
|
-
*
|
|
33
|
-
* @param session - the session to read.
|
|
34
|
-
* @returns the full event log in log order (the same shape 0.1.1-rc.2's `events`
|
|
35
|
-
* returned, so existing consumers are unchanged).
|
|
36
|
-
*/
|
|
37
|
-
export declare function eventsOf(session: Session): readonly SessionEvent[];
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Version-neutral settings-namespace reading for the host half.
|
|
3
|
-
*
|
|
4
|
-
* This is a "0.1.1-rc.2 ↔ 0.1.2-rc.1" dual channel. DSH 0.1.1-rc.2 exposes a
|
|
5
|
-
* `settingsNamespace(value)` brand helper, and `settings.get` is typed to
|
|
6
|
-
* require a branded `SettingsNamespace`. The 0.1.2 line (0.1.2-rc.1) removed
|
|
7
|
-
* that helper (the `SettingsNamespace` *type* remains) and `settings.get`
|
|
8
|
-
* accepts the raw namespace string. This module collapses both into one runtime
|
|
9
|
-
* call: on 0.1.1-rc.2 the brand is a compile-time marker erased at runtime (so
|
|
10
|
-
* `settingsNamespace(ns)` returns `ns`), on 0.1.2-rc.1 the brand helper is
|
|
11
|
-
* absent and the raw `ns` string is used directly. That is what lets a single
|
|
12
|
-
* compiled host bundle link and run on both harness generations.
|
|
13
|
-
*
|
|
14
|
-
* @module dsh-rewind/settings-locale
|
|
15
|
-
*/
|
|
16
|
-
/** Minimal structural face of the settings provider the host reads from. */
|
|
17
|
-
export interface SettingsProviderLike {
|
|
18
|
-
/**
|
|
19
|
-
* Read one registered settings section by namespace. Accepts whatever the
|
|
20
|
-
* running DSH generation passes: a branded `SettingsNamespace` (0.1.1-rc.2,
|
|
21
|
-
* brand erased) or the raw namespace string (0.1.2-rc.1).
|
|
22
|
-
*/
|
|
23
|
-
get(ns: string): unknown;
|
|
24
|
-
}
|
|
25
|
-
/** The `settingsNamespace(ns)` brand helper, or `undefined` when removed (0.1.2-rc.1). */
|
|
26
|
-
export type SettingsNamespaceBrand = ((value: string) => string) | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* Read one settings section keyed by `ns`, tolerant of the settings-namespace
|
|
29
|
-
* brand across DSH generations. Pass the brand helper when available (the
|
|
30
|
-
* 0.1.1-rc.2 path); it is `undefined` on 0.1.2-rc.1, where the raw `ns` string
|
|
31
|
-
* is used directly. Never throws: an absent section simply returns `undefined`.
|
|
32
|
-
*/
|
|
33
|
-
export declare function readSettingsSection(provider: SettingsProviderLike, ns: string, brand: SettingsNamespaceBrand): unknown;
|