@jigyasudham/veto 3.1.2 → 3.2.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 (79) hide show
  1. package/README.md +26 -1
  2. package/dist/cli.js +51 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/host.d.ts +23 -0
  5. package/dist/host.d.ts.map +1 -0
  6. package/dist/host.js +81 -0
  7. package/dist/host.js.map +1 -0
  8. package/dist/server/handlers/observability.d.ts.map +1 -1
  9. package/dist/server/handlers/observability.js +16 -1
  10. package/dist/server/handlers/observability.js.map +1 -1
  11. package/dist/server/handlers/session.d.ts.map +1 -1
  12. package/dist/server/handlers/session.js +18 -5
  13. package/dist/server/handlers/session.js.map +1 -1
  14. package/dist/server.d.ts.map +1 -1
  15. package/dist/server.js +17 -0
  16. package/dist/server.js.map +1 -1
  17. package/dist/tools/definitions.d.ts +3 -3
  18. package/dist/tools/definitions.js +3 -3
  19. package/dist/tools/definitions.js.map +1 -1
  20. package/dist/transcripts/adapters/claude.d.ts +2 -24
  21. package/dist/transcripts/adapters/claude.d.ts.map +1 -1
  22. package/dist/transcripts/adapters/claude.js +31 -129
  23. package/dist/transcripts/adapters/claude.js.map +1 -1
  24. package/dist/transcripts/adapters/codex.d.ts +4 -0
  25. package/dist/transcripts/adapters/codex.d.ts.map +1 -0
  26. package/dist/transcripts/adapters/codex.js +120 -0
  27. package/dist/transcripts/adapters/codex.js.map +1 -0
  28. package/dist/transcripts/adapters/gemini.d.ts +4 -0
  29. package/dist/transcripts/adapters/gemini.d.ts.map +1 -0
  30. package/dist/transcripts/adapters/gemini.js +124 -0
  31. package/dist/transcripts/adapters/gemini.js.map +1 -0
  32. package/dist/transcripts/adapters/index.d.ts +16 -0
  33. package/dist/transcripts/adapters/index.d.ts.map +1 -0
  34. package/dist/transcripts/adapters/index.js +36 -0
  35. package/dist/transcripts/adapters/index.js.map +1 -0
  36. package/dist/transcripts/adapters/jsonl.d.ts +67 -0
  37. package/dist/transcripts/adapters/jsonl.d.ts.map +1 -0
  38. package/dist/transcripts/adapters/jsonl.js +138 -0
  39. package/dist/transcripts/adapters/jsonl.js.map +1 -0
  40. package/dist/transcripts/archive.d.ts.map +1 -1
  41. package/dist/transcripts/archive.js +2 -1
  42. package/dist/transcripts/archive.js.map +1 -1
  43. package/dist/transcripts/discover.d.ts +50 -0
  44. package/dist/transcripts/discover.d.ts.map +1 -0
  45. package/dist/transcripts/discover.js +247 -0
  46. package/dist/transcripts/discover.js.map +1 -0
  47. package/dist/transcripts/expand.d.ts +33 -2
  48. package/dist/transcripts/expand.d.ts.map +1 -1
  49. package/dist/transcripts/expand.js +95 -9
  50. package/dist/transcripts/expand.js.map +1 -1
  51. package/dist/transcripts/ingest.js +2 -2
  52. package/dist/transcripts/ingest.js.map +1 -1
  53. package/dist/transcripts/mapping.d.ts +8 -0
  54. package/dist/transcripts/mapping.d.ts.map +1 -1
  55. package/dist/transcripts/mapping.js +1 -1
  56. package/dist/transcripts/mapping.js.map +1 -1
  57. package/dist/transcripts/metric.d.ts +80 -0
  58. package/dist/transcripts/metric.d.ts.map +1 -0
  59. package/dist/transcripts/metric.js +306 -0
  60. package/dist/transcripts/metric.js.map +1 -0
  61. package/dist/transcripts/on-save.d.ts +18 -0
  62. package/dist/transcripts/on-save.d.ts.map +1 -1
  63. package/dist/transcripts/on-save.js +41 -2
  64. package/dist/transcripts/on-save.js.map +1 -1
  65. package/dist/transcripts/pyramid.d.ts +8 -0
  66. package/dist/transcripts/pyramid.d.ts.map +1 -1
  67. package/dist/transcripts/pyramid.js +40 -6
  68. package/dist/transcripts/pyramid.js.map +1 -1
  69. package/dist/transcripts/recall.d.ts +2 -0
  70. package/dist/transcripts/recall.d.ts.map +1 -1
  71. package/dist/transcripts/recall.js +36 -12
  72. package/dist/transcripts/recall.js.map +1 -1
  73. package/dist/transcripts/search.d.ts.map +1 -1
  74. package/dist/transcripts/search.js +20 -11
  75. package/dist/transcripts/search.js.map +1 -1
  76. package/dist/transcripts/toc.js +3 -4
  77. package/dist/transcripts/toc.js.map +1 -1
  78. package/package.json +2 -2
  79. package/server.json +2 -2
