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.
@@ -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
- if (!available()) {
259
- return { enabled: false, versions: [] }
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['retrace/versions']
269
- if (!value) return { enabled: false, versions: [] }
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.2",
4
+ "version": "0.4.3",
5
5
  "packageManager": "pnpm@11.7.0",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",