@jigyasudham/veto 2.9.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +83 -4
  2. package/dist/cli/statusline.d.ts +9 -0
  3. package/dist/cli/statusline.d.ts.map +1 -1
  4. package/dist/cli/statusline.js +59 -3
  5. package/dist/cli/statusline.js.map +1 -1
  6. package/dist/cli.js +166 -5
  7. package/dist/cli.js.map +1 -1
  8. package/dist/memory/config.d.ts +10 -0
  9. package/dist/memory/config.d.ts.map +1 -1
  10. package/dist/memory/config.js +48 -8
  11. package/dist/memory/config.js.map +1 -1
  12. package/dist/memory/local.d.ts.map +1 -1
  13. package/dist/memory/local.js +32 -10
  14. package/dist/memory/local.js.map +1 -1
  15. package/dist/server/handlers/core.d.ts.map +1 -1
  16. package/dist/server/handlers/core.js +14 -1
  17. package/dist/server/handlers/core.js.map +1 -1
  18. package/dist/server/handlers/session.d.ts.map +1 -1
  19. package/dist/server/handlers/session.js +51 -2
  20. package/dist/server/handlers/session.js.map +1 -1
  21. package/dist/tools/definitions.d.ts +23 -3
  22. package/dist/tools/definitions.d.ts.map +1 -1
  23. package/dist/tools/definitions.js +11 -3
  24. package/dist/tools/definitions.js.map +1 -1
  25. package/dist/transcripts/adapters/claude.d.ts +27 -0
  26. package/dist/transcripts/adapters/claude.d.ts.map +1 -0
  27. package/dist/transcripts/adapters/claude.js +194 -0
  28. package/dist/transcripts/adapters/claude.js.map +1 -0
  29. package/dist/transcripts/archive.d.ts +23 -0
  30. package/dist/transcripts/archive.d.ts.map +1 -0
  31. package/dist/transcripts/archive.js +101 -0
  32. package/dist/transcripts/archive.js.map +1 -0
  33. package/dist/transcripts/cache.d.ts +66 -0
  34. package/dist/transcripts/cache.d.ts.map +1 -0
  35. package/dist/transcripts/cache.js +0 -0
  36. package/dist/transcripts/cache.js.map +1 -0
  37. package/dist/transcripts/chunk.d.ts +26 -0
  38. package/dist/transcripts/chunk.d.ts.map +1 -0
  39. package/dist/transcripts/chunk.js +54 -0
  40. package/dist/transcripts/chunk.js.map +1 -0
  41. package/dist/transcripts/config.d.ts +52 -0
  42. package/dist/transcripts/config.d.ts.map +1 -0
  43. package/dist/transcripts/config.js +135 -0
  44. package/dist/transcripts/config.js.map +1 -0
  45. package/dist/transcripts/embed.d.ts +58 -0
  46. package/dist/transcripts/embed.d.ts.map +1 -0
  47. package/dist/transcripts/embed.js +303 -0
  48. package/dist/transcripts/embed.js.map +1 -0
  49. package/dist/transcripts/expand.d.ts +20 -0
  50. package/dist/transcripts/expand.d.ts.map +1 -0
  51. package/dist/transcripts/expand.js +97 -0
  52. package/dist/transcripts/expand.js.map +1 -0
  53. package/dist/transcripts/ingest.d.ts +17 -0
  54. package/dist/transcripts/ingest.d.ts.map +1 -0
  55. package/dist/transcripts/ingest.js +120 -0
  56. package/dist/transcripts/ingest.js.map +1 -0
  57. package/dist/transcripts/manage.d.ts +42 -0
  58. package/dist/transcripts/manage.d.ts.map +1 -0
  59. package/dist/transcripts/manage.js +123 -0
  60. package/dist/transcripts/manage.js.map +1 -0
  61. package/dist/transcripts/mapping.d.ts +23 -0
  62. package/dist/transcripts/mapping.d.ts.map +1 -0
  63. package/dist/transcripts/mapping.js +42 -0
  64. package/dist/transcripts/mapping.js.map +1 -0
  65. package/dist/transcripts/mask.d.ts +26 -0
  66. package/dist/transcripts/mask.d.ts.map +1 -0
  67. package/dist/transcripts/mask.js +121 -0
  68. package/dist/transcripts/mask.js.map +1 -0
  69. package/dist/transcripts/on-save.d.ts +12 -0
  70. package/dist/transcripts/on-save.d.ts.map +1 -0
  71. package/dist/transcripts/on-save.js +37 -0
  72. package/dist/transcripts/on-save.js.map +1 -0
  73. package/dist/transcripts/pyramid.d.ts +38 -0
  74. package/dist/transcripts/pyramid.d.ts.map +1 -0
  75. package/dist/transcripts/pyramid.js +113 -0
  76. package/dist/transcripts/pyramid.js.map +1 -0
  77. package/dist/transcripts/recall.d.ts +46 -0
  78. package/dist/transcripts/recall.d.ts.map +1 -0
  79. package/dist/transcripts/recall.js +107 -0
  80. package/dist/transcripts/recall.js.map +1 -0
  81. package/dist/transcripts/schema.d.ts +79 -0
  82. package/dist/transcripts/schema.d.ts.map +1 -0
  83. package/dist/transcripts/schema.js +178 -0
  84. package/dist/transcripts/schema.js.map +1 -0
  85. package/dist/transcripts/search.d.ts +57 -0
  86. package/dist/transcripts/search.d.ts.map +1 -0
  87. package/dist/transcripts/search.js +332 -0
  88. package/dist/transcripts/search.js.map +1 -0
  89. package/dist/transcripts/store.d.ts +21 -0
  90. package/dist/transcripts/store.d.ts.map +1 -0
  91. package/dist/transcripts/store.js +105 -0
  92. package/dist/transcripts/store.js.map +1 -0
  93. package/dist/transcripts/toc.d.ts +18 -0
  94. package/dist/transcripts/toc.d.ts.map +1 -0
  95. package/dist/transcripts/toc.js +96 -0
  96. package/dist/transcripts/toc.js.map +1 -0
  97. package/dist/transcripts/tokenize.d.ts +14 -0
  98. package/dist/transcripts/tokenize.d.ts.map +1 -0
  99. package/dist/transcripts/tokenize.js +70 -0
  100. package/dist/transcripts/tokenize.js.map +1 -0
  101. package/dist/transcripts/vectors.d.ts +40 -0
  102. package/dist/transcripts/vectors.d.ts.map +1 -0
  103. package/dist/transcripts/vectors.js +203 -0
  104. package/dist/transcripts/vectors.js.map +1 -0
  105. package/package.json +3 -2
  106. package/server.json +2 -2