@@ -0,0 +1,80 @@
1
+ /** Below this many eligible resumes the result is noise, and reports as such. */
2
+ export declare const MIN_ELIGIBLE_RESUMES = 30;
3
+ /** A window shorter than this cannot show a habit, only a mood. */
4
+ export declare const MIN_WINDOW_DAYS = 30;
5
+ /** Eligible resumes that reach for recall. */
6
+ export declare const ATTACH_TARGET = 0.3;
7
+ /**
8
+ * Ceiling on queries the AI had to REFORMULATE.
9
+ *
10
+ * This deliberately replaced an "expansion rate >= 50%" target, which was
11
+ * self-defeating: it assumed opening an excerpt is the desired outcome, so
12
+ * improving phase 1 until its snippets answer the question outright would have
13
+ * DRIVEN THE NUMBER DOWN and scored the improvement as a failure. Expansion is
14
+ * still reported, but it is not a target.
15
+ *
16
+ * Reformulation is gated instead because it is the one unambiguous signal in the
17
+ * data: a query followed by another query means phase 1 did not serve the first
18
+ * one. A query followed by nothing cannot be read — satisfied and gave-up look
19
+ * identical from here — so it is reported as `silent` and never scored.
20
+ */
21
+ export declare const REFORMULATION_CEILING = 0.4;
22
+ /**
23
+ * How long after a resume a recall query still counts as belonging to it (and
24
+ * likewise a query → its expansion). Long enough for a real working session,
25
+ * short enough that tomorrow's query is not credited to yesterday's resume.
26
+ */
27
+ export declare const ATTRIBUTION_WINDOW_HOURS = 6;
28
+ export type MetricVerdict = 'insufficient_data' | 'healthy' | 'not_reached_for' | 'retrieval_not_landing';
29
+ export type RecallMetric = {
30
+ window: {
31
+ from: string | null;
32
+ to: string | null;
33
+ days: number;
34
+ };
35
+ coverage: {
36
+ captureEnabled: boolean;
37
+ captureEnabledAt: string | null;
38
+ archives: number;
39
+ events: number;
40
+ projectsWithArchives: string[];
41
+ };
42
+ resumes: {
43
+ total: number;
44
+ inWindow: number;
45
+ eligible: number;
46
+ ineligible: number;
47
+ unscoped: number;
48
+ };
49
+ attach: {
50
+ attached: number;
51
+ rate: number | null;
52
+ };
53
+ /**
54
+ * Every query lands in exactly one bucket. `silent` is deliberately NOT scored:
55
+ * a query followed by nothing is indistinguishable between "phase 1 answered
56
+ * it" and "the AI gave up", and pretending otherwise would invent a number.
57
+ */
58
+ queries: {
59
+ total: number;
60
+ expanded: number;
61
+ reformulated: number;
62
+ silent: number;
63
+ expansionRate: number | null;
64
+ reformulationRate: number | null;
65
+ };
66
+ depth: {
67
+ expands: number;
68
+ perExpandingQuery: number | null;
69
+ distinctSessionsExpanded: number;
70
+ };
71
+ verdict: {
72
+ code: MetricVerdict;
73
+ headline: string;
74
+ detail: string;
75
+ };
76
+ };
77
+ export declare function recallMetric(): RecallMetric;
78
+ /** Human-readable report for `veto transcripts metric`. */
79
+ export declare function renderRecallMetric(m: RecallMetric): string;
80
+ //# sourceMappingURL=metric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric.d.ts","sourceRoot":"","sources":["../../src/transcripts/metric.ts"],"names":[],"mappings":"AAsCA,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,mEAAmE;AACnE,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,8CAA8C;AAC9C,eAAO,MAAM,aAAa,MAAO,CAAC;AAClC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,MAAO,CAAC;AAC1C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAI1C,MAAM,MAAM,aAAa,GACrB,mBAAmB,GACnB,SAAS,GACT,iBAAiB,GACjB,uBAAuB,CAAC;AAE5B,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,QAAQ,EAAE;QACR,cAAc,EAAE,OAAO,CAAC;QACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,oBAAoB,EAAE,MAAM,EAAE,CAAC;KAChC,CAAC;IACF,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAClD;;;;OAIG;IACH,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC;IACF,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,wBAAwB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/F,OAAO,EAAE;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACpE,CAAC;AAyCF,wBAAgB,YAAY,IAAI,YAAY,CA2J3C;AAID,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAkC1D"}
@@ -0,0 +1,306 @@
1
+ // The v3.0 success metric — "does deep recall actually get used?" (VERSION-3).
2
+ //
3
+ // v3.0 shipped without a confirmed success metric, so three releases later there
4
+ // was no measure of whether transcript recall is reached for at all. This
5
+ // computes that measure.
6
+ //
7
+ // IT IS A HEALTH CHECK, NOT THE v3.2 GATE. v3.2 (lesson mining) was written as
8
+ // gated on "once recall proves demand", and it is tempting to point this number
9
+ // at that gate. Do not: it reads ONE local database, and no threshold on a
10
+ // single user — who is also the person who built the feature — can become market
11
+ // evidence. Council 06b7b55c (YELLOW, 2026-08-22) was explicit that binding v3.2
12
+ // to this number would leave v3.2 blocked on something that can never be
13
+ // representative. Demand evidence lives outside the product.
14
+ //
15
+ // NOTHING NEW IS INSTRUMENTED. Every tool call is already traced into veto.db's
16
+ // tool_call_trace_log, and archives.captured_at already says when recall became
17
+ // possible, so the metric is derived from data that exists rather than from new
18
+ // telemetry. Only the SHAPE of a recall call is read (which keys the args had),
19
+ // never the query text — the metric must not become a second copy of what the
20
+ // user searched for.
21
+ //
22
+ // WHAT THIS CAN AND CANNOT ANSWER. It reads one machine's local database and
23
+ // nothing is ever uploaded, by design. So it answers "is recall being used HERE"
24
+ // — dogfooding, and whether the two-call loop completes at all. It cannot
25
+ // measure market demand; that evidence lives outside the product (downloads,
26
+ // issues, user reports) and the v3.2 gate should not be argued from this number
27
+ // alone. Any user can run it against their own data.
28
+ import { getDb } from '../memory/local.js';
29
+ import { normalizeProjectDir } from '../memory/local.js';
30
+ import { getTranscriptsDb, transcriptsAvailable } from './store.js';
31
+ import { getConfig } from '../memory/config.js';
32
+ // ─── Pre-registered thresholds ───────────────────────────────────────────────
33
+ // Fixed BEFORE the numbers are read so the gate cannot be argued backwards from
34
+ // whatever the data happens to say. They are a judgement call, not a discovery;
35
+ // change them deliberately and in the open, not to make a release pass.
36
+ /** Below this many eligible resumes the result is noise, and reports as such. */
37
+ export const MIN_ELIGIBLE_RESUMES = 30;
38
+ /** A window shorter than this cannot show a habit, only a mood. */
39
+ export const MIN_WINDOW_DAYS = 30;
40
+ /** Eligible resumes that reach for recall. */
41
+ export const ATTACH_TARGET = 0.30;
42
+ /**
43
+ * Ceiling on queries the AI had to REFORMULATE.
44
+ *
45
+ * This deliberately replaced an "expansion rate >= 50%" target, which was
46
+ * self-defeating: it assumed opening an excerpt is the desired outcome, so
47
+ * improving phase 1 until its snippets answer the question outright would have
48
+ * DRIVEN THE NUMBER DOWN and scored the improvement as a failure. Expansion is
49
+ * still reported, but it is not a target.
50
+ *
51
+ * Reformulation is gated instead because it is the one unambiguous signal in the
52
+ * data: a query followed by another query means phase 1 did not serve the first
53
+ * one. A query followed by nothing cannot be read — satisfied and gave-up look
54
+ * identical from here — so it is reported as `silent` and never scored.
55
+ */
56
+ export const REFORMULATION_CEILING = 0.40;
57
+ /**
58
+ * How long after a resume a recall query still counts as belonging to it (and
59
+ * likewise a query → its expansion). Long enough for a real working session,
60
+ * short enough that tomorrow's query is not credited to yesterday's resume.
61
+ */
62
+ export const ATTRIBUTION_WINDOW_HOURS = 6;
63
+ const RESUME_TOOLS = ['veto_continue', 'veto_session_restore'];
64
+ /** SQLite `datetime('now')` text and ISO timestamps compared on one scale (both UTC). */
65
+ function toSqlTime(iso) {
66
+ return iso.replace('T', ' ').slice(0, 19);
67
+ }
68
+ function hoursBetween(a, b) {
69
+ const ta = Date.parse(a.replace(' ', 'T') + 'Z');
70
+ const tb = Date.parse(b.replace(' ', 'T') + 'Z');
71
+ if (Number.isNaN(ta) || Number.isNaN(tb))
72
+ return Number.POSITIVE_INFINITY;
73
+ return (tb - ta) / 3_600_000;
74
+ }
75
+ /** Recall calls split by which phase of the two-call loop they are. */
76
+ function classifyReplay(argsJson) {
77
+ if (!argsJson)
78
+ return 'legacy';
79
+ try {
80
+ const a = JSON.parse(argsJson);
81
+ if (a.expand && typeof a.expand === 'object')
82
+ return 'expand';
83
+ if (a.query)
84
+ return 'query';
85
+ }
86
+ catch { /* unparseable args are not recall */ }
87
+ return 'legacy'; // the unrelated session_id tool-call trace mode
88
+ }
89
+ /** Which archived session an expand opened, when it named one (for depth). */
90
+ function expandTarget(argsJson) {
91
+ if (!argsJson)
92
+ return null;
93
+ try {
94
+ const a = JSON.parse(argsJson);
95
+ const e = a.expand;
96
+ if (!e)
97
+ return null;
98
+ if (typeof e.source_session_id === 'string')
99
+ return e.source_session_id;
100
+ if (typeof e.archive_id === 'string')
101
+ return e.archive_id;
102
+ if (typeof e.event_id === 'string')
103
+ return `event:${e.event_id}`;
104
+ }
105
+ catch { /* ignore */ }
106
+ return null;
107
+ }
108
+ export function recallMetric() {
109
+ const db = getDb();
110
+ const cfg = getConfig().transcripts;
111
+ // ── Coverage: when did recall become possible, and over how much?
112
+ let archives = [];
113
+ let events = 0;
114
+ if (transcriptsAvailable()) {
115
+ try {
116
+ const tdb = getTranscriptsDb();
117
+ archives = tdb.prepare('SELECT project_dir, captured_at FROM archives').all();
118
+ events = tdb.prepare('SELECT COUNT(*) AS n FROM events').get().n;
119
+ }
120
+ catch { /* sidecar unreadable — reported as zero coverage below */ }
121
+ }
122
+ // Recall is only possible for a project from the moment it first has an archive.
123
+ const firstArchiveByProject = new Map();
124
+ for (const a of archives) {
125
+ if (!a.project_dir)
126
+ continue;
127
+ const p = normalizeProjectDir(a.project_dir);
128
+ const t = toSqlTime(a.captured_at);
129
+ const prev = firstArchiveByProject.get(p);
130
+ if (!prev || t < prev)
131
+ firstArchiveByProject.set(p, t);
132
+ }
133
+ const earliestArchive = [...firstArchiveByProject.values()].sort()[0] ?? null;
134
+ // ── Traces. Resumes carry the veto session id, which resolves the project.
135
+ const resumeRows = db.prepare(`SELECT t.recorded_at, t.tool_name, t.args_json, s.project_dir
136
+ FROM tool_call_trace_log t
137
+ LEFT JOIN sessions s ON s.id = t.session_id
138
+ WHERE t.tool_name IN (${RESUME_TOOLS.map(() => '?').join(',')})
139
+ AND t.result_status = 'success'
140
+ ORDER BY t.recorded_at`).all(...RESUME_TOOLS);
141
+ const replayRows = db.prepare(`SELECT recorded_at, tool_name, args_json, NULL AS project_dir
142
+ FROM tool_call_trace_log
143
+ WHERE tool_name = 'veto_session_replay' AND result_status = 'success'
144
+ ORDER BY recorded_at`).all();
145
+ const queries = replayRows.filter(r => classifyReplay(r.args_json) === 'query');
146
+ const expands = replayRows.filter(r => classifyReplay(r.args_json) === 'expand');
147
+ // ── Eligibility. A resume counts only if recall could have helped it: it
148
+ // happened after that project's first archive existed. Resumes whose project
149
+ // cannot be resolved are excluded from BOTH sides rather than guessed at.
150
+ let inWindow = 0, eligible = 0, ineligible = 0, unscoped = 0;
151
+ const eligibleTimes = [];
152
+ for (const r of resumeRows) {
153
+ if (!earliestArchive || r.recorded_at < earliestArchive)
154
+ continue;
155
+ inWindow++;
156
+ if (!r.project_dir) {
157
+ unscoped++;
158
+ continue;
159
+ }
160
+ const first = firstArchiveByProject.get(normalizeProjectDir(r.project_dir));
161
+ if (first && r.recorded_at >= first) {
162
+ eligible++;
163
+ eligibleTimes.push(r.recorded_at);
164
+ }
165
+ else
166
+ ineligible++;
167
+ }
168
+ // ── Attach: an eligible resume followed by a recall query, before the next
169
+ // resume and inside the attribution window.
170
+ const resumeTimes = resumeRows.map(r => r.recorded_at);
171
+ let attached = 0;
172
+ for (const t of eligibleTimes) {
173
+ const nextResume = resumeTimes.find(x => x > t) ?? null;
174
+ const hit = queries.some(q => q.recorded_at > t
175
+ && (!nextResume || q.recorded_at < nextResume)
176
+ && hoursBetween(t, q.recorded_at) <= ATTRIBUTION_WINDOW_HOURS);
177
+ if (hit)
178
+ attached++;
179
+ }
180
+ // ── What became of each query. Exactly one bucket each:
181
+ // expanded — led to opening an exact excerpt
182
+ // reformulated — followed by ANOTHER query in the window: phase 1 failed it
183
+ // silent — neither; unreadable, so never scored (see REFORMULATION_CEILING)
184
+ const queryTimes = queries.map(q => q.recorded_at);
185
+ let expandedQueries = 0, reformulated = 0;
186
+ for (const t of queryTimes) {
187
+ const nextQuery = queryTimes.find(x => x > t) ?? null;
188
+ const expandedHere = expands.some(e => e.recorded_at > t
189
+ && (!nextQuery || e.recorded_at < nextQuery)
190
+ && hoursBetween(t, e.recorded_at) <= ATTRIBUTION_WINDOW_HOURS);
191
+ if (expandedHere) {
192
+ expandedQueries++;
193
+ continue;
194
+ }
195
+ if (nextQuery && hoursBetween(t, nextQuery) <= ATTRIBUTION_WINDOW_HOURS)
196
+ reformulated++;
197
+ }
198
+ const silent = queries.length - expandedQueries - reformulated;
199
+ const distinctExpanded = new Set(expands.map(e => expandTarget(e.args_json)).filter(Boolean)).size;
200
+ const from = earliestArchive;
201
+ const to = resumeRows.length || replayRows.length
202
+ ? [...resumeRows, ...replayRows].map(r => r.recorded_at).sort().slice(-1)[0]
203
+ : null;
204
+ const days = from && to ? Math.max(0, Math.round(hoursBetween(from, to) / 24)) : 0;
205
+ const attachRate = eligible > 0 ? attached / eligible : null;
206
+ const expansionRate = queries.length > 0 ? expandedQueries / queries.length : null;
207
+ const reformulationRate = queries.length > 0 ? reformulated / queries.length : null;
208
+ // ── Verdict. Sample size is checked FIRST: a rate over three resumes is a
209
+ // number, not evidence, and reporting it as a verdict is how a metric starts
210
+ // lying.
211
+ let code;
212
+ let headline;
213
+ let detail;
214
+ if (eligible < MIN_ELIGIBLE_RESUMES || days < MIN_WINDOW_DAYS) {
215
+ code = 'insufficient_data';
216
+ headline = 'Not enough data to judge yet';
217
+ detail = `Needs ${MIN_ELIGIBLE_RESUMES} eligible resumes over ${MIN_WINDOW_DAYS} days; have ${eligible} over ${days}.`
218
+ + (expands.length === 0 && queries.length > 0
219
+ ? ` Observation, not a verdict: ${queries.length} recall quer${queries.length === 1 ? 'y has' : 'ies have'} run and none opened an excerpt.`
220
+ + ` That is only a defect if phase 1 was not already enough — which this data cannot tell you.`
221
+ : '');
222
+ }
223
+ else if ((attachRate ?? 0) < ATTACH_TARGET) {
224
+ code = 'not_reached_for';
225
+ headline = 'Recall is available but rarely reached for';
226
+ detail = `Attach rate ${(100 * (attachRate ?? 0)).toFixed(0)}% is below the ${(100 * ATTACH_TARGET).toFixed(0)}% target.`;
227
+ }
228
+ else if ((reformulationRate ?? 0) > REFORMULATION_CEILING) {
229
+ code = 'retrieval_not_landing';
230
+ headline = 'Recall is used, but queries keep having to be re-asked';
231
+ detail = `Attach rate ${(100 * (attachRate ?? 0)).toFixed(0)}% meets the target, but `
232
+ + `${(100 * (reformulationRate ?? 0)).toFixed(0)}% of queries were reformulated `
233
+ + `(ceiling ${(100 * REFORMULATION_CEILING).toFixed(0)}%) — phase 1 is not serving them.`;
234
+ }
235
+ else {
236
+ code = 'healthy';
237
+ headline = 'Deep recall is reached for, and phase 1 serves the query';
238
+ detail = `Attach ${(100 * (attachRate ?? 0)).toFixed(0)}% and reformulation `
239
+ + `${(100 * (reformulationRate ?? 0)).toFixed(0)}% are both within target.`;
240
+ }
241
+ return {
242
+ window: { from, to, days },
243
+ coverage: {
244
+ captureEnabled: cfg.enabled,
245
+ captureEnabledAt: cfg.consent_at,
246
+ archives: archives.length,
247
+ events,
248
+ projectsWithArchives: [...firstArchiveByProject.keys()],
249
+ },
250
+ resumes: { total: resumeRows.length, inWindow, eligible, ineligible, unscoped },
251
+ attach: { attached, rate: attachRate },
252
+ queries: {
253
+ total: queries.length, expanded: expandedQueries, reformulated, silent,
254
+ expansionRate, reformulationRate,
255
+ },
256
+ depth: {
257
+ expands: expands.length,
258
+ perExpandingQuery: expandedQueries > 0 ? expands.length / expandedQueries : null,
259
+ distinctSessionsExpanded: distinctExpanded,
260
+ },
261
+ verdict: { code, headline, detail },
262
+ };
263
+ }
264
+ const pct = (r) => (r === null ? '—' : `${(100 * r).toFixed(0)}%`);
265
+ /** Human-readable report for `veto transcripts metric`. */
266
+ export function renderRecallMetric(m) {
267
+ const lines = [];
268
+ lines.push(' Deep-recall adoption — the v3.0 success metric');
269
+ lines.push(' ─────────────────────────────────────────────────────');
270
+ if (!m.coverage.captureEnabled) {
271
+ lines.push(' Transcript capture is OFF, so recall was never possible here.');
272
+ lines.push(' Nothing to measure until: veto transcripts enable');
273
+ return lines.join('\n');
274
+ }
275
+ lines.push(` Window: ${m.window.from ?? '(no archives yet)'} → ${m.window.to ?? '—'} (${m.window.days}d)`);
276
+ lines.push(` Coverage: ${m.coverage.archives} archive(s), ${m.coverage.events} events, `
277
+ + `${m.coverage.projectsWithArchives.length} project(s)`);
278
+ lines.push('');
279
+ lines.push(` Resumes: ${m.resumes.eligible} eligible `
280
+ + `(of ${m.resumes.inWindow} since recall became possible; `
281
+ + `${m.resumes.ineligible} in projects with no archive, ${m.resumes.unscoped} unattributable)`);
282
+ lines.push(` Attach rate: ${pct(m.attach.rate)} ${m.attach.attached}/${m.resumes.eligible} eligible resumes reached for recall`
283
+ + ` ${c(m.attach.rate, ATTACH_TARGET)} target ${pct(ATTACH_TARGET)}`);
284
+ lines.push(` Re-asked: ${pct(m.queries.reformulationRate)} ${m.queries.reformulated}/${m.queries.total} queries had to be reformulated`
285
+ + ` ${c(m.queries.reformulationRate === null ? null : 1 - m.queries.reformulationRate, 1 - REFORMULATION_CEILING)} ceiling ${pct(REFORMULATION_CEILING)}`);
286
+ lines.push(` Of ${m.queries.total} quer${m.queries.total === 1 ? 'y' : 'ies'}: `
287
+ + `${m.queries.expanded} opened an excerpt · ${m.queries.reformulated} re-asked · ${m.queries.silent} neither`);
288
+ lines.push(` Depth: ${m.depth.expands} expansion(s), `
289
+ + `${m.depth.perExpandingQuery === null ? '—' : m.depth.perExpandingQuery.toFixed(1)} per expanding query, `
290
+ + `${m.depth.distinctSessionsExpanded} distinct session(s) opened`);
291
+ lines.push('');
292
+ lines.push(` Verdict: ${m.verdict.headline}`);
293
+ lines.push(` ${m.verdict.detail}`);
294
+ lines.push('');
295
+ lines.push(' Reads THIS machine only — nothing is uploaded. It is a health check on');
296
+ lines.push(' whether recall works for you. It is NOT evidence of demand across users,');
297
+ lines.push(' and must not be used on its own to justify building on top of recall.');
298
+ lines.push(' "Neither" is not scored: satisfied and gave-up look identical from here.');
299
+ return lines.join('\n');
300
+ }
301
+ function c(rate, target) {
302
+ if (rate === null)
303
+ return ' ';
304
+ return rate >= target ? '✓' : '✗';
305
+ }
306
+ //# sourceMappingURL=metric.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric.js","sourceRoot":"","sources":["../../src/transcripts/metric.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,30 @@
1
+ import { type TranscriptSource } from './adapters/index.js';
1
2
  export type OnSaveTranscript = {
2
3
  status: string;
4
+ source?: string;
3
5
  events?: number;
4
6
  secrets_redacted?: number;
5
7
  archive_dir?: string;
6
8
  note?: string;
7
9
  };
