@goondocks/myco 0.6.0 → 0.6.2
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +10 -11
- package/dist/{chunk-2YBUL3IL.js → chunk-25DJSF2K.js} +3 -3
- package/dist/{chunk-24DOZEUJ.js → chunk-ALBVNGCF.js} +591 -27
- package/dist/chunk-ALBVNGCF.js.map +1 -0
- package/dist/{chunk-E7OBRBCQ.js → chunk-CK24O5YQ.js} +12 -2
- package/dist/chunk-CK24O5YQ.js.map +1 -0
- package/dist/{chunk-2GSX3BK2.js → chunk-CPVXNRGW.js} +4 -4
- package/dist/{chunk-L25U7PIG.js → chunk-CQ4RKK67.js} +2 -2
- package/dist/{chunk-ZMYNRTTD.js → chunk-HRGHDMYI.js} +4 -3
- package/dist/chunk-HRGHDMYI.js.map +1 -0
- package/dist/{chunk-5FNZ7AMX.js → chunk-IWBWZQK6.js} +2 -2
- package/dist/{chunk-MQSYSQ6T.js → chunk-JSK7L46L.js} +11 -6
- package/dist/{chunk-MQSYSQ6T.js.map → chunk-JSK7L46L.js.map} +1 -1
- package/dist/{chunk-KUMVJIJW.js → chunk-LDKXXKF6.js} +6 -10
- package/dist/{chunk-KUMVJIJW.js.map → chunk-LDKXXKF6.js.map} +1 -1
- package/dist/{chunk-QGJ2ZIUZ.js → chunk-MWW62YZP.js} +37 -5
- package/dist/chunk-MWW62YZP.js.map +1 -0
- package/dist/{chunk-2ZBB3MQT.js → chunk-PQWQC3RF.js} +444 -21
- package/dist/chunk-PQWQC3RF.js.map +1 -0
- package/dist/{chunk-5QWZT4AB.js → chunk-RNWALAFP.js} +2 -2
- package/dist/{chunk-3EM23DMD.js → chunk-RXJHB7W4.js} +2 -2
- package/dist/{chunk-GNR3QAER.js → chunk-RY76WEN3.js} +2 -2
- package/dist/{chunk-GDYYJTTT.js → chunk-V5R6O6RP.js} +3 -3
- package/dist/{chunk-6BSDCZ5Q.js → chunk-WBLTISAK.js} +8 -3
- package/dist/chunk-WBLTISAK.js.map +1 -0
- package/dist/{chunk-YTANWAGE.js → chunk-XNAM6Z4O.js} +2 -2
- package/dist/{chunk-P3WO3N3I.js → chunk-YG6MLLGL.js} +19 -3
- package/dist/{chunk-P3WO3N3I.js.map → chunk-YG6MLLGL.js.map} +1 -1
- package/dist/{cli-K7SUTP7A.js → cli-LMBBPV2D.js} +20 -20
- package/dist/{client-YJMNTITQ.js → client-FDKJ4BY7.js} +5 -5
- package/dist/{config-G5GGT5A6.js → config-HDUFDOQN.js} +3 -3
- package/dist/{curate-6T5NKVXK.js → curate-DYE4VCBJ.js} +10 -11
- package/dist/{curate-6T5NKVXK.js.map → curate-DYE4VCBJ.js.map} +1 -1
- package/dist/{detect-providers-S3M5TAMW.js → detect-providers-I2QQFDJW.js} +3 -3
- package/dist/{digest-O35VHYFP.js → digest-PNHFM7JJ.js} +11 -13
- package/dist/{digest-O35VHYFP.js.map → digest-PNHFM7JJ.js.map} +1 -1
- package/dist/{init-TFLSATB3.js → init-7N7F6W6U.js} +8 -8
- package/dist/{main-JEUQS3BY.js → main-3JZDUJLU.js} +177 -40
- package/dist/main-3JZDUJLU.js.map +1 -0
- package/dist/{rebuild-7SH5GSNX.js → rebuild-WXKQ5HZO.js} +10 -11
- package/dist/{rebuild-7SH5GSNX.js.map → rebuild-WXKQ5HZO.js.map} +1 -1
- package/dist/reprocess-PKRDV67L.js +79 -0
- package/dist/reprocess-PKRDV67L.js.map +1 -0
- package/dist/{restart-NLJLB52D.js → restart-WSJRHRHI.js} +6 -6
- package/dist/{search-2BVRF54H.js → search-SWMJ4MZ3.js} +6 -6
- package/dist/{server-4AMZNP4F.js → server-NTRVB5ZM.js} +14 -18
- package/dist/{server-4AMZNP4F.js.map → server-NTRVB5ZM.js.map} +1 -1
- package/dist/{session-start-AZAF3DTE.js → session-start-KQ4KCQMZ.js} +9 -9
- package/dist/setup-digest-BOYOSM4B.js +15 -0
- package/dist/setup-llm-PCZ64ALK.js +15 -0
- package/dist/src/cli.js +4 -4
- package/dist/src/daemon/main.js +4 -4
- package/dist/src/hooks/post-tool-use.js +5 -5
- package/dist/src/hooks/session-end.js +5 -5
- package/dist/src/hooks/session-start.js +4 -4
- package/dist/src/hooks/stop.js +7 -7
- package/dist/src/hooks/user-prompt-submit.js +5 -5
- package/dist/src/mcp/server.js +4 -4
- package/dist/src/prompts/consolidation.md +2 -0
- package/dist/src/prompts/digest-7500.md +68 -0
- package/dist/{stats-MKDIZFIQ.js → stats-2OUQSEZO.js} +6 -6
- package/dist/ui/assets/index-Bk4X_8-Z.css +1 -0
- package/dist/ui/assets/index-D3SY7ZHY.js +299 -0
- package/dist/ui/index.html +2 -2
- package/dist/{verify-7DW7LAND.js → verify-MG5O7SBU.js} +6 -6
- package/dist/{version-RQLD7VBP.js → version-NKOECSVH.js} +4 -4
- package/package.json +3 -3
- package/dist/chunk-24DOZEUJ.js.map +0 -1
- package/dist/chunk-2ZBB3MQT.js.map +0 -1
- package/dist/chunk-3JCXYLHD.js +0 -33
- package/dist/chunk-3JCXYLHD.js.map +0 -1
- package/dist/chunk-6BSDCZ5Q.js.map +0 -1
- package/dist/chunk-B5UZSHQV.js +0 -250
- package/dist/chunk-B5UZSHQV.js.map +0 -1
- package/dist/chunk-E7OBRBCQ.js.map +0 -1
- package/dist/chunk-KC7ENQTN.js +0 -436
- package/dist/chunk-KC7ENQTN.js.map +0 -1
- package/dist/chunk-QGJ2ZIUZ.js.map +0 -1
- package/dist/chunk-UVGAVYWZ.js +0 -157
- package/dist/chunk-UVGAVYWZ.js.map +0 -1
- package/dist/chunk-ZMYNRTTD.js.map +0 -1
- package/dist/main-JEUQS3BY.js.map +0 -1
- package/dist/reprocess-Q4YH2ZBK.js +0 -268
- package/dist/reprocess-Q4YH2ZBK.js.map +0 -1
- package/dist/setup-digest-YLZZGSSR.js +0 -15
- package/dist/setup-llm-JOXBSLXC.js +0 -15
- package/dist/ui/assets/index-D37IoDXS.css +0 -1
- package/dist/ui/assets/index-DA61Ial2.js +0 -289
- /package/dist/{chunk-2YBUL3IL.js.map → chunk-25DJSF2K.js.map} +0 -0
- /package/dist/{chunk-2GSX3BK2.js.map → chunk-CPVXNRGW.js.map} +0 -0
- /package/dist/{chunk-L25U7PIG.js.map → chunk-CQ4RKK67.js.map} +0 -0
- /package/dist/{chunk-5FNZ7AMX.js.map → chunk-IWBWZQK6.js.map} +0 -0
- /package/dist/{chunk-5QWZT4AB.js.map → chunk-RNWALAFP.js.map} +0 -0
- /package/dist/{chunk-3EM23DMD.js.map → chunk-RXJHB7W4.js.map} +0 -0
- /package/dist/{chunk-GNR3QAER.js.map → chunk-RY76WEN3.js.map} +0 -0
- /package/dist/{chunk-GDYYJTTT.js.map → chunk-V5R6O6RP.js.map} +0 -0
- /package/dist/{chunk-YTANWAGE.js.map → chunk-XNAM6Z4O.js.map} +0 -0
- /package/dist/{cli-K7SUTP7A.js.map → cli-LMBBPV2D.js.map} +0 -0
- /package/dist/{client-YJMNTITQ.js.map → client-FDKJ4BY7.js.map} +0 -0
- /package/dist/{config-G5GGT5A6.js.map → config-HDUFDOQN.js.map} +0 -0
- /package/dist/{detect-providers-S3M5TAMW.js.map → detect-providers-I2QQFDJW.js.map} +0 -0
- /package/dist/{init-TFLSATB3.js.map → init-7N7F6W6U.js.map} +0 -0
- /package/dist/{restart-NLJLB52D.js.map → restart-WSJRHRHI.js.map} +0 -0
- /package/dist/{search-2BVRF54H.js.map → search-SWMJ4MZ3.js.map} +0 -0
- /package/dist/{session-start-AZAF3DTE.js.map → session-start-KQ4KCQMZ.js.map} +0 -0
- /package/dist/{setup-digest-YLZZGSSR.js.map → setup-digest-BOYOSM4B.js.map} +0 -0
- /package/dist/{setup-llm-JOXBSLXC.js.map → setup-llm-PCZ64ALK.js.map} +0 -0
- /package/dist/{stats-MKDIZFIQ.js.map → stats-2OUQSEZO.js.map} +0 -0
- /package/dist/{verify-7DW7LAND.js.map → verify-MG5O7SBU.js.map} +0 -0
- /package/dist/{version-RQLD7VBP.js.map → version-NKOECSVH.js.map} +0 -0
|
@@ -1,43 +1,61 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
ARTIFACT_TYPES,
|
|
4
|
+
CONVERSATION_HEADING,
|
|
5
|
+
VaultWriter,
|
|
6
|
+
bareSessionId,
|
|
7
|
+
buildClassificationPrompt,
|
|
8
|
+
buildExtractionPrompt,
|
|
9
|
+
buildSummaryPrompt,
|
|
10
|
+
buildTitlePrompt,
|
|
11
|
+
callout,
|
|
12
|
+
extractJson,
|
|
13
|
+
extractSection,
|
|
12
14
|
formatNoteForPrompt,
|
|
13
15
|
formatNotesForPrompt,
|
|
16
|
+
formatSporeBody,
|
|
17
|
+
indexNote,
|
|
18
|
+
isActiveSpore,
|
|
14
19
|
loadPrompt,
|
|
15
20
|
rebuildIndex,
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
require_gray_matter,
|
|
22
|
+
sessionNoteId,
|
|
23
|
+
stripReasoningTokens,
|
|
24
|
+
supersedeSpore,
|
|
25
|
+
supersededIdsSchema
|
|
26
|
+
} from "./chunk-ALBVNGCF.js";
|
|
18
27
|
import {
|
|
19
28
|
generateEmbedding
|
|
20
29
|
} from "./chunk-RGVBGTD6.js";
|
|
21
30
|
import {
|
|
22
31
|
stripFrontmatter
|
|
23
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-RY76WEN3.js";
|
|
24
33
|
import {
|
|
25
34
|
initFts
|
|
26
35
|
} from "./chunk-6FQISQNA.js";
|
|
27
36
|
import {
|
|
37
|
+
external_exports,
|
|
28
38
|
require_dist
|
|
29
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-JSK7L46L.js";
|
|
40
|
+
import {
|
|
41
|
+
AgentRegistry,
|
|
42
|
+
claudeCodeAdapter,
|
|
43
|
+
createPerProjectAdapter
|
|
44
|
+
} from "./chunk-RNWALAFP.js";
|
|
30
45
|
import {
|
|
46
|
+
AI_RESPONSE_PREVIEW_CHARS,
|
|
31
47
|
CHARS_PER_TOKEN,
|
|
48
|
+
COMMAND_PREVIEW_CHARS,
|
|
32
49
|
CURATION_CLUSTER_SIMILARITY,
|
|
33
50
|
DIGEST_LLM_REQUEST_TIMEOUT_MS,
|
|
34
51
|
DIGEST_SUBSTRATE_TYPE_WEIGHTS,
|
|
35
52
|
DIGEST_TIER_MIN_CONTEXT,
|
|
36
53
|
EMBEDDING_INPUT_LIMIT,
|
|
37
54
|
LLM_REASONING_MODE,
|
|
55
|
+
PROMPT_PREVIEW_CHARS,
|
|
38
56
|
SUPERSESSION_MAX_TOKENS,
|
|
39
57
|
estimateTokens
|
|
40
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-WBLTISAK.js";
|
|
41
59
|
import {
|
|
42
60
|
__toESM
|
|
43
61
|
} from "./chunk-PZUWP5VK.js";
|
|
@@ -226,6 +244,11 @@ ${body}
|
|
|
226
244
|
}
|
|
227
245
|
this.cycleInProgress = true;
|
|
228
246
|
try {
|
|
247
|
+
if (this.llm.ensureLoaded) {
|
|
248
|
+
const { context_window: contextWindow, gpu_kv_cache: gpuKvCache } = this.config.digest.intelligence;
|
|
249
|
+
this.log("debug", "Verifying digest model", { contextWindow, gpuKvCache });
|
|
250
|
+
await this.llm.ensureLoaded(contextWindow, gpuKvCache);
|
|
251
|
+
}
|
|
229
252
|
for (const hook of this.prePassHooks) {
|
|
230
253
|
try {
|
|
231
254
|
await hook.fn();
|
|
@@ -239,11 +262,6 @@ ${body}
|
|
|
239
262
|
}
|
|
240
263
|
}
|
|
241
264
|
async runCycleInternal(opts) {
|
|
242
|
-
if (this.llm.ensureLoaded) {
|
|
243
|
-
const { context_window: contextWindow, gpu_kv_cache: gpuKvCache } = this.config.digest.intelligence;
|
|
244
|
-
this.log("debug", "Verifying digest model", { contextWindow, gpuKvCache });
|
|
245
|
-
await this.llm.ensureLoaded(contextWindow, gpuKvCache);
|
|
246
|
-
}
|
|
247
265
|
const startTime = Date.now();
|
|
248
266
|
const fullReprocess = opts?.fullReprocess ?? false;
|
|
249
267
|
const lastTimestamp = fullReprocess ? null : this.getLastCycleTimestamp();
|
|
@@ -431,7 +449,249 @@ var Metabolism = class {
|
|
|
431
449
|
}
|
|
432
450
|
};
|
|
433
451
|
|
|
452
|
+
// src/daemon/processor.ts
|
|
453
|
+
var SUMMARIZATION_FAILED_MARKER = "summarization failed";
|
|
454
|
+
var ClassificationResponseSchema = external_exports.object({
|
|
455
|
+
artifacts: external_exports.array(external_exports.object({
|
|
456
|
+
source_path: external_exports.string(),
|
|
457
|
+
artifact_type: external_exports.enum(ARTIFACT_TYPES),
|
|
458
|
+
title: external_exports.string(),
|
|
459
|
+
tags: external_exports.array(external_exports.string()).default([])
|
|
460
|
+
})).default([])
|
|
461
|
+
});
|
|
462
|
+
var BufferProcessor = class {
|
|
463
|
+
constructor(backend, contextWindow = 8192, captureConfig) {
|
|
464
|
+
this.backend = backend;
|
|
465
|
+
this.contextWindow = contextWindow;
|
|
466
|
+
this.extractionMaxTokens = captureConfig?.extraction_max_tokens ?? 2048;
|
|
467
|
+
this.summaryMaxTokens = captureConfig?.summary_max_tokens ?? 512;
|
|
468
|
+
this.titleMaxTokens = captureConfig?.title_max_tokens ?? 32;
|
|
469
|
+
this.classificationMaxTokens = captureConfig?.classification_max_tokens ?? 1024;
|
|
470
|
+
}
|
|
471
|
+
extractionMaxTokens;
|
|
472
|
+
summaryMaxTokens;
|
|
473
|
+
titleMaxTokens;
|
|
474
|
+
classificationMaxTokens;
|
|
475
|
+
truncateForContext(data, maxTokens) {
|
|
476
|
+
const available = this.contextWindow - maxTokens;
|
|
477
|
+
const dataTokens = estimateTokens(data);
|
|
478
|
+
if (dataTokens <= available) return data;
|
|
479
|
+
const charBudget = available * CHARS_PER_TOKEN;
|
|
480
|
+
return data.slice(0, charBudget);
|
|
481
|
+
}
|
|
482
|
+
async process(events, sessionId) {
|
|
483
|
+
const rawPrompt = this.buildPromptForExtraction(events, sessionId);
|
|
484
|
+
const prompt = this.truncateForContext(rawPrompt, this.extractionMaxTokens);
|
|
485
|
+
try {
|
|
486
|
+
const response = await this.backend.summarize(prompt, { maxTokens: this.extractionMaxTokens, reasoning: LLM_REASONING_MODE });
|
|
487
|
+
const parsed = extractJson(response.text);
|
|
488
|
+
return {
|
|
489
|
+
summary: parsed.summary,
|
|
490
|
+
observations: parsed.observations ?? [],
|
|
491
|
+
degraded: false
|
|
492
|
+
};
|
|
493
|
+
} catch (error) {
|
|
494
|
+
return {
|
|
495
|
+
summary: `LLM processing failed for session ${sessionId}. ${events.length} events captured. Error: ${error.message}`,
|
|
496
|
+
observations: [],
|
|
497
|
+
degraded: true
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
buildPromptForExtraction(events, sessionId) {
|
|
502
|
+
const toolSummary = this.summarizeEvents(events);
|
|
503
|
+
return buildExtractionPrompt(sessionId, events.length, toolSummary, this.extractionMaxTokens);
|
|
504
|
+
}
|
|
505
|
+
async summarizeSession(conversationMarkdown, sessionId, user) {
|
|
506
|
+
const truncatedContent = this.truncateForContext(conversationMarkdown, this.summaryMaxTokens);
|
|
507
|
+
const summaryPrompt = buildSummaryPrompt(sessionId, user ?? "unknown", truncatedContent, this.summaryMaxTokens);
|
|
508
|
+
let summaryText;
|
|
509
|
+
try {
|
|
510
|
+
const response = await this.backend.summarize(summaryPrompt, { maxTokens: this.summaryMaxTokens, reasoning: LLM_REASONING_MODE });
|
|
511
|
+
summaryText = stripReasoningTokens(response.text);
|
|
512
|
+
} catch (error) {
|
|
513
|
+
summaryText = `Session ${sessionId} \u2014 ${SUMMARIZATION_FAILED_MARKER}: ${error.message}`;
|
|
514
|
+
}
|
|
515
|
+
const titlePrompt = buildTitlePrompt(summaryText, sessionId);
|
|
516
|
+
let title;
|
|
517
|
+
try {
|
|
518
|
+
const response = await this.backend.summarize(titlePrompt, { maxTokens: this.titleMaxTokens, reasoning: LLM_REASONING_MODE });
|
|
519
|
+
title = stripReasoningTokens(response.text).trim();
|
|
520
|
+
} catch {
|
|
521
|
+
title = `Session ${sessionId}`;
|
|
522
|
+
}
|
|
523
|
+
return { summary: summaryText, title };
|
|
524
|
+
}
|
|
525
|
+
async classifyArtifacts(candidates, sessionId) {
|
|
526
|
+
if (candidates.length === 0) return [];
|
|
527
|
+
const prompt = this.buildPromptForClassification(candidates, sessionId);
|
|
528
|
+
const response = await this.backend.summarize(prompt, { maxTokens: this.classificationMaxTokens, reasoning: LLM_REASONING_MODE });
|
|
529
|
+
const raw = extractJson(response.text);
|
|
530
|
+
const parsed = ClassificationResponseSchema.parse(raw);
|
|
531
|
+
return parsed.artifacts;
|
|
532
|
+
}
|
|
533
|
+
buildPromptForClassification(candidates, sessionId) {
|
|
534
|
+
return buildClassificationPrompt(sessionId, candidates, this.classificationMaxTokens);
|
|
535
|
+
}
|
|
536
|
+
summarizeEvents(events) {
|
|
537
|
+
const toolCounts = /* @__PURE__ */ new Map();
|
|
538
|
+
const filesAccessed = /* @__PURE__ */ new Set();
|
|
539
|
+
const prompts = [];
|
|
540
|
+
const aiResponses = [];
|
|
541
|
+
for (const event of events) {
|
|
542
|
+
if (event.type === "user_prompt") {
|
|
543
|
+
const prompt = String(event.prompt ?? "");
|
|
544
|
+
if (prompt) prompts.push(prompt.slice(0, PROMPT_PREVIEW_CHARS));
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
if (event.type === "ai_response") {
|
|
548
|
+
const content = String(event.content ?? "");
|
|
549
|
+
if (content) aiResponses.push(content.slice(0, AI_RESPONSE_PREVIEW_CHARS));
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
const tool = String(event.tool_name ?? event.tool ?? "unknown");
|
|
553
|
+
toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);
|
|
554
|
+
const input = event.tool_input ?? event.input;
|
|
555
|
+
if (input?.path) filesAccessed.add(String(input.path));
|
|
556
|
+
if (input?.file_path) filesAccessed.add(String(input.file_path));
|
|
557
|
+
if (input?.command) filesAccessed.add(`[cmd] ${String(input.command).slice(0, COMMAND_PREVIEW_CHARS)}`);
|
|
558
|
+
}
|
|
559
|
+
const lines = [];
|
|
560
|
+
if (prompts.length > 0) {
|
|
561
|
+
lines.push("### User Prompts");
|
|
562
|
+
for (const p of prompts) {
|
|
563
|
+
lines.push(`- "${p}"`);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
lines.push("\n### Tool Usage");
|
|
567
|
+
for (const [tool, count] of toolCounts) {
|
|
568
|
+
lines.push(`- ${tool}: ${count} calls`);
|
|
569
|
+
}
|
|
570
|
+
if (filesAccessed.size > 0) {
|
|
571
|
+
lines.push("\n### Files Accessed");
|
|
572
|
+
for (const file of filesAccessed) {
|
|
573
|
+
lines.push(`- ${file}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (aiResponses.length > 0) {
|
|
577
|
+
lines.push("\n### AI Responses");
|
|
578
|
+
for (const r of aiResponses) {
|
|
579
|
+
lines.push(`- "${r}"`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return lines.join("\n");
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
// src/capture/transcript-miner.ts
|
|
587
|
+
var TranscriptMiner = class {
|
|
588
|
+
registry;
|
|
589
|
+
constructor(config) {
|
|
590
|
+
this.registry = new AgentRegistry(config?.additionalAdapters);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Extract all conversation turns for a session.
|
|
594
|
+
* Convenience wrapper — delegates to getAllTurnsWithSource.
|
|
595
|
+
*/
|
|
596
|
+
getAllTurns(sessionId) {
|
|
597
|
+
return this.getAllTurnsWithSource(sessionId).turns;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Extract turns using the hook-provided transcript path first (fast, no scanning),
|
|
601
|
+
* then fall back to adapter registry scanning if the path isn't provided.
|
|
602
|
+
*/
|
|
603
|
+
getAllTurnsWithSource(sessionId, transcriptPath) {
|
|
604
|
+
if (transcriptPath) {
|
|
605
|
+
const result2 = this.registry.parseTurnsFromPath(transcriptPath);
|
|
606
|
+
if (result2) return result2;
|
|
607
|
+
}
|
|
608
|
+
const result = this.registry.getTranscriptTurns(sessionId);
|
|
609
|
+
if (result) return result;
|
|
610
|
+
return { turns: [], source: "none" };
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
function extractTurnsFromBuffer(events) {
|
|
614
|
+
const turns = [];
|
|
615
|
+
let current = null;
|
|
616
|
+
for (const event of events) {
|
|
617
|
+
const type = event.type;
|
|
618
|
+
if (type === "user_prompt") {
|
|
619
|
+
if (current) turns.push(current);
|
|
620
|
+
current = {
|
|
621
|
+
prompt: String(event.prompt ?? "").slice(0, PROMPT_PREVIEW_CHARS),
|
|
622
|
+
toolCount: 0,
|
|
623
|
+
timestamp: String(event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
624
|
+
};
|
|
625
|
+
} else if (type === "tool_use") {
|
|
626
|
+
if (current) current.toolCount++;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
if (current) turns.push(current);
|
|
630
|
+
return turns;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// src/vault/observations.ts
|
|
634
|
+
function writeObservationNotes(observations, sessionId, writer, index, vaultDir) {
|
|
635
|
+
const results = [];
|
|
636
|
+
for (const obs of observations) {
|
|
637
|
+
const obsId = `${obs.type}-${sessionId.slice(-6)}-${Date.now()}`;
|
|
638
|
+
const body = formatSporeBody({
|
|
639
|
+
title: obs.title,
|
|
640
|
+
observationType: obs.type,
|
|
641
|
+
content: obs.content,
|
|
642
|
+
sessionId,
|
|
643
|
+
root_cause: obs.root_cause,
|
|
644
|
+
fix: obs.fix,
|
|
645
|
+
rationale: obs.rationale,
|
|
646
|
+
alternatives_rejected: obs.alternatives_rejected,
|
|
647
|
+
gained: obs.gained,
|
|
648
|
+
sacrificed: obs.sacrificed,
|
|
649
|
+
tags: obs.tags
|
|
650
|
+
});
|
|
651
|
+
const relativePath = writer.writeSpore({
|
|
652
|
+
id: obsId,
|
|
653
|
+
observation_type: obs.type,
|
|
654
|
+
session: sessionNoteId(sessionId),
|
|
655
|
+
tags: obs.tags,
|
|
656
|
+
content: body
|
|
657
|
+
});
|
|
658
|
+
indexNote(index, vaultDir, relativePath);
|
|
659
|
+
results.push({ id: obsId, path: relativePath, observation: obs });
|
|
660
|
+
}
|
|
661
|
+
return results;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// src/services/vault-ops.ts
|
|
665
|
+
import fs3 from "fs";
|
|
666
|
+
import path3 from "path";
|
|
667
|
+
|
|
668
|
+
// src/intelligence/batch.ts
|
|
669
|
+
var LLM_BATCH_CONCURRENCY = 3;
|
|
670
|
+
var EMBEDDING_BATCH_CONCURRENCY = 4;
|
|
671
|
+
async function batchExecute(items, fn, options) {
|
|
672
|
+
const { concurrency, onProgress } = options;
|
|
673
|
+
let succeeded = 0;
|
|
674
|
+
let failed = 0;
|
|
675
|
+
const results = [];
|
|
676
|
+
for (let i = 0; i < items.length; i += concurrency) {
|
|
677
|
+
const batch = items.slice(i, i + concurrency);
|
|
678
|
+
const settled = await Promise.allSettled(batch.map(fn));
|
|
679
|
+
for (const result of settled) {
|
|
680
|
+
if (result.status === "fulfilled") {
|
|
681
|
+
succeeded++;
|
|
682
|
+
results.push({ status: "fulfilled", value: result.value });
|
|
683
|
+
} else {
|
|
684
|
+
failed++;
|
|
685
|
+
results.push({ status: "rejected", reason: result.reason?.message ?? String(result.reason) });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
onProgress?.(succeeded + failed, items.length);
|
|
689
|
+
}
|
|
690
|
+
return { succeeded, failed, results };
|
|
691
|
+
}
|
|
692
|
+
|
|
434
693
|
// src/services/vault-ops.ts
|
|
694
|
+
var import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
435
695
|
async function runRebuild(ctx, embeddingProvider, onProgress) {
|
|
436
696
|
const { index, vaultDir } = ctx;
|
|
437
697
|
initFts(index);
|
|
@@ -651,14 +911,177 @@ async function runCuration(deps, dryRun) {
|
|
|
651
911
|
superseded: totalSuperseded
|
|
652
912
|
};
|
|
653
913
|
}
|
|
914
|
+
function updateTitleAndSummary(body, newTitle, newNarrative) {
|
|
915
|
+
let updated = body.replace(/^# .*/m, `# ${newTitle}`);
|
|
916
|
+
const summaryCallout = callout("abstract", "Summary", newNarrative);
|
|
917
|
+
updated = updated.replace(/> \[!abstract\] Summary\n(?:> .*\n?)*/m, summaryCallout + "\n");
|
|
918
|
+
return updated;
|
|
919
|
+
}
|
|
920
|
+
async function runReprocess(ctx, llmProvider, embeddingProvider, options, onProgress) {
|
|
921
|
+
const { vaultDir, config, index } = ctx;
|
|
922
|
+
const log = ctx.log ?? (() => {
|
|
923
|
+
});
|
|
924
|
+
const sessionFilter = options?.session;
|
|
925
|
+
const dateFilter = options?.date;
|
|
926
|
+
const failedOnly = options?.failed ?? false;
|
|
927
|
+
const skipLlm = options?.indexOnly ?? false;
|
|
928
|
+
const effectiveLlm = skipLlm ? null : llmProvider;
|
|
929
|
+
const processor = effectiveLlm ? new BufferProcessor(effectiveLlm, config.intelligence.llm.context_window, config.capture) : null;
|
|
930
|
+
const writer = new VaultWriter(vaultDir);
|
|
931
|
+
const miner = new TranscriptMiner({
|
|
932
|
+
additionalAdapters: config.capture.transcript_paths.map(
|
|
933
|
+
(p) => createPerProjectAdapter(p, claudeCodeAdapter.parseTurns)
|
|
934
|
+
)
|
|
935
|
+
});
|
|
936
|
+
const sessionsDir = path3.join(vaultDir, "sessions");
|
|
937
|
+
if (!fs3.existsSync(sessionsDir)) {
|
|
938
|
+
return { sessionsFound: 0, sessionsProcessed: 0, observationsExtracted: 0, summariesRegenerated: 0, embeddingsQueued: 0 };
|
|
939
|
+
}
|
|
940
|
+
const sessionFiles = [];
|
|
941
|
+
for (const dateDir of fs3.readdirSync(sessionsDir)) {
|
|
942
|
+
if (dateFilter && dateDir !== dateFilter) continue;
|
|
943
|
+
const datePath = path3.join(sessionsDir, dateDir);
|
|
944
|
+
if (!fs3.statSync(datePath).isDirectory()) continue;
|
|
945
|
+
for (const file of fs3.readdirSync(datePath)) {
|
|
946
|
+
if (!file.startsWith("session-") || !file.endsWith(".md")) continue;
|
|
947
|
+
const sessionId = file.replace("session-", "").replace(".md", "");
|
|
948
|
+
if (sessionFilter && !sessionId.includes(sessionFilter)) continue;
|
|
949
|
+
sessionFiles.push({ relativePath: path3.join("sessions", dateDir, file), sessionId });
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (sessionFiles.length === 0) {
|
|
953
|
+
return { sessionsFound: 0, sessionsProcessed: 0, observationsExtracted: 0, summariesRegenerated: 0, embeddingsQueued: 0 };
|
|
954
|
+
}
|
|
955
|
+
const tasks = [];
|
|
956
|
+
for (const { relativePath, sessionId } of sessionFiles) {
|
|
957
|
+
const rawContent = fs3.readFileSync(path3.join(vaultDir, relativePath), "utf-8");
|
|
958
|
+
const hasFailed = rawContent.includes(SUMMARIZATION_FAILED_MARKER);
|
|
959
|
+
if (failedOnly && !hasFailed) continue;
|
|
960
|
+
const { data: frontmatter, content: body } = (0, import_gray_matter.default)(rawContent);
|
|
961
|
+
const bare = bareSessionId(sessionId);
|
|
962
|
+
const turnsResult = miner.getAllTurnsWithSource(bare);
|
|
963
|
+
const conversationSection = extractSection(body, CONVERSATION_HEADING);
|
|
964
|
+
const fmEnd = rawContent.indexOf("---", 4);
|
|
965
|
+
const frontmatterBlock = rawContent.slice(0, fmEnd + 3);
|
|
966
|
+
const batchEvents = turnsResult && turnsResult.turns.length > 0 ? turnsResult.turns.map((t) => ({
|
|
967
|
+
type: "turn",
|
|
968
|
+
prompt: t.prompt,
|
|
969
|
+
tool_count: t.toolCount,
|
|
970
|
+
response: t.aiResponse ?? "",
|
|
971
|
+
timestamp: t.timestamp
|
|
972
|
+
})) : null;
|
|
973
|
+
tasks.push({ relativePath, sessionId, bare, frontmatter, frontmatterBlock, body, conversationSection, batchEvents, turnCount: turnsResult?.turns.length ?? 0, hasFailed });
|
|
974
|
+
}
|
|
975
|
+
if (tasks.length === 0) {
|
|
976
|
+
return { sessionsFound: sessionFiles.length, sessionsProcessed: 0, observationsExtracted: 0, summariesRegenerated: 0, embeddingsQueued: 0 };
|
|
977
|
+
}
|
|
978
|
+
log("info", `Reprocessing ${tasks.length} session(s)`, { filters: { session: sessionFilter, date: dateFilter, failed: failedOnly, indexOnly: skipLlm } });
|
|
979
|
+
let embeddingsQueued = 0;
|
|
980
|
+
const embedPending = [];
|
|
981
|
+
const fireEmbed = (id, text, metadata) => {
|
|
982
|
+
if (!ctx.vectorIndex) return;
|
|
983
|
+
embeddingsQueued++;
|
|
984
|
+
const vec = ctx.vectorIndex;
|
|
985
|
+
const p = generateEmbedding(embeddingProvider, text).then((emb) => {
|
|
986
|
+
vec.upsert(id, emb.embedding, metadata);
|
|
987
|
+
}).catch((err) => {
|
|
988
|
+
log("warn", `Embedding failed for ${id}`, { error: err.message });
|
|
989
|
+
});
|
|
990
|
+
embedPending.push(p);
|
|
991
|
+
};
|
|
992
|
+
let totalObservations = 0;
|
|
993
|
+
const extractionResult = await batchExecute(
|
|
994
|
+
tasks,
|
|
995
|
+
async (task) => {
|
|
996
|
+
let obs = 0;
|
|
997
|
+
if (processor && task.batchEvents) {
|
|
998
|
+
const result = await processor.process(task.batchEvents, task.bare);
|
|
999
|
+
if (result.observations.length > 0) {
|
|
1000
|
+
writeObservationNotes(result.observations, task.bare, writer, index, vaultDir);
|
|
1001
|
+
obs = result.observations.length;
|
|
1002
|
+
for (const o of result.observations) {
|
|
1003
|
+
fireEmbed(
|
|
1004
|
+
`${o.type}-${task.bare.slice(-6)}-${Date.now()}`,
|
|
1005
|
+
`${o.title}
|
|
1006
|
+
${o.content}`.slice(0, EMBEDDING_INPUT_LIMIT),
|
|
1007
|
+
{ type: "spore", session_id: task.bare }
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
indexNote(index, vaultDir, task.relativePath);
|
|
1013
|
+
const embText = `${task.frontmatter.title ?? ""}
|
|
1014
|
+
${task.frontmatter.summary ?? ""}`.slice(0, EMBEDDING_INPUT_LIMIT);
|
|
1015
|
+
if (embText.trim()) {
|
|
1016
|
+
fireEmbed(sessionNoteId(task.bare), embText, { type: "session", session_id: task.bare });
|
|
1017
|
+
}
|
|
1018
|
+
return obs;
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
concurrency: LLM_BATCH_CONCURRENCY,
|
|
1022
|
+
onProgress: (done, total) => onProgress?.("extraction", done, total)
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
1025
|
+
for (const r of extractionResult.results) {
|
|
1026
|
+
if (r.status === "fulfilled") totalObservations += r.value;
|
|
1027
|
+
}
|
|
1028
|
+
let summarized = 0;
|
|
1029
|
+
if (processor) {
|
|
1030
|
+
const summarizableTasks = tasks.filter((t) => t.conversationSection);
|
|
1031
|
+
if (summarizableTasks.length > 0) {
|
|
1032
|
+
const summaryResult = await batchExecute(
|
|
1033
|
+
summarizableTasks,
|
|
1034
|
+
async (task) => {
|
|
1035
|
+
const user = typeof task.frontmatter.user === "string" ? task.frontmatter.user : void 0;
|
|
1036
|
+
const result = await processor.summarizeSession(task.conversationSection, task.bare, user);
|
|
1037
|
+
if (result.summary.includes(SUMMARIZATION_FAILED_MARKER)) {
|
|
1038
|
+
log("warn", `Summarization failed for ${task.sessionId.slice(0, 12)}`);
|
|
1039
|
+
return false;
|
|
1040
|
+
}
|
|
1041
|
+
const updatedBody = updateTitleAndSummary(task.body, result.title, result.summary);
|
|
1042
|
+
fs3.writeFileSync(path3.join(vaultDir, task.relativePath), task.frontmatterBlock + updatedBody);
|
|
1043
|
+
indexNote(index, vaultDir, task.relativePath);
|
|
1044
|
+
return true;
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
concurrency: LLM_BATCH_CONCURRENCY,
|
|
1048
|
+
onProgress: (done, total) => onProgress?.("summarization", done, total)
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1051
|
+
for (const r of summaryResult.results) {
|
|
1052
|
+
if (r.status === "fulfilled" && r.value) summarized++;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
await Promise.allSettled(embedPending);
|
|
1057
|
+
log("info", "Reprocess completed", {
|
|
1058
|
+
sessions: tasks.length,
|
|
1059
|
+
observations: totalObservations,
|
|
1060
|
+
summaries: summarized,
|
|
1061
|
+
embeddings: embeddingsQueued
|
|
1062
|
+
});
|
|
1063
|
+
return {
|
|
1064
|
+
sessionsFound: sessionFiles.length,
|
|
1065
|
+
sessionsProcessed: tasks.length,
|
|
1066
|
+
observationsExtracted: totalObservations,
|
|
1067
|
+
summariesRegenerated: summarized,
|
|
1068
|
+
embeddingsQueued
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
654
1071
|
|
|
655
1072
|
export {
|
|
656
1073
|
readLastTimestamp,
|
|
657
1074
|
appendTraceRecord,
|
|
658
1075
|
DigestEngine,
|
|
659
1076
|
Metabolism,
|
|
1077
|
+
SUMMARIZATION_FAILED_MARKER,
|
|
1078
|
+
BufferProcessor,
|
|
1079
|
+
TranscriptMiner,
|
|
1080
|
+
extractTurnsFromBuffer,
|
|
1081
|
+
writeObservationNotes,
|
|
660
1082
|
runRebuild,
|
|
661
1083
|
runDigest,
|
|
662
|
-
runCuration
|
|
1084
|
+
runCuration,
|
|
1085
|
+
runReprocess
|
|
663
1086
|
};
|
|
664
|
-
//# sourceMappingURL=chunk-
|
|
1087
|
+
//# sourceMappingURL=chunk-PQWQC3RF.js.map
|