@@ -0,0 +1,303 @@
1
+ // Pure-JS Model2Vec inference — the semantic half of transcript recall.
2
+ //
3
+ // The model is frozen DATA, not an API: a quantized matrix plus a vocabulary.
4
+ // So this is a reimplementation against a pinned contract, not a translation
5
+ // of upstream code. The contract lives in the model package's `model.json`
6
+ // and every assumption below is asserted at load time, because the failure
7
+ // mode we care about is not a crash — it is plausible-looking wrong vectors.
8
+ //
9
+ // Correctness is pinned by tests/transcripts/embed.test.ts, which replays the
10
+ // golden vectors shipped alongside the weights (fixed text -> expected
11
+ // output, generated by the reference Python implementation in
12
+ // scripts/repack-model.py). If this file drifts, those fail.
13
+ //
14
+ // Zero dependencies, and nothing here runs at import: the model is resolved
15
+ // on first use and never at server boot (condition A2), so a missing or
16
+ // corrupt copy degrades search to BM25 instead of taking Veto down.
17
+ import { readFileSync } from 'node:fs';
18
+ import { createRequire } from 'node:module';
19
+ import { dirname, join } from 'node:path';
20
+ const _require = createRequire(import.meta.url);
21
+ /** Dim of the shipped table. Cross-checked against the header on load. */
22
+ const EXPECTED_FORMAT = 'veto-model/1';
23
+ // model2vec normalizes with this epsilon; matching it keeps golden vectors
24
+ // bit-comparable for zero-norm inputs instead of producing NaN.
25
+ const NORM_EPSILON = 1e-32;
26
+ let _model;
27
+ /** Package root holding the payload. Env override exists for tests and for
28
+ * local work before the model package is published. */
29
+ function modelDir() {
30
+ if (process.env.VETO_MODEL_DIR)
31
+ return join(process.env.VETO_MODEL_DIR, 'model');
32
+ // The package's exports map points at the header; the payload sits beside it.
33
+ return dirname(_require.resolve('@jigyasudham/veto-model/model.json'));
34
+ }
35
+ // ---------------------------------------------------------------------------
36
+ // BertNormalizer
37
+ //
38
+ // Order is upstream's and matters: clean -> CJK spacing -> accents -> case.
39
+ // ---------------------------------------------------------------------------
40
+ // Upstream treats tab/newline/CR as text, not control chars, and strips the
41
+ // rest of the C categories along with NUL and the replacement char.
42
+ const CONTROL = /\p{C}/u;
43
+ const PUNCT = /[!-/:-@[-`{-~]|\p{P}/u;
44
+ function isControl(ch) {
45
+ if (ch === '\t' || ch === '\n' || ch === '\r')
46
+ return false;
47
+ return CONTROL.test(ch);
48
+ }
49
+ function isWhitespace(ch) {
50
+ return ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r' || /\s/u.test(ch);
51
+ }
52
+ // The CJK blocks BERT spaces out so every ideograph becomes its own word.
53
+ // Hiragana/katakana are deliberately absent upstream — they tokenize as runs.
54
+ function isChinese(cp) {
55
+ return ((cp >= 0x4e00 && cp <= 0x9fff) ||
56
+ (cp >= 0x3400 && cp <= 0x4dbf) ||
57
+ (cp >= 0x20000 && cp <= 0x2a6df) ||
58
+ (cp >= 0x2a700 && cp <= 0x2b73f) ||
59
+ (cp >= 0x2b740 && cp <= 0x2b81f) ||
60
+ (cp >= 0x2b820 && cp <= 0x2ceaf) ||
61
+ (cp >= 0xf900 && cp <= 0xfaff) ||
62
+ (cp >= 0x2f800 && cp <= 0x2fa1f));
63
+ }
64
+ function normalize(text, m) {
65
+ let out = text;
66
+ if (m.cleanText) {
67
+ let buf = '';
68
+ for (const ch of out) {
69
+ // NUL and U+FFFD as escapes, matching upstream's filter. Literals
70
+ // here embed raw control bytes and make tools treat this file as binary.
71
+ if (ch === '\u0000' || ch === '\uFFFD' || isControl(ch))
72
+ continue;
73
+ buf += isWhitespace(ch) ? ' ' : ch;
74
+ }
75
+ out = buf;
76
+ }
77
+ if (m.handleChineseChars) {
78
+ let buf = '';
79
+ for (const ch of out) {
80
+ const cp = ch.codePointAt(0);
81
+ buf += isChinese(cp) ? ` ${ch} ` : ch;
82
+ }
83
+ out = buf;
84
+ }
85
+ // `strip_accents: null` in tokenizer.json does NOT mean "off" — upstream
86
+ // resolves it to the value of `lowercase`. Reading the null literally is
87
+ // the silent-divergence bug this whole file is most likely to have; it only
88
+ // shows on accented text, so the golden set carries "café naïve résumé".
89
+ if (m.stripAccents)
90
+ out = out.normalize('NFD').replace(/\p{Mn}/gu, '');
91
+ if (m.lowercase)
92
+ out = out.toLowerCase();
93
+ return out;
94
+ }
95
+ // ---------------------------------------------------------------------------
96
+ // BertPreTokenizer — split on whitespace, then isolate punctuation as its own
97
+ // word. "Isolated" means the punctuation is KEPT as a token, not discarded.
98
+ // ---------------------------------------------------------------------------
99
+ function preTokenize(text) {
100
+ const words = [];
101
+ for (const chunk of text.split(/\s+/u)) {
102
+ if (!chunk)
103
+ continue;
104
+ let cur = '';
105
+ for (const ch of chunk) {
106
+ if (PUNCT.test(ch)) {
107
+ if (cur) {
108
+ words.push(cur);
109
+ cur = '';
110
+ }
111
+ words.push(ch);
112
+ }
113
+ else {
114
+ cur += ch;
115
+ }
116
+ }
117
+ if (cur)
118
+ words.push(cur);
119
+ }
120
+ return words;
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // WordPiece — greedy longest-match-first, continuation pieces carry "##".
124
+ // Operates on code points, not UTF-16 units, so astral characters (emoji)
125
+ // are matched and length-capped as single characters like upstream does.
126
+ // ---------------------------------------------------------------------------
127
+ function wordPiece(word, m, out) {
128
+ const chars = Array.from(word);
129
+ if (chars.length > m.maxWordChars) {
130
+ if (m.unkId !== undefined)
131
+ out.push(m.unkId);
132
+ return;
133
+ }
134
+ const pieces = [];
135
+ let start = 0;
136
+ while (start < chars.length) {
137
+ let end = chars.length;
138
+ let id;
139
+ while (start < end) {
140
+ const sub = (start > 0 ? m.prefix : '') + chars.slice(start, end).join('');
141
+ id = m.vocab.get(sub);
142
+ if (id !== undefined)
143
+ break;
144
+ end -= 1;
145
+ }
146
+ // No prefix of the remainder is in the vocabulary: upstream discards every
147
+ // piece found so far and emits a single UNK for the whole word.
148
+ if (id === undefined) {
149
+ if (m.unkId !== undefined)
150
+ out.push(m.unkId);
151
+ return;
152
+ }
153
+ pieces.push(id);
154
+ start = end;
155
+ }
156
+ for (const p of pieces)
157
+ out.push(p);
158
+ }
159
+ /** Token ids for `text`, with no special tokens added (the shipped contract). */
160
+ export function tokenizeForEmbedding(text, model = load()) {
161
+ const ids = [];
162
+ for (const word of preTokenize(normalize(text, model)))
163
+ wordPiece(word, model, ids);
164
+ // Upstream drops UNK entirely rather than pooling it (model2vec model.py:166,
165
+ // "necessary for word-level models"), so an out-of-vocab word contributes
166
+ // nothing instead of dragging every vector toward a shared UNK row. Filtering
167
+ // here rather than skipping at emit time matches upstream for the odd case of
168
+ // a literal "[UNK]" in the input, which WordPiece would otherwise keep.
169
+ return model.unkId === undefined ? ids : ids.filter((id) => id !== model.unkId);
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // Load
173
+ // ---------------------------------------------------------------------------
174
+ function load() {
175
+ if (_model)
176
+ return _model;
177
+ const dir = modelDir();
178
+ const header = JSON.parse(readFileSync(join(dir, 'model.json'), 'utf8'));
179
+ if (header.format !== EXPECTED_FORMAT) {
180
+ throw new Error(`veto-model: unsupported payload format ${header.format} (expected ${EXPECTED_FORMAT})`);
181
+ }
182
+ // model2vec multiplies token rows by an optional per-token weight vector
183
+ // before pooling. potion-base-8M ships none, and this implementation pools
184
+ // unweighted — so a model that DOES ship them must not load silently.
185
+ if (header.inference.per_token_weights != null) {
186
+ throw new Error('veto-model: payload declares per-token weights, which this implementation does not apply');
187
+ }
188
+ if (header.inference.add_special_tokens) {
189
+ throw new Error('veto-model: payload expects special tokens, which this implementation does not add');
190
+ }
191
+ if (header.inference.pooling !== 'mean' || !header.inference.normalize) {
192
+ throw new Error(`veto-model: unsupported inference contract (${header.inference.pooling}, normalize=${header.inference.normalize})`);
193
+ }
194
+ const { vocab_size: vocabSize, dim } = header;
195
+ const tableBuf = readFileSync(join(dir, 'embeddings.int8.bin'));
196
+ const scaleBuf = readFileSync(join(dir, 'scales.f32.bin'));
197
+ if (tableBuf.length !== vocabSize * dim) {
198
+ throw new Error(`veto-model: table is ${tableBuf.length} bytes, expected ${vocabSize * dim}`);
199
+ }
200
+ if (scaleBuf.length !== vocabSize * 4) {
201
+ throw new Error(`veto-model: scales are ${scaleBuf.length} bytes, expected ${vocabSize * 4}`);
202
+ }
203
+ const tok = JSON.parse(readFileSync(join(dir, 'tokenizer.json'), 'utf8'));
204
+ const norm = tok.normalizer ?? {};
205
+ const tm = tok.model ?? {};
206
+ if (tm.type !== 'WordPiece' || norm.type !== 'BertNormalizer' || tok.pre_tokenizer?.type !== 'BertPreTokenizer') {
207
+ throw new Error(`veto-model: unsupported tokenizer (${norm.type} / ${tok.pre_tokenizer?.type} / ${tm.type})`);
208
+ }
209
+ const vocab = new Map(Object.entries(tm.vocab ?? {}));
210
+ if (vocab.size !== vocabSize) {
211
+ throw new Error(`veto-model: vocab has ${vocab.size} entries, table has ${vocabSize} rows`);
212
+ }
213
+ const lowercase = norm.lowercase !== false;
214
+ const model = {
215
+ header,
216
+ dim,
217
+ table: new Int8Array(tableBuf.buffer, tableBuf.byteOffset, tableBuf.length),
218
+ // Little-endian float32; Node is LE on every supported platform, and a
219
+ // byteOffset-aligned view would be brittle, so copy through a DataView.
220
+ scales: readScales(scaleBuf, vocabSize),
221
+ vocab,
222
+ unkId: tm.unk_token ? vocab.get(tm.unk_token) : undefined,
223
+ prefix: tm.continuing_subword_prefix ?? '##',
224
+ maxWordChars: tm.max_input_chars_per_word ?? 100,
225
+ lowercase,
226
+ // Resolve null the way upstream does — see normalize().
227
+ stripAccents: norm.strip_accents == null ? lowercase : norm.strip_accents,
228
+ cleanText: norm.clean_text !== false,
229
+ handleChineseChars: norm.handle_chinese_chars !== false,
230
+ };
231
+ if (model.stripAccents !== header.tokenizer.strip_accents_effective) {
232
+ throw new Error('veto-model: resolved strip_accents disagrees with the payload header');
233
+ }
234
+ _model = model;
235
+ return model;
236
+ }
237
+ function readScales(buf, n) {
238
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.length);
239
+ const out = new Float32Array(n);
240
+ for (let i = 0; i < n; i++)
241
+ out[i] = view.getFloat32(i * 4, true);
242
+ return out;
243
+ }
244
+ // ---------------------------------------------------------------------------
245
+ // Embed
246
+ // ---------------------------------------------------------------------------
247
+ /**
248
+ * Embed `text` into a unit-length vector.
249
+ *
250
+ * Gather each token's row, dequantize it by that row's scale, mean-pool, then
251
+ * L2-normalize. Text with no tokens (empty or punctuation-free-of-vocab)
252
+ * yields the zero vector rather than NaN — upstream's behaviour, and the
253
+ * reason the epsilon is in the denominator.
254
+ */
255
+ export function embed(text, model = load()) {
256
+ const ids = tokenizeForEmbedding(text, model);
257
+ const { dim, table, scales } = model;
258
+ const out = new Float32Array(dim);
259
+ if (ids.length === 0)
260
+ return out;
261
+ for (const id of ids) {
262
+ const base = id * dim;
263
+ const scale = scales[id];
264
+ for (let d = 0; d < dim; d++)
265
+ out[d] += table[base + d] * scale;
266
+ }
267
+ let norm = 0;
268
+ for (let d = 0; d < dim; d++) {
269
+ out[d] /= ids.length;
270
+ norm += out[d] * out[d];
271
+ }
272
+ norm = Math.sqrt(norm) + NORM_EPSILON;
273
+ for (let d = 0; d < dim; d++)
274
+ out[d] /= norm;
275
+ return out;
276
+ }
277
+ /** Cosine similarity of two unit vectors — a dot product, given the inputs. */
278
+ export function cosine(a, b) {
279
+ let s = 0;
280
+ for (let i = 0; i < a.length; i++)
281
+ s += a[i] * b[i];
282
+ return s;
283
+ }
284
+ /** True when the model package resolves and its payload passes validation. */
285
+ export function embeddingsAvailable() {
286
+ try {
287
+ load();
288
+ return true;
289
+ }
290
+ catch {
291
+ return false;
292
+ }
293
+ }
294
+ /** Upstream model id + revision of the loaded payload, for recall provenance. */
295
+ export function modelProvenance() {
296
+ const { upstream } = load().header;
297
+ return { model_id: upstream.model_id, revision: upstream.revision };
298
+ }
299
+ /** Drop the cached table. Tests only — production loads once per process. */
300
+ export function resetModelCache() {
301
+ _model = undefined;
302
+ }
303
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../src/transcripts/embed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { ArchiveRow } from './schema.js';
2
+ export declare function _resetExpandCache(): void;
3
+ export type ExpandResult = {
4
+ ok: boolean;
5
+ reason?: string;
6
+ text?: string;
7
+ secretsRedacted?: number;
8
+ source?: string;
9
+ sourceSessionId?: string;
10
+ provenance?: string;
11
+ fromSeq?: number;
12
+ toSeq?: number;
13
+ };
14
+ /** Serve a byte range from an archive, masked. Bounds are validated first. */
15
+ export declare function expandBytes(archive: ArchiveRow, offset: number, length: number): ExpandResult;
16
+ /** Expand a single event to its exact source line (masked), with a turn/timestamp citation. */
17
+ export declare function expandEvent(eventId: string): ExpandResult;
18
+ /** Expand a seq range to the exact contiguous L0 lines it covers (masked). */
19
+ export declare function expandRange(archiveId: string, fromSeq: number, toSeq: number): ExpandResult;
20
+ //# sourceMappingURL=expand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expand.d.ts","sourceRoot":"","sources":["../../src/transcripts/expand.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,aAAa,CAAC;AAYxD,wBAAgB,iBAAiB,IAAI,IAAI,CAAmB;AAE5D,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkBF,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAa7F;AAED,+FAA+F;AAC/F,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CASzD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAa3F"}
@@ -0,0 +1,97 @@
1
+ // Mask-on-expansion: serve exact L0 bytes, always masked (VERSION-3 item 6, Step 7).
2
+ //
3
+ // L0 is stored RAW (Rule 0), but nothing leaves this module unmasked. Every byte
4
+ // range served out of an archive passes through mask() first, so even though a
5
+ // secret may sit in the raw archive on disk, it can never transit into an AI
6
+ // context through Veto. Offsets are validated against the archive length before
7
+ // any slice (S6) so a corrupt index can never read out of bounds. This is the
8
+ // read-side counterpart to Step 6's mask-on-write, and it is tested here BEFORE
9
+ // the recall tool (Step 11) is allowed to trust it.
10
+ import { readFileSync, existsSync, statSync } from 'node:fs';
11
+ import { gunzipSync } from 'node:zlib';
12
+ import { getTranscriptsDb } from './store.js';
13
+ import { mask } from './mask.js';
14
+ // Small 1-entry cache so a recall that expands several ranges gunzips once.
15
+ let _cache = null;
16
+ function loadArchive(path) {
17
+ const { mtimeMs } = statSync(path);
18
+ if (_cache && _cache.path === path && _cache.mtimeMs === mtimeMs)
19
+ return _cache.buf;
20
+ const buf = gunzipSync(readFileSync(path));
21
+ _cache = { path, mtimeMs, buf };
22
+ return buf;
23
+ }
24
+ export function _resetExpandCache() { _cache = null; }
25
+ function getArchiveById(id) {
26
+ const db = getTranscriptsDb();
27
+ return db.prepare(`SELECT * FROM archives WHERE id = ?`).get(id) ?? null;
28
+ }
29
+ function cite(archive, loc) {
30
+ const parts = [archive.source, `session ${archive.source_session_id}`];
31
+ if (loc.seq !== undefined) {
32
+ parts.push(loc.toSeq !== undefined && loc.toSeq !== loc.seq ? `turns ${loc.seq}-${loc.toSeq}` : `turn ${loc.seq}`);
33
+ }
34
+ if (loc.ts)
35
+ parts.push(loc.ts);
36
+ if (loc.offset !== undefined && loc.length !== undefined)
37
+ parts.push(`bytes ${loc.offset}-${loc.offset + loc.length}`);
38
+ return `[${parts.join(' · ')}]`;
39
+ }
40
+ /** Serve a byte range from an archive, masked. Bounds are validated first. */
41
+ export function expandBytes(archive, offset, length) {
42
+ if (!existsSync(archive.archive_path))
43
+ return { ok: false, reason: 'archive_missing' };
44
+ let buf;
45
+ try {
46
+ buf = loadArchive(archive.archive_path);
47
+ }
48
+ catch {
49
+ return { ok: false, reason: 'unreadable' };
50
+ }
51
+ if (!Number.isInteger(offset) || !Number.isInteger(length) || offset < 0 || length < 0 || offset + length > buf.length) {
52
+ return { ok: false, reason: 'out_of_bounds' };
53
+ }
54
+ const m = mask(buf.toString('utf8', offset, offset + length));
55
+ return {
56
+ ok: true, text: m.text, secretsRedacted: m.count,
57
+ source: archive.source, sourceSessionId: archive.source_session_id,
58
+ provenance: cite(archive, { offset, length }),
59
+ };
60
+ }
61
+ /** Expand a single event to its exact source line (masked), with a turn/timestamp citation. */
62
+ export function expandEvent(eventId) {
63
+ const db = getTranscriptsDb();
64
+ const ev = db.prepare(`SELECT * FROM events WHERE id = ?`).get(eventId) ?? null;
65
+ if (!ev)
66
+ return { ok: false, reason: 'event_not_found' };
67
+ const archive = getArchiveById(ev.archive_id);
68
+ if (!archive)
69
+ return { ok: false, reason: 'archive_not_found' };
70
+ const r = expandBytes(archive, ev.raw_offset, ev.raw_length);
71
+ if (r.ok) {
72
+ r.provenance = cite(archive, { seq: ev.seq, ts: ev.ts_utc });
73
+ r.fromSeq = ev.seq;
74
+ r.toSeq = ev.seq;
75
+ }
76
+ return r;
77
+ }
78
+ /** Expand a seq range to the exact contiguous L0 lines it covers (masked). */
79
+ export function expandRange(archiveId, fromSeq, toSeq) {
80
+ const db = getTranscriptsDb();
81
+ const archive = getArchiveById(archiveId);
82
+ if (!archive)
83
+ return { ok: false, reason: 'archive_not_found' };
84
+ const rows = db.prepare(`SELECT raw_offset, raw_length FROM events WHERE archive_id = ? AND seq BETWEEN ? AND ? ORDER BY seq`).all(archiveId, Math.min(fromSeq, toSeq), Math.max(fromSeq, toSeq));
85
+ if (rows.length === 0)
86
+ return { ok: false, reason: 'no_events' };
87
+ const start = Math.min(...rows.map(r => r.raw_offset));
88
+ const end = Math.max(...rows.map(r => r.raw_offset + r.raw_length));
89
+ const r = expandBytes(archive, start, end - start);
90
+ if (r.ok) {
91
+ r.provenance = cite(archive, { seq: fromSeq, toSeq });
92
+ r.fromSeq = fromSeq;
93
+ r.toSeq = toSeq;
94
+ }
95
+ return r;
96
+ }
97
+ //# sourceMappingURL=expand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expand.js","sourceRoot":"","sources":["../../src/transcripts/expand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { type EventRow } from './schema.js';
2
+ export declare const PARSER_VERSION = 2;
3
+ export type IngestStatus = 'indexed' | 'already_indexed' | 'not_found' | 'archive_missing' | 'session_mismatch' | 'error';
4
+ export type IngestResult = {
5
+ status: IngestStatus;
6
+ events?: number;
7
+ secretsRedacted?: number;
8
+ reason?: string;
9
+ };
10
+ /** (Re)derive events for one archive. Best-effort: never throws. */
11
+ export declare function ingestArchive(archiveId: string): IngestResult;
12
+ /** Ensure an archive is indexed at the current parser version (lazy trigger for recall). */
13
+ export declare function ensureIndexed(archiveId: string): IngestResult;
14
+ /** Ingest by source session id (looks up its archive). */
15
+ export declare function ingestSession(sourceSessionId: string, source?: string): IngestResult;
16
+ export declare function getEvents(archiveId: string): EventRow[];
17
+ //# sourceMappingURL=ingest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/transcripts/ingest.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAqC,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAO/E,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,MAAM,MAAM,YAAY,GACpB,SAAS,GAAG,iBAAiB,GAAG,WAAW,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,OAAO,CAAC;AAEnG,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAWF,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA0F7D;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAE7D;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,YAAY,CAOtF;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,CAGvD"}
@@ -0,0 +1,120 @@
1
+ // Ingest: derive normalized events from an L0 archive (VERSION-3 item 6, Step 6).
2
+ //
3
+ // Idempotent + lazy via the archive's parser_version + indexed_through_seq
4
+ // watermark: a fresh or grown archive (Step 5 resets both) gets (re)indexed; an
5
+ // unchanged, already-indexed archive is a no-op; a parser upgrade re-derives.
6
+ // Session-id verification (council/devil): if the archive's session id does not
7
+ // appear anywhere in the parsed file, the mapping pointed at the wrong transcript
8
+ // and we SKIP rather than index a mismatched file.
9
+ import { readFileSync, existsSync } from 'node:fs';
10
+ import { gunzipSync } from 'node:zlib';
11
+ import { randomUUID } from 'node:crypto';
12
+ import { getTranscriptsDb } from './store.js';
13
+ import { resetCaches } from './cache.js';
14
+ import { parseClaudeTranscript } from './adapters/claude.js';
15
+ import { tokenize } from './tokenize.js';
16
+ import { SEARCHABLE_KINDS } from './schema.js';
17
+ const SEARCHABLE = new Set(SEARCHABLE_KINDS);
18
+ // Bump when the parser changes in a way that should re-derive existing archives.
19
+ // v2: the portable search index replaced events_fts — archives ingested at v1
20
+ // have events but no search_docs/postings rows, so they must re-derive.
21
+ export const PARSER_VERSION = 2;
22
+ function getArchiveById(archiveId) {
23
+ const db = getTranscriptsDb();
24
+ return db.prepare(`SELECT * FROM archives WHERE id = ?`).get(archiveId) ?? null;
25
+ }
26
+ function needsIndexing(row) {
27
+ return row.parser_version !== PARSER_VERSION;
28
+ }
29
+ /** (Re)derive events for one archive. Best-effort: never throws. */
30
+ export function ingestArchive(archiveId) {
31
+ try {
32
+ const db = getTranscriptsDb();
33
+ const row = getArchiveById(archiveId);
34
+ if (!row)
35
+ return { status: 'not_found' };
36
+ if (!needsIndexing(row))
37
+ return { status: 'already_indexed', events: row.indexed_through_seq };
38
+ if (!existsSync(row.archive_path))
39
+ return { status: 'archive_missing' };
40
+ const buf = gunzipSync(readFileSync(row.archive_path));
41
+ const { events, sessionIds, secretsRedacted } = parseClaudeTranscript(buf);
42
+ if (sessionIds.size > 0 && !sessionIds.has(row.source_session_id)) {
43
+ return { status: 'session_mismatch', reason: 'archive session id not present in transcript' };
44
+ }
45
+ const ins = db.prepare(`INSERT INTO events (id, archive_id, source_session_id, seq, line_index, block_index, kind,
46
+ source_type, role, tool_name, text, secret_count, event_uuid, parent_uuid, is_sidechain,
47
+ ts_source, ts_utc, raw_offset, raw_length)
48
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
49
+ const insDoc = db.prepare(`INSERT INTO search_docs (event_id, archive_id, source_session_id, project_dir, seq, kind, len)
50
+ VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING id`);
51
+ const insTerm = db.prepare(`INSERT INTO search_terms (term) VALUES (?)
52
+ ON CONFLICT(term) DO UPDATE SET term = term RETURNING id`);
53
+ const insPosting = db.prepare(`INSERT INTO search_postings (term_id, doc_id, tf) VALUES (?, ?, ?)`);
54
+ // Term ids are cached per ingest run — a session reuses its vocabulary
55
+ // heavily, so most lookups never hit the upsert.
56
+ const termIds = new Map();
57
+ const termId = (term) => {
58
+ let id = termIds.get(term);
59
+ if (id === undefined) {
60
+ id = Number(insTerm.get(term).id);
61
+ termIds.set(term, id);
62
+ }
63
+ return id;
64
+ };
65
+ db.exec('BEGIN');
66
+ try {
67
+ db.prepare(`DELETE FROM events WHERE archive_id = ?`).run(archiveId);
68
+ db.prepare(`DELETE FROM search_postings WHERE doc_id IN (SELECT id FROM search_docs WHERE archive_id = ?)`).run(archiveId);
69
+ // Doc ids are reassigned by this re-derive, so stale vectors would not
70
+ // just orphan — they would silently re-attach to the wrong events.
71
+ db.prepare(`DELETE FROM search_vectors WHERE doc_id IN (SELECT id FROM search_docs WHERE archive_id = ?)`).run(archiveId);
72
+ db.prepare(`DELETE FROM search_docs WHERE archive_id = ?`).run(archiveId);
73
+ for (const e of events) {
74
+ const eventId = randomUUID();
75
+ ins.run(eventId, archiveId, row.source_session_id, e.seq, e.lineIndex, e.blockIndex, e.kind, e.sourceType, e.role, e.toolName, e.text, e.secretCount, e.eventUuid, e.parentUuid, e.isSidechain ? 1 : 0, e.tsSource, e.tsUtc, e.rawOffset, e.rawLength);
76
+ // Index the searchable, non-empty events (text is already masked).
77
+ if (SEARCHABLE.has(e.kind) && e.text && e.text.trim()) {
78
+ const tokens = tokenize(e.text);
79
+ const tf = new Map();
80
+ for (const t of tokens)
81
+ tf.set(t, (tf.get(t) ?? 0) + 1);
82
+ const docId = Number(insDoc.get(eventId, archiveId, row.source_session_id, row.project_dir, e.seq, e.kind, tokens.length).id);
83
+ for (const [term, count] of tf)
84
+ insPosting.run(termId(term), docId, count);
85
+ }
86
+ }
87
+ // Vectors were just dropped with their docs; clearing the marker lets
88
+ // the lazy embed pass rebuild them without re-parsing the transcript.
89
+ db.prepare(`UPDATE archives SET indexed_through_seq = ?, parser_version = ?, chunker_version = 0, embed_model = NULL
90
+ WHERE id = ?`).run(events.length, PARSER_VERSION, archiveId);
91
+ db.exec('COMMIT');
92
+ resetCaches();
93
+ }
94
+ catch (e) {
95
+ db.exec('ROLLBACK');
96
+ throw e;
97
+ }
98
+ return { status: 'indexed', events: events.length, secretsRedacted };
99
+ }
100
+ catch (e) {
101
+ return { status: 'error', reason: e instanceof Error ? e.message : String(e) };
102
+ }
103
+ }
104
+ /** Ensure an archive is indexed at the current parser version (lazy trigger for recall). */
105
+ export function ensureIndexed(archiveId) {
106
+ return ingestArchive(archiveId);
107
+ }
108
+ /** Ingest by source session id (looks up its archive). */
109
+ export function ingestSession(sourceSessionId, source = 'claude') {
110
+ const db = getTranscriptsDb();
111
+ const row = db.prepare(`SELECT id FROM archives WHERE source = ? AND source_session_id = ?`).get(source, sourceSessionId) ?? null;
112
+ if (!row)
113
+ return { status: 'not_found' };
114
+ return ingestArchive(row.id);
115
+ }
116
+ export function getEvents(archiveId) {
117
+ const db = getTranscriptsDb();
118
+ return db.prepare(`SELECT * FROM events WHERE archive_id = ? ORDER BY seq`).all(archiveId);
119
+ }
120
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/transcripts/ingest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { type Segment } from './toc.js';
2
+ import { type SessionFacts } from './pyramid.js';
3
+ export type ArchiveSummary = {
4
+ sourceSessionId: string;
5
+ source: string;
6
+ projectDir: string | null;
7
+ events: number;
8
+ sourceBytes: number;
9
+ archiveBytes: number;
10
+ capturedAt: string;
11
+ updatedAt: string;
12
+ indexed: boolean;
13
+ };
14
+ export declare function listArchives(opts?: {
15
+ projectDir?: string;
16
+ limit?: number;
17
+ }): ArchiveSummary[];
18
+ export type ArchiveDetail = {
19
+ summary: ArchiveSummary;
20
+ toc: Segment[];
21
+ facts: SessionFacts;
22
+ } | null;
23
+ export declare function showArchive(sourceSessionId: string, source?: string): ArchiveDetail;
24
+ export type PurgeResult = {
25
+ archives: number;
26
+ events: number;
27
+ indexRows: number;
28
+ files: number;
29
+ mappings: number;
30
+ };
31
+ export declare function purgeSession(sourceSessionId: string, source?: string): PurgeResult;
32
+ export declare function purgeProject(projectDir: string): PurgeResult;
33
+ export declare function purgeAll(): PurgeResult;
34
+ export type DiskUsage = {
35
+ archives: number;
36
+ archiveBytes: number;
37
+ dbBytes: number;
38
+ totalBytes: number;
39
+ };
40
+ export declare function transcriptsDiskUsage(): DiskUsage;
41
+ export declare function fmtBytes(n: number): string;
42
+ //# sourceMappingURL=manage.d.ts.map