10
+ /** Map a declared save platform onto a capture source; unknown platforms → claude. */
11
+ export declare function sourceForPlatform(platform?: string | null): TranscriptSource;
12
+ /**
13
+ * Which host's transcript to archive.
14
+ *
15
+ * The MCP handshake wins whenever it resolves, because capture is a question
16
+ * about WHICH PROCESS is hosting Veto — not about what the model believes it is.
17
+ * A model in Codex that leaves `platform` at its default would otherwise make
18
+ * Veto look for a Claude transcript and silently archive nothing.
19
+ *
20
+ * When the host is unrecognized (a client Veto has no marker for) the declared
21
+ * platform is the only signal left, so it is used; and if that is not a
22
+ * supported source either, capture is skipped rather than guessed.
23
+ */
24
+ export declare function captureSourceFor(host: TranscriptSource | null, declaredPlatform?: string | null): TranscriptSource | null;
8
25
  export declare function captureOnSave(opts: {
9
26
  projectDir?: string | null;
10
27
  vetoSessionId?: string | null;
28
+ platform?: string | null;
11
29
  }): Promise<OnSaveTranscript | null>;
12
30
  //# sourceMappingURL=on-save.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"on-save.d.ts","sourceRoot":"","sources":["../../src/transcripts/on-save.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAyBzI"}
