@seanhogg/builderforce-memory 2026.10.27 → 2026.10.29

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 (253) hide show
  1. package/dist/ingest/IngestionPipeline.d.ts +1 -8
  2. package/dist/ingest/IngestionPipeline.d.ts.map +1 -1
  3. package/dist/ingest/IngestionPipeline.js +3 -15
  4. package/dist/ingest/IngestionPipeline.js.map +1 -1
  5. package/dist/ingest/docsExtract.d.ts +30 -0
  6. package/dist/ingest/docsExtract.d.ts.map +1 -0
  7. package/dist/ingest/docsExtract.js +221 -0
  8. package/dist/ingest/docsExtract.js.map +1 -0
  9. package/dist/ingest/hash.d.ts +15 -0
  10. package/dist/ingest/hash.d.ts.map +1 -0
  11. package/dist/ingest/hash.js +22 -0
  12. package/dist/ingest/hash.js.map +1 -0
  13. package/dist/ingest/parsers.d.ts.map +1 -1
  14. package/dist/ingest/parsers.js +4 -0
  15. package/dist/ingest/parsers.js.map +1 -1
  16. package/dist/ingest/types.d.ts +7 -0
  17. package/dist/ingest/types.d.ts.map +1 -1
  18. package/dist/ingest/types.js.map +1 -1
  19. package/dist/knowledge/build.d.ts +24 -0
  20. package/dist/knowledge/build.d.ts.map +1 -0
  21. package/dist/knowledge/build.js +263 -0
  22. package/dist/knowledge/build.js.map +1 -0
  23. package/dist/knowledge/cards.d.ts +17 -0
  24. package/dist/knowledge/cards.d.ts.map +1 -0
  25. package/dist/knowledge/cards.js +118 -0
  26. package/dist/knowledge/cards.js.map +1 -0
  27. package/dist/knowledge/findings.d.ts +24 -0
  28. package/dist/knowledge/findings.d.ts.map +1 -0
  29. package/dist/knowledge/findings.js +152 -0
  30. package/dist/knowledge/findings.js.map +1 -0
  31. package/dist/knowledge/importance.d.ts +21 -0
  32. package/dist/knowledge/importance.d.ts.map +1 -0
  33. package/dist/knowledge/importance.js +70 -0
  34. package/dist/knowledge/importance.js.map +1 -0
  35. package/dist/knowledge/index.d.ts +31 -0
  36. package/dist/knowledge/index.d.ts.map +1 -0
  37. package/dist/knowledge/index.js +26 -0
  38. package/dist/knowledge/index.js.map +1 -0
  39. package/dist/knowledge/judge.d.ts +86 -0
  40. package/dist/knowledge/judge.d.ts.map +1 -0
  41. package/dist/knowledge/judge.js +213 -0
  42. package/dist/knowledge/judge.js.map +1 -0
  43. package/dist/knowledge/model.d.ts +333 -0
  44. package/dist/knowledge/model.d.ts.map +1 -0
  45. package/dist/knowledge/model.js +13 -0
  46. package/dist/knowledge/model.js.map +1 -0
  47. package/dist/knowledge/packs/docs.d.ts +17 -0
  48. package/dist/knowledge/packs/docs.d.ts.map +1 -0
  49. package/dist/knowledge/packs/docs.js +89 -0
  50. package/dist/knowledge/packs/docs.js.map +1 -0
  51. package/dist/knowledge/partitions.d.ts +31 -0
  52. package/dist/knowledge/partitions.d.ts.map +1 -0
  53. package/dist/knowledge/partitions.js +135 -0
  54. package/dist/knowledge/partitions.js.map +1 -0
  55. package/dist/knowledge/plan.d.ts +33 -0
  56. package/dist/knowledge/plan.d.ts.map +1 -0
  57. package/dist/knowledge/plan.js +89 -0
  58. package/dist/knowledge/plan.js.map +1 -0
  59. package/dist/knowledge/refs.d.ts +40 -0
  60. package/dist/knowledge/refs.d.ts.map +1 -0
  61. package/dist/knowledge/refs.js +102 -0
  62. package/dist/knowledge/refs.js.map +1 -0
  63. package/dist/knowledge/resolve.d.ts +35 -0
  64. package/dist/knowledge/resolve.d.ts.map +1 -0
  65. package/dist/knowledge/resolve.js +67 -0
  66. package/dist/knowledge/resolve.js.map +1 -0
  67. package/dist/knowledge/review.d.ts +23 -0
  68. package/dist/knowledge/review.d.ts.map +1 -0
  69. package/dist/knowledge/review.js +233 -0
  70. package/dist/knowledge/review.js.map +1 -0
  71. package/dist/knowledge/sources.d.ts +47 -0
  72. package/dist/knowledge/sources.d.ts.map +1 -0
  73. package/dist/knowledge/sources.js +136 -0
  74. package/dist/knowledge/sources.js.map +1 -0
  75. package/dist/knowledge/stores/localSnapshotStore.d.ts +50 -0
  76. package/dist/knowledge/stores/localSnapshotStore.d.ts.map +1 -0
  77. package/dist/knowledge/stores/localSnapshotStore.js +125 -0
  78. package/dist/knowledge/stores/localSnapshotStore.js.map +1 -0
  79. package/dist/knowledge/trace.d.ts +32 -0
  80. package/dist/knowledge/trace.d.ts.map +1 -0
  81. package/dist/knowledge/trace.js +102 -0
  82. package/dist/knowledge/trace.js.map +1 -0
  83. package/dist/knowledge/truncate.d.ts +24 -0
  84. package/dist/knowledge/truncate.d.ts.map +1 -0
  85. package/dist/knowledge/truncate.js +128 -0
  86. package/dist/knowledge/truncate.js.map +1 -0
  87. package/dist/memory/SemanticRecall.d.ts.map +1 -1
  88. package/dist/memory/SemanticRecall.js +3 -1
  89. package/dist/memory/SemanticRecall.js.map +1 -1
  90. package/dist/retrieval/HybridRetriever.d.ts.map +1 -1
  91. package/dist/retrieval/HybridRetriever.js +3 -1
  92. package/dist/retrieval/HybridRetriever.js.map +1 -1
  93. package/dist/retrieval/bm25.d.ts +3 -2
  94. package/dist/retrieval/bm25.d.ts.map +1 -1
  95. package/dist/retrieval/bm25.js +5 -3
  96. package/dist/retrieval/bm25.js.map +1 -1
  97. package/dist/retrieval/fusion.d.ts +2 -1
  98. package/dist/retrieval/fusion.d.ts.map +1 -1
  99. package/dist/retrieval/fusion.js +4 -2
  100. package/dist/retrieval/fusion.js.map +1 -1
  101. package/dist/retrieval/hnsw.d.ts +49 -11
  102. package/dist/retrieval/hnsw.d.ts.map +1 -1
  103. package/dist/retrieval/hnsw.js +57 -29
  104. package/dist/retrieval/hnsw.js.map +1 -1
  105. package/dist/retrieval/index.d.ts +7 -3
  106. package/dist/retrieval/index.d.ts.map +1 -1
  107. package/dist/retrieval/index.js +5 -2
  108. package/dist/retrieval/index.js.map +1 -1
  109. package/dist/retrieval/knowledge-index/bytes.d.ts +43 -0
  110. package/dist/retrieval/knowledge-index/bytes.d.ts.map +1 -0
  111. package/dist/retrieval/knowledge-index/bytes.js +151 -0
  112. package/dist/retrieval/knowledge-index/bytes.js.map +1 -0
  113. package/dist/retrieval/knowledge-index/cascade.d.ts +37 -0
  114. package/dist/retrieval/knowledge-index/cascade.d.ts.map +1 -0
  115. package/dist/retrieval/knowledge-index/cascade.js +111 -0
  116. package/dist/retrieval/knowledge-index/cascade.js.map +1 -0
  117. package/dist/retrieval/knowledge-index/compact.d.ts +18 -0
  118. package/dist/retrieval/knowledge-index/compact.d.ts.map +1 -0
  119. package/dist/retrieval/knowledge-index/compact.js +64 -0
  120. package/dist/retrieval/knowledge-index/compact.js.map +1 -0
  121. package/dist/retrieval/knowledge-index/csr.d.ts +41 -0
  122. package/dist/retrieval/knowledge-index/csr.d.ts.map +1 -0
  123. package/dist/retrieval/knowledge-index/csr.js +76 -0
  124. package/dist/retrieval/knowledge-index/csr.js.map +1 -0
  125. package/dist/retrieval/knowledge-index/digest.d.ts +21 -0
  126. package/dist/retrieval/knowledge-index/digest.d.ts.map +1 -0
  127. package/dist/retrieval/knowledge-index/digest.js +50 -0
  128. package/dist/retrieval/knowledge-index/digest.js.map +1 -0
  129. package/dist/retrieval/knowledge-index/embeddings.d.ts +32 -0
  130. package/dist/retrieval/knowledge-index/embeddings.d.ts.map +1 -0
  131. package/dist/retrieval/knowledge-index/embeddings.js +78 -0
  132. package/dist/retrieval/knowledge-index/embeddings.js.map +1 -0
  133. package/dist/retrieval/knowledge-index/expand.d.ts +19 -0
  134. package/dist/retrieval/knowledge-index/expand.d.ts.map +1 -0
  135. package/dist/retrieval/knowledge-index/expand.js +49 -0
  136. package/dist/retrieval/knowledge-index/expand.js.map +1 -0
  137. package/dist/retrieval/knowledge-index/index.d.ts +40 -0
  138. package/dist/retrieval/knowledge-index/index.d.ts.map +1 -0
  139. package/dist/retrieval/knowledge-index/index.js +134 -0
  140. package/dist/retrieval/knowledge-index/index.js.map +1 -0
  141. package/dist/retrieval/knowledge-index/lexical.d.ts +26 -0
  142. package/dist/retrieval/knowledge-index/lexical.d.ts.map +1 -0
  143. package/dist/retrieval/knowledge-index/lexical.js +76 -0
  144. package/dist/retrieval/knowledge-index/lexical.js.map +1 -0
  145. package/dist/retrieval/knowledge-index/pairs.d.ts +22 -0
  146. package/dist/retrieval/knowledge-index/pairs.d.ts.map +1 -0
  147. package/dist/retrieval/knowledge-index/pairs.js +51 -0
  148. package/dist/retrieval/knowledge-index/pairs.js.map +1 -0
  149. package/dist/retrieval/knowledge-index/prune.d.ts +21 -0
  150. package/dist/retrieval/knowledge-index/prune.d.ts.map +1 -0
  151. package/dist/retrieval/knowledge-index/prune.js +43 -0
  152. package/dist/retrieval/knowledge-index/prune.js.map +1 -0
  153. package/dist/retrieval/knowledge-index/quantize.d.ts +37 -0
  154. package/dist/retrieval/knowledge-index/quantize.d.ts.map +1 -0
  155. package/dist/retrieval/knowledge-index/quantize.js +77 -0
  156. package/dist/retrieval/knowledge-index/quantize.js.map +1 -0
  157. package/dist/retrieval/knowledge-index/serialize.d.ts +18 -0
  158. package/dist/retrieval/knowledge-index/serialize.d.ts.map +1 -0
  159. package/dist/retrieval/knowledge-index/serialize.js +123 -0
  160. package/dist/retrieval/knowledge-index/serialize.js.map +1 -0
  161. package/dist/retrieval/knowledge-index/sha256.d.ts +30 -0
  162. package/dist/retrieval/knowledge-index/sha256.d.ts.map +1 -0
  163. package/dist/retrieval/knowledge-index/sha256.js +130 -0
  164. package/dist/retrieval/knowledge-index/sha256.js.map +1 -0
  165. package/dist/retrieval/knowledge-index/state.d.ts +55 -0
  166. package/dist/retrieval/knowledge-index/state.d.ts.map +1 -0
  167. package/dist/retrieval/knowledge-index/state.js +67 -0
  168. package/dist/retrieval/knowledge-index/state.js.map +1 -0
  169. package/dist/retrieval/knowledge-index/tokenize.d.ts +20 -0
  170. package/dist/retrieval/knowledge-index/tokenize.d.ts.map +1 -0
  171. package/dist/retrieval/knowledge-index/tokenize.js +42 -0
  172. package/dist/retrieval/knowledge-index/tokenize.js.map +1 -0
  173. package/dist/retrieval/knowledge-index/traverse.d.ts +26 -0
  174. package/dist/retrieval/knowledge-index/traverse.d.ts.map +1 -0
  175. package/dist/retrieval/knowledge-index/traverse.js +90 -0
  176. package/dist/retrieval/knowledge-index/traverse.js.map +1 -0
  177. package/dist/retrieval/knowledge-index/types.d.ts +85 -0
  178. package/dist/retrieval/knowledge-index/types.d.ts.map +1 -0
  179. package/dist/retrieval/knowledge-index/types.js +9 -0
  180. package/dist/retrieval/knowledge-index/types.js.map +1 -0
  181. package/dist/retrieval/mmr.d.ts +11 -4
  182. package/dist/retrieval/mmr.d.ts.map +1 -1
  183. package/dist/retrieval/mmr.js +28 -8
  184. package/dist/retrieval/mmr.js.map +1 -1
  185. package/dist/retrieval/order.d.ts +41 -0
  186. package/dist/retrieval/order.d.ts.map +1 -0
  187. package/dist/retrieval/order.js +54 -0
  188. package/dist/retrieval/order.js.map +1 -0
  189. package/dist/retrieval/weightedFusion.d.ts +2 -1
  190. package/dist/retrieval/weightedFusion.d.ts.map +1 -1
  191. package/dist/retrieval/weightedFusion.js +7 -5
  192. package/dist/retrieval/weightedFusion.js.map +1 -1
  193. package/dist/vectorstore/MemoryVectorStore.d.ts.map +1 -1
  194. package/dist/vectorstore/MemoryVectorStore.js +2 -1
  195. package/dist/vectorstore/MemoryVectorStore.js.map +1 -1
  196. package/package.json +16 -5
  197. package/src/ingest/IngestionPipeline.ts +3 -15
  198. package/src/ingest/docsExtract.ts +219 -0
  199. package/src/ingest/hash.ts +22 -0
  200. package/src/ingest/parsers.ts +4 -0
  201. package/src/ingest/types.ts +7 -0
  202. package/src/knowledge/build.test.ts +150 -0
  203. package/src/knowledge/build.ts +266 -0
  204. package/src/knowledge/cards.ts +130 -0
  205. package/src/knowledge/docs.test.ts +118 -0
  206. package/src/knowledge/findings.ts +159 -0
  207. package/src/knowledge/importance.ts +72 -0
  208. package/src/knowledge/index.ts +53 -0
  209. package/src/knowledge/judge.ts +231 -0
  210. package/src/knowledge/model.ts +312 -0
  211. package/src/knowledge/packs/docs.ts +91 -0
  212. package/src/knowledge/partitions.test.ts +98 -0
  213. package/src/knowledge/partitions.ts +119 -0
  214. package/src/knowledge/plan.ts +115 -0
  215. package/src/knowledge/refs.ts +108 -0
  216. package/src/knowledge/resolve.ts +78 -0
  217. package/src/knowledge/review.test.ts +180 -0
  218. package/src/knowledge/review.ts +235 -0
  219. package/src/knowledge/sources.ts +146 -0
  220. package/src/knowledge/stores/localSnapshotStore.test.ts +82 -0
  221. package/src/knowledge/stores/localSnapshotStore.ts +159 -0
  222. package/src/knowledge/testkit.test-util.ts +92 -0
  223. package/src/knowledge/trace.test.ts +91 -0
  224. package/src/knowledge/trace.ts +111 -0
  225. package/src/knowledge/truncate.ts +118 -0
  226. package/src/memory/SemanticRecall.ts +3 -1
  227. package/src/retrieval/HybridRetriever.ts +3 -1
  228. package/src/retrieval/bm25.ts +5 -3
  229. package/src/retrieval/fusion.ts +5 -2
  230. package/src/retrieval/hnsw.ts +82 -35
  231. package/src/retrieval/index.ts +17 -3
  232. package/src/retrieval/knowledge-index/bytes.ts +166 -0
  233. package/src/retrieval/knowledge-index/cascade.ts +125 -0
  234. package/src/retrieval/knowledge-index/compact.ts +68 -0
  235. package/src/retrieval/knowledge-index/csr.ts +102 -0
  236. package/src/retrieval/knowledge-index/digest.ts +54 -0
  237. package/src/retrieval/knowledge-index/embeddings.ts +85 -0
  238. package/src/retrieval/knowledge-index/expand.ts +55 -0
  239. package/src/retrieval/knowledge-index/index.ts +162 -0
  240. package/src/retrieval/knowledge-index/lexical.ts +78 -0
  241. package/src/retrieval/knowledge-index/pairs.ts +57 -0
  242. package/src/retrieval/knowledge-index/prune.ts +48 -0
  243. package/src/retrieval/knowledge-index/quantize.ts +78 -0
  244. package/src/retrieval/knowledge-index/serialize.ts +124 -0
  245. package/src/retrieval/knowledge-index/sha256.ts +122 -0
  246. package/src/retrieval/knowledge-index/state.ts +108 -0
  247. package/src/retrieval/knowledge-index/tokenize.ts +41 -0
  248. package/src/retrieval/knowledge-index/traverse.ts +95 -0
  249. package/src/retrieval/knowledge-index/types.ts +78 -0
  250. package/src/retrieval/mmr.ts +35 -10
  251. package/src/retrieval/order.ts +68 -0
  252. package/src/retrieval/weightedFusion.ts +8 -5
  253. package/src/vectorstore/MemoryVectorStore.ts +2 -1
