dsh-retrace 0.4.2 → 0.4.3
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/lib/client.bundle.js +326 -80
- package/lib/client.js +434 -101
- package/lib/dynamic-client.js +326 -80
- package/lib/forkmap.js +106 -0
- package/lib/http.js +14 -0
- package/lib/projection/forkmap.js +69 -0
- package/lib/versioning.js +16 -5
- package/package.json +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-retrace — `retrace/forkmap` projection unit definition.
|
|
3
|
+
*
|
|
4
|
+
* Registered on the official `ctx.sessionProjections` registry alongside
|
|
5
|
+
* `retrace/versions` (PLAN §5.2, P2.1). Same contract as the versions unit:
|
|
6
|
+
*
|
|
7
|
+
* - `stateSchema` — zod schema of the RAW fold state (plain JSON; the
|
|
8
|
+
* durable checkpoint validates rows against it),
|
|
9
|
+
* - `init` / `apply` — the deterministic fold (lib/forkmap.js),
|
|
10
|
+
* - `wire` — the client-visible view ({viewSchema, view}); a unit WITHOUT
|
|
11
|
+
* `wire` registers as checkpoint-only and is never served in
|
|
12
|
+
* `session/projection` push frames or `snapshot()` (the framework
|
|
13
|
+
* contract the P0 versions definition missed; found by the P1 smoke).
|
|
14
|
+
*
|
|
15
|
+
* Unlike the versions unit, the fork-map state is NOT truncated: the whole
|
|
16
|
+
* branch topology must survive (VERSION_LIMIT=200 truncation would drop old
|
|
17
|
+
* fork points). Per-boundary payloads are tiny (seqs only), so the projection
|
|
18
|
+
* stays small even for long sessions; node content stays out of the fold
|
|
19
|
+
* (lazy reads via the HTTP surface when the client needs detail).
|
|
20
|
+
*/
|
|
21
|
+
import { z } from 'zod'
|
|
22
|
+
import {
|
|
23
|
+
applyForkmap,
|
|
24
|
+
createForkmapState,
|
|
25
|
+
viewForkmap,
|
|
26
|
+
} from '../forkmap.js'
|
|
27
|
+
|
|
28
|
+
const FORK_KINDS = ['recall', 'edit', 'regenerate', 'restore', 'compaction', 'replace']
|
|
29
|
+
|
|
30
|
+
const forkmapNodeSchema = z.object({
|
|
31
|
+
seq: z.number().int().nonnegative(),
|
|
32
|
+
type: z.string(),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const forkmapBoundarySchema = z.object({
|
|
36
|
+
seq: z.number().int().nonnegative(),
|
|
37
|
+
kind: z.enum(FORK_KINDS),
|
|
38
|
+
replacedSeqs: z.array(z.number().int().nonnegative()),
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
/** Raw fold-state schema (durable checkpoint rows validate against it). */
|
|
42
|
+
export const forkmapStateSchema = z.object({
|
|
43
|
+
nodes: z.array(forkmapNodeSchema),
|
|
44
|
+
boundaries: z.array(forkmapBoundarySchema),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
/** The wire view schema (what the registry validates and clients receive). */
|
|
48
|
+
export const forkmapViewSchema = forkmapStateSchema
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The `retrace/forkmap` unit — register via
|
|
52
|
+
* `ctx.sessionProjections.register(forkmapProjectionDefinition)`.
|
|
53
|
+
*/
|
|
54
|
+
export const forkmapProjectionDefinition = {
|
|
55
|
+
key: 'retrace/forkmap',
|
|
56
|
+
stateSchema: forkmapStateSchema,
|
|
57
|
+
init: () => createForkmapState(),
|
|
58
|
+
apply: (state, event) => applyForkmap(state, event),
|
|
59
|
+
wire: {
|
|
60
|
+
viewSchema: forkmapViewSchema,
|
|
61
|
+
view: (state) => viewForkmap(state),
|
|
62
|
+
},
|
|
63
|
+
/** Bump when the serialized fold state or fold semantics change. */
|
|
64
|
+
stateVersion: 1,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Top-level aliases (unit tests drive the definition directly).
|
|
68
|
+
forkmapProjectionDefinition.schema = forkmapProjectionDefinition.wire.viewSchema
|
|
69
|
+
forkmapProjectionDefinition.view = forkmapProjectionDefinition.wire.view
|
package/lib/versioning.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
retraceDomainSpec,
|
|
25
25
|
} from './artifact-store.js'
|
|
26
26
|
import { versionsProjectionDefinition } from './projection/versions.js'
|
|
27
|
+
import { forkmapProjectionDefinition } from './projection/forkmap.js'
|
|
27
28
|
import { createGitAdapter, createSubprocessRunner } from './git-adapter.js'
|
|
28
29
|
|
|
29
30
|
/** Max bytes snapshotted per touched file (over → file skipped, version kept). */
|
|
@@ -221,6 +222,8 @@ export function createVersioningSeam(ctx, log = () => {}, options = {}) {
|
|
|
221
222
|
ctx.inject(['sessionProjections', 'sessionQuery', 'storageDomain'], (seam) => {
|
|
222
223
|
seamCtx = seam
|
|
223
224
|
disposers.push(seam.sessionProjections.register(versionsProjectionDefinition))
|
|
225
|
+
// P2.1 — the fork-map unit: pure fold (branch topology), no side effects.
|
|
226
|
+
disposers.push(seam.sessionProjections.register(forkmapProjectionDefinition))
|
|
224
227
|
disposers.push(
|
|
225
228
|
seam.sessionProjections.onChanged((session, key, value, seq) => {
|
|
226
229
|
if (key !== 'retrace/versions') return
|
|
@@ -255,9 +258,16 @@ export function createVersioningSeam(ctx, log = () => {}, options = {}) {
|
|
|
255
258
|
|
|
256
259
|
/** HTTP fallback channel: the live projection snapshot for one session. */
|
|
257
260
|
function snapshot(sessionId) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
+
return snapshotKey(sessionId, 'retrace/versions', { enabled: false, versions: [] })
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** HTTP fallback channel: the fork-map projection snapshot (P2.1). */
|
|
265
|
+
function snapshotForkmap(sessionId) {
|
|
266
|
+
return snapshotKey(sessionId, 'retrace/forkmap', { enabled: false, nodes: [], boundaries: [] })
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function snapshotKey(sessionId, key, empty) {
|
|
270
|
+
if (!available()) return empty
|
|
261
271
|
const session = ctx.sessions.get(sessionId)
|
|
262
272
|
if (!session) {
|
|
263
273
|
const error = new Error(`session "${sessionId}" not found`)
|
|
@@ -265,8 +275,8 @@ export function createVersioningSeam(ctx, log = () => {}, options = {}) {
|
|
|
265
275
|
throw error
|
|
266
276
|
}
|
|
267
277
|
const cut = seamCtx.sessionProjections.snapshot(session)
|
|
268
|
-
const value = cut.values[
|
|
269
|
-
if (!value) return
|
|
278
|
+
const value = cut.values[key]
|
|
279
|
+
if (!value) return empty
|
|
270
280
|
return { enabled: configFor(sessionId).versioning, ...value }
|
|
271
281
|
}
|
|
272
282
|
|
|
@@ -367,6 +377,7 @@ export function createVersioningSeam(ctx, log = () => {}, options = {}) {
|
|
|
367
377
|
configFor,
|
|
368
378
|
setConfig,
|
|
369
379
|
snapshot,
|
|
380
|
+
snapshotForkmap,
|
|
370
381
|
readEvent,
|
|
371
382
|
readSurface,
|
|
372
383
|
agentOf,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-retrace",
|
|
3
3
|
"description": "Retrace · 回溯 — Recall, edit-and-resend, regenerate, and conversation/artifact versioning (timeline, rollback, fork map) for DeepSeek Harness — Web and Desktop",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.3",
|
|
5
5
|
"packageManager": "pnpm@11.7.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|