1
+ {"version":3,"file":"on-save.d.ts","sourceRoot":"","sources":["../../src/transcripts/on-save.ts"],"names":[],"mappings":"AAcA,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOhF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAG5E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,GAAG,IAAI,EAC7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,GAC/B,gBAAgB,GAAG,IAAI,CAIzB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAoCnC"}
@@ -3,20 +3,59 @@
3
3
  // Runs capture, then (bounded) ingest so the save response can report the leak
4
4
  // count and the one-time first-capture note. Never throws — the caller wraps it
5
5
  // too, but this returns null on any problem so a save is never affected.
6
+ //
7
+ // The source is the platform the save declares (`veto_session_save`'s `platform`
8
+ // arg), because that is the CLI whose transcript the user is actually in. Claude
9
+ // Code publishes its own mapping from the statusline; Codex and Gemini have no
10
+ // such hook, so their mapping is discovered from disk first (see discover.ts).
6
11
  import { isCaptureEnabled, firstCaptureNote, effectiveTranscriptsDir } from './config.js';
7
12
  import { captureSession } from './archive.js';
8
13
  import { ingestArchive } from './ingest.js';
14
+ import { isTranscriptSource } from './adapters/index.js';
9
15
  // Don't parse+index a monster transcript inline on the save path (architect:
