@fractalsynapse/dsh-chapters 0.0.0-stage → 0.2.21

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 (195) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +76 -2
  3. package/cordis.patch.yml +363 -0
  4. package/docs/architecture.md +692 -0
  5. package/docs/autorun-guide.md +248 -0
  6. package/docs/backlog.md +2022 -0
  7. package/docs/contract.md +938 -0
  8. package/docs/development.md +990 -0
  9. package/docs/host-compaction-seam.md +225 -0
  10. package/docs/host-protected-head-ask.md +80 -0
  11. package/docs/knowledge-repo.md +1332 -0
  12. package/docs/plans-carriage.md +571 -0
  13. package/docs/project-state.md +642 -0
  14. package/docs/provider.md +98 -0
  15. package/docs/superpowers/plans/2026-10-17-chapters-save.md +198 -0
  16. package/docs/superpowers/plans/2026-11-02-chapter-removal.md +151 -0
  17. package/docs/superpowers/specs/2026-11-02-chapter-removal-design.md +115 -0
  18. package/docs/verify.md +561 -0
  19. package/lib/archive.d.ts +161 -0
  20. package/lib/archive.js +229 -0
  21. package/lib/archive.js.map +1 -0
  22. package/lib/arrival.d.ts +23 -0
  23. package/lib/arrival.js +125 -0
  24. package/lib/arrival.js.map +1 -0
  25. package/lib/artifact-query.d.ts +62 -0
  26. package/lib/artifact-query.js +187 -0
  27. package/lib/artifact-query.js.map +1 -0
  28. package/lib/attach.d.ts +46 -0
  29. package/lib/attach.js +120 -0
  30. package/lib/attach.js.map +1 -0
  31. package/lib/auto-save.d.ts +145 -0
  32. package/lib/auto-save.js +334 -0
  33. package/lib/auto-save.js.map +1 -0
  34. package/lib/aux-message.d.ts +17 -0
  35. package/lib/aux-message.js +20 -0
  36. package/lib/aux-message.js.map +1 -0
  37. package/lib/client.js +1419 -0
  38. package/lib/client.js.map +1 -0
  39. package/lib/codegraph.d.ts +76 -0
  40. package/lib/codegraph.js +190 -0
  41. package/lib/codegraph.js.map +1 -0
  42. package/lib/commands.d.ts +52 -0
  43. package/lib/commands.js +946 -0
  44. package/lib/commands.js.map +1 -0
  45. package/lib/compose.d.ts +30 -0
  46. package/lib/compose.js +185 -0
  47. package/lib/compose.js.map +1 -0
  48. package/lib/continue-core.d.ts +245 -0
  49. package/lib/continue-core.js +405 -0
  50. package/lib/continue-core.js.map +1 -0
  51. package/lib/diag.d.ts +55 -0
  52. package/lib/diag.js +186 -0
  53. package/lib/diag.js.map +1 -0
  54. package/lib/engine-core.d.ts +301 -0
  55. package/lib/engine-core.js +531 -0
  56. package/lib/engine-core.js.map +1 -0
  57. package/lib/engine-note.d.ts +35 -0
  58. package/lib/engine-note.js +32 -0
  59. package/lib/engine-note.js.map +1 -0
  60. package/lib/engine.d.ts +329 -0
  61. package/lib/engine.js +1179 -0
  62. package/lib/engine.js.map +1 -0
  63. package/lib/enrich-queue.d.ts +66 -0
  64. package/lib/enrich-queue.js +126 -0
  65. package/lib/enrich-queue.js.map +1 -0
  66. package/lib/enrich-store.d.ts +31 -0
  67. package/lib/enrich-store.js +103 -0
  68. package/lib/enrich-store.js.map +1 -0
  69. package/lib/enrich-wire.d.ts +163 -0
  70. package/lib/enrich-wire.js +353 -0
  71. package/lib/enrich-wire.js.map +1 -0
  72. package/lib/enrich.d.ts +102 -0
  73. package/lib/enrich.js +267 -0
  74. package/lib/enrich.js.map +1 -0
  75. package/lib/gitops.d.ts +107 -0
  76. package/lib/gitops.js +539 -0
  77. package/lib/gitops.js.map +1 -0
  78. package/lib/index.d.ts +241 -0
  79. package/lib/index.js +1162 -0
  80. package/lib/index.js.map +1 -0
  81. package/lib/indexing.d.ts +98 -0
  82. package/lib/indexing.js +223 -0
  83. package/lib/indexing.js.map +1 -0
  84. package/lib/injections.d.ts +90 -0
  85. package/lib/injections.js +165 -0
  86. package/lib/injections.js.map +1 -0
  87. package/lib/last-resort.d.ts +24 -0
  88. package/lib/last-resort.js +27 -0
  89. package/lib/last-resort.js.map +1 -0
  90. package/lib/log-shape.d.ts +38 -0
  91. package/lib/log-shape.js +93 -0
  92. package/lib/log-shape.js.map +1 -0
  93. package/lib/models-command.d.ts +74 -0
  94. package/lib/models-command.js +100 -0
  95. package/lib/models-command.js.map +1 -0
  96. package/lib/notice.d.ts +74 -0
  97. package/lib/notice.js +92 -0
  98. package/lib/notice.js.map +1 -0
  99. package/lib/plans.d.ts +154 -0
  100. package/lib/plans.js +315 -0
  101. package/lib/plans.js.map +1 -0
  102. package/lib/preset.d.ts +186 -0
  103. package/lib/preset.js +212 -0
  104. package/lib/preset.js.map +1 -0
  105. package/lib/prompt-keys.d.ts +7 -0
  106. package/lib/prompt-keys.js +8 -0
  107. package/lib/prompt-keys.js.map +1 -0
  108. package/lib/prompt-loop.d.ts +73 -0
  109. package/lib/prompt-loop.js +147 -0
  110. package/lib/prompt-loop.js.map +1 -0
  111. package/lib/prompt-push.d.ts +47 -0
  112. package/lib/prompt-push.js +115 -0
  113. package/lib/prompt-push.js.map +1 -0
  114. package/lib/prompt-runner.d.ts +48 -0
  115. package/lib/prompt-runner.js +90 -0
  116. package/lib/prompt-runner.js.map +1 -0
  117. package/lib/prompt-state.d.ts +142 -0
  118. package/lib/prompt-state.js +101 -0
  119. package/lib/prompt-state.js.map +1 -0
  120. package/lib/prompt.d.ts +270 -0
  121. package/lib/prompt.js +408 -0
  122. package/lib/prompt.js.map +1 -0
  123. package/lib/provider.d.ts +44 -0
  124. package/lib/provider.js +66 -0
  125. package/lib/provider.js.map +1 -0
  126. package/lib/redact.d.ts +24 -0
  127. package/lib/redact.js +85 -0
  128. package/lib/redact.js.map +1 -0
  129. package/lib/registry.d.ts +187 -0
  130. package/lib/registry.js +235 -0
  131. package/lib/registry.js.map +1 -0
  132. package/lib/removal.d.ts +159 -0
  133. package/lib/removal.js +556 -0
  134. package/lib/removal.js.map +1 -0
  135. package/lib/render.d.ts +97 -0
  136. package/lib/render.js +530 -0
  137. package/lib/render.js.map +1 -0
  138. package/lib/repair-run.d.ts +76 -0
  139. package/lib/repair-run.js +506 -0
  140. package/lib/repair-run.js.map +1 -0
  141. package/lib/repair.d.ts +208 -0
  142. package/lib/repair.js +357 -0
  143. package/lib/repair.js.map +1 -0
  144. package/lib/repo.d.ts +78 -0
  145. package/lib/repo.js +184 -0
  146. package/lib/repo.js.map +1 -0
  147. package/lib/rules-commands.d.ts +46 -0
  148. package/lib/rules-commands.js +379 -0
  149. package/lib/rules-commands.js.map +1 -0
  150. package/lib/rules.d.ts +267 -0
  151. package/lib/rules.js +478 -0
  152. package/lib/rules.js.map +1 -0
  153. package/lib/save-core.d.ts +72 -0
  154. package/lib/save-core.js +220 -0
  155. package/lib/save-core.js.map +1 -0
  156. package/lib/search.d.ts +112 -0
  157. package/lib/search.js +282 -0
  158. package/lib/search.js.map +1 -0
  159. package/lib/session-rules.d.ts +222 -0
  160. package/lib/session-rules.js +454 -0
  161. package/lib/session-rules.js.map +1 -0
  162. package/lib/signature.d.ts +45 -0
  163. package/lib/signature.js +199 -0
  164. package/lib/signature.js.map +1 -0
  165. package/lib/store.d.ts +156 -0
  166. package/lib/store.js +368 -0
  167. package/lib/store.js.map +1 -0
  168. package/lib/sync.d.ts +220 -0
  169. package/lib/sync.js +810 -0
  170. package/lib/sync.js.map +1 -0
  171. package/lib/tools.d.ts +113 -0
  172. package/lib/tools.js +1090 -0
  173. package/lib/tools.js.map +1 -0
  174. package/lib/treedx/client.d.ts +57 -0
  175. package/lib/treedx/client.js +82 -0
  176. package/lib/treedx/client.js.map +1 -0
  177. package/lib/treedx/provider.d.ts +39 -0
  178. package/lib/treedx/provider.js +479 -0
  179. package/lib/treedx/provider.js.map +1 -0
  180. package/lib/treedx/state.d.ts +27 -0
  181. package/lib/treedx/state.js +65 -0
  182. package/lib/treedx/state.js.map +1 -0
  183. package/lib/types.d.ts +210 -0
  184. package/lib/types.js +31 -0
  185. package/lib/types.js.map +1 -0
  186. package/lib/version.d.ts +9 -0
  187. package/lib/version.js +10 -0
  188. package/lib/version.js.map +1 -0
  189. package/lib/vocabulary.d.ts +41 -0
  190. package/lib/vocabulary.js +118 -0
  191. package/lib/vocabulary.js.map +1 -0
  192. package/lib/warnings.d.ts +10 -0
  193. package/lib/warnings.js +18 -0
  194. package/lib/warnings.js.map +1 -0
  195. package/package.json +151 -3
