agentcache 0.2.3 → 0.3.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.
package/dist/mcp.js CHANGED
@@ -1,548 +1,35 @@
1
1
  import {
2
2
  evaluatePolicy
3
3
  } from "./chunk-T7BJPANN.js";
4
+ import {
5
+ computeCanonicalHash,
6
+ processClustering,
7
+ processExtraction,
8
+ startCompile
9
+ } from "./chunk-IER56P6A.js";
10
+ import {
11
+ spawnCompileAll
12
+ } from "./chunk-RXBTPJVW.js";
4
13
  import {
5
14
  parseTranscript
6
- } from "./chunk-OSFK44XC.js";
15
+ } from "./chunk-TE6DBLJ5.js";
7
16
  import {
8
17
  findProjectRoot,
9
18
  getDbPath,
10
- getGitContext,
11
19
  getProjectId,
12
20
  isInitialized
13
21
  } from "./chunk-WHP4Z32Z.js";
14
22
  import {
15
23
  SqliteKnowledgeRepository
16
24
  } from "./chunk-MMSMDJ4O.js";
17
- import "./chunk-MLKGABMK.js";
25
+ import "./chunk-KFQGP6VL.js";
18
26
 
19
27
  // src/mcp.ts
20
28
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
21
29
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
30
  import { CallToolRequestSchema, ListToolsRequestSchema, RootsListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
23
-
24
- // src/knowledge/compiler.ts
25
- import { randomUUID as randomUUID3 } from "crypto";
26
-
27
- // src/knowledge/passes/1-extractor.ts
28
- import { randomUUID } from "crypto";
29
- var EXTRACT_PROMPT_VERSION = "extract-v1";
30
- function buildExtractionPrompt(events) {
31
- const transcript = events.filter((e) => e.content || e.tool_name).map((e) => {
32
- if (e.role) return `[${e.role}]: ${e.content}`;
33
- if (e.tool_name) return `[tool:${e.tool_name}]: ${JSON.stringify(e.tool_input).slice(0, 500)}`;
34
- return "";
35
- }).filter(Boolean).join("\n");
36
- return `You are a knowledge extraction engine. Analyze this coding session transcript and extract distinct learnings.
37
-
38
- Extract into four types:
39
- - rule: a standing instruction or constraint the developer expressed
40
- - lesson: a mistake made and what fixed it
41
- - decision: an architectural or design choice with rationale
42
- - context: current task state, open threads, what was left in progress
43
-
44
- Return ONLY valid JSON: { "observations": [{ "type": "rule"|"lesson"|"decision"|"context", "content": "...", "sourceQuote": "...", "confidence": "high"|"medium" }] }
45
-
46
- Only return high and medium confidence items. Ignore conversational noise, tool outputs, and implementation details that aren't generalizable.
47
-
48
- <transcript>
49
- ${transcript}
50
- </transcript>`;
51
- }
52
- function parseExtractionResponse(text, sessionId, project) {
53
- const jsonMatch = text.match(/\{[\s\S]*\}/);
54
- if (!jsonMatch) return [];
55
- const parsed = JSON.parse(jsonMatch[0]);
56
- if (!parsed.observations || !Array.isArray(parsed.observations)) return [];
57
- const now = Date.now();
58
- return parsed.observations.filter((o) => o.type && o.content && o.confidence).filter((o) => ["high", "medium"].includes(o.confidence)).map((o) => ({
59
- id: `obs_${randomUUID().slice(0, 8)}`,
60
- sessionId,
61
- timestamp: now,
62
- type: o.type,
63
- content: o.content,
64
- sourceQuote: o.sourceQuote || "",
65
- confidence: o.confidence,
66
- project,
67
- scope: o.scope || (o.type === "rule" || o.type === "lesson" ? "global" : "project")
68
- }));
69
- }
70
-
71
- // src/knowledge/passes/2-normalizer.ts
72
- var FILLER_PATTERNS = [
73
- /^i (noticed|realized|learned|found|discovered|think) that /i,
74
- /^it (seems|appears|looks) (like|that) /i,
75
- /^we should /i,
76
- /^you should /i,
77
- /^basically,? /i,
78
- /^essentially,? /i,
79
- /^actually,? /i
80
- ];
81
- var IMPERATIVE_RULES = [
82
- [/^you should never /i, "Never "],
83
- [/^we should never /i, "Never "],
84
- [/^don't ever /i, "Never "],
85
- [/^never /i, "Never "],
86
- [/^you should always /i, "Always "],
87
- [/^we should always /i, "Always "],
88
- [/^always /i, "Always "]
89
- ];
90
- function normalize(observations) {
91
- const normalized = observations.map((obs) => ({
92
- ...obs,
93
- content: normalizeContent(obs.content, obs.type)
94
- }));
95
- const seen = /* @__PURE__ */ new Set();
96
- return normalized.filter((obs) => {
97
- const key = obs.content.toLowerCase().trim();
98
- if (seen.has(key)) return false;
99
- seen.add(key);
100
- return true;
101
- });
102
- }
103
- function normalizeContent(content, type) {
104
- let text = content.trim();
105
- for (const pattern of FILLER_PATTERNS) {
106
- text = text.replace(pattern, "");
107
- }
108
- if (type === "rule") {
109
- for (const [pattern, replacement] of IMPERATIVE_RULES) {
110
- if (pattern.test(text)) {
111
- text = text.replace(pattern, replacement);
112
- break;
113
- }
114
- }
115
- }
116
- text = text.charAt(0).toUpperCase() + text.slice(1);
117
- const firstSentenceEnd = text.search(/\. [A-Z]/);
118
- if (firstSentenceEnd > 0) {
119
- text = text.slice(0, firstSentenceEnd + 1);
120
- }
121
- return text;
122
- }
123
-
124
- // src/knowledge/passes/3-canonicalizer.ts
125
- import { createHash } from "crypto";
126
- var STOP_WORDS = /* @__PURE__ */ new Set([
127
- "a",
128
- "an",
129
- "the",
130
- "is",
131
- "are",
132
- "was",
133
- "were",
134
- "be",
135
- "been",
136
- "being",
137
- "have",
138
- "has",
139
- "had",
140
- "do",
141
- "does",
142
- "did",
143
- "will",
144
- "would",
145
- "could",
146
- "should",
147
- "may",
148
- "might",
149
- "shall",
150
- "can",
151
- "need",
152
- "must",
153
- "to",
154
- "of",
155
- "in",
156
- "for",
157
- "on",
158
- "with",
159
- "at",
160
- "by",
161
- "from",
162
- "as",
163
- "into",
164
- "through",
165
- "during",
166
- "before",
167
- "after",
168
- "above",
169
- "below",
170
- "this",
171
- "that",
172
- "these",
173
- "those",
174
- "it",
175
- "its",
176
- "and",
177
- "but",
178
- "or",
179
- "nor",
180
- "not",
181
- "so",
182
- "yet",
183
- "all",
184
- "each",
185
- "every",
186
- "both",
187
- "few",
188
- "more",
189
- "most",
190
- "i",
191
- "we",
192
- "you",
193
- "they",
194
- "he",
195
- "she"
196
- ]);
197
- var ANTONYM_MAP = [
198
- [/\bnever\b/g, "forbidden"],
199
- [/\bdon'?t\b/g, "forbidden"],
200
- [/\bavoid\b/g, "forbidden"],
201
- [/\bprohibit(ed)?\b/g, "forbidden"],
202
- [/\balways\b/g, "required"],
203
- [/\bmust\b/g, "required"],
204
- [/\brequire(d)?\b/g, "required"],
205
- [/\buse\b/g, "use"],
206
- [/\bprefer\b/g, "use"]
207
- ];
208
- function canonicalize(observations, existingCanonicalKeys) {
209
- const canonicalized = observations.map((obs) => ({
210
- ...obs,
211
- canonicalKey: computeCanonicalKey(obs.content)
212
- }));
213
- const existingSet = new Set(existingCanonicalKeys || []);
214
- const autoReinforced = [];
215
- const needsClustering = [];
216
- for (const obs of canonicalized) {
217
- if (existingSet.has(obs.canonicalKey)) {
218
- autoReinforced.push(obs);
219
- } else {
220
- needsClustering.push(obs);
221
- }
222
- }
223
- return { observations: canonicalized, autoReinforced, needsClustering };
224
- }
225
- function computeCanonicalKey(content) {
226
- let text = content.toLowerCase().trim();
227
- for (const [pattern, replacement] of ANTONYM_MAP) {
228
- text = text.replace(pattern, replacement);
229
- }
230
- text = text.replace(/[^\w\s]/g, " ");
231
- const tokens = text.split(/\s+/).filter((t) => !STOP_WORDS.has(t) && t.length > 1).sort();
232
- return tokens.join(" ");
233
- }
234
- function computeCanonicalHash(content) {
235
- const key = computeCanonicalKey(content);
236
- return createHash("sha256").update(key).digest("hex").slice(0, 16);
237
- }
238
-
239
- // src/knowledge/passes/4-clusterer.ts
240
- var CLUSTER_PROMPT_VERSION = "cluster-v1";
241
- function buildClusteringPrompt(observations, existingItems) {
242
- const obsJson = observations.map((o) => ({
243
- id: o.id,
244
- type: o.type,
245
- content: o.content,
246
- canonicalKey: o.canonicalKey
247
- }));
248
- const itemsJson = existingItems.filter((i) => i.status === "active").map((i) => ({
249
- id: i.id,
250
- type: i.type,
251
- content: i.content,
252
- canonicalHash: i.canonicalHash
253
- }));
254
- return `You are a knowledge clustering engine. Determine whether new observations create new knowledge or relate to existing items. Be conservative.
255
-
256
- For each observation, assign an action:
257
- CREATE \u2014 genuinely new knowledge, no existing item covers it
258
- REINFORCE \u2014 confirms an existing item (provide targetKnowledgeItemId)
259
- SUPERSEDE \u2014 replaces/corrects an existing item (provide targetKnowledgeItemId)
260
- DEPRECATE \u2014 makes an existing item irrelevant (provide targetKnowledgeItemId)
261
- IGNORE \u2014 duplicate, trivial, or too vague to keep
262
-
263
- New observations:
264
- ${JSON.stringify(obsJson, null, 2)}
265
-
266
- Existing knowledge items:
267
- ${JSON.stringify(itemsJson, null, 2)}
268
-
269
- Return ONLY valid JSON: { "clusters": [{ "observationId": "...", "action": "CREATE"|"REINFORCE"|"SUPERSEDE"|"DEPRECATE"|"IGNORE", "targetKnowledgeItemId": "..." (only if action targets an existing item), "reasoning": "..." }] }`;
270
- }
271
- function parseClusteringResponse(text, observations) {
272
- const jsonMatch = text.match(/\{[\s\S]*\}/);
273
- if (!jsonMatch) {
274
- return observations.map((o) => ({ observationId: o.id, action: "CREATE", reasoning: "Parse failure \u2014 defaulting to CREATE" }));
275
- }
276
- const parsed = JSON.parse(jsonMatch[0]);
277
- if (!parsed.clusters || !Array.isArray(parsed.clusters)) {
278
- return observations.map((o) => ({ observationId: o.id, action: "CREATE", reasoning: "Parse failure \u2014 defaulting to CREATE" }));
279
- }
280
- return parsed.clusters.map((c) => ({
281
- observationId: c.observationId,
282
- action: c.action || "CREATE",
283
- targetKnowledgeItemId: c.targetKnowledgeItemId || void 0,
284
- reasoning: c.reasoning || ""
285
- }));
286
- }
287
-
288
- // src/knowledge/passes/5-contradiction.ts
289
- var CONTRADICTION_PROMPT_VERSION = "contradiction-v1";
290
-
291
- // src/knowledge/passes/6-compile.ts
292
- import { randomUUID as randomUUID2 } from "crypto";
293
- function calculateConfidence(count) {
294
- if (count >= 7) return "high";
295
- if (count >= 3) return "medium";
296
- return "low";
297
- }
298
- function compileKnowledge(clusters, existingItems, observations, project, now) {
299
- const itemMap = new Map(existingItems.map((i) => [i.id, { ...i }]));
300
- const obsMap = new Map(observations.map((o) => [o.id, o]));
301
- const result = {
302
- created: [],
303
- reinforced: [],
304
- superseded: [],
305
- deprecated: [],
306
- ignored: 0
307
- };
308
- for (const cluster of clusters) {
309
- const obs = obsMap.get(cluster.observationId);
310
- if (!obs) continue;
311
- switch (cluster.action) {
312
- case "CREATE": {
313
- const newItem = {
314
- id: `ki_${randomUUID2().slice(0, 8)}`,
315
- canonicalHash: computeCanonicalHash(obs.content),
316
- type: obs.type,
317
- title: obs.content.slice(0, 80),
318
- content: obs.content,
319
- confidence: "low",
320
- observationCount: 1,
321
- authority: "AUTO",
322
- status: "active",
323
- supersededById: void 0,
324
- enforce: false,
325
- project,
326
- scope: obs.scope || (obs.type === "rule" || obs.type === "lesson" ? "global" : "project"),
327
- createdAt: now,
328
- updatedAt: now,
329
- lastSeenAt: now,
330
- metadata: {}
331
- };
332
- result.created.push(newItem);
333
- break;
334
- }
335
- case "REINFORCE": {
336
- const target = itemMap.get(cluster.targetKnowledgeItemId);
337
- if (!target) break;
338
- target.observationCount += 1;
339
- target.lastSeenAt = now;
340
- target.updatedAt = now;
341
- target.confidence = calculateConfidence(target.observationCount);
342
- result.reinforced.push(target);
343
- break;
344
- }
345
- case "SUPERSEDE": {
346
- const target = itemMap.get(cluster.targetKnowledgeItemId);
347
- if (target) {
348
- const newItem = {
349
- id: `ki_${randomUUID2().slice(0, 8)}`,
350
- canonicalHash: computeCanonicalHash(obs.content),
351
- type: obs.type,
352
- title: obs.content.slice(0, 80),
353
- content: obs.content,
354
- confidence: "low",
355
- observationCount: 1,
356
- authority: "AUTO",
357
- status: "active",
358
- supersededById: void 0,
359
- enforce: false,
360
- project,
361
- scope: obs.scope || (obs.type === "rule" || obs.type === "lesson" ? "global" : "project"),
362
- createdAt: now,
363
- updatedAt: now,
364
- lastSeenAt: now,
365
- metadata: {}
366
- };
367
- target.status = "superseded";
368
- target.updatedAt = now;
369
- target.supersededById = newItem.id;
370
- result.superseded.push(target);
371
- result.created.push(newItem);
372
- }
373
- break;
374
- }
375
- case "DEPRECATE": {
376
- const target = itemMap.get(cluster.targetKnowledgeItemId);
377
- if (target) {
378
- target.status = "deprecated";
379
- target.updatedAt = now;
380
- result.deprecated.push(target);
381
- }
382
- break;
383
- }
384
- case "IGNORE":
385
- result.ignored += 1;
386
- break;
387
- }
388
- }
389
- return result;
390
- }
391
-
392
- // src/knowledge/compiler.ts
393
- var COMPILER_VERSION = "0.1.0";
394
- function startCompile(events, sessionId, project, projectRoot, repo, transcriptPath) {
395
- const git = getGitContext(projectRoot);
396
- const session = {
397
- id: sessionId,
398
- project,
399
- startedAt: Date.now() - 6e4,
400
- endedAt: Date.now(),
401
- gitBranch: git.branch,
402
- gitCommit: git.commit,
403
- provider: "agent",
404
- model: "host-agent",
405
- transcriptPath: transcriptPath || "",
406
- observationCount: 0
407
- };
408
- repo.saveSession(session);
409
- const prompt = buildExtractionPrompt(events);
410
- return { sessionId, project, projectRoot, prompt };
411
- }
412
- function processExtraction(repo, responseText, sessionId, project, projectRoot) {
413
- const rawObservations = parseExtractionResponse(responseText, sessionId, project);
414
- const normalized = normalize(rawObservations);
415
- const existingItems = repo.getKnowledgeItems(project, { status: "active" });
416
- const existingKeys = existingItems.map((i) => computeCanonicalKey(i.content));
417
- const canonicalized = canonicalize(normalized, existingKeys);
418
- for (const obs of canonicalized.autoReinforced) {
419
- const matchingItem = existingItems.find(
420
- (item) => computeCanonicalKey(item.content) === obs.canonicalKey
421
- );
422
- if (matchingItem) {
423
- const newCount = matchingItem.observationCount + 1;
424
- const confidence = newCount >= 7 ? "high" : newCount >= 3 ? "medium" : "low";
425
- repo.updateKnowledgeItem(matchingItem.id, {
426
- observationCount: newCount,
427
- lastSeenAt: Date.now(),
428
- updatedAt: Date.now(),
429
- confidence
430
- });
431
- }
432
- }
433
- repo.saveObservations(normalized);
434
- if (canonicalized.needsClustering.length === 0) {
435
- saveCompileRun(repo, sessionId, project, normalized.length, canonicalized.autoReinforced.length, 0, 0, 0, 0, 0, Date.now());
436
- return {
437
- status: "complete",
438
- diagnostics: formatDiagnostics(normalized.length, canonicalized.autoReinforced.length, 0, 0, 0, 0, 0, project, sessionId)
439
- };
440
- }
441
- const clusteringPrompt = buildClusteringPrompt(canonicalized.needsClustering, existingItems);
442
- return {
443
- status: "needs_clustering",
444
- clusteringPrompt,
445
- sessionId
446
- };
447
- }
448
- function processClustering(repo, responseText, sessionId, project, projectRoot) {
449
- const startedAt = Date.now();
450
- const existingItems = repo.getKnowledgeItems(project, { status: "active" });
451
- const observations = repo.getObservations(project);
452
- const sessionObs = observations.filter((o) => o.sessionId === sessionId);
453
- const canonicalized = canonicalize(sessionObs);
454
- const needsClustering = canonicalized.needsClustering;
455
- const clusters = parseClusteringResponse(responseText, needsClustering);
456
- const contradictions = [];
457
- const supersedeActions = clusters.filter((c) => c.action === "SUPERSEDE");
458
- for (const s of supersedeActions) {
459
- if (s.targetKnowledgeItemId) {
460
- const target = existingItems.find((i) => i.id === s.targetKnowledgeItemId);
461
- if (target) {
462
- contradictions.push({
463
- id: `con_${randomUUID3().slice(0, 8)}`,
464
- project,
465
- itemAId: target.id,
466
- itemBId: s.observationId,
467
- topic: target.title.slice(0, 50),
468
- description: `"${target.content}" superseded by new observation`,
469
- recommendation: "keep_newer",
470
- resolved: false,
471
- createdAt: Date.now()
472
- });
473
- }
474
- }
475
- }
476
- for (const c of contradictions) {
477
- repo.saveContradiction(c);
478
- }
479
- const now = Date.now();
480
- const compiled = compileKnowledge(clusters, existingItems, needsClustering, project, now);
481
- for (const item of compiled.created) repo.saveKnowledgeItem(item);
482
- for (const item of compiled.reinforced) {
483
- repo.updateKnowledgeItem(item.id, {
484
- observationCount: item.observationCount,
485
- lastSeenAt: item.lastSeenAt,
486
- updatedAt: item.updatedAt,
487
- confidence: item.confidence
488
- });
489
- }
490
- for (const item of compiled.superseded) {
491
- repo.updateKnowledgeItem(item.id, {
492
- status: item.status,
493
- updatedAt: item.updatedAt,
494
- supersededById: item.supersededById
495
- });
496
- }
497
- for (const item of compiled.deprecated) {
498
- repo.updateKnowledgeItem(item.id, { status: item.status, updatedAt: item.updatedAt });
499
- }
500
- const totalObs = sessionObs.length;
501
- saveCompileRun(repo, sessionId, project, totalObs, 0, compiled.created.length, compiled.reinforced.length, compiled.superseded.length, compiled.deprecated.length, compiled.ignored, startedAt);
502
- return {
503
- status: "complete",
504
- diagnostics: formatDiagnostics(totalObs, 0, compiled.created.length, compiled.reinforced.length, compiled.superseded.length, compiled.deprecated.length, compiled.ignored, project, sessionId)
505
- };
506
- }
507
- function saveCompileRun(repo, sessionId, project, observationsProcessed, autoReinforced, created, reinforced, superseded, deprecated, ignored, startedAt) {
508
- const endedAt = Date.now();
509
- const run = {
510
- id: `cr_${randomUUID3().slice(0, 8)}`,
511
- project,
512
- sessionId,
513
- compilerVersion: COMPILER_VERSION,
514
- promptVersions: { extract: EXTRACT_PROMPT_VERSION, cluster: CLUSTER_PROMPT_VERSION, contradiction: CONTRADICTION_PROMPT_VERSION },
515
- startedAt,
516
- endedAt,
517
- durationMs: endedAt - startedAt,
518
- observationsProcessed,
519
- knowledgeCreated: created,
520
- knowledgeReinforced: reinforced + autoReinforced,
521
- knowledgeDeprecated: deprecated,
522
- knowledgeSuperseded: superseded,
523
- knowledgeIgnored: ignored,
524
- contradictionsDetected: 0,
525
- diagnostics: ""
526
- };
527
- repo.saveCompileRun(run);
528
- }
529
- function formatDiagnostics(extracted, autoReinforced, created, reinforced, superseded, deprecated, ignored, project, sessionId) {
530
- return [
531
- `AgentCache Compiler v${COMPILER_VERSION}`,
532
- `Project: ${project} | Session: ${sessionId}`,
533
- ` ${extracted} observations processed`,
534
- autoReinforced > 0 ? ` ${autoReinforced} auto-reinforced (no LLM needed)` : "",
535
- ` ${created} new knowledge items`,
536
- ` ${reinforced} reinforced`,
537
- superseded > 0 ? ` ${superseded} superseded` : "",
538
- deprecated > 0 ? ` ${deprecated} deprecated` : "",
539
- ignored > 0 ? ` ${ignored} ignored` : ""
540
- ].filter(Boolean).join("\n");
541
- }
542
-
543
- // src/mcp.ts
544
31
  import { existsSync } from "fs";
545
- import { randomUUID as randomUUID4 } from "crypto";
32
+ import { randomUUID } from "crypto";
546
33
  function defaultScope(type) {
547
34
  return type === "rule" || type === "lesson" ? "global" : "project";
548
35
  }
@@ -742,10 +229,23 @@ async function startMcpServer() {
742
229
  }
743
230
  if (!output) output = "No compiled knowledge yet. This will populate as you use AgentCache across sessions.\n";
744
231
  const pendingCount = repo.getPendingCount();
745
- if (pendingCount > 0) {
746
- output = `<!-- ${pendingCount} previous session(s) pending compilation. Call compile_extract to process. -->
747
-
748
- ` + output;
232
+ if (pendingCount > 20) {
233
+ const spawned = spawnCompileAll();
234
+ if (spawned) {
235
+ output += `
236
+ ---
237
+ Background compilation started for ${pendingCount} pending sessions. Knowledge will be available in future sessions.
238
+ `;
239
+ } else {
240
+ output += `
241
+ ---
242
+ ${pendingCount} sessions pending compilation (background compiler already running).
243
+ `;
244
+ }
245
+ } else if (pendingCount > 0) {
246
+ output += `
247
+ <!-- ${pendingCount} session(s) pending compilation (below threshold, will process when backlog grows). -->
248
+ `;
749
249
  }
750
250
  output += "\n---\nIMPORTANT: Submit observations incrementally as they happen during this session.\nWhen you learn something (rule, lesson, decision, context), call compile_submit immediately.\nDo NOT wait until the end \u2014 sessions can terminate without warning.\n";
751
251
  return { content: [{ type: "text", text: output.trim() }] };
@@ -753,7 +253,7 @@ async function startMcpServer() {
753
253
  case "compile_submit": {
754
254
  const args = request.params.arguments;
755
255
  const project = args.project || detectedProject;
756
- const sessionId = `sess_${randomUUID4().slice(0, 8)}`;
256
+ const sessionId = `sess_${randomUUID().slice(0, 8)}`;
757
257
  const observationsWithScope = args.observations.map((o) => ({
758
258
  ...o,
759
259
  scope: o.scope || defaultScope(o.type)
@@ -788,7 +288,7 @@ async function startMcpServer() {
788
288
  if (events.length === 0) {
789
289
  return { content: [{ type: "text", text: JSON.stringify({ message: "Empty transcript, skipped." }) }] };
790
290
  }
791
- const sessionId = `sess_${randomUUID4().slice(0, 8)}`;
291
+ const sessionId = `sess_${randomUUID().slice(0, 8)}`;
792
292
  const project = entry.project || (args.project || detectedProject);
793
293
  const state = startCompile(events, sessionId, project, entry.projectRoot || projectRoot, repo, entry.transcriptPath);
794
294
  return { content: [{ type: "text", text: JSON.stringify({ sessionId: state.sessionId, prompt: state.prompt }) }] };
@@ -804,7 +304,7 @@ async function startMcpServer() {
804
304
  const args = request.params.arguments;
805
305
  const project = args.project || detectedProject;
806
306
  const scope = args.scope || defaultScope(args.type);
807
- const sessionId = `manual_${randomUUID4().slice(0, 8)}`;
307
+ const sessionId = `manual_${randomUUID().slice(0, 8)}`;
808
308
  repo.saveSession({
809
309
  id: sessionId,
810
310
  project,
@@ -818,7 +318,7 @@ async function startMcpServer() {
818
318
  observationCount: 1
819
319
  });
820
320
  const obs = {
821
- id: `obs_${randomUUID4().slice(0, 8)}`,
321
+ id: `obs_${randomUUID().slice(0, 8)}`,
822
322
  sessionId,
823
323
  timestamp: Date.now(),
824
324
  type: args.type,
@@ -830,7 +330,7 @@ async function startMcpServer() {
830
330
  };
831
331
  repo.saveObservation(obs);
832
332
  repo.saveKnowledgeItem({
833
- id: `ki_${randomUUID4().slice(0, 8)}`,
333
+ id: `ki_${randomUUID().slice(0, 8)}`,
834
334
  canonicalHash: computeCanonicalHash(args.content),
835
335
  type: args.type,
836
336
  title: args.content.slice(0, 80),
@@ -9,7 +9,7 @@ import {
9
9
  isInitialized,
10
10
  migrateFromLegacy
11
11
  } from "./chunk-WHP4Z32Z.js";
12
- import "./chunk-MLKGABMK.js";
12
+ import "./chunk-KFQGP6VL.js";
13
13
  export {
14
14
  findProjectRoot,
15
15
  getClaudeTranscriptsDir,
@@ -1,3 +1,6 @@
1
+ import {
2
+ spawnCompileAll
3
+ } from "./chunk-RXBTPJVW.js";
1
4
  import {
2
5
  detectInstalledIdes,
3
6
  registerClaudeHooks,
@@ -11,7 +14,7 @@ import {
11
14
  import {
12
15
  SqliteKnowledgeRepository
13
16
  } from "./chunk-MMSMDJ4O.js";
14
- import "./chunk-MLKGABMK.js";
17
+ import "./chunk-KFQGP6VL.js";
15
18
 
16
19
  // src/postinstall.ts
17
20
  import { mkdirSync } from "fs";
@@ -35,6 +38,10 @@ try {
35
38
  console.error(`agentcache: registered with ${registered.join(", ")}`);
36
39
  }
37
40
  console.error("agentcache: ready. Knowledge compiles automatically across all sessions.");
41
+ const spawned = spawnCompileAll();
42
+ if (spawned) {
43
+ console.error("agentcache: background compilation started for existing transcripts.");
44
+ }
38
45
  } catch (err) {
39
46
  console.error(`agentcache postinstall: ${err.message}. Run 'agentcache setup' manually.`);
40
47
  }
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  SqliteKnowledgeRepository
12
12
  } from "./chunk-MMSMDJ4O.js";
13
- import "./chunk-MLKGABMK.js";
13
+ import "./chunk-KFQGP6VL.js";
14
14
 
15
15
  // src/hooks/pre-tool-use.ts
16
16
  function handlePreToolUse(input) {