@@ -0,0 +1,233 @@
1
+ /**
2
+ * knowledge/review.ts — `reviewDirectory`: point it at a folder and it learns what the
3
+ * folder says (PRD 38 §4.3).
4
+ *
5
+ * plan (walk + manifest diff) → per changed file: read · parse (the ONE ParserRegistry,
6
+ * composed from the packs) · extract (cached by content hash) · judge (changed sections
7
+ * of judged kinds, within budget) · write · markStale → analyzers → compare near-duplicate
8
+ * claims → manifest + scope digest.
9
+ *
10
+ * Store judgement, compute perception: only `model` facts and relations are written —
11
+ * `extracted` output goes to the extracted cache, never to memory ({@link assertStoredBatch}).
12
+ * Abort is honoured between files; a file is written whole or not at all. A file whose
13
+ * sections were cut by the budget stays "changed" in the manifest, so continuing re-plans it
14
+ * and judges only the sections not judged yet.
15
+ */
16
+ import { hashText } from '../ingest/hash.js';
17
+ import { sha256Hex } from '../retrieval/knowledge-index/sha256.js';
18
+ import { SECTION_INDEX_BADGE } from '../ingest/docsExtract.js';
19
+ import { planDetail } from './plan.js';
20
+ import { asPathSource, composePacks, filesManifestKey, isBinaryText, judgedManifestKey, manifestMap, resolveRelativePath, saveManifestMap, } from './sources.js';
21
+ import { budgetLeft, compareClaims, DEFAULT_REVIEW_MODEL_CALLS, JudgedBatch, judgeSections, } from './judge.js';
22
+ import { entityName, knownKeysOf, resolveEntities } from './resolve.js';
23
+ import { basenameOf, canonicalJson, compareStr, factKeyOf, srcRef } from './refs.js';
24
+ /** Throws if a batch carries `extracted` items — perception is never memory. */
25
+ export function assertStoredBatch(batch) {
26
+ const bad = [...batch.facts, ...batch.relations].find((x) => x.origin === 'extracted');
27
+ if (bad)
28
+ throw new Error('knowledge: extracted output is never written to a KnowledgeStore');
29
+ }
30
+ async function extractedFor(store, parser, pack, src, sections, ctx, hash) {
31
+ const ref = srcRef(ctx.rootId, src.id);
32
+ const cached = await store.getExtracted?.(hash);
33
+ const hit = cached?.find((e) => e.sourceRef === ref);
34
+ if (hit)
35
+ return hit;
36
+ const ex = parser.extract
37
+ ? { ...parser.extract(src, sections, ctx), sourceHash: hash }
38
+ : {
39
+ sourceRef: ref, sourceHash: hash, edges: [], keys: [{ ref, key: src.id }],
40
+ nodes: [{ ref, kind: 'file', label: basenameOf(src.id), pack, importance: 0, origin: 'extracted', sourceHash: hash }],
41
+ };
42
+ await store.putExtracted?.(hash, [...(cached ?? []).filter((e) => e.sourceRef !== ref), ex]);
43
+ return ex;
44
+ }
45
+ /** Stored knowledge, indexed for re-anchoring unchanged sections without a model call. */
46
+ class StoredIndex {
47
+ facts;
48
+ from = new Map();
49
+ to = new Map();
50
+ constructor(facts, relations) {
51
+ this.facts = new Map(facts.map((f) => [f.key, f]));
52
+ for (const r of relations) {
53
+ if (r.origin !== 'model')
54
+ continue;
55
+ (this.from.get(r.from) ?? this.from.set(r.from, []).get(r.from)).push(r);
56
+ (this.to.get(r.to) ?? this.to.set(r.to, []).get(r.to)).push(r);
57
+ }
58
+ }
59
+ /** An unchanged section keeps its claims and mentions; they are re-anchored to the file's new hash. */
60
+ refresh(section, path, hash, batch, entities) {
61
+ const reanchor = (f) => ({
62
+ ...f, fileAnchors: f.fileAnchors.map((a) => (a.path === path ? { ...a, contentHash: hash } : a)),
63
+ });
64
+ const relation = (r) => batch.relation({ ...r, sourceHash: hash, staleAt: null });
65
+ for (const r of this.to.get(section) ?? []) {
66
+ if (r.kind !== 'about')
67
+ continue;
68
+ relation(r);
69
+ const key = factKeyOf(r.from);
70
+ const fact = key && (batch.facts.get(key) ?? this.facts.get(key));
71
+ if (fact && fact.origin === 'model')
72
+ batch.fact(reanchor(fact));
73
+ for (const m of this.from.get(r.from) ?? [])
74
+ if (m.kind === 'mentions')
75
+ relation(m);
76
+ }
77
+ for (const r of this.from.get(section) ?? []) {
78
+ if (r.kind !== 'mentions')
79
+ continue;
80
+ relation(r);
81
+ const ent = entities.get(r.to);
82
+ if (ent && ent.origin === 'model') {
83
+ const next = reanchor(ent);
84
+ entities.set(r.to, next);
85
+ batch.fact(next);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ export async function reviewDirectory(args) {
91
+ const now = () => Date.now();
92
+ const started = now();
93
+ const { source, store, packs, manifest, signal } = args;
94
+ const rootId = source.rootId;
95
+ const scope = { rootId };
96
+ const progress = (p) => args.onProgress?.(p);
97
+ const report = {
98
+ rootId, digest: '', extracted: 0, judged: 0, unjudged: 0, invalidJudgements: 0,
99
+ factsWritten: 0, relationsWritten: 0, staleMarked: 0, aborted: false, durationMs: 0,
100
+ };
101
+ const detail = await planDetail(source, manifest, packs);
102
+ progress({ phase: 'plan', done: detail.files.length, total: detail.files.length });
103
+ const composed = composePacks(packs);
104
+ const packIds = packs.map((p) => p.id).sort(compareStr);
105
+ const scopeRecord = { rootId, title: source.title, packs: packIds };
106
+ const [storedFacts, storedRelations] = await Promise.all([store.facts(scope), store.relations(scope)]);
107
+ const stored = new StoredIndex(storedFacts, storedRelations);
108
+ const entities = new Map(storedFacts.filter((f) => f.key.startsWith('ent:')).map((f) => [f.key, f]));
109
+ const ctx = {
110
+ rootId,
111
+ knownKeys: knownKeysOf(resolveEntities([...entities.keys()].map((k) => ({ ref: k, key: entityName(k) })))),
112
+ resolvePath: resolveRelativePath,
113
+ };
114
+ const budget = {
115
+ modelCalls: args.budget?.modelCalls ?? DEFAULT_REVIEW_MODEL_CALLS,
116
+ deadline: started + (Number.isFinite(args.budget?.ms) ? args.budget.ms : Number.POSITIVE_INFINITY),
117
+ used: 0, now,
118
+ };
119
+ const batch = new JudgedBatch();
120
+ const judgedPrior = await manifestMap(manifest, judgedManifestKey(rootId));
121
+ const judgedNow = new Map(judgedPrior);
122
+ const filesNow = new Map(detail.prior);
123
+ const newClaims = new Map();
124
+ const write = async (withScope = scopeRecord) => {
125
+ const out = batch.take();
126
+ assertStoredBatch(out);
127
+ if (out.facts.length === 0 && out.relations.length === 0 && withScope === scopeRecord)
128
+ return;
129
+ await store.write({ scope: withScope, ...out });
130
+ report.factsWritten += out.facts.length;
131
+ report.relationsWritten += out.relations.length;
132
+ };
133
+ const changed = detail.files.filter((f) => f.changed);
134
+ for (const [i, f] of changed.entries()) {
135
+ if (signal?.aborted) {
136
+ report.aborted = true;
137
+ break;
138
+ }
139
+ progress({ phase: 'extract', done: i, total: changed.length, path: f.path });
140
+ const doc = await source.read(f.path);
141
+ if (doc.content.kind === 'text' && isBinaryText(doc.content.text))
142
+ continue;
143
+ const src = asPathSource(doc, f.path, f.hash);
144
+ const hit = composed.resolve(src);
145
+ if (!hit)
146
+ continue;
147
+ const sections = hit.parser.parse(src);
148
+ const ex = await extractedFor(store, hit.parser, hit.pack.id, src, sections, ctx, f.hash);
149
+ report.extracted += 1;
150
+ const spec = hit.pack.judgement;
151
+ let complete = true;
152
+ if (spec && args.judgement && (spec.claims || spec.entities)) {
153
+ const kinds = new Set(spec.nodeKinds);
154
+ const toJudge = [];
155
+ for (const node of ex.nodes) {
156
+ const index = node.badges?.[SECTION_INDEX_BADGE];
157
+ const text = typeof index === 'number' ? sections[index]?.text : undefined;
158
+ if (!kinds.has(node.kind) || !text)
159
+ continue;
160
+ if (judgedPrior.get(node.ref) === hashText(text))
161
+ stored.refresh(node.ref, f.path, f.hash, batch, entities);
162
+ else
163
+ toJudge.push({ ref: node.ref, text });
164
+ }
165
+ const unjudgedBefore = batch.unjudged;
166
+ progress({ phase: 'judge', done: i, total: changed.length, path: f.path });
167
+ try {
168
+ const claims = await judgeSections({
169
+ port: args.judgement, pack: hit.pack.id, path: f.path, fileHash: f.hash, sections: toJudge,
170
+ budget, batch, entities, ...(signal ? { signal } : {}),
171
+ onJudged: (ref) => judgedNow.set(ref, hashText(toJudge.find((s) => s.ref === ref).text)),
172
+ });
173
+ for (const c of claims)
174
+ newClaims.set(c.ref, { text: c.text, hash: f.hash });
175
+ }
176
+ catch (err) {
177
+ if (!signal?.aborted)
178
+ throw err;
179
+ batch.take();
180
+ report.aborted = true;
181
+ break;
182
+ }
183
+ complete = batch.unjudged === unjudgedBefore;
184
+ }
185
+ progress({ phase: 'write', done: i, total: changed.length, path: f.path });
186
+ await write();
187
+ await store.markStale(scope, srcRef(rootId, f.path), f.hash);
188
+ report.staleMarked += 1;
189
+ if (complete)
190
+ filesNow.set(f.path, f.hash);
191
+ }
192
+ if (!report.aborted) {
193
+ for (const path of detail.plan.removed) {
194
+ await store.markStale(scope, srcRef(rootId, path), '');
195
+ report.staleMarked += 1;
196
+ filesNow.delete(path);
197
+ }
198
+ for (const pack of packs) {
199
+ if (!pack.analyzers)
200
+ continue;
201
+ for (const ex of await pack.analyzers.analyse(rootId, signal)) {
202
+ await store.putExtracted?.(ex.sourceHash, [ex]);
203
+ report.extracted += 1;
204
+ }
205
+ }
206
+ progress({ phase: 'resolve', done: 0, total: newClaims.size });
207
+ const wantsCompare = packs.some((p) => p.judgement?.contradictions);
208
+ if (wantsCompare && args.judgement && args.similar && newClaims.size > 0 && budgetLeft(budget)) {
209
+ const pairs = await args.similar([...newClaims.keys()].sort(compareStr));
210
+ const claims = new Map(newClaims);
211
+ for (const p of pairs) {
212
+ for (const id of [p.a, p.b]) {
213
+ const fact = !claims.has(id) ? stored.facts.get(factKeyOf(id) ?? '') : undefined;
214
+ if (fact?.key.startsWith('claim:'))
215
+ claims.set(id, { text: fact.content, hash: fact.fileAnchors[0]?.contentHash ?? '' });
216
+ }
217
+ }
218
+ progress({ phase: 'judge', done: 0, total: pairs.length });
219
+ await compareClaims({ port: args.judgement, pairs, claims, budget, batch, ...(signal ? { signal } : {}) });
220
+ }
221
+ }
222
+ report.judged = batch.judged;
223
+ report.unjudged = batch.unjudged;
224
+ report.invalidJudgements = batch.invalid;
225
+ report.digest = sha256Hex(canonicalJson({ rootId, packs: packIds, files: [...filesNow].sort((a, b) => compareStr(a[0], b[0])) }));
226
+ await saveManifestMap(manifest, filesManifestKey(rootId), filesNow);
227
+ await saveManifestMap(manifest, judgedManifestKey(rootId), judgedNow);
228
+ await write(report.aborted ? scopeRecord : { ...scopeRecord, lastDigest: report.digest, lastReviewedAt: new Date(now()).toISOString() });
229
+ report.durationMs = now() - started;
230
+ progress({ phase: 'done', done: changed.length, total: changed.length });
231
+ return report;
232
+ }
233
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/knowledge/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * knowledge/sources.ts — what a review needs to know about a file BEFORE (or without)
3
+ * reading it: its pack, its media type, whether it is binary or ignored. Shared by
4
+ * `planReview` and `reviewDirectory`, so the plan's numbers and the run agree.
5
+ */
6
+ import { ParserRegistry } from '../ingest/parsers.js';
7
+ import { type IngestManifest, type SourceDocument } from '../ingest/types.js';
8
+ import type { KnowledgePack, KnowledgeParser } from './model.js';
9
+ /** Default per-file size cap (bytes). */
10
+ export declare const DEFAULT_MAX_FILE_BYTES: number;
11
+ /** Ignore files read through the source, when present. */
12
+ export declare const IGNORE_FILES: readonly [".gitignore", ".builderforce/ignore"];
13
+ export declare function mediaTypeOfPath(path: string): string;
14
+ /** By extension — the plan never reads a file to decide. (pdf/office text needs a host extractor.) */
15
+ export declare function isBinaryPath(path: string): boolean;
16
+ /** A NUL in the first 8 KB means binary, whatever the extension said. */
17
+ export declare function isBinaryText(text: string): boolean;
18
+ /** A read source with its id set to the root-relative path and a media type filled in. */
19
+ export declare function asPathSource(doc: SourceDocument, path: string, hash: string): SourceDocument;
20
+ /** A content-free stand-in, so `accepts` can pick a pack without a read. */
21
+ export declare function stubSource(path: string): SourceDocument;
22
+ export interface ComposedPacks {
23
+ /** The ONE registry, composed from the packs' parsers in pack order. */
24
+ registry: ParserRegistry;
25
+ resolve(source: SourceDocument): {
26
+ parser: KnowledgeParser;
27
+ pack: KnowledgePack;
28
+ } | undefined;
29
+ }
30
+ export declare function composePacks(packs: readonly KnowledgePack[]): ComposedPacks;
31
+ /**
32
+ * A `.gitignore`-style matcher: `#` comments, `!` negation (last match wins), a trailing
33
+ * `/` for directories only, a `/` elsewhere anchors to the root, otherwise any depth.
34
+ */
35
+ export declare function ignoreMatcher(texts: readonly string[]): (path: string) => boolean;
36
+ /** Manifest entry holding `{ id: path, hash }` for every reviewed file of a root. */
37
+ export declare const filesManifestKey: (rootId: string) => string;
38
+ /** Manifest entry holding `{ id: sectionRef, hash: textHash }` for every judged section. */
39
+ export declare const judgedManifestKey: (rootId: string) => string;
40
+ export declare function manifestMap(manifest: IngestManifest, key: string): Promise<Map<string, string>>;
41
+ export declare function saveManifestMap(manifest: IngestManifest, key: string, map: ReadonlyMap<string, string>): Promise<void>;
42
+ /**
43
+ * Resolves a link/import target against the linking file's folder (a leading `/` is the
44
+ * root). Pure path arithmetic: undefined only when the target escapes the root.
45
+ */
46
+ export declare function resolveRelativePath(fromPath: string, target: string): string | undefined;
47
+ //# sourceMappingURL=sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../../src/knowledge/sources.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAA6C,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIjE,yCAAyC;AACzC,eAAO,MAAM,sBAAsB,QAAkB,CAAC;AACtD,0DAA0D;AAC1D,eAAO,MAAM,YAAY,iDAAkD,CAAC;AAwB5E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CAK5F;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAEvD;AAED,MAAM,WAAW,aAAa;IAC1B,wEAAwE;IACxE,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG;QAAE,MAAM,EAAE,eAAe,CAAC;QAAC,IAAI,EAAE,aAAa,CAAA;KAAE,GAAG,SAAS,CAAC;CACjG;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAY3E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAuBjF;AAED,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,MAA+B,CAAC;AAClF,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,MAAsC,CAAC;AAE1F,wBAAsB,WAAW,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAGrG;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5H;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWxF"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * knowledge/sources.ts — what a review needs to know about a file BEFORE (or without)
3
+ * reading it: its pack, its media type, whether it is binary or ignored. Shared by
4
+ * `planReview` and `reviewDirectory`, so the plan's numbers and the run agree.
5
+ */
6
+ import { ParserRegistry } from '../ingest/parsers.js';
7
+ import { CONTENT_HASH_FIELD } from '../ingest/types.js';
8
+ import { matchGlob } from './partitions.js';
9
+ import { compareStr } from './refs.js';
10
+ /** Default per-file size cap (bytes). */
11
+ export const DEFAULT_MAX_FILE_BYTES = 2 * 1024 * 1024;
12
+ /** Ignore files read through the source, when present. */
13
+ export const IGNORE_FILES = ['.gitignore', '.builderforce/ignore'];
14
+ /** Always ignored: VCS internals, installed dependencies, builderforce config. */
15
+ const DEFAULT_IGNORES = ['.git/', 'node_modules/', '.builderforce/', '/.gitignore'];
16
+ const MEDIA_TYPES = {
17
+ md: 'text/markdown', markdown: 'text/markdown', mdx: 'text/markdown',
18
+ html: 'text/html', htm: 'text/html', xhtml: 'application/xhtml+xml', xml: 'application/xml',
19
+ json: 'application/json', csv: 'text/csv', tsv: 'text/tab-separated-values',
20
+ };
21
+ const BINARY_EXT = new Set([
22
+ 'png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'ico', 'icns', 'tif', 'tiff', 'psd', 'avif', 'heic',
23
+ 'mp3', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'wav', 'flac', 'ogg', 'm4a',
24
+ 'zip', 'gz', 'tgz', 'bz2', 'xz', '7z', 'rar', 'tar', 'jar', 'war',
25
+ 'exe', 'dll', 'so', 'dylib', 'bin', 'o', 'a', 'class', 'wasm', 'node', 'pyc',
26
+ 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp',
27
+ 'ttf', 'otf', 'woff', 'woff2', 'eot', 'sqlite', 'db', 'vsix', 'lock',
28
+ ]);
29
+ const extOf = (path) => {
30
+ const m = /\.([A-Za-z0-9]+)$/.exec(path);
31
+ return m ? m[1].toLowerCase() : '';
32
+ };
33
+ export function mediaTypeOfPath(path) {
34
+ return MEDIA_TYPES[extOf(path)] ?? 'text/plain';
35
+ }
36
+ /** By extension — the plan never reads a file to decide. (pdf/office text needs a host extractor.) */
37
+ export function isBinaryPath(path) {
38
+ return BINARY_EXT.has(extOf(path));
39
+ }
40
+ /** A NUL in the first 8 KB means binary, whatever the extension said. */
41
+ export function isBinaryText(text) {
42
+ return text.slice(0, 8192).includes('\u0000');
43
+ }
44
+ /** A read source with its id set to the root-relative path and a media type filled in. */
45
+ export function asPathSource(doc, path, hash) {
46
+ const content = doc.content.kind === 'text' && !doc.content.mediaType
47
+ ? { ...doc.content, mediaType: mediaTypeOfPath(path) }
48
+ : doc.content;
49
+ return { ...doc, id: path, content, metadata: { ...(doc.metadata ?? {}), [CONTENT_HASH_FIELD]: hash } };
50
+ }
51
+ /** A content-free stand-in, so `accepts` can pick a pack without a read. */
52
+ export function stubSource(path) {
53
+ return { id: path, tenantId: '', content: { kind: 'text', text: '', mediaType: mediaTypeOfPath(path) } };
54
+ }
55
+ export function composePacks(packs) {
56
+ const owner = new Map();
57
+ for (const pack of packs)
58
+ for (const p of pack.parsers)
59
+ if (!owner.has(p))
60
+ owner.set(p, pack);
61
+ const registry = new ParserRegistry([...owner.keys()]);
62
+ return {
63
+ registry,
64
+ resolve(source) {
65
+ const parser = registry.resolve(source);
66
+ const pack = parser && owner.get(parser);
67
+ return parser && pack ? { parser, pack } : undefined;
68
+ },
69
+ };
70
+ }
71
+ /**
72
+ * A `.gitignore`-style matcher: `#` comments, `!` negation (last match wins), a trailing
73
+ * `/` for directories only, a `/` elsewhere anchors to the root, otherwise any depth.
74
+ */
75
+ export function ignoreMatcher(texts) {
76
+ const rules = [];
77
+ for (const line of [...DEFAULT_IGNORES, ...texts.flatMap((t) => t.split(/\r?\n/))]) {
78
+ let p = line.replace(/\s+$/, '');
79
+ if (!p || p.startsWith('#'))
80
+ continue;
81
+ const negate = p.startsWith('!');
82
+ if (negate)
83
+ p = p.slice(1);
84
+ const dirOnly = p.endsWith('/');
85
+ if (dirOnly)
86
+ p = p.slice(0, -1);
87
+ const anchored = p.includes('/');
88
+ p = p.replace(/^\//, '');
89
+ if (p)
90
+ rules.push({ glob: anchored ? p : `**/${p}`, negate, dirOnly });
91
+ }
92
+ return (path) => {
93
+ const segments = path.split('/');
94
+ const dirs = segments.slice(0, -1).map((_, i) => segments.slice(0, i + 1).join('/'));
95
+ let ignored = false;
96
+ for (const r of rules) {
97
+ const hit = (r.dirOnly ? dirs : [...dirs, path]).some((c) => matchGlob(c, r.glob));
98
+ if (hit)
99
+ ignored = !r.negate;
100
+ }
101
+ return ignored;
102
+ };
103
+ }
104
+ /** Manifest entry holding `{ id: path, hash }` for every reviewed file of a root. */
105
+ export const filesManifestKey = (rootId) => `knowledge:${rootId}`;
106
+ /** Manifest entry holding `{ id: sectionRef, hash: textHash }` for every judged section. */
107
+ export const judgedManifestKey = (rootId) => `knowledge:${rootId}:judged`;
108
+ export async function manifestMap(manifest, key) {
109
+ const prior = (await manifest.get(key)) ?? [];
110
+ return new Map(prior.map((f) => [f.id, f.hash]));
111
+ }
112
+ export async function saveManifestMap(manifest, key, map) {
113
+ const entries = [...map].sort((a, b) => compareStr(a[0], b[0])).map(([id, hash]) => ({ id, hash }));
114
+ await manifest.set(key, entries);
115
+ }
116
+ /**
117
+ * Resolves a link/import target against the linking file's folder (a leading `/` is the
118
+ * root). Pure path arithmetic: undefined only when the target escapes the root.
119
+ */
120
+ export function resolveRelativePath(fromPath, target) {
121
+ const t = target.replace(/\\/g, '/');
122
+ const out = t.startsWith('/') ? [] : fromPath.split('/').slice(0, -1);
123
+ for (const seg of t.split('/')) {
124
+ if (seg === '' || seg === '.')
125
+ continue;
126
+ if (seg === '..') {
127
+ if (out.length === 0)
128
+ return undefined;
129
+ out.pop();
130
+ }
131
+ else
132
+ out.push(seg);
133
+ }
134
+ return out.length ? out.join('/') : undefined;
135
+ }
136
+ //# sourceMappingURL=sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../src/knowledge/sources.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAmE,MAAM,oBAAoB,CAAC;AAEzH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,yCAAyC;AACzC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACtD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,YAAY,EAAE,sBAAsB,CAAU,CAAC;AAC5E,kFAAkF;AAClF,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAC;AAEpF,MAAM,WAAW,GAA2B;IACxC,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,eAAe;IACpE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,uBAAuB,EAAE,GAAG,EAAE,iBAAiB;IAC3F,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,2BAA2B;CAC9E,CAAC;AAEF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACvB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;IAC/F,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;IACtE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IACjE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;IAC5E,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IACvE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM;CACvE,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,CAAC,IAAY,EAAU,EAAE;IACnC,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,IAAY;IACxC,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,YAAY,CAAC;AACpD,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,YAAY,CAAC,IAAY;IACrC,OAAO,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,YAAY,CAAC,GAAmB,EAAE,IAAY,EAAE,IAAY;IACxE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS;QACjE,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE;QACtD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;IAClB,OAAO,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;AAC5G,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;AAC7G,CAAC;AAQD,MAAM,UAAU,YAAY,CAAC,KAA+B;IACxD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkC,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9F,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvD,OAAO;QACH,QAAQ;QACR,OAAO,CAAC,MAAM;YACV,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAgC,CAAC;YACvE,MAAM,IAAI,GAAG,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACzC,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,CAAC;KACJ,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAwB;IAClD,MAAM,KAAK,GAA+D,EAAE,CAAC;IAC7E,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,eAAe,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACtC,MAAM,MAAM,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,OAAO;YAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACrF,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACnF,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QACjC,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC,CAAC;AACN,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,aAAa,MAAM,EAAE,CAAC;AAClF,4FAA4F;AAC5F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,aAAa,MAAM,SAAS,CAAC;AAE1F,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAwB,EAAE,GAAW;IACnE,MAAM,KAAK,GAAuB,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClE,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAU,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAwB,EAAE,GAAW,EAAE,GAAgC;IACzG,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACpG,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,MAAc;IAChE,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG;YAAE,SAAS;QACxC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACf,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YACvC,GAAG,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;;YAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * knowledge/stores/localSnapshotStore.ts — a {@link KnowledgeStore} over one JSON snapshot,
3
+ * for a folder not linked to a project (PRD 38 §4.2, §5.1).
4
+ *
5
+ * Persistence is a port (`read`/`write` of the whole snapshot string), so this module has
6
+ * no `fs`: the memory MCP host persists it beside its own snapshot through its shared JSON
7
+ * file, a browser host in IndexedDB. Upserts use the platform's unique keys — a fact by
8
+ * `key`, a relation by `(from, to, kind)`, a scope by `rootId` — so linking a folder later
9
+ * uploads the same rows idempotently. The snapshot is written canonically (sorted), so
10
+ * equal content is equal bytes.
11
+ */
12
+ import type { Extracted, KnowledgeStore, NodeRef, Scope, ScopeRecord, StoredFact, StoredRelation } from '../model.js';
13
+ export interface SnapshotPersistence {
14
+ read(): Promise<string | undefined>;
15
+ write(snapshot: string): Promise<void>;
16
+ }
17
+ export interface KnowledgeSnapshot {
18
+ version: 1;
19
+ scopes: ScopeRecord[];
20
+ facts: Record<string, StoredFact[]>;
21
+ relations: Record<string, StoredRelation[]>;
22
+ extracted: Record<string, Extracted[]>;
23
+ }
24
+ export interface LocalSnapshotStoreOptions {
25
+ /** ISO clock for `staleAt`. Default `new Date().toISOString()`. */
26
+ now?(): string;
27
+ }
28
+ export declare class LocalSnapshotStore implements KnowledgeStore {
29
+ private readonly persistence;
30
+ private snapshot;
31
+ /** Serializes mutations so two writers never interleave a read-modify-write. */
32
+ private queue;
33
+ private readonly now;
34
+ constructor(persistence: SnapshotPersistence, opts?: LocalSnapshotStoreOptions);
35
+ private load;
36
+ private mutate;
37
+ scopes(): Promise<ScopeRecord[]>;
38
+ facts(scope: Scope): Promise<StoredFact[]>;
39
+ relations(scope: Scope): Promise<StoredRelation[]>;
40
+ write(batch: {
41
+ scope: ScopeRecord;
42
+ facts: StoredFact[];
43
+ relations: StoredRelation[];
44
+ }): Promise<void>;
45
+ markStale(scope: Scope, sourceRef: NodeRef, currentHash: string): Promise<void>;
46
+ getExtracted(hash: string): Promise<Extracted[] | undefined>;
47
+ putExtracted(hash: string, extracted: Extracted[]): Promise<void>;
48
+ }
49
+ export declare function localSnapshotStore(persistence: SnapshotPersistence, opts?: LocalSnapshotStoreOptions): LocalSnapshotStore;
50
+ //# sourceMappingURL=localSnapshotStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localSnapshotStore.d.ts","sourceRoot":"","sources":["../../../src/knowledge/stores/localSnapshotStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACR,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EACrF,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,mBAAmB;IAChC,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACpC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,yBAAyB;IACtC,mEAAmE;IACnE,GAAG,CAAC,IAAI,MAAM,CAAC;CAClB;AAyBD,qBAAa,kBAAmB,YAAW,cAAc;IAMzC,OAAO,CAAC,QAAQ,CAAC,WAAW;IALxC,OAAO,CAAC,QAAQ,CAAgC;IAChD,gFAAgF;IAChF,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEN,WAAW,EAAE,mBAAmB,EAAE,IAAI,GAAE,yBAA8B;YAIrF,IAAI;IAKlB,OAAO,CAAC,MAAM;IAUR,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAKhC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAK1C,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAKxD,KAAK,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,SAAS,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBrG,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYzE,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC;IAKlE,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpE;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,yBAAyB,GAAG,kBAAkB,CAEzH"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * knowledge/stores/localSnapshotStore.ts — a {@link KnowledgeStore} over one JSON snapshot,
3
+ * for a folder not linked to a project (PRD 38 §4.2, §5.1).
4
+ *
5
+ * Persistence is a port (`read`/`write` of the whole snapshot string), so this module has
6
+ * no `fs`: the memory MCP host persists it beside its own snapshot through its shared JSON
7
+ * file, a browser host in IndexedDB. Upserts use the platform's unique keys — a fact by
8
+ * `key`, a relation by `(from, to, kind)`, a scope by `rootId` — so linking a folder later
9
+ * uploads the same rows idempotently. The snapshot is written canonically (sorted), so
10
+ * equal content is equal bytes.
11
+ */
12
+ import { canonicalJson, compareStr, pathOfRef } from '../refs.js';
13
+ const relKey = (r) => `${r.from}\u0000${r.to}\u0000${r.kind}`;
14
+ function empty() {
15
+ return { version: 1, scopes: [], facts: {}, relations: {}, extracted: {} };
16
+ }
17
+ function parse(text) {
18
+ if (!text)
19
+ return empty();
20
+ try {
21
+ const s = JSON.parse(text);
22
+ return {
23
+ version: 1,
24
+ scopes: Array.isArray(s.scopes) ? s.scopes : [],
25
+ facts: s.facts && typeof s.facts === 'object' ? s.facts : {},
26
+ relations: s.relations && typeof s.relations === 'object' ? s.relations : {},
27
+ extracted: s.extracted && typeof s.extracted === 'object' ? s.extracted : {},
28
+ };
29
+ }
30
+ catch {
31
+ // A corrupt snapshot is rebuilt by the next review rather than failing every read.
32
+ return empty();
33
+ }
34
+ }
35
+ export class LocalSnapshotStore {
36
+ persistence;
37
+ snapshot;
38
+ /** Serializes mutations so two writers never interleave a read-modify-write. */
39
+ queue = Promise.resolve();
40
+ now;
41
+ constructor(persistence, opts = {}) {
42
+ this.persistence = persistence;
43
+ this.now = opts.now ?? (() => new Date().toISOString());
44
+ }
45
+ async load() {
46
+ if (!this.snapshot)
47
+ this.snapshot = parse(await this.persistence.read());
48
+ return this.snapshot;
49
+ }
50
+ mutate(fn) {
51
+ const run = this.queue.then(async () => {
52
+ const s = await this.load();
53
+ fn(s);
54
+ await this.persistence.write(serialize(s));
55
+ });
56
+ this.queue = run.catch(() => undefined);
57
+ return run;
58
+ }
59
+ async scopes() {
60
+ await this.queue;
61
+ return [...(await this.load()).scopes];
62
+ }
63
+ async facts(scope) {
64
+ await this.queue;
65
+ return [...((await this.load()).facts[scope.rootId] ?? [])];
66
+ }
67
+ async relations(scope) {
68
+ await this.queue;
69
+ return [...((await this.load()).relations[scope.rootId] ?? [])];
70
+ }
71
+ write(batch) {
72
+ const bad = [...batch.facts, ...batch.relations].find((x) => x.origin === 'extracted');
73
+ if (bad)
74
+ return Promise.reject(new Error('knowledge: extracted output is never stored'));
75
+ return this.mutate((s) => {
76
+ const rootId = batch.scope.rootId;
77
+ const prior = s.scopes.find((x) => x.rootId === rootId);
78
+ const merged = { ...(prior ?? {}), ...stripUndefined(batch.scope) };
79
+ s.scopes = [...s.scopes.filter((x) => x.rootId !== rootId), merged];
80
+ const facts = new Map((s.facts[rootId] ?? []).map((f) => [f.key, f]));
81
+ for (const f of batch.facts)
82
+ facts.set(f.key, { ...f });
83
+ s.facts[rootId] = [...facts.values()];
84
+ const relations = new Map((s.relations[rootId] ?? []).map((r) => [relKey(r), r]));
85
+ for (const r of batch.relations)
86
+ relations.set(relKey(r), { ...r });
87
+ s.relations[rootId] = [...relations.values()];
88
+ });
89
+ }
90
+ markStale(scope, sourceRef, currentHash) {
91
+ const path = pathOfRef(sourceRef);
92
+ return this.mutate((s) => {
93
+ const at = this.now();
94
+ const onSource = (ref) => path !== undefined && pathOfRef(ref) === path;
95
+ s.relations[scope.rootId] = (s.relations[scope.rootId] ?? []).map((r) => r.origin === 'model' && !r.staleAt && r.sourceHash !== currentHash && (onSource(r.from) || onSource(r.to))
96
+ ? { ...r, staleAt: at }
97
+ : r);
98
+ });
99
+ }
100
+ async getExtracted(hash) {
101
+ await this.queue;
102
+ return (await this.load()).extracted[hash];
103
+ }
104
+ putExtracted(hash, extracted) {
105
+ return this.mutate((s) => { s.extracted[hash] = extracted; });
106
+ }
107
+ }
108
+ export function localSnapshotStore(persistence, opts) {
109
+ return new LocalSnapshotStore(persistence, opts);
110
+ }
111
+ function stripUndefined(o) {
112
+ return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));
113
+ }
114
+ /** Canonical: scopes by rootId, facts by key, relations by (from, to, kind), keys sorted. */
115
+ function serialize(s) {
116
+ const sortRecord = (rec, by) => Object.fromEntries(Object.keys(rec).sort(compareStr).map((k) => [k, [...rec[k]].sort(by)]));
117
+ return canonicalJson({
118
+ version: 1,
119
+ scopes: [...s.scopes].sort((a, b) => compareStr(a.rootId, b.rootId)),
120
+ facts: sortRecord(s.facts, (a, b) => compareStr(a.key, b.key)),
121
+ relations: sortRecord(s.relations, (a, b) => compareStr(relKey(a), relKey(b))),
122
+ extracted: s.extracted,
123
+ });
124
+ }
125
+ //# sourceMappingURL=localSnapshotStore.js.map