@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
package/lib/types.d.ts ADDED
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Pure data types for the chapter archive. No cordis, no DSH imports — this module is what makes the
3
+ * archive unit-testable without booting a harness, which is the whole testing strategy in
4
+ * docs/development.md § Test Layers.
5
+ *
6
+ * Event field names here were taken from real session logs read during Phase 0 (see
7
+ * spikes/probe/FINDINGS.md), not guessed: `user/message` carries `data.{id,role,source,content}` and
8
+ * `tool/call` carries `data.{callId,name,arguments}`. Where the shape is uncertain the renderer degrades
9
+ * rather than throws, because a dropped detail in an archive is worse than an ugly one.
10
+ */
11
+ export type ContentBlock = {
12
+ type: 'text';
13
+ text: string;
14
+ } | {
15
+ type: 'image';
16
+ mimeType?: string;
17
+ data?: string;
18
+ path?: string;
19
+ } | {
20
+ type: string;
21
+ [key: string]: unknown;
22
+ };
23
+ /**
24
+ * One durable session event, as an archive input.
25
+ *
26
+ * `data` is **required**, and that is load-bearing (#58). It used to be optional, which is how
27
+ * `sessionQuery.listEvents` output — a `SessionEventRecord` carrying `seq`/`type`/`time`/`surface`
28
+ * and NO payload — type-checked as an event list. The renderer's defensive `ev.data ?? {}` then
29
+ * turned every row into a structurally valid, EMPTY chapter: tool names `unknown`, args `{}`,
30
+ * results the `sha256("")` blob at 0 B, all messages unrendered. Read the host's `readSession` or
31
+ * a live `snapshotEvents()` instead — `docs/contract.md` § Durable reads, pinned by
32
+ * `tests/unit/host-durable-read.test.ts`.
33
+ */
34
+ export interface SessionEventLike {
35
+ type: string;
36
+ seq: number;
37
+ time?: number;
38
+ surfaceOp?: string;
39
+ data: Record<string, unknown>;
40
+ }
41
+ /** One chapter = a contiguous, closed range of durable event seqs. Integers, never text anchors. */
42
+ export interface ChapterRange {
43
+ title: string;
44
+ summary: string;
45
+ startSeq: number;
46
+ endSeq: number;
47
+ }
48
+ /** The model's sparse exceptions about tool results. Absence means "use the default rule". */
49
+ export interface ToolResultOverride {
50
+ seq: number;
51
+ inline: boolean;
52
+ }
53
+ /**
54
+ * A session plan's verdict, as the log states it (`src/plans.ts`). `failed` is the
55
+ * family where the host threw without a human verdict (no review channel, service
56
+ * reloaded mid-review, the call ran outside plan mode, the markdown had no heading)
57
+ * — labelling those `rejected` would invent a decision nobody made.
58
+ */
59
+ export type PlanStatus = 'approved' | 'rejected' | 'dismissed' | 'pending' | 'superseded' | 'failed';
60
+ /** One plan's machine facts, carried in the chapter record and the registry row. */
61
+ export interface PlanFact {
62
+ seq: number;
63
+ status: PlanStatus;
64
+ title: string;
65
+ sha256: string;
66
+ artifactPath: string;
67
+ bytes: number;
68
+ estTokens: number;
69
+ resultSeq: number | null;
70
+ }
71
+ /**
72
+ * The notice's flat plan row (archived facts and live, unarchived docs unify here).
73
+ * Rows travel in CAUSAL order — chapters root-first, plans within a chapter by seq,
74
+ * then the caller's unarchived tail. Every session numbers its own events from zero,
75
+ * so a `seq` in one session is NOT comparable with a `seq` in another: the builder's
76
+ * order is the chronology, and nothing downstream may re-sort by `seq`
77
+ * (docs/plans-carriage.md § 4).
78
+ */
79
+ export interface NoticePlan {
80
+ title: string;
81
+ status: PlanStatus;
82
+ seq: number;
83
+ chapterNumber?: number;
84
+ chapterPath?: string;
85
+ artifactPath?: string;
86
+ /** The plan's own `kind: plan` document, when one was written. */
87
+ docPath?: string;
88
+ sha256?: string;
89
+ estTokens?: number;
90
+ }
91
+ export interface RenderConfig {
92
+ /** Below this estimated token count a tool result stays inline without needing a model override. */
93
+ toolResultDeferFloorTokens: number;
94
+ /** Chapter sizes past this are flagged for a split at the next boundary. Never truncated. */
95
+ chapterTokenTarget: number;
96
+ /**
97
+ * Verbatim plan characters printed inline under a plan's reference. The full text is
98
+ * ALWAYS artifact-backed, so this is a display budget, never a data decision.
99
+ * 0 = pointer only (the artifact line and outline still print).
100
+ */
101
+ planInlineChars?: number;
102
+ /**
103
+ * Above this estimated token count a tool-call ARGUMENT is artifact-backed and the
104
+ * inline text is a bounded head. 0 = off: every argument keeps the plain head rule,
105
+ * so a deployment opts in deliberately (it changes chapter bytes, hence tapes).
106
+ */
107
+ callArgArtifactTokens?: number;
108
+ /**
109
+ * Credential redaction patterns applied at the render chokepoint (record §9).
110
+ * Absent → the built-in conservative set. Extensible per deployment.
111
+ */
112
+ redactions?: readonly import('./redact.ts').RedactPattern[];
113
+ /**
114
+ * Lineage stamp (issue #47): the id of the PARENT session when the authoring
115
+ * session is a subagent child. Copied verbatim from the durable
116
+ * `session.header.parentSession` the HOST writes (`childSessionMeta`), never
117
+ * inferred. Emitted ONLY when a non-empty string — a session without a parent
118
+ * renders byte-identically to the pre-feature shape, which is what keeps every
119
+ * existing chapter file and every model tape un-re-recorded (same discipline
120
+ * as the plans block, verify.md P8).
121
+ */
122
+ subagentOf?: string;
123
+ }
124
+ /**
125
+ * Read the lineage the kernel stamped into a session header, or undefined.
126
+ * The ONE sanctioned reader of `parentSession` for chapter rendering — every
127
+ * archive door (save, auto-save, compaction finalize) passes its output into
128
+ * `RenderConfig.subagentOf`, so the field is stamped the same way everywhere.
129
+ */
130
+ export declare function lineageOf(header: {
131
+ parentSession?: string;
132
+ } | undefined): string | undefined;
133
+ export interface ArtifactRef {
134
+ /** Content hash; the artifact path is derived from it, so identical results dedupe across a subtree. */
135
+ sha256: string;
136
+ /** Relative path from the store root, as it will be printed in the chapter and read back. */
137
+ path: string;
138
+ bytes: number;
139
+ /** The exact bytes to write. Written whether or not the body was also inlined. */
140
+ content: string;
141
+ /** True when the chapter body also carries the text, i.e. the model asked to keep it visible. */
142
+ inlined: boolean;
143
+ toolName: string;
144
+ sourceSeq: number;
145
+ }
146
+ /**
147
+ * A plan DOCUMENT the writer emits beside its chapter: the whole plan as its own
148
+ * indexed file (`kind: plan`), so plans are queryable as plans — by topic, by
149
+ * status, by how they evolved — instead of only as bytes inside a transcript.
150
+ * It lives in `chapters/` on purpose: the pool transport, the mirror rehydrate and
151
+ * the corpus index then pick it up with zero special casing.
152
+ */
153
+ export interface PlanDocFile {
154
+ seq: number;
155
+ title: string;
156
+ status: PlanStatus;
157
+ body: string;
158
+ sha256: string;
159
+ /** The transcript chapter that cites it, once the writer knows its path. */
160
+ chapterPath?: string | undefined;
161
+ /** The document this one supersedes (same title, earlier submission). */
162
+ supersedes?: string | undefined;
163
+ topics: string[];
164
+ estTokens: number;
165
+ }
166
+ export interface RenderedChapter {
167
+ range: ChapterRange;
168
+ /** Index topics (deterministic floor: paths + top terms). P2 enrichment may relabel. */
169
+ topics: string[];
170
+ /** Full Markdown file body, YAML frontmatter included. */
171
+ markdown: string;
172
+ artifacts: ArtifactRef[];
173
+ stats: {
174
+ /** chars/4 estimate until tokenMeter is wired at the host boundary; labelled as an estimate. */
175
+ estimatedTokens: number;
176
+ estimatedBytes: number;
177
+ events: number;
178
+ /** user+assistant MESSAGE events in the chapter (record §7.3: counts, not tokens). */
179
+ messages: number;
180
+ toolCalls: number;
181
+ toolResultsInlined: number;
182
+ toolResultsDeferred: number;
183
+ /** True when the chapter exceeds chapterTokenTarget — a split signal, never a truncation licence. */
184
+ overTarget: boolean;
185
+ /** Events in the range that produced no rendered output, so a silent hole is visible. */
186
+ unrenderedSeqs: number[];
187
+ /** Plans submitted inside this range, with the artifact that carries their full
188
+ * text. Absent (not an empty list) on chapters rendered before this feature —
189
+ * the same "never a lying zero" rule `messages` follows. */
190
+ plans?: PlanFact[] | undefined;
191
+ /** Folded `plan/mode` state at the range's end; 'unknown' when the log never said. */
192
+ planMode?: 'active' | 'inactive' | 'unknown' | undefined;
193
+ /** Tool-call arguments artifact-backed by the `callArgArtifactTokens` rule. */
194
+ invocationArtifacts?: number | undefined;
195
+ /** Files to emit beside this chapter (one per plan in range). */
196
+ planDocs?: PlanDocFile[] | undefined;
197
+ };
198
+ }
199
+ /** A candidate tool result, enumerated by the plugin so the model never guesses at sizes. */
200
+ export interface ToolResultCandidate {
201
+ seq: number;
202
+ toolName: string;
203
+ bytes: number;
204
+ estimatedTokens: number;
205
+ excerpt: string;
206
+ }
207
+ export declare class RangeError extends Error {
208
+ readonly code: 'overlapping' | 'gap' | 'descending' | 'beyond-ceiling' | 'empty';
209
+ constructor(code: RangeError['code'], message: string);
210
+ }
package/lib/types.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Pure data types for the chapter archive. No cordis, no DSH imports — this module is what makes the
3
+ * archive unit-testable without booting a harness, which is the whole testing strategy in
4
+ * docs/development.md § Test Layers.
5
+ *
6
+ * Event field names here were taken from real session logs read during Phase 0 (see
7
+ * spikes/probe/FINDINGS.md), not guessed: `user/message` carries `data.{id,role,source,content}` and
8
+ * `tool/call` carries `data.{callId,name,arguments}`. Where the shape is uncertain the renderer degrades
9
+ * rather than throws, because a dropped detail in an archive is worse than an ugly one.
10
+ */
11
+ /**
12
+ * Read the lineage the kernel stamped into a session header, or undefined.
13
+ * The ONE sanctioned reader of `parentSession` for chapter rendering — every
14
+ * archive door (save, auto-save, compaction finalize) passes its output into
15
+ * `RenderConfig.subagentOf`, so the field is stamped the same way everywhere.
16
+ */
17
+ export function lineageOf(header) {
18
+ if (header === undefined)
19
+ return undefined;
20
+ const p = header.parentSession;
21
+ return typeof p === 'string' && p !== '' ? p : undefined;
22
+ }
23
+ export class RangeError extends Error {
24
+ code;
25
+ constructor(code, message) {
26
+ super(message);
27
+ this.code = code;
28
+ this.name = 'RangeError';
29
+ }
30
+ }
31
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmHH;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,MAA8C;IACtE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC1C,MAAM,CAAC,GAAG,MAAM,CAAC,aAAa,CAAA;IAC9B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC1D,CAAC;AAgFD,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAmE;IAChF,YAAY,IAAwB,EAAE,OAAe;QACnD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAA;IAC1B,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The plugin's own version, stamped into chapter provenance (#61).
3
+ *
4
+ * This audit had to *infer* which build wrote which registry row from file mtimes, because `generated:`
5
+ * recorded a model name and a timestamp and nothing else. Attribution is a fact the writer knows and the
6
+ * reader cannot recover later, so it belongs in the bytes. A row in tests asserts this literal equals
7
+ * `package.json`'s version — the one place a hand-mirrored constant must never be allowed to drift.
8
+ */
9
+ export declare const PLUGIN_VERSION = "0.2.21";
package/lib/version.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The plugin's own version, stamped into chapter provenance (#61).
3
+ *
4
+ * This audit had to *infer* which build wrote which registry row from file mtimes, because `generated:`
5
+ * recorded a model name and a timestamp and nothing else. Attribution is a fact the writer knows and the
6
+ * reader cannot recover later, so it belongs in the bytes. A row in tests asserts this literal equals
7
+ * `package.json`'s version — the one place a hand-mirrored constant must never be allowed to drift.
8
+ */
9
+ export const PLUGIN_VERSION = '0.2.21';
10
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAA"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * P2 S4 — the emergent vocabulary canonicalizer (record §6.3). Pure functions
3
+ * over topic lists; the sync pass feeds it chapter topics and applies (or,
4
+ * in shadow mode, merely reports) the merge candidates.
5
+ *
6
+ * No seed lists, no hand-editing expectation: plugin-owned curation entries,
7
+ * every one carrying its signal + counts, written to
8
+ * `edits/<harnessId>/curation.jsonl` — git-visible, revertible, and already
9
+ * consumed by the index build (P1 plumbing).
10
+ */
11
+ export interface VocabOpts {
12
+ coMin: number;
13
+ overlapMin: number;
14
+ }
15
+ export interface VocabCandidate {
16
+ from: string;
17
+ to: string;
18
+ cooccur: number;
19
+ overlap: number;
20
+ reason: 'co-occurrence' | 'alias-pattern' | 'token-overlap';
21
+ }
22
+ /**
23
+ * Candidates over a corpus of per-chapter topic lists. Canonical direction:
24
+ * the MORE FREQUENT label survives (`to`); alphabetical tie-break. Pairs
25
+ * already aliased (either direction) are skipped by the caller — this module
26
+ * only proposes, applying and deduping against existing entries is the pass.
27
+ */
28
+ export declare function analyzeTopics(chapterTopics: string[][], opts: VocabOpts): {
29
+ candidates: VocabCandidate[];
30
+ frequency: Map<string, number>;
31
+ };
32
+ /**
33
+ * The curation lines to append (topic-alias facts) given the aliases already
34
+ * known. A 'from' already aliased (anywhere in the chain) is skipped, and
35
+ * chains are resolved to their final target so we never write a->b when b
36
+ * already maps to c (write a->c instead — deterministic, order-independent).
37
+ */
38
+ export declare function planAppends(candidates: VocabCandidate[], existing: Map<string, string>, at: string): {
39
+ lines: string[];
40
+ plan: VocabCandidate[];
41
+ };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * P2 S4 — the emergent vocabulary canonicalizer (record §6.3). Pure functions
3
+ * over topic lists; the sync pass feeds it chapter topics and applies (or,
4
+ * in shadow mode, merely reports) the merge candidates.
5
+ *
6
+ * No seed lists, no hand-editing expectation: plugin-owned curation entries,
7
+ * every one carrying its signal + counts, written to
8
+ * `edits/<harnessId>/curation.jsonl` — git-visible, revertible, and already
9
+ * consumed by the index build (P1 plumbing).
10
+ */
11
+ const tokenize = (t) => new Set(t.toLowerCase().split(/[^a-z0-9]+/).filter((s) => s.length > 0));
12
+ const stem = (tok) => (tok.length > 3 && tok.endsWith('s') ? tok.slice(0, -1) : tok);
13
+ const jaccard = (a, b) => {
14
+ if (a.size === 0 || b.size === 0)
15
+ return 0;
16
+ let inter = 0;
17
+ for (const x of a)
18
+ if (b.has(x))
19
+ inter += 1;
20
+ return inter / (a.size + b.size - inter);
21
+ };
22
+ /** one token is a prefix of the other, or equal after plural stemming */
23
+ const aliasPattern = (a, b) => {
24
+ const ta = [...tokenize(a)], tb = [...tokenize(b)];
25
+ if (ta.length === 0 || tb.length === 0)
26
+ return false;
27
+ const pa = ta[0], pb = tb[0];
28
+ if (ta.length === 1 && tb.length === 1) {
29
+ if (pa !== pb && (pa.startsWith(pb) || pb.startsWith(pa)))
30
+ return true;
31
+ if (stem(pa) === stem(pb) && pa !== pb)
32
+ return true;
33
+ }
34
+ return false;
35
+ };
36
+ /**
37
+ * Candidates over a corpus of per-chapter topic lists. Canonical direction:
38
+ * the MORE FREQUENT label survives (`to`); alphabetical tie-break. Pairs
39
+ * already aliased (either direction) are skipped by the caller — this module
40
+ * only proposes, applying and deduping against existing entries is the pass.
41
+ */
42
+ export function analyzeTopics(chapterTopics, opts) {
43
+ const frequency = new Map();
44
+ const cooc = new Map();
45
+ for (const topics of chapterTopics) {
46
+ const uniq = [...new Set(topics.map((t) => t.toLowerCase().trim()).filter((t) => t.length > 0))];
47
+ for (const t of uniq)
48
+ frequency.set(t, (frequency.get(t) ?? 0) + 1);
49
+ for (let i = 0; i < uniq.length; i++) {
50
+ for (let k = i + 1; k < uniq.length; k++) {
51
+ const key = [uniq[i], uniq[k]].sort().join('\u0000');
52
+ cooc.set(key, (cooc.get(key) ?? 0) + 1);
53
+ }
54
+ }
55
+ }
56
+ const labels = [...frequency.keys()].sort();
57
+ const candidates = [];
58
+ for (let i = 0; i < labels.length; i++) {
59
+ for (let k = i + 1; k < labels.length; k++) {
60
+ const a = labels[i], b = labels[k];
61
+ const overlap = jaccard(tokenize(a), tokenize(b));
62
+ const alias = aliasPattern(a, b);
63
+ const co = cooc.get([a, b].sort().join('\u0000')) ?? 0;
64
+ const byFreq = (frequency.get(b) ?? 0) - (frequency.get(a) ?? 0);
65
+ const from = byFreq < 0 ? b : a;
66
+ const to = byFreq < 0 ? a : b;
67
+ let reason = null;
68
+ if (alias)
69
+ reason = 'alias-pattern';
70
+ else if (co >= opts.coMin)
71
+ reason = 'co-occurrence';
72
+ else if (overlap >= opts.overlapMin)
73
+ reason = 'token-overlap';
74
+ if (reason === null)
75
+ continue;
76
+ candidates.push({ from, to, cooccur: co, overlap: Number(overlap.toFixed(3)), reason });
77
+ }
78
+ }
79
+ candidates.sort((x, y) => x.from < y.from ? -1 : x.from > y.from ? 1 : 0);
80
+ return { candidates, frequency };
81
+ }
82
+ /**
83
+ * The curation lines to append (topic-alias facts) given the aliases already
84
+ * known. A 'from' already aliased (anywhere in the chain) is skipped, and
85
+ * chains are resolved to their final target so we never write a->b when b
86
+ * already maps to c (write a->c instead — deterministic, order-independent).
87
+ */
88
+ export function planAppends(candidates, existing, at) {
89
+ const resolve = (label, depth = 0) => {
90
+ if (depth > 10)
91
+ return label;
92
+ const next = existing.get(label);
93
+ return next === undefined || next === label ? label : resolve(next, depth + 1);
94
+ };
95
+ const plan = [];
96
+ const seen = new Map(existing);
97
+ const lines = [];
98
+ for (const c of candidates) {
99
+ // a RAW 'from' that already aliases is stale by definition (skip); the
100
+ // target folds forward through known chains so we never write into the
101
+ // middle of one (a->b when b->c exists becomes a->c)
102
+ if (existing.has(c.from) || seen.has(c.from))
103
+ continue;
104
+ const to = resolve(c.to);
105
+ const from = c.from;
106
+ if (from === to)
107
+ continue;
108
+ seen.set(from, to);
109
+ const entry = { ...c, from, to };
110
+ plan.push(entry);
111
+ // topic-alias matches the index layer's CurationFact; the reason/count
112
+ // payload is carried alongside (parseCuration ignores unknown keys) so
113
+ // every merge is self-documenting in git
114
+ lines.push(JSON.stringify({ type: 'topic-alias', from, to, at, reason: `${entry.reason}: cooccur=${entry.cooccur} overlap=${entry.overlap}` }));
115
+ }
116
+ return { lines, plan };
117
+ }
118
+ //# sourceMappingURL=vocabulary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vocabulary.js","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The one formatter that turns a door's warnings into text a human reads (#61).
3
+ *
4
+ * The field failure was delivery, not detection: `writeArchive` produced 86 warnings across six SAIP
5
+ * saves — naming the hollow chapter, the oversize chapters and an unarchived 0–4082 hole — and every door
6
+ * reduced them to `(86 warning(s))`. A count is not a message. So all doors call THIS, which shows the
7
+ * first `cap` texts and then says how many more there are, because "the withheld count is mandatory"
8
+ * is already the rule for rules selection (record §7.4) and for search results.
9
+ */
10
+ export declare function formatWarnings(warnings: readonly string[], cap: number): string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The one formatter that turns a door's warnings into text a human reads (#61).
3
+ *
4
+ * The field failure was delivery, not detection: `writeArchive` produced 86 warnings across six SAIP
5
+ * saves — naming the hollow chapter, the oversize chapters and an unarchived 0–4082 hole — and every door
6
+ * reduced them to `(86 warning(s))`. A count is not a message. So all doors call THIS, which shows the
7
+ * first `cap` texts and then says how many more there are, because "the withheld count is mandatory"
8
+ * is already the rule for rules selection (record §7.4) and for search results.
9
+ */
10
+ export function formatWarnings(warnings, cap) {
11
+ if (warnings.length === 0)
12
+ return '';
13
+ const shown = Math.max(1, Math.floor(cap));
14
+ const head = warnings.slice(0, shown);
15
+ const rest = warnings.length - head.length;
16
+ return head.join('; ') + (rest > 0 ? `; …and ${rest} more` : '');
17
+ }
18
+ //# sourceMappingURL=warnings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnings.js","sourceRoot":"","sources":["../src/warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,QAA2B,EAAE,GAAW;IACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AAClE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,154 @@
1
1
  {
2
2
  "name": "@fractalsynapse/dsh-chapters",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.21",
4
+ "description": "dsh plugin: verbatim chapter archive + zero-token index for small-context models",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "main": "lib/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ },
13
+ "./cordis.patch.yml": "./cordis.patch.yml",
14
+ "./package.json": "./package.json",
15
+ "./engine": "./lib/engine.js",
16
+ "./preset": "./lib/preset.js",
17
+ "./tools": "./lib/tools.js",
18
+ "./store": "./lib/store.js",
19
+ "./registry": "./lib/registry.js",
20
+ "./client": "./lib/client.js"
21
+ },
22
+ "files": [
23
+ "lib",
24
+ "cordis.patch.yml",
25
+ "docs",
26
+ "README.md"
27
+ ],
28
+ "dsh": {
29
+ "bundle": {
30
+ "patch": "./cordis.patch.yml"
31
+ },
32
+ "client": {
33
+ "platform": "web",
34
+ "immediately": false,
35
+ "inject": [
36
+ "@deepseek-ai/dsh-api-remotes",
37
+ "@deepseek-ai/dsh-client-ui-commands"
38
+ ]
39
+ }
40
+ },
41
+ "scripts": {
42
+ "test": "node --test tests/unit/*.test.ts tests/integration/*.test.ts",
43
+ "typecheck": "tsc -p tsconfig.json --noEmit",
44
+ "typecheck:client": "tsc -p tsconfig.client.strict.json",
45
+ "typecheck:e2e": "tsc -p tsconfig.e2e.json --noEmit",
46
+ "build": "tsc -p tsconfig.json && tsdown -c tsdown.client.config.ts --config-loader tsx",
47
+ "corpus:stamp": "node scripts/build-stamp.mjs stamp",
48
+ "corpus:check": "node scripts/build-stamp.mjs check",
49
+ "build:client": "tsdown -c tsdown.client.config.ts",
50
+ "test:unit": "node --test tests/unit/*.test.ts",
51
+ "e2e:one": "bash scripts/e2e-one.sh",
52
+ "e2e:harness:live": "E2E_PROVIDER=harness MODE=live bash scripts/e2e-one.sh",
53
+ "corpus:heal": "E2E_PROVIDER=harness MODE=heal bash scripts/e2e-one.sh",
54
+ "corpus:record": "E2E_PROVIDER=harness MODE=record bash scripts/e2e-one.sh",
55
+ "test:e2e": "PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=suite && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=heavy && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=arrival && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=enrich && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=fanout && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=rules && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=fork && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=plans && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=prompt && PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npx playwright test -c tests/e2e/playwright.config.ts --project=prompt-off",
56
+ "test:all": "npm test && npm run test:e2e",
57
+ "test:integration": "node --test tests/integration/*.test.ts",
58
+ "test:e2e:record": "E2E_MODEL=record npm run test:e2e",
59
+ "test:e2e:replay": "E2E_MODEL=replay bash scripts/chain-replay.sh",
60
+ "coverage:e2e": "E2E_COVERAGE=1 PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright npm run test:e2e:replay && node scripts/e2e-coverage.mjs",
61
+ "coverage": "node --test --experimental-test-coverage tests/unit/*.test.ts tests/integration/*.test.ts",
62
+ "coverage:ci": "c8 --check-coverage --statements 85 --branches 85 --functions 85 --lines 85 --reporter=text-summary --reporter=json-summary --report-dir var/coverage node --test tests/unit/*.test.ts tests/integration/*.test.ts",
63
+ "test:e2e:cache": "E2E_PORT=41739 PLAYWRIGHT_BROWSERS_PATH=$PWD/var/ms-playwright playwright test -c tests/e2e/playwright.config.ts --project=cache",
64
+ "bench": "node benchmarks/run-bench.mjs",
65
+ "bench:nightly": "node benchmarks/run-bench.mjs --every 60",
66
+ "docs:dev": "npm --prefix site run dev",
67
+ "docs:build": "npm --prefix site run build",
68
+ "mining:probe": "node scripts/mining-probe.mjs",
69
+ "llm:where": "node -e \"import('./scripts/llm.mjs').then(async m=>{const t=await m.resolve({});console.log(t.base,t.model,t.regime,'| credential:',m.apiKeySource(),'| key found:',m.apiKey()!==null)})\"",
70
+ "prepublishOnly": "npm run build"
71
+ },
72
+ "peerDependencies": {
73
+ "@deepseek-ai/cordis": "^4.0.0",
74
+ "@deepseek-ai/cordis-plugin-loader": "*",
75
+ "@deepseek-ai/dsh-compaction": "*",
76
+ "@deepseek-ai/dsh-compaction-basic": "*",
77
+ "@deepseek-ai/dsh-home-paths": "*",
78
+ "@deepseek-ai/dsh-storage-domain": "*",
79
+ "@deepseek-ai/dsh-tools": "*",
80
+ "@deepseek-ai/schemastery": "*"
81
+ },
82
+ "peerDependenciesMeta": {
83
+ "@deepseek-ai/cordis": {
84
+ "optional": true
85
+ },
86
+ "@deepseek-ai/dsh-compaction": {
87
+ "optional": true
88
+ },
89
+ "@deepseek-ai/dsh-tools": {
90
+ "optional": true
91
+ },
92
+ "@deepseek-ai/schemastery": {
93
+ "optional": true
94
+ },
95
+ "@deepseek-ai/dsh-storage-domain": {
96
+ "optional": true
97
+ },
98
+ "@deepseek-ai/dsh-compaction-basic": {
99
+ "optional": true
100
+ },
101
+ "@deepseek-ai/dsh-home-paths": {
102
+ "optional": true
103
+ },
104
+ "@deepseek-ai/cordis-plugin-loader": {
105
+ "optional": true
106
+ }
107
+ },
108
+ "devDependencies": {
109
+ "@deepseek-ai/cordis": "^4.0.2",
110
+ "@deepseek-ai/cordis-plugin-loader": "^1.0.4",
111
+ "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
112
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2",
113
+ "@deepseek-ai/dsh-commands": "0.2.0-rc.2",
114
+ "@deepseek-ai/dsh-compaction": "0.2.0-rc.2",
115
+ "@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2",
116
+ "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
117
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
118
+ "@deepseek-ai/dsh-scope": "0.2.0-rc.2",
119
+ "@deepseek-ai/dsh-session": "0.2.0-rc.2",
120
+ "@deepseek-ai/dsh-session-format-v3-to-v4": "0.2.0-rc.2",
121
+ "@deepseek-ai/dsh-storage": "0.2.0-rc.2",
122
+ "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2",
123
+ "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
124
+ "@deepseek-ai/schemastery": "3.18.2",
125
+ "@playwright/test": "^1.64.1",
126
+ "@types/node": "^22.20.3",
127
+ "@types/react": "~18.3.1",
128
+ "c8": "^12.0.0",
129
+ "react": "^18.2.0",
130
+ "react-dom": "^18.2.0",
131
+ "tsdown": "^0.22.2",
132
+ "tsx": "^4.23.15",
133
+ "typescript": "^5.9.3"
134
+ },
135
+ "dependencies": {
136
+ "isomorphic-git": "^1.42.2",
137
+ "zod": "^4.4.3"
138
+ },
139
+ "repository": {
140
+ "type": "git",
141
+ "url": "git+https://github.com/fractalsynapse/dsh-chapters.git"
142
+ },
143
+ "homepage": "https://github.com/fractalsynapse/dsh-chapters#readme",
144
+ "bugs": {
145
+ "url": "https://github.com/fractalsynapse/dsh-chapters/issues"
146
+ },
147
+ "engines": {
148
+ "node": ">=24"
149
+ },
150
+ "publishConfig": {
151
+ "access": "public",
152
+ "provenance": true
153
+ }
6
154
  }