@@ -0,0 +1,220 @@
1
+ /**
2
+ * saveSession — the archive-only pipeline, ONE implementation (issue #47).
3
+ *
4
+ * Extracted verbatim from the `/chapters-save` command body so door 3 (the human
5
+ * command) and door 5 (subagent settlement) cannot drift: same watermark, same
6
+ * composition, same render + write + commit. Policy stays OUTSIDE this function —
7
+ * what to say to the human, whether to run enrichment now or queue it, whether to
8
+ * schedule a sync — because those differ per door by design; the ARCHIVE does not.
9
+ *
10
+ * Rules this honors (AGENTS.md): never trusts ranges it did not derive, anchors
11
+ * ONLY on `turn/end` (an interrupted tail is skipped, never half-archived), writes
12
+ * append-only with read-back verification, and stamps lineage from the durable
13
+ * header only (`RenderConfig.subagentOf` via `lineageOf`).
14
+ */
15
+ import { composeChapters } from "./compose.js";
16
+ import { deriveRanges } from "./continue-core.js";
17
+ import { estimateTokens, oversizeRanges, renderChapter } from "./render.js";
18
+ import { chapterTopics } from "./signature.js";
19
+ import { makeArchiveFs, commitChapters } from "./store.js";
20
+ import { releaseReservation, reserve, reservePlan as reservePlanNumber } from "./registry.js";
21
+ /** One serialized read-allocate-write for a door that cannot use makeAllocator (same rule, #59). */
22
+ async function reserveNumbers(store, sessionId, attemptId, count, plan = false) {
23
+ let numbers = [];
24
+ await store.mutate(sessionId, (state) => {
25
+ const r = plan ? reservePlanNumber(state, attemptId, count) : reserve(state, attemptId, count);
26
+ numbers = r.numbers;
27
+ return r.state;
28
+ });
29
+ return { numbers };
30
+ }
31
+ import { writeArchive, attemptKey } from "./archive.js";
32
+ import { supersedeChapter } from "./repair.js";
33
+ /**
34
+ * Split a range whose RENDERED size would blow past the oversize ceiling (#60, repair path only).
35
+ *
36
+ * The normal doors cut on `turn/end` and warn when a chapter is over `chapterTokenTarget`, because a
37
+ * boundary is around the corner and clipping is forbidden. A REPAIR span can be one gigantic turn — a
38
+ * delegated subagent whose single turn ran to 4 MB — where there IS no next boundary, and refusing it
39
+ * (the #59c gate) would leave the husk superseded-by-nothing. So the repair splits at EVENT boundaries
40
+ * inside the turn: nothing is truncated, every byte still lands in a chapter, and the TOC gains several
41
+ * consecutive ranges instead of one unreadable one. The rule that binds is completeness, not "one chapter
42
+ * per turn" — and a chapter nobody can `read` back is not an archive.
43
+ */
44
+ function splitOversize(chapters, events, chapterTokenTarget, oversizeFactor) {
45
+ const ceiling = Math.floor(chapterTokenTarget * oversizeFactor);
46
+ const notes = [];
47
+ const out = [];
48
+ for (const c of chapters) {
49
+ const inRange = events.filter((e) => e.seq >= c.startSeq && e.seq <= c.endSeq);
50
+ const total = inRange.reduce((m, e) => m + estimateTokens(JSON.stringify(e.data ?? {})), 0);
51
+ if (total <= ceiling) {
52
+ out.push(c);
53
+ continue;
54
+ }
55
+ const parts = Math.ceil(total / ceiling);
56
+ const perPart = Math.ceil(inRange.length / parts);
57
+ let title = c.title;
58
+ for (let i = 0, n = 0; i < inRange.length; i += perPart, n++) {
59
+ const from = inRange[i].seq;
60
+ const to = inRange[Math.min(i + perPart, inRange.length) - 1].seq;
61
+ out.push({ ...c, title: n === 0 ? title : `${title} (part ${n + 1})`, startSeq: from, endSeq: to });
62
+ }
63
+ notes.push(`"${c.title}" (seqs ${c.startSeq}-${c.endSeq}) is ${total} est tokens in a single unfinished turn — split into ${parts} chapters at event boundaries (repair path; nothing truncated)`);
64
+ }
65
+ return { ranges: out, notes };
66
+ }
67
+ /**
68
+ * Force a repaired archive to cover exactly the span the finding named (#60). Composition may still cut
69
+ * it into topics - a cut is a chapter boundary, not a loss - but nothing may start above `fromSeq` or
70
+ * stop before the last completed turn inside the span, or the hole the finding reported stays open while
71
+ * the repair reports success.
72
+ */
73
+ function clampSpan(chapters, fromSeq, toSeq, events) {
74
+ // Nothing to clamp: the span held no completed turn at all. Returning EMPTY is the honest answer —
75
+ // inventing a title here would fabricate a chapter, and an empty `records` makes the caller skip the
76
+ // supersede, which is exactly right: a record is never marked superseded without its replacement (#60).
77
+ if (chapters.length === 0)
78
+ return [];
79
+ const lastCompleted = events.reduce((m, e) => (e.type === 'turn/end' && e.seq <= toSeq && e.seq > m ? e.seq : m), fromSeq);
80
+ return chapters.map((c, i) => ({
81
+ ...c,
82
+ startSeq: i === 0 ? Math.min(c.startSeq, fromSeq) : Math.max(c.startSeq, chapters[i - 1].endSeq + 1),
83
+ endSeq: i === chapters.length - 1 ? lastCompleted : Math.min(c.endSeq, lastCompleted),
84
+ }));
85
+ }
86
+ export async function saveSession(a) {
87
+ const { events, sessionId, cwd, store, config } = a;
88
+ if (cwd === '')
89
+ throw new Error('saveSession: session has no workspace cwd — nowhere reachable to write');
90
+ if (sessionId === '')
91
+ throw new Error('saveSession: no session id to own the archive');
92
+ // A repair targets a span it chose; every other door archives the watermark tail up to the last
93
+ // completed turn. One pipeline, one difference (#60).
94
+ const anchor = a.span !== undefined ? a.span.toSeq : [...events].reverse().find((e) => e.type === 'turn/end')?.seq;
95
+ if (anchor === undefined) {
96
+ return { skipped: 'no-completed-turn', fromSeq: 0, anchor: -1, lastArchived: 0, priorChapters: 0, records: [], warnings: [] };
97
+ }
98
+ // Watermark: only archive what is newer than the last saved chapter.
99
+ const state = await store.get(sessionId);
100
+ const lastArchived = state.chapters.reduce((m, c) => Math.max(m, c.endSeq), 0);
101
+ const fromSeq = a.span !== undefined ? a.span.fromSeq : (lastArchived > 0 ? lastArchived + 1 : 0);
102
+ // A REPAIR span is deliberate re-derivation of seqs the watermark has already passed (#60): the
103
+ // nothing-new guard is about not re-archiving a tail, and would otherwise refuse to fix the hole a
104
+ // hollow chapter sits exactly on top of. The span caller has already decided what needs re-rendering.
105
+ if (a.span === undefined && fromSeq > 0 && anchor <= lastArchived) {
106
+ return { skipped: 'nothing-new', fromSeq, anchor, lastArchived, priorChapters: state.chapters.length, records: [], warnings: [] };
107
+ }
108
+ // Topic-sequential composition — same pipeline as fork/continue.
109
+ const composed = composeChapters(events, fromSeq, anchor, state.collections, {
110
+ mergeThreshold: config.mergeThreshold,
111
+ chapterLimit: config.chapterLimit,
112
+ });
113
+ let chapters = composed.chapters.length > 0
114
+ ? composed.chapters
115
+ : deriveRanges(events, anchor, config.chapterTokenTarget, fromSeq).chapters;
116
+ const repairNotes = [];
117
+ if (a.span !== undefined) {
118
+ // A repair's span is bounded by the finding, so force exactly that range: composition inside a hole
119
+ // may cut it into topics, and a cut is fine, but nothing may start above `fromSeq` or end below the
120
+ // last completed turn inside the span.
121
+ chapters = clampSpan(chapters, a.span.fromSeq, a.span.toSeq, events);
122
+ // A repair span may be one enormous turn; the oversize gate would refuse it and leave the husk
123
+ // un-replaced. Split inside it at event boundaries — see `splitOversize`.
124
+ const split = splitOversize(chapters, events, config.chapterTokenTarget, config.chapterOversizeFactor ?? 2);
125
+ chapters = split.ranges;
126
+ repairNotes.push(...split.notes);
127
+ }
128
+ // Render + write archive (same as runContinue steps 2-3, minus child creation).
129
+ const below = events.filter((e) => e.seq <= anchor);
130
+ const renderConfig = {
131
+ toolResultDeferFloorTokens: config.toolResultDeferFloorTokens,
132
+ chapterTokenTarget: config.chapterTokenTarget,
133
+ ...(config.planInlineChars !== undefined ? { planInlineChars: config.planInlineChars } : {}),
134
+ ...(config.callArgArtifactTokens !== undefined ? { callArgArtifactTokens: config.callArgArtifactTokens } : {}),
135
+ ...(a.subagentOf !== undefined && a.subagentOf !== '' ? { subagentOf: a.subagentOf } : {}),
136
+ };
137
+ const rendered = chapters.map((range) => renderChapter(below, range, renderConfig, [], chapterTopics(below, range.startSeq, range.endSeq)));
138
+ // #58 — NEVER commit an archive that rendered nothing. A `tool/call` is always preceded by an
139
+ // `assistant/message`, so a non-empty range with zero rendered messages is not a short
140
+ // conversation: it is a read that carried no payloads. The real instance was
141
+ // `sessionQuery.listEvents`, whose `SessionEventRecord` rows have `seq`/`type`/`time`/`surface`
142
+ // and no `data` — 12 children on this machine archived as `**unknown**` / `{}` / `0 B` shells.
143
+ // The refusal is BEFORE `writeArchive`, so no number is reserved and no file is written: a
144
+ // committed husk would poison the watermark (`max(endSeq)`), and the child could then never be
145
+ // re-archived without a repair (#60). Refuse with numbers, never truncate — AGENTS.md.
146
+ //
147
+ // AMENDED #60: the test is on the ARCHIVE, not on each chapter. A repair may split one enormous turn
148
+ // into consecutive parts, and a part holding only tool calls legitimately renders zero messages —
149
+ // refusing the whole re-read over that stranded five SAIP children's knowledge again, which is the
150
+ // opposite of what the gate protects. "No payloads anywhere" is the anomaly; `describeHollow` keeps
151
+ // naming every message-free part so it is never silent, and the single-chapter case (#58's instance)
152
+ // still refuses exactly as before.
153
+ const describeHollow = (r) => {
154
+ const un = r.stats.unrenderedSeqs;
155
+ return `"${r.range.title}" spans seqs ${r.range.startSeq}..${r.range.endSeq}: ${r.stats.events} events, `
156
+ + `${r.stats.toolCalls} tool calls, 0 rendered messages, ${un.length} unrendered`
157
+ + `${un.length > 0 ? ` (first: ${un.slice(0, 5).join(', ')})` : ''}`;
158
+ };
159
+ const hollow = rendered.filter((r) => r.stats.events > 0 && r.stats.messages === 0);
160
+ if (rendered.length > 0 && hollow.length === rendered.length) {
161
+ return {
162
+ skipped: 'payloadless',
163
+ fromSeq,
164
+ anchor,
165
+ lastArchived,
166
+ priorChapters: state.chapters.length,
167
+ records: [],
168
+ warnings: hollow.map((r) => `${describeHollow(r)} — the read carried event SHAPES but no payloads; nothing was reserved or written`),
169
+ };
170
+ }
171
+ // Parts that carry tool calls but no prose are reported and STILL archived (#60): "what was
172
+ // attempted" is half the record, and silence about it is the defect class this issue is named for.
173
+ const hollowNotes = hollow.map((r) => `${describeHollow(r)} — archived for its tool calls, not a payload failure`);
174
+ // #59: refuse before reserving anything, exactly like the payloadless gate — a spent number with no
175
+ // file behind it is the burned-reservation state this whole round is eliminating. The factor is
176
+ // config, never a literal: over `chapterTokenTarget` warns, over `target × factor` refuses.
177
+ const oversize = oversizeRanges(rendered, config.chapterTokenTarget, config.chapterOversizeFactor ?? 2);
178
+ if (oversize.errors.length > 0) {
179
+ return {
180
+ skipped: 'oversize', fromSeq, anchor, lastArchived,
181
+ priorChapters: state.chapters.length, records: [], warnings: oversize.errors,
182
+ };
183
+ }
184
+ const wrote = await writeArchive({
185
+ fs: makeArchiveFs(cwd),
186
+ allocator: {
187
+ // One section per allocation (#59) — identical semantics to makeAllocator, which is why the
188
+ // shared helper is used by every other door; this door had its own copy of the race.
189
+ async reserve(attemptId, count) {
190
+ const { numbers } = await reserveNumbers(store, sessionId, attemptId, count);
191
+ return numbers;
192
+ },
193
+ async reservePlan(attemptId, count) {
194
+ const { numbers } = await reserveNumbers(store, sessionId, attemptId, count, true);
195
+ return numbers;
196
+ },
197
+ async release(attemptId) {
198
+ await store.mutate(sessionId, (state) => releaseReservation(state, attemptId));
199
+ },
200
+ },
201
+ // raw value: makeArchiveFs roots RELATIVE paths at the session cwd and
202
+ // passes absolute ones through — resolving here would double-root relative stores
203
+ storeRoot: config.artifactStoreRoot,
204
+ cwd, // #69: records are stored workspace-relative
205
+ rootSessionId: state.rootSession,
206
+ chapters: rendered,
207
+ attemptId: attemptKey(sessionId, anchor, a.attemptSalt),
208
+ });
209
+ // Commit chapter records to session state so search index picks them up.
210
+ if (a.supersede !== undefined && wrote.records.length > 0) {
211
+ // Commit AND mark in one section: no reader can ever see the replacement without the old record
212
+ // marked, or the mark without its replacement (#60).
213
+ await store.mutate(sessionId, (fresh) => supersedeChapter(fresh, a.supersede.over, wrote.records, a.supersede.reason));
214
+ }
215
+ else {
216
+ await commitChapters(store, sessionId, wrote.records);
217
+ }
218
+ return { skipped: null, fromSeq, anchor, lastArchived, priorChapters: state.chapters.length, records: wrote.records, warnings: [...repairNotes, ...hollowNotes, ...oversize.indivisible, ...wrote.warnings] };
219
+ }
220
+ //# sourceMappingURL=save-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-core.js","sourceRoot":"","sources":["../src/save-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ import { type IndexEntry } from './indexing.ts';
2
+ export interface SearchResult {
3
+ score: number;
4
+ date: string;
5
+ kind: 'chapter' | 'rule' | 'plan';
6
+ title: string;
7
+ path: string;
8
+ /** S5 stitch view: every member file behind a coherented entry. */
9
+ paths?: string[];
10
+ topics: string[];
11
+ }
12
+ export interface SearchOutcome {
13
+ results: SearchResult[];
14
+ /** Every match found (results may be a packed prefix of this). */
15
+ total: number;
16
+ shown: number;
17
+ budget: {
18
+ requested: number;
19
+ used: number;
20
+ remaining: number;
21
+ };
22
+ line: string;
23
+ }
24
+ /** Term-hit score: topic hits 2x, title 1x, summary 1x. Zero = no match, full stop. */
25
+ export declare function baseScore(entry: IndexEntry, terms: readonly string[], summary: string): number;
26
+ /**
27
+ * The full score: term hits plus a recency tie-break. Recency ONLY breaks
28
+ * ties between real matches — a fresh mtime must never rank an entry that
29
+ * matches no term (that would surface unrelated fresh files on any query).
30
+ */
31
+ export declare function scoreEntry(entry: IndexEntry, terms: readonly string[], now: number, summary: string): number;
32
+ /**
33
+ * CodeGraph symbol boost: when a search query contains tokens matching
34
+ * symbols stored in a chapter's frontmatter, add a bounded bonus. This
35
+ * breaks ties toward structurally-relevant chapters without ever ranking
36
+ * a non-matching entry above a matching one.
37
+ *
38
+ * @param bonusPerMatch — per-symbol bonus (default 0.2, capped at 1.0 total)
39
+ */
40
+ export declare function codegraphBoost(entry: IndexEntry, terms: readonly string[], bonusPerMatch?: number): number;
41
+ /** Load the corpus from a clone directory: chapters + rules, frontmatter-parsed. */
42
+ export declare function loadCorpus(cloneDir: string): {
43
+ entries: IndexEntry[];
44
+ summaries: Map<string, string>;
45
+ };
46
+ /**
47
+ * The search itself: score, sort (score desc, then path for determinism),
48
+ * format lines `score | date | kind | title | path (topics: …)`, and pack
49
+ * lines to the requested token budget. The agent sees `total` vs `shown` so
50
+ * it can re-request with a larger budget — no silent truncation.
51
+ */
52
+ export declare function searchKnowledge(cloneDir: string, query: string, maxTokens: number, opts?: {
53
+ now?: number;
54
+ projectKey?: string;
55
+ harnessId?: string;
56
+ rulesCoreBonus?: number;
57
+ }): SearchOutcome;
58
+ /**
59
+ * The ranking and packing shared by BOTH corpora — the pool mirror and the local
60
+ * store. Kept as one function on purpose: two scorers is how a "works in the pool,
61
+ * empty at home" divergence would be born, and the only difference between the two
62
+ * doors is where the entries came from.
63
+ */
64
+ export declare function rankEntries(entries: IndexEntry[], summaries: Map<string, string>, terms: string[], now: number, coreRuleIds: Set<string> | null, rulesCoreBonus: number, maxTokens: number): {
65
+ results: SearchResult[];
66
+ total: number;
67
+ shown: number;
68
+ budget: {
69
+ requested: number;
70
+ used: number;
71
+ remaining: number;
72
+ };
73
+ line: string;
74
+ };
75
+ /**
76
+ * The SAME corpus read straight off the workspace store, for the case that matters
77
+ * most and was previously unanswered: a project with NO pool linked. Every chapter,
78
+ * every `kind: plan` document and every rule already exists under the store root —
79
+ * indexed by nothing but their own frontmatter — and until now `chapters_search`
80
+ * returned an empty list there, so a session that asked "what did we plan about X"
81
+ * was told to go link a remote instead of being told the truth it already had.
82
+ *
83
+ * Paths come back relative to the workspace (`<storeRoot>/<session>/chapters/…`), so
84
+ * a result opens with the `read` tool with no translation, which is the whole point
85
+ * of a citation. Scope is stated by the caller, not assumed: this is this machine's
86
+ * store, not the shared pool, and the result note says so.
87
+ */
88
+ export declare function buildLocalCorpus(storeRoot: string): {
89
+ entries: IndexEntry[];
90
+ summaries: Map<string, string>;
91
+ };
92
+ /**
93
+ * Search THIS machine's store (no pool required). Returns the same shape as
94
+ * `searchKnowledge`, plus `empty` so the caller can tell "nothing matched" apart
95
+ * from "nothing to match against" — those two feel identical to a session and are
96
+ * completely different facts about the workspace.
97
+ */
98
+ export declare function searchLocalStore(storeRoot: string, query: string, maxTokens: number, opts?: {
99
+ rulesCoreBonus?: number;
100
+ }): {
101
+ results: SearchResult[];
102
+ total: number;
103
+ shown: number;
104
+ budget: {
105
+ requested: number;
106
+ used: number;
107
+ remaining: number;
108
+ };
109
+ line: string;
110
+ documents: number;
111
+ empty: boolean;
112
+ };
package/lib/search.js ADDED
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Knowledge search (knowledge-repo.md §8): a DETERMINISTIC scorer over the
3
+ * mirrored corpus (the clone is the corpus — it holds local + pulled files),
4
+ * packed to a token budget the AGENT chooses (it knows its window; we
5
+ * measure with the project's one estimator). No model in the loop, ever —
6
+ * reproducible, inspectable, and free.
7
+ */
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { entryFromChapter } from "./indexing.js";
11
+ function entryBody(text) {
12
+ const i = text.indexOf('\n---\n');
13
+ return i === -1 ? '' : text.slice(i + 5).trim();
14
+ }
15
+ import { estimateTokens } from "./render.js";
16
+ import { collectMirrorRules } from "./rules.js";
17
+ import { stitchFragments } from "./indexing.js";
18
+ const DAY = 24 * 60 * 60 * 1000;
19
+ const tokenize = (text) => text.toLowerCase().split(/[^a-z0-9/._-]+/).filter((t) => t.length >= 2 && t !== 'the' && t !== 'and');
20
+ const recencyBonus = (mtime, now) => {
21
+ if (mtime === undefined)
22
+ return 0;
23
+ const ageDays = (now - mtime) / DAY;
24
+ if (ageDays <= 30)
25
+ return 1;
26
+ if (ageDays <= 180)
27
+ return 0.5;
28
+ return 0;
29
+ };
30
+ /** Term-hit score: topic hits 2x, title 1x, summary 1x. Zero = no match, full stop. */
31
+ export function baseScore(entry, terms, summary) {
32
+ let score = 0;
33
+ for (const t of terms) {
34
+ if (entry.topics.some((topic) => topic.toLowerCase().includes(t)))
35
+ score += 2;
36
+ if (entry.category !== undefined && entry.category.toLowerCase().includes(t))
37
+ score += 1.5;
38
+ if (entry.title.toLowerCase().includes(t))
39
+ score += 1;
40
+ if (summary.toLowerCase().includes(t))
41
+ score += 1;
42
+ }
43
+ return score;
44
+ }
45
+ /**
46
+ * The full score: term hits plus a recency tie-break. Recency ONLY breaks
47
+ * ties between real matches — a fresh mtime must never rank an entry that
48
+ * matches no term (that would surface unrelated fresh files on any query).
49
+ */
50
+ export function scoreEntry(entry, terms, now, summary) {
51
+ const base = baseScore(entry, terms, summary);
52
+ return base === 0 ? 0 : base + recencyBonus(entry.mtime, now);
53
+ }
54
+ /**
55
+ * CodeGraph symbol boost: when a search query contains tokens matching
56
+ * symbols stored in a chapter's frontmatter, add a bounded bonus. This
57
+ * breaks ties toward structurally-relevant chapters without ever ranking
58
+ * a non-matching entry above a matching one.
59
+ *
60
+ * @param bonusPerMatch — per-symbol bonus (default 0.2, capped at 1.0 total)
61
+ */
62
+ export function codegraphBoost(entry, terms, bonusPerMatch = 0.2) {
63
+ if (entry.codegraphSymbols === undefined || entry.codegraphSymbols.length === 0)
64
+ return 0;
65
+ if (terms.length === 0)
66
+ return 0;
67
+ let matched = 0;
68
+ for (const t of terms) {
69
+ for (const sym of entry.codegraphSymbols) {
70
+ // Case-insensitive substring match: query term "auth" matches symbol "authenticate".
71
+ if (sym.toLowerCase().includes(t) || t.includes(sym.toLowerCase())) {
72
+ matched++;
73
+ break; // one match per term
74
+ }
75
+ }
76
+ }
77
+ return Math.min(matched * bonusPerMatch, 1.0);
78
+ }
79
+ /** Load the corpus from a clone directory: chapters + rules, frontmatter-parsed. */
80
+ export function loadCorpus(cloneDir) {
81
+ const entries = [];
82
+ const summaries = new Map();
83
+ // rel paths mirror the REPO layout (chapters/<key>/…, rules/<key>/…) so
84
+ // search results are directly readable paths and project scoping is a
85
+ // prefix match on the second path segment.
86
+ const collect = (top, kind) => {
87
+ const root = path.join(cloneDir, top);
88
+ if (!fs.existsSync(root))
89
+ return;
90
+ const walk = (dir, rel) => {
91
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
92
+ const p = path.join(dir, e.name);
93
+ if (e.isDirectory()) {
94
+ walk(p, rel === '' ? e.name : path.join(rel, e.name));
95
+ continue;
96
+ }
97
+ if (e.name.endsWith('.md')) {
98
+ const relPath = rel === '' ? e.name : path.join(rel, e.name);
99
+ const text = fs.readFileSync(p, 'utf8');
100
+ const entry = entryFromChapter(path.join(top, relPath), text, fs.statSync(p).mtimeMs);
101
+ // A plan document declares its own kind in frontmatter and lives in the
102
+ // chapters/ tree — the directory must not flatten it back to 'chapter',
103
+ // or "search the plans" would be impossible (plans-carriage § 11).
104
+ entries.push({ ...entry, kind: entry.kind === 'plan' ? 'plan' : kind });
105
+ const fm = /^---[\s\S]*?summary:\s*(.*)$/m.exec(text);
106
+ if (fm !== null)
107
+ summaries.set(entry.path, fm[1].trim().replace(/^"|"$/g, ''));
108
+ // P3: rules carry no summary field — their BODY is the scannable
109
+ // surface; score terms against it like a chapter's summary
110
+ else if (entry.kind === 'rule')
111
+ summaries.set(entry.path, entryBody(text).slice(0, 500));
112
+ }
113
+ }
114
+ };
115
+ walk(root, '');
116
+ };
117
+ collect('chapters', 'chapter');
118
+ collect('rules', 'rule');
119
+ return { entries: stitchFragments(entries), summaries }; // S5: search sees stitched views too
120
+ }
121
+ /**
122
+ * The search itself: score, sort (score desc, then path for determinism),
123
+ * format lines `score | date | kind | title | path (topics: …)`, and pack
124
+ * lines to the requested token budget. The agent sees `total` vs `shown` so
125
+ * it can re-request with a larger budget — no silent truncation.
126
+ */
127
+ export function searchKnowledge(cloneDir, query, maxTokens, opts = {}) {
128
+ const now = opts.now ?? Date.now();
129
+ const terms = tokenize(query);
130
+ // P3 §8: rules that THIS machine approved get a small, explicit bonus —
131
+ // computed here (per-machine), never baked into the shared index shards.
132
+ let coreRuleIds = null;
133
+ if (opts.harnessId !== undefined && opts.rulesCoreBonus !== undefined && opts.rulesCoreBonus > 0) {
134
+ try {
135
+ coreRuleIds = new Set(collectMirrorRules(cloneDir, opts.projectKey ?? '', opts.harnessId)
136
+ .filter((r) => r.status === 'core').map((r) => r.relPath));
137
+ }
138
+ catch {
139
+ coreRuleIds = null;
140
+ }
141
+ }
142
+ if (terms.length === 0) {
143
+ return { results: [], total: 0, shown: 0, budget: { requested: maxTokens, used: 0, remaining: maxTokens }, line: '' };
144
+ }
145
+ const { entries, summaries } = loadCorpus(cloneDir);
146
+ const scoped = opts.projectKey !== undefined
147
+ ? entries.filter((e) => e.path.startsWith(`chapters/${opts.projectKey}`) || e.path.startsWith(`rules/${opts.projectKey}`))
148
+ : entries;
149
+ return rankEntries(scoped, summaries, terms, now, coreRuleIds, opts.rulesCoreBonus ?? 0, maxTokens);
150
+ }
151
+ /**
152
+ * The ranking and packing shared by BOTH corpora — the pool mirror and the local
153
+ * store. Kept as one function on purpose: two scorers is how a "works in the pool,
154
+ * empty at home" divergence would be born, and the only difference between the two
155
+ * doors is where the entries came from.
156
+ */
157
+ export function rankEntries(entries, summaries, terms, now, coreRuleIds, rulesCoreBonus, maxTokens) {
158
+ const scored = entries
159
+ .map((e) => ({
160
+ e,
161
+ score: scoreEntry(e, terms, now, summaries.get(e.path) ?? '')
162
+ + (coreRuleIds !== null && e.kind === 'rule' && coreRuleIds.has(e.path) ? rulesCoreBonus : 0)
163
+ + codegraphBoost(e, terms),
164
+ }))
165
+ .filter((x) => x.score > 0)
166
+ .sort((a, b) => b.score - a.score || (a.e.path < b.e.path ? -1 : 1));
167
+ const results = scored.map((x) => ({
168
+ score: Number(x.score.toFixed(2)),
169
+ date: x.e.mtime !== undefined ? new Date(x.e.mtime).toISOString().slice(0, 10) : '----',
170
+ kind: x.e.kind,
171
+ title: x.e.title,
172
+ path: x.e.path,
173
+ ...(x.e.paths !== undefined ? { paths: x.e.paths } : {}),
174
+ topics: x.e.topics,
175
+ }));
176
+ const lines = [];
177
+ let used = 0;
178
+ for (const r of results) {
179
+ const line = `${r.score.toFixed(2)} | ${r.date} | ${r.kind} | ${r.title} | ${r.path}${r.paths !== undefined && r.paths.length > 1 ? ` [+${r.paths.length - 1} stitched part(s)]` : ''}${r.topics.length > 0 ? ` (topics: ${r.topics.join(', ')})` : ''}`;
180
+ const cost = estimateTokens(line);
181
+ if (lines.length > 0 && used + cost > maxTokens)
182
+ break;
183
+ lines.push(line);
184
+ used += cost;
185
+ }
186
+ return {
187
+ results: results.slice(0, lines.length),
188
+ total: results.length,
189
+ shown: lines.length,
190
+ budget: { requested: maxTokens, used, remaining: Math.max(0, maxTokens - used) },
191
+ line: lines.join('\n'),
192
+ };
193
+ }
194
+ /**
195
+ * The SAME corpus read straight off the workspace store, for the case that matters
196
+ * most and was previously unanswered: a project with NO pool linked. Every chapter,
197
+ * every `kind: plan` document and every rule already exists under the store root —
198
+ * indexed by nothing but their own frontmatter — and until now `chapters_search`
199
+ * returned an empty list there, so a session that asked "what did we plan about X"
200
+ * was told to go link a remote instead of being told the truth it already had.
201
+ *
202
+ * Paths come back relative to the workspace (`<storeRoot>/<session>/chapters/…`), so
203
+ * a result opens with the `read` tool with no translation, which is the whole point
204
+ * of a citation. Scope is stated by the caller, not assumed: this is this machine's
205
+ * store, not the shared pool, and the result note says so.
206
+ */
207
+ export function buildLocalCorpus(storeRoot) {
208
+ const entries = [];
209
+ const summaries = new Map();
210
+ if (!fs.existsSync(storeRoot))
211
+ return { entries, summaries };
212
+ const addFile = (abs, rel) => {
213
+ let text;
214
+ try {
215
+ text = fs.readFileSync(abs, 'utf8');
216
+ }
217
+ catch {
218
+ return;
219
+ }
220
+ const entry = entryFromChapter(rel, text, fs.statSync(abs).mtimeMs);
221
+ entries.push(entry);
222
+ const fm = /^---[\s\S]*?summary:\s*(.*)$/m.exec(text);
223
+ if (fm !== null)
224
+ summaries.set(entry.path, fm[1].trim().replace(/^"|"$/g, ''));
225
+ else if (entry.kind !== 'chapter')
226
+ summaries.set(entry.path, entryBody(text).slice(0, 500));
227
+ };
228
+ const walk = (dir, rel, leaf) => {
229
+ let items;
230
+ try {
231
+ items = fs.readdirSync(dir, { withFileTypes: true });
232
+ }
233
+ catch {
234
+ return;
235
+ }
236
+ for (const e of items) {
237
+ const abs = path.join(dir, e.name);
238
+ const r = rel === '' ? e.name : `${rel}/${e.name}`;
239
+ if (e.isDirectory()) {
240
+ walk(abs, r, leaf);
241
+ continue;
242
+ }
243
+ if (e.name.endsWith('.md'))
244
+ addFile(abs, path.posix.join(leaf, r));
245
+ }
246
+ };
247
+ for (const top of fs.readdirSync(storeRoot, { withFileTypes: true })) {
248
+ if (!top.isDirectory())
249
+ continue;
250
+ if (top.name === 'artifacts')
251
+ continue; // blobs are queried by chapters_artifact, not indexed twice
252
+ const abs = path.join(storeRoot, top.name);
253
+ if (top.name === 'rules') {
254
+ walk(abs, '', 'rules');
255
+ continue;
256
+ }
257
+ // a session tree: chapters/ holds transcript chapters AND plan documents
258
+ const chapters = path.join(abs, 'chapters');
259
+ if (fs.existsSync(chapters))
260
+ walk(chapters, '', path.posix.join(top.name, 'chapters'));
261
+ const rules = path.join(abs, 'rules');
262
+ if (fs.existsSync(rules))
263
+ walk(rules, '', path.posix.join(top.name, 'rules'));
264
+ }
265
+ return { entries, summaries };
266
+ }
267
+ /**
268
+ * Search THIS machine's store (no pool required). Returns the same shape as
269
+ * `searchKnowledge`, plus `empty` so the caller can tell "nothing matched" apart
270
+ * from "nothing to match against" — those two feel identical to a session and are
271
+ * completely different facts about the workspace.
272
+ */
273
+ export function searchLocalStore(storeRoot, query, maxTokens, opts = {}) {
274
+ const { entries, summaries } = buildLocalCorpus(storeRoot);
275
+ const terms = tokenize(query);
276
+ if (terms.length === 0) {
277
+ return { results: [], total: 0, shown: 0, budget: { requested: maxTokens, used: 0, remaining: maxTokens }, line: '', documents: entries.length, empty: entries.length === 0 };
278
+ }
279
+ const ranked = rankEntries(entries, summaries, terms, Date.now(), null, opts.rulesCoreBonus ?? 0, maxTokens);
280
+ return { ...ranked, documents: entries.length, empty: entries.length === 0 };
281
+ }
282
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}