10
16
  // keep save-time work bounded). Above this, capture still archives; indexing is
11
17
  // deferred to first recall (Step 11's ensureIndexed).
12
18
  const INLINE_INGEST_MAX_BYTES = 16 * 1024 * 1024;
19
+ /** Map a declared save platform onto a capture source; unknown platforms → claude. */
20
+ export function sourceForPlatform(platform) {
21
+ const p = (platform ?? '').trim().toLowerCase();
22
+ return isTranscriptSource(p) ? p : 'claude';
23
+ }
24
+ /**
25
+ * Which host's transcript to archive.
26
+ *
27
+ * The MCP handshake wins whenever it resolves, because capture is a question
28
+ * about WHICH PROCESS is hosting Veto — not about what the model believes it is.
29
+ * A model in Codex that leaves `platform` at its default would otherwise make
30
+ * Veto look for a Claude transcript and silently archive nothing.
31
+ *
32
+ * When the host is unrecognized (a client Veto has no marker for) the declared
33
+ * platform is the only signal left, so it is used; and if that is not a
34
+ * supported source either, capture is skipped rather than guessed.
35
+ */
36
+ export function captureSourceFor(host, declaredPlatform) {
37
+ if (host)
38
+ return host;
39
+ const p = (declaredPlatform ?? '').trim().toLowerCase();
40
+ return isTranscriptSource(p) ? p : null;
41
+ }
13
42
  export async function captureOnSave(opts) {
14
43
  if (!isCaptureEnabled())
15
44
  return null;
16
- const cap = await captureSession({ source: 'claude', projectDir: opts.projectDir, vetoSessionId: opts.vetoSessionId });
45
+ const source = sourceForPlatform(opts.platform);
46
+ // Codex/Gemini publish no session mapping of their own — find theirs on disk
47
+ // before capture looks one up. Bounded and best-effort.
48
+ if (source !== 'claude') {
49
+ try {
50
+ const { discoverSessions } = await import('./discover.js');
51
+ discoverSessions(source);
52
+ }
53
+ catch { /* discovery is best-effort; capture will just find no mapping */ }
54
+ }
55
+ const cap = await captureSession({ source, projectDir: opts.projectDir, vetoSessionId: opts.vetoSessionId });
17
56
  if (!cap.ok)
18
57
  return null; // skipped (no mapping / missing / too_large) or error — stay silent
19
- const out = { status: cap.status };
58
+ const out = { status: cap.status, source };
20
59
  // Index inline for small transcripts so we can report the leak count now.
21
60
  if (cap.archiveId && cap.status === 'archived' && (cap.sourceBytes ?? 0) <= INLINE_INGEST_MAX_BYTES) {
22
61
  const ing = ingestArchive(cap.archiveId);
@@ -1 +1 @@
1
- {"version":3,"file":"on-save.js","sourceRoot":"","sources":["../../src/transcripts/on-save.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,yEAAyE;AAEzE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,6EAA6E;AAC7E,gFAAgF;AAChF,sDAAsD;AACtD,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAUjD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAmE;IACrG,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;IACvH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC,CAAC,oEAAoE;IAE9F,MAAM,GAAG,GAAqB,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;IAErD,0EAA0E;IAC1E,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,uBAAuB,EAAE,CAAC;QACpG,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YACxB,GAAG,CAAC,gBAAgB,GAAG,GAAG,CAAC,eAAe,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,IAAI,IAAI,EAAE,CAAC;QACT,GAAG,CAAC,WAAW,GAAG,uBAAuB,EAAE,CAAC;QAC5C,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,gBAAgB;YAC7B,CAAC,CAAC,GAAG,IAAI,KAAK,GAAG,CAAC,gBAAgB,uDAAuD;YACzF,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"on-save.js","sourceRoot":"","sources":["../../src/transcripts/on-save.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,15 @@
1
1
  export declare const EDIT_TOOLS: Set<string>;
2
+ export declare const SHELL_TOOLS: Set<string>;
2
3
  export declare const FILE_RE: RegExp;
3
4
  export declare const COMMAND_RE: RegExp;
5
+ export declare const PATCH_FILE_RE: RegExp;
4
6
  export declare const ERROR_RE: RegExp;
7
+ /**
8
+ * File paths a tool-call digest touched. Handles both shapes an edit tool can
9
+ * take: JSON args with a path key (Claude, Gemini) and a patch body whose
10
+ * envelope names the files (Codex apply_patch, which can touch several at once).
11
+ */
12
+ export declare function extractFiles(text: string): string[];
5
13
  export type SpineEntry = {
6
14
  seq: number;
7
15
  role: string;
@@ -1 +1 @@
1
- {"version":3,"file":"pyramid.d.ts","sourceRoot":"","sources":["../../src/transcripts/pyramid.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,UAAU,aAA0D,CAAC;AAClF,eAAO,MAAM,OAAO,QAAqE,CAAC;AAC1F,eAAO,MAAM,UAAU,QAA8B,CAAC;AACtD,eAAO,MAAM,QAAQ,QAAmH,CAAC;AAEzI,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtG,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzH,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qEAAqE;AACrE,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE,CAc1D;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA4D1D;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CASnD"}
1
+ {"version":3,"file":"pyramid.d.ts","sourceRoot":"","sources":["../../src/transcripts/pyramid.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,UAAU,aAIrB,CAAC;AACH,eAAO,MAAM,WAAW,aAItB,CAAC;AACH,eAAO,MAAM,OAAO,QAAqE,CAAC;AAC1F,eAAO,MAAM,UAAU,QAA8B,CAAC;AAGtD,eAAO,MAAM,aAAa,QAA6C,CAAC;AACxE,eAAO,MAAM,QAAQ,QAAmH,CAAC;AAEzI;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAWnD;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtG,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzH,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qEAAqE;AACrE,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE,CAc1D;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA2D1D;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CASnD"}
@@ -7,11 +7,46 @@
7
7
  // • L2 spine: user messages verbatim + assistant conclusions, tool chatter
8
8
  // stripped. The searchable conversation backbone (the portable index indexes it in Step 10).
9
9
  import { getTranscriptsDb } from './store.js';
10
- // Shared deterministic extractors (reused by the TOC in Step 9).
11
- export const EDIT_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
10
+ // Shared deterministic extractors (reused by the TOC in Step 9). The tool names
11
+ // span all three hosts, because facts are derived from the normalized events and
12
+ // a Codex or Gemini session must yield the same file/command facts a Claude one
13
+ // does: Claude edits with Edit/Write, Codex with apply_patch, Gemini with
14
+ // replace/write_file — and each shells out under its own name.
15
+ export const EDIT_TOOLS = new Set([
16
+ 'Edit', 'Write', 'MultiEdit', 'NotebookEdit', // claude
17
+ 'apply_patch', // codex
18
+ 'replace', 'write_file', // gemini
19
+ ]);
20
+ export const SHELL_TOOLS = new Set([
21
+ 'Bash', // claude
22
+ 'shell_command', 'local_shell_call', // codex
23
+ 'run_shell_command', // gemini
24
+ ]);
12
25
  export const FILE_RE = /"(?:file_path|filePath|notebook_path|file|path)"\s*:\s*"([^"]+)"/;
13
26
  export const COMMAND_RE = /"command"\s*:\s*"([^"]+)"/;
27
+ // Codex's apply_patch takes a patch body rather than JSON args, so its file names
28
+ // only appear in the patch envelope.
29
+ export const PATCH_FILE_RE = /\*\*\* (?:Add|Update|Delete) File: (.+)/g;
14
30
  export const ERROR_RE = /\b(error|errno|failed|failure|exception|traceback|not found|cannot|denied|refused|non-zero|exit code [1-9])\b/i;
31
+ /**
32
+ * File paths a tool-call digest touched. Handles both shapes an edit tool can
33
+ * take: JSON args with a path key (Claude, Gemini) and a patch body whose
34
+ * envelope names the files (Codex apply_patch, which can touch several at once).
35
+ */
36
+ export function extractFiles(text) {
37
+ const out = [];
38
+ const m = text.match(FILE_RE);
39
+ if (m)
40
+ out.push(m[1]);
41
+ PATCH_FILE_RE.lastIndex = 0;
42
+ let p;
43
+ while ((p = PATCH_FILE_RE.exec(text)) !== null) {
44
+ const f = p[1].trim();
45
+ if (f)
46
+ out.push(f);
47
+ }
48
+ return out;
49
+ }
15
50
  /** L2 — the conversation spine (user + assistant text, in order). */
16
51
  export function buildSpine(archiveId) {
17
52
  const db = getTranscriptsDb();
@@ -65,11 +100,10 @@ export function buildFacts(archiveId) {
65
100
  toolCounts.set(name, (toolCounts.get(name) ?? 0) + 1);
66
101
  if (r.text) {
67
102
  if (EDIT_TOOLS.has(name)) {
68
- const m = r.text.match(FILE_RE);
69
- if (m)
70
- files.add(m[1]);
103
+ for (const f of extractFiles(r.text))
104
+ files.add(f);
71
105
  }
72
- else if (name === 'Bash') {
106
+ else if (SHELL_TOOLS.has(name)) {
73
107
  const m = r.text.match(COMMAND_RE);
74
108
  if (m)
75
109
  commands.push(m[1].slice(0, 200));
@@ -1 +1 @@
1
- {"version":3,"file":"pyramid.js","sourceRoot":"","sources":["../../src/transcripts/pyramid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pyramid.js","sourceRoot":"","sources":["../../src/transcripts/pyramid.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,kFAAkF;AAClF,8DAA8D;AAC9D,gFAAgF;AAChF,gFAAgF;AAChF,6EAA6E;AAC7E,iGAAiG;AAEjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAChF,0EAA0E;AAC1E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IAChC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAI,SAAS;IACzD,aAAa,EAAoC,QAAQ;IACzD,SAAS,EAAE,YAAY,EAA0B,SAAS;CAC3D,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IACjC,MAAM,EAA2C,SAAS;IAC1D,eAAe,EAAE,kBAAkB,EAAc,QAAQ;IACzD,mBAAmB,EAA8B,SAAS;CAC3D,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,kEAAkE,CAAC;AAC1F,MAAM,CAAC,MAAM,UAAU,GAAG,2BAA2B,CAAC;AACtD,kFAAkF;AAClF,qCAAqC;AACrC,MAAM,CAAC,MAAM,aAAa,GAAG,0CAA0C,CAAC;AACxE,MAAM,CAAC,MAAM,QAAQ,GAAG,gHAAgH,CAAC;AAEzI;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtB,aAAa,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAeD,qEAAqE;AACrE,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB;;kBAEc,CACf,CAAC,GAAG,CAAC,SAAS,CAAqG,CAAC;IACrH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;QAClE,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,EAAE,EAAE,CAAC,CAAC,MAAM;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;KACnB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,oFAAoF,CACrF,CAAC,GAAG,CAAC,SAAS,CAA6F,CAAC;IAE7G,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5G,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,MAAM,GAAkB,IAAI,CAAC;IAEjC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,GAAG,OAAO;gBAAE,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;YACvD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM;gBAAE,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtD,CAAC;QACD,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,cAAc;gBAAE,MAAM,CAAC,IAAI,EAAE,CAAC;gBAAC,MAAM;YAC1C,KAAK,mBAAmB;gBAAE,MAAM,CAAC,SAAS,EAAE,CAAC;gBAAC,MAAM;YACpD,KAAK,WAAW;gBAAE,MAAM,CAAC,SAAS,EAAE,CAAC;gBAAC,MAAM;YAC5C,KAAK,aAAa;gBAChB,MAAM,CAAC,YAAY,EAAE,CAAC;gBACtB,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;oBAAE,UAAU,EAAE,CAAC;gBAClD,MAAM;YACR,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC;gBACnC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACtD,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;oBACX,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBACzB,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;4BAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACrD,CAAC;yBAAM,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBACjC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;wBACnC,IAAI,CAAC;4BAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;gBACD,MAAM;YACR,CAAC;YACD,OAAO,CAAC,CAAC,MAAM;QACjB,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC;SACpC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;SACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAErC,OAAO;QACL,SAAS;QACT,OAAO;QACP,MAAM;QACN,MAAM;QACN,KAAK;QACL,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC;QACjB,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,UAAU;KACX,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,WAAW,CAAC,CAAe;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,CAAC,MAAM,CAAC,SAAS,YAAY,CAAC,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;IACjI,IAAI,CAAC,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5G,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtF,IAAI,CAAC,CAAC,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}