@treeseed/dsh-chapters 0.1.0

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.
Files changed (119) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +644 -0
  3. package/cordis.patch.yml +88 -0
  4. package/docs/architecture.md +460 -0
  5. package/docs/contract.md +375 -0
  6. package/docs/development.md +437 -0
  7. package/docs/host-compaction-seam.md +117 -0
  8. package/docs/knowledge-repo.md +730 -0
  9. package/docs/provider.md +98 -0
  10. package/docs/verify.md +200 -0
  11. package/lib/archive.d.ts +88 -0
  12. package/lib/archive.js +114 -0
  13. package/lib/archive.js.map +1 -0
  14. package/lib/arrival.d.ts +23 -0
  15. package/lib/arrival.js +86 -0
  16. package/lib/arrival.js.map +1 -0
  17. package/lib/artifact-query.d.ts +53 -0
  18. package/lib/artifact-query.js +130 -0
  19. package/lib/artifact-query.js.map +1 -0
  20. package/lib/client.js +234 -0
  21. package/lib/client.js.map +1 -0
  22. package/lib/commands.d.ts +28 -0
  23. package/lib/commands.js +305 -0
  24. package/lib/commands.js.map +1 -0
  25. package/lib/compose.d.ts +30 -0
  26. package/lib/compose.js +131 -0
  27. package/lib/compose.js.map +1 -0
  28. package/lib/continue-core.d.ts +153 -0
  29. package/lib/continue-core.js +252 -0
  30. package/lib/continue-core.js.map +1 -0
  31. package/lib/engine-core.d.ts +219 -0
  32. package/lib/engine-core.js +405 -0
  33. package/lib/engine-core.js.map +1 -0
  34. package/lib/engine.d.ts +211 -0
  35. package/lib/engine.js +571 -0
  36. package/lib/engine.js.map +1 -0
  37. package/lib/enrich-queue.d.ts +66 -0
  38. package/lib/enrich-queue.js +100 -0
  39. package/lib/enrich-queue.js.map +1 -0
  40. package/lib/enrich-store.d.ts +31 -0
  41. package/lib/enrich-store.js +103 -0
  42. package/lib/enrich-store.js.map +1 -0
  43. package/lib/enrich-wire.d.ts +73 -0
  44. package/lib/enrich-wire.js +209 -0
  45. package/lib/enrich-wire.js.map +1 -0
  46. package/lib/enrich.d.ts +73 -0
  47. package/lib/enrich.js +150 -0
  48. package/lib/enrich.js.map +1 -0
  49. package/lib/gitops.d.ts +107 -0
  50. package/lib/gitops.js +539 -0
  51. package/lib/gitops.js.map +1 -0
  52. package/lib/index.d.ts +81 -0
  53. package/lib/index.js +305 -0
  54. package/lib/index.js.map +1 -0
  55. package/lib/indexing.d.ts +85 -0
  56. package/lib/indexing.js +212 -0
  57. package/lib/indexing.js.map +1 -0
  58. package/lib/injections.d.ts +66 -0
  59. package/lib/injections.js +83 -0
  60. package/lib/injections.js.map +1 -0
  61. package/lib/notice.d.ts +60 -0
  62. package/lib/notice.js +84 -0
  63. package/lib/notice.js.map +1 -0
  64. package/lib/provider.d.ts +44 -0
  65. package/lib/provider.js +66 -0
  66. package/lib/provider.js.map +1 -0
  67. package/lib/redact.d.ts +24 -0
  68. package/lib/redact.js +85 -0
  69. package/lib/redact.js.map +1 -0
  70. package/lib/registry.d.ts +120 -0
  71. package/lib/registry.js +130 -0
  72. package/lib/registry.js.map +1 -0
  73. package/lib/render.d.ts +40 -0
  74. package/lib/render.js +280 -0
  75. package/lib/render.js.map +1 -0
  76. package/lib/repo.d.ts +78 -0
  77. package/lib/repo.js +184 -0
  78. package/lib/repo.js.map +1 -0
  79. package/lib/rules-commands.d.ts +24 -0
  80. package/lib/rules-commands.js +138 -0
  81. package/lib/rules-commands.js.map +1 -0
  82. package/lib/rules.d.ts +90 -0
  83. package/lib/rules.js +185 -0
  84. package/lib/rules.js.map +1 -0
  85. package/lib/search.d.ts +48 -0
  86. package/lib/search.js +152 -0
  87. package/lib/search.js.map +1 -0
  88. package/lib/signature.d.ts +28 -0
  89. package/lib/signature.js +149 -0
  90. package/lib/signature.js.map +1 -0
  91. package/lib/store.d.ts +130 -0
  92. package/lib/store.js +235 -0
  93. package/lib/store.js.map +1 -0
  94. package/lib/sync.d.ts +183 -0
  95. package/lib/sync.js +719 -0
  96. package/lib/sync.js.map +1 -0
  97. package/lib/tools.d.ts +84 -0
  98. package/lib/tools.js +581 -0
  99. package/lib/tools.js.map +1 -0
  100. package/lib/treedx/client.d.ts +57 -0
  101. package/lib/treedx/client.js +82 -0
  102. package/lib/treedx/client.js.map +1 -0
  103. package/lib/treedx/provider.d.ts +39 -0
  104. package/lib/treedx/provider.js +479 -0
  105. package/lib/treedx/provider.js.map +1 -0
  106. package/lib/treedx/state.d.ts +27 -0
  107. package/lib/treedx/state.js +65 -0
  108. package/lib/treedx/state.js.map +1 -0
  109. package/lib/types.d.ts +100 -0
  110. package/lib/types.js +19 -0
  111. package/lib/types.js.map +1 -0
  112. package/lib/vocabulary.d.ts +41 -0
  113. package/lib/vocabulary.js +118 -0
  114. package/lib/vocabulary.js.map +1 -0
  115. package/package.json +132 -0
  116. package/presets/chapters/agent.cordis.yml +272 -0
  117. package/presets/chapters/preset.yml +3 -0
  118. package/presets/probe-roots/agent.cordis.yml +11 -0
  119. package/presets/probe-roots/preset.yml +3 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAA;AAW9D,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAiB;IACvC,GAAG,gBAAgB;IACnB,IAAI,EAAE,KAAK;IACX,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,OAAO,CAAC,MAAM,EAAE;CACjD,CAAA;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAA6B,CAAC,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;AAE5E,MAAM,UAAU,gBAAgB,CAAC,QAAsB;IACrD,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAA+C;IAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAA;IAClC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,+BAA+B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;IAC9F,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,UAAwB,EAAE,MAAc;IACtE,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,UAAU,CAAA;IACxC,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,qCAAqC,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,sCAAsC,UAAU,oDAAoD,CAAC,CAAA;IAC1J,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface RedactPattern {
2
+ name: string;
3
+ /** Global regex; the secret is the whole match unless `secretGroup` names a capture group. */
4
+ regex: RegExp;
5
+ /** Capture group holding the secret (e.g. keep `token=`, redact the value). Default: whole match. */
6
+ secretGroup?: number;
7
+ }
8
+ /** Built-in set (record §9). New patterns are config additions, not magic. */
9
+ export declare const DEFAULT_REDACTIONS: readonly RedactPattern[];
10
+ export interface RedactionResult {
11
+ text: string;
12
+ /** Number of secret occurrences replaced. */
13
+ count: number;
14
+ /** Distinct markers produced (for tests/audit; order of first appearance). */
15
+ markers: string[];
16
+ }
17
+ /**
18
+ * Replace every pattern match's secret with its stable marker.
19
+ * `secretGroup` semantics: the named group is the LABEL to keep; the secret
20
+ * is the rest of the match (url-credential-param, bearer). Without it, the
21
+ * whole match is the secret. Markers never re-match any pattern (verified by
22
+ * test), so passes compose safely.
23
+ */
24
+ export declare function redactText(text: string, patterns?: readonly RedactPattern[]): RedactionResult;
package/lib/redact.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Deterministic credential redaction (knowledge-repo.md §9).
3
+ *
4
+ * The user's position, adopted: credentials only, deterministic patterns only,
5
+ * everything else byte-identical — the character of the conversation is
6
+ * historical value and stays intact. The marker is deliberate and stable:
7
+ * ⟦redacted:credential sha256=8f3a1c2b⟧
8
+ * (a) obviously not a real value to any model reading a chapter,
9
+ * (b) deterministic per secret — same secret, same marker, so diffs and
10
+ * cross-chapter greps stay stable,
11
+ * (c) leaks nothing but an 8-hex prefix hash, which is also what lets a user
12
+ * ask "which secrets touched my sessions" without exposing them.
13
+ *
14
+ * Patterns are conservative by design and config-extensible; redaction is a
15
+ * speed bump, not a guarantee (the record says so, and so does the in-repo
16
+ * notice). Applied once, at the render chokepoint (src/render.ts), so chapters
17
+ * and artifact files are both covered without caller changes.
18
+ */
19
+ import { createHash } from 'node:crypto';
20
+ /** Built-in set (record §9). New patterns are config additions, not magic. */
21
+ export const DEFAULT_REDACTIONS = [
22
+ { name: 'pem-private-key', regex: /-----BEGIN (?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/g },
23
+ { name: 'aws-access-key-id', regex: /\bAKIA[0-9A-Z]{16}\b/g },
24
+ { name: 'github-token', regex: /\b(?:ghp|gho|ghs|ghu)_[A-Za-z0-9]{16,}\b/g },
25
+ { name: 'github-fine-grained', regex: /\bgithub_pat_[A-Za-z0-9_]{16,}\b/g },
26
+ { name: 'openai-style-key', regex: /\bsk-[A-Za-z0-9_-]{16,}\b/g },
27
+ { name: 'jwt', regex: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\b/g },
28
+ { name: 'bearer-token', regex: /\b(Bearer\s+)[A-Za-z0-9._~+/=-]{16,}/gi, secretGroup: 1 },
29
+ { name: 'url-credential-param', regex: /([?&](?:token|api[_-]?key|apikey|key|secret|password)=)[^&\s"'`]+/gi, secretGroup: 1 },
30
+ ];
31
+ /**
32
+ * `Bearer <tok>` → redact the token, keep the `Bearer ` label: the pattern's
33
+ * `secretGroup` names the capture that is NOT the secret; here we invert —
34
+ * the label is group 1, so the secret is the remainder of the match after
35
+ * the group. Implemented via a post-step in redactText (label-aware patterns).
36
+ */
37
+ function markerFor(secret) {
38
+ const h = createHash('sha256').update(secret, 'utf8').digest('hex').slice(0, 8);
39
+ return `⟦redacted:credential sha256=${h}⟧`;
40
+ }
41
+ /**
42
+ * Replace every pattern match's secret with its stable marker.
43
+ * `secretGroup` semantics: the named group is the LABEL to keep; the secret
44
+ * is the rest of the match (url-credential-param, bearer). Without it, the
45
+ * whole match is the secret. Markers never re-match any pattern (verified by
46
+ * test), so passes compose safely.
47
+ */
48
+ export function redactText(text, patterns = DEFAULT_REDACTIONS) {
49
+ let out = text;
50
+ let count = 0;
51
+ const markers = [];
52
+ for (const p of patterns) {
53
+ const re = new RegExp(p.regex.source, p.regex.flags.includes('g') ? p.regex.flags : p.regex.flags + 'g');
54
+ const matches = Array.from(out.matchAll(re));
55
+ if (matches.length === 0)
56
+ continue;
57
+ // splice back-to-front so earlier indices stay valid
58
+ for (let i = matches.length - 1; i >= 0; i -= 1) {
59
+ const m = matches[i];
60
+ const whole = m[0];
61
+ let keep = '';
62
+ let secret = whole;
63
+ // label-group patterns (bearer, url-credential): the named group is a
64
+ // PREFIX of the match and is kept; the remainder is the secret. Any
65
+ // other shape falls through to whole-match redaction (safe default).
66
+ if (p.secretGroup !== undefined) {
67
+ const label = m[p.secretGroup];
68
+ if (typeof label === 'string' && label.length > 0 && whole.startsWith(label)) {
69
+ keep = label;
70
+ secret = whole.slice(label.length);
71
+ }
72
+ }
73
+ if (secret.length === 0)
74
+ continue;
75
+ const marker = markerFor(secret);
76
+ const start = m.index + keep.length;
77
+ out = out.slice(0, start) + marker + out.slice(start + secret.length);
78
+ count += 1;
79
+ if (!markers.includes(marker))
80
+ markers.push(marker);
81
+ }
82
+ }
83
+ return { text: out, count, markers };
84
+ }
85
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Registry — pure ancestry/numbering state. No cordis, no zod, no I/O: this is
3
+ * the L0 layer (docs/development.md § Test Layers); `src/store.ts` is the thin
4
+ * storage-domain adapter over it, deliberately untested because it is glue.
5
+ *
6
+ * The registry is the SOLE authority on ancestry (contract.md § Lineage: the
7
+ * kernel header carries `parentSession` for seed lineage we deliberately do not
8
+ * use; the UI graph will show our children as unrelated roots). Corruptions it
9
+ * must survive: cycles (walk guard throws, never hangs), duplicate chapter ids
10
+ * (append is idempotent), retry-after-crash (reserve is attempt-keyed, so the
11
+ * same `sourceSession@ceiling` reuses its numbers — archive.ts depends on it).
12
+ *
13
+ * Numbering is per-author-session (invariant: chapters keyed by creating
14
+ * session, so siblings cannot collide), and the flat index is built by the
15
+ * PLUGIN walking the ancestor path — the model never traverses a graph.
16
+ */
17
+ import type { ChapterRecord } from './archive.ts';
18
+ import type { CollectionSignature } from './signature.ts';
19
+ export interface SessionState {
20
+ /** Registry-level parent, set at continuation commit. null until linked. */
21
+ parentSession: string | null;
22
+ /** Root of the ancestry tree; the store directory key. Self for a root session. */
23
+ rootSession: string;
24
+ /** Next unallocated chapter number for THIS author session. */
25
+ nextChapterNumber: number;
26
+ chapters: ChapterRecord[];
27
+ /** attemptKey -> numbers, so an idempotent retry reuses rather than duplicates. */
28
+ reservations: Record<string, number[]>;
29
+ /**
30
+ * compactionId -> the plan summarize() committed to: the TOC text already
31
+ * cited `path`, so finalize (possibly after a crash and process restart)
32
+ * must reproduce it exactly. Rebuilding the title from messages is not
33
+ * available post-commit — this manifest is the durable bridge.
34
+ */
35
+ plans: Record<string, {
36
+ number: number;
37
+ path: string;
38
+ title: string;
39
+ summary: string;
40
+ chapters?: PlanChapter[] | undefined;
41
+ }>;
42
+ /**
43
+ * compactionId -> chapter numbers, written when a compaction's chapter bodies
44
+ * are durably finalized post-commit. Idempotence key for the finalizer and
45
+ * the reconciliation scan (FINDINGS § correlation seam).
46
+ */
47
+ finalized: Record<string, number[]>;
48
+ /**
49
+ * Per-turn deterministic signatures, appended at turn/end (knowledge-repo
50
+ * §4.1). The composer (§4.2) reads these at archive time; P2 enrichment may
51
+ * relabel later but never rewrites them. Append-only like chapters.
52
+ */
53
+ collections: CollectionSignature[];
54
+ }
55
+ export declare const freshSession: (sessionId: string) => SessionState;
56
+ /**
57
+ * One composed chapter of a compaction plan (r29): the composer's range,
58
+ * its reserved number and cited path, durable BEFORE the summary text cites
59
+ * them. Legacy single-chapter plans keep the four flat fields and omit this.
60
+ */
61
+ export interface PlanChapter {
62
+ number: number;
63
+ path: string;
64
+ title: string;
65
+ summary: string;
66
+ startSeq: number;
67
+ endSeq: number;
68
+ }
69
+ /** Persist a summarize-time plan so finalization survives a restart. */
70
+ export declare function rememberPlan(state: SessionState, compactionId: string, plan: {
71
+ number: number;
72
+ path: string;
73
+ title: string;
74
+ summary: string;
75
+ chapters?: PlanChapter[];
76
+ }): SessionState;
77
+ /** Record a post-commit finalization for one compaction. Same write twice is a no-op. */
78
+ export declare function markFinalized(state: SessionState, compactionId: string, numbers: readonly number[]): SessionState;
79
+ /** True when a compaction's chapters are already committed (finalizer + scan use this). */
80
+ export declare const isFinalized: (state: SessionState, compactionId: string) => boolean;
81
+ /** Immutably updated copy with `n` numbers reserved for `attemptId`. */
82
+ export declare function reserve(state: SessionState, attemptId: string, count: number): {
83
+ state: SessionState;
84
+ numbers: number[];
85
+ };
86
+ /** Append verified chapter records. A record with an existing (number) identity is a no-op — retries are safe. */
87
+ export declare function appendChapters(state: SessionState, records: readonly ChapterRecord[]): SessionState;
88
+ /**
89
+ * Commit point for a continuation: the child inherits the PARENT's root and
90
+ * gets its direct parent recorded. Set once, never rewritten — re-pointing a
91
+ * linked session would silently re-home every chapter below it. Same link
92
+ * twice is a no-op (retry safety); a DIFFERENT link is corruption or a bug,
93
+ * and it throws.
94
+ */
95
+ export declare function linkChild(state: SessionState, parentSessionId: string, parentRootSession: string): SessionState;
96
+ /**
97
+ * Walk parent links root-first. Throws on a cycle or a missing parent — both
98
+ * are registry corruption, and an infinite walk is how a small bad write
99
+ * becomes a hung plugin at the worst moment.
100
+ */
101
+ export declare function ancestorPath(get: (id: string) => SessionState | undefined, sessionId: string, maxDepth?: number): string[];
102
+ export interface IndexEntry {
103
+ /** Session that authored the chapter, for back-links. */
104
+ authorSession: string;
105
+ number: number;
106
+ path: string;
107
+ title: string;
108
+ summary: string;
109
+ /** Integrity verdict supplied by the caller (verifyChapter via its fs port). */
110
+ status: 'ok' | 'modified' | 'missing';
111
+ }
112
+ /**
113
+ * The flat, chronological, numbered index the TOC renders — reading order IS
114
+ * causal order (docs/architecture.md § Ancestry). Ancestor sessions first;
115
+ * within a session, by reserved number. Siblings are excluded by construction:
116
+ * the walk never enters them.
117
+ */
118
+ export declare function buildIndex(path: readonly string[], get: (id: string) => SessionState | undefined, status: (record: ChapterRecord) => IndexEntry['status']): IndexEntry[];
119
+ /** Append one turn's signature. Idempotent per turn (same seqs → no-op), like appendChapters. */
120
+ export declare function appendCollection(state: SessionState, sig: CollectionSignature): SessionState;
@@ -0,0 +1,130 @@
1
+ export const freshSession = (sessionId) => ({
2
+ parentSession: null,
3
+ rootSession: sessionId,
4
+ nextChapterNumber: 1,
5
+ collections: [],
6
+ chapters: [],
7
+ reservations: {},
8
+ plans: {},
9
+ finalized: {},
10
+ });
11
+ /** Persist a summarize-time plan so finalization survives a restart. */
12
+ export function rememberPlan(state, compactionId, plan) {
13
+ return { ...state, plans: { ...state.plans, [compactionId]: plan } };
14
+ }
15
+ /** Record a post-commit finalization for one compaction. Same write twice is a no-op. */
16
+ export function markFinalized(state, compactionId, numbers) {
17
+ if (state.finalized[compactionId] !== undefined)
18
+ return state;
19
+ return { ...state, finalized: { ...state.finalized, [compactionId]: [...numbers] } };
20
+ }
21
+ /** True when a compaction's chapters are already committed (finalizer + scan use this). */
22
+ export const isFinalized = (state, compactionId) => state.finalized[compactionId] !== undefined;
23
+ /** Immutably updated copy with `n` numbers reserved for `attemptId`. */
24
+ export function reserve(state, attemptId, count) {
25
+ if (count <= 0 || !Number.isInteger(count)) {
26
+ throw new Error(`reserve: count must be a positive integer, got ${count}`);
27
+ }
28
+ const existing = state.reservations[attemptId];
29
+ if (existing !== undefined) {
30
+ if (existing.length !== count) {
31
+ // Same attempt, different size: the caller's chapter set changed under a
32
+ // half-finished attempt. Reusing a shorter list would silently drop
33
+ // chapters; growing would collide. Refuse — never guess.
34
+ throw new Error(`reserve: attempt "${attemptId}" already holds ${existing.length} numbers, requested ${count}`);
35
+ }
36
+ return { state, numbers: [...existing] };
37
+ }
38
+ const numbers = Array.from({ length: count }, (_, i) => state.nextChapterNumber + i);
39
+ return {
40
+ state: {
41
+ ...state,
42
+ nextChapterNumber: state.nextChapterNumber + count,
43
+ reservations: { ...state.reservations, [attemptId]: numbers },
44
+ },
45
+ numbers,
46
+ };
47
+ }
48
+ /** Append verified chapter records. A record with an existing (number) identity is a no-op — retries are safe. */
49
+ export function appendChapters(state, records) {
50
+ const known = new Set(state.chapters.map((c) => c.number));
51
+ const fresh = records.filter((r) => !known.has(r.number));
52
+ if (fresh.length === 0)
53
+ return state;
54
+ return { ...state, chapters: [...state.chapters, ...fresh] };
55
+ }
56
+ /**
57
+ * Commit point for a continuation: the child inherits the PARENT's root and
58
+ * gets its direct parent recorded. Set once, never rewritten — re-pointing a
59
+ * linked session would silently re-home every chapter below it. Same link
60
+ * twice is a no-op (retry safety); a DIFFERENT link is corruption or a bug,
61
+ * and it throws.
62
+ */
63
+ export function linkChild(state, parentSessionId, parentRootSession) {
64
+ if (state.parentSession !== null) {
65
+ if (state.parentSession === parentSessionId && state.rootSession === parentRootSession)
66
+ return state;
67
+ throw new Error(`linkChild: session already linked to parent ${state.parentSession} (root ${state.rootSession});`
68
+ + ` refusing rewrite to parent ${parentSessionId} (root ${parentRootSession})`);
69
+ }
70
+ return { ...state, parentSession: parentSessionId, rootSession: parentRootSession };
71
+ }
72
+ /**
73
+ * Walk parent links root-first. Throws on a cycle or a missing parent — both
74
+ * are registry corruption, and an infinite walk is how a small bad write
75
+ * becomes a hung plugin at the worst moment.
76
+ */
77
+ export function ancestorPath(get, sessionId, maxDepth = 1000) {
78
+ const path = [];
79
+ const seen = new Set();
80
+ let cursor = sessionId;
81
+ while (cursor !== undefined) {
82
+ if (seen.has(cursor))
83
+ throw new Error(`ancestorPath: cycle through ${cursor}`);
84
+ if (seen.size >= maxDepth)
85
+ throw new Error(`ancestorPath: exceeded depth ${maxDepth}`);
86
+ seen.add(cursor);
87
+ const state = get(cursor);
88
+ if (state === undefined) {
89
+ if (cursor === sessionId)
90
+ return [cursor]; // unregistered root: itself is the path
91
+ throw new Error(`ancestorPath: missing state for parent ${cursor} (registry corruption)`);
92
+ }
93
+ path.unshift(cursor);
94
+ cursor = state.parentSession ?? undefined;
95
+ }
96
+ return path;
97
+ }
98
+ /**
99
+ * The flat, chronological, numbered index the TOC renders — reading order IS
100
+ * causal order (docs/architecture.md § Ancestry). Ancestor sessions first;
101
+ * within a session, by reserved number. Siblings are excluded by construction:
102
+ * the walk never enters them.
103
+ */
104
+ export function buildIndex(path, get, status) {
105
+ const entries = [];
106
+ for (const sessionId of path) {
107
+ const state = get(sessionId);
108
+ if (state === undefined)
109
+ continue;
110
+ for (const chapter of [...state.chapters].sort((a, b) => a.number - b.number)) {
111
+ entries.push({
112
+ authorSession: sessionId,
113
+ number: chapter.number,
114
+ path: chapter.path,
115
+ title: chapter.title,
116
+ summary: chapter.summary,
117
+ status: status(chapter),
118
+ });
119
+ }
120
+ }
121
+ return entries;
122
+ }
123
+ /** Append one turn's signature. Idempotent per turn (same seqs → no-op), like appendChapters. */
124
+ export function appendCollection(state, sig) {
125
+ const last = state.collections[state.collections.length - 1];
126
+ if (last !== undefined && last.seqs.length === sig.seqs.length && last.seqs.every((q, i) => q === sig.seqs[i]))
127
+ return state;
128
+ return { ...state, collections: [...state.collections, sig] };
129
+ }
130
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { ArtifactRef, ChapterRange, RenderConfig, RenderedChapter, SessionEventLike, ToolResultCandidate, ToolResultOverride } from './types.ts';
2
+ /** chars/4 until the host tokenMeter is wired in. Labelled an estimate everywhere it surfaces. */
3
+ export declare const estimateTokens: (text: string) => number;
4
+ /**
5
+ * A fence strictly longer than any backtick run inside `body`, so embedded code blocks cannot close it.
6
+ * Markdown requires the closing fence to be at least as long as the opening one.
7
+ */
8
+ export declare function longerFence(body: string): string;
9
+ /** Wrapped in a fence long enough to survive any content, including nested fences. */
10
+ export declare function fenced(content: string, info?: string): string;
11
+ export declare const sha256: (text: string) => string;
12
+ /** `artifacts/8f/8f3a1c9d….txt` — sharded so one directory never holds the whole subtree. */
13
+ export declare const artifactPath: (hash: string) => string;
14
+ export declare function artifactRef(text: string, opts: {
15
+ toolName: string;
16
+ sourceSeq: number;
17
+ inlined: boolean;
18
+ }): ArtifactRef;
19
+ /**
20
+ * Validate model-supplied ranges. Never trust them (hard rule): an overlap duplicates archived text and a
21
+ * gap silently drops history, so both are errors here rather than data that quietly goes missing.
22
+ */
23
+ export declare function validateRanges(chapters: ChapterRange[], archiveCeiling: number): ChapterRange[];
24
+ /** Enumerate tool results in a range so the model can decide keep/defer against real sizes. */
25
+ export declare function toolResultCandidates(events: SessionEventLike[], range: ChapterRange): ToolResultCandidate[];
26
+ /**
27
+ * Render one chapter. `overrides` is the model's sparse exception list; anything not named follows the
28
+ * default rule (small results inline, large ones deferred). Either way the artifact is written, so a wrong
29
+ * call costs a `read` and never loses data.
30
+ */
31
+ export declare function renderChapter(events: SessionEventLike[], range: ChapterRange, config: RenderConfig, overrides?: readonly ToolResultOverride[], topics?: readonly string[]): RenderedChapter;
32
+ /**
33
+ * The cumulative index that replaces compacted history. Built from registry records, never from an LLM —
34
+ * which is the entire latency argument: no summarization call, no tokens, no paraphrase.
35
+ */
36
+ export declare function renderIndex(entries: readonly {
37
+ path: string;
38
+ title: string;
39
+ summary: string;
40
+ }[]): string;