@goondocks/myco 0.6.2 → 0.6.4

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 (98) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/dist/{chunk-LDKXXKF6.js → chunk-2ZIBCEYO.js} +4 -4
  4. package/dist/{chunk-PQWQC3RF.js → chunk-4XVKZ3WA.js} +137 -146
  5. package/dist/chunk-4XVKZ3WA.js.map +1 -0
  6. package/dist/{chunk-MWW62YZP.js → chunk-7WHF2OIZ.js} +21 -19
  7. package/dist/chunk-7WHF2OIZ.js.map +1 -0
  8. package/dist/{chunk-JSK7L46L.js → chunk-ERG2IEWX.js} +22 -4
  9. package/dist/{chunk-JSK7L46L.js.map → chunk-ERG2IEWX.js.map} +1 -1
  10. package/dist/{chunk-RXJHB7W4.js → chunk-FPRXMJLT.js} +2 -2
  11. package/dist/{chunk-RY76WEN3.js → chunk-GENQ5QGP.js} +2 -2
  12. package/dist/{chunk-YG6MLLGL.js → chunk-HYVT345Y.js} +2 -2
  13. package/dist/{chunk-WBLTISAK.js → chunk-J4D4CROB.js} +32 -6
  14. package/dist/chunk-J4D4CROB.js.map +1 -0
  15. package/dist/{chunk-IWBWZQK6.js → chunk-MDLSAFPP.js} +2 -2
  16. package/dist/{chunk-HRGHDMYI.js → chunk-NL6WQO56.js} +2 -2
  17. package/dist/{chunk-V5R6O6RP.js → chunk-NLUE6CYG.js} +3 -3
  18. package/dist/{chunk-CQ4RKK67.js → chunk-O6PERU7U.js} +2 -2
  19. package/dist/{chunk-XNAM6Z4O.js → chunk-P723N2LP.js} +2 -2
  20. package/dist/{chunk-CK24O5YQ.js → chunk-QN4W3JUA.js} +2 -2
  21. package/dist/{chunk-ALBVNGCF.js → chunk-UP4P4OAA.js} +55 -44
  22. package/dist/{chunk-ALBVNGCF.js.map → chunk-UP4P4OAA.js.map} +1 -1
  23. package/dist/{chunk-CPVXNRGW.js → chunk-YIQLYIHW.js} +4 -4
  24. package/dist/{chunk-25DJSF2K.js → chunk-YTFXA4RX.js} +3 -3
  25. package/dist/{chunk-RNWALAFP.js → chunk-Z74SDEKE.js} +2 -2
  26. package/dist/chunk-Z74SDEKE.js.map +1 -0
  27. package/dist/{cli-LMBBPV2D.js → cli-IHILSS6N.js} +20 -20
  28. package/dist/{client-FDKJ4BY7.js → client-AGFNR2S4.js} +5 -5
  29. package/dist/{config-HDUFDOQN.js → config-IBS6KOLQ.js} +3 -3
  30. package/dist/{curate-DYE4VCBJ.js → curate-3D4GHKJH.js} +9 -10
  31. package/dist/{curate-DYE4VCBJ.js.map → curate-3D4GHKJH.js.map} +1 -1
  32. package/dist/{detect-providers-I2QQFDJW.js → detect-providers-XEP4QA3R.js} +3 -3
  33. package/dist/{digest-PNHFM7JJ.js → digest-7HLJXL77.js} +11 -11
  34. package/dist/{init-7N7F6W6U.js → init-ARQ53JOR.js} +8 -8
  35. package/dist/{main-3JZDUJLU.js → main-6AGPIMH2.js} +1972 -374
  36. package/dist/main-6AGPIMH2.js.map +1 -0
  37. package/dist/{rebuild-WXKQ5HZO.js → rebuild-Q2ACEB6F.js} +9 -10
  38. package/dist/{rebuild-WXKQ5HZO.js.map → rebuild-Q2ACEB6F.js.map} +1 -1
  39. package/dist/{reprocess-PKRDV67L.js → reprocess-CDEFGQOV.js} +11 -11
  40. package/dist/{restart-WSJRHRHI.js → restart-XCMILOL5.js} +6 -6
  41. package/dist/{search-SWMJ4MZ3.js → search-7W25SKCB.js} +6 -6
  42. package/dist/{server-NTRVB5ZM.js → server-6UDN35QN.js} +11 -11
  43. package/dist/{session-start-KQ4KCQMZ.js → session-start-K6IGAC7H.js} +9 -9
  44. package/dist/setup-digest-X5PN27F4.js +15 -0
  45. package/dist/setup-llm-S5OHQJXK.js +15 -0
  46. package/dist/src/cli.js +4 -4
  47. package/dist/src/daemon/main.js +4 -4
  48. package/dist/src/hooks/post-tool-use.js +5 -5
  49. package/dist/src/hooks/session-end.js +5 -5
  50. package/dist/src/hooks/session-start.js +4 -4
  51. package/dist/src/hooks/stop.js +7 -7
  52. package/dist/src/hooks/user-prompt-submit.js +5 -5
  53. package/dist/src/mcp/server.js +4 -4
  54. package/dist/src/prompts/extraction.md +4 -4
  55. package/dist/{stats-2OUQSEZO.js → stats-TTSDXGJV.js} +6 -6
  56. package/dist/ui/assets/index-08wKT7wS.css +1 -0
  57. package/dist/ui/assets/index-CMSMi4Jb.js +369 -0
  58. package/dist/ui/index.html +2 -2
  59. package/dist/{verify-MG5O7SBU.js → verify-TOWQHPBX.js} +6 -6
  60. package/dist/{version-NKOECSVH.js → version-36RVCQA6.js} +4 -4
  61. package/package.json +1 -1
  62. package/dist/chunk-MWW62YZP.js.map +0 -1
  63. package/dist/chunk-PQWQC3RF.js.map +0 -1
  64. package/dist/chunk-RNWALAFP.js.map +0 -1
  65. package/dist/chunk-WBLTISAK.js.map +0 -1
  66. package/dist/main-3JZDUJLU.js.map +0 -1
  67. package/dist/setup-digest-BOYOSM4B.js +0 -15
  68. package/dist/setup-llm-PCZ64ALK.js +0 -15
  69. package/dist/ui/assets/index-Bk4X_8-Z.css +0 -1
  70. package/dist/ui/assets/index-D3SY7ZHY.js +0 -299
  71. /package/dist/{chunk-LDKXXKF6.js.map → chunk-2ZIBCEYO.js.map} +0 -0
  72. /package/dist/{chunk-RXJHB7W4.js.map → chunk-FPRXMJLT.js.map} +0 -0
  73. /package/dist/{chunk-RY76WEN3.js.map → chunk-GENQ5QGP.js.map} +0 -0
  74. /package/dist/{chunk-YG6MLLGL.js.map → chunk-HYVT345Y.js.map} +0 -0
  75. /package/dist/{chunk-IWBWZQK6.js.map → chunk-MDLSAFPP.js.map} +0 -0
  76. /package/dist/{chunk-HRGHDMYI.js.map → chunk-NL6WQO56.js.map} +0 -0
  77. /package/dist/{chunk-V5R6O6RP.js.map → chunk-NLUE6CYG.js.map} +0 -0
  78. /package/dist/{chunk-CQ4RKK67.js.map → chunk-O6PERU7U.js.map} +0 -0
  79. /package/dist/{chunk-XNAM6Z4O.js.map → chunk-P723N2LP.js.map} +0 -0
  80. /package/dist/{chunk-CK24O5YQ.js.map → chunk-QN4W3JUA.js.map} +0 -0
  81. /package/dist/{chunk-CPVXNRGW.js.map → chunk-YIQLYIHW.js.map} +0 -0
  82. /package/dist/{chunk-25DJSF2K.js.map → chunk-YTFXA4RX.js.map} +0 -0
  83. /package/dist/{cli-LMBBPV2D.js.map → cli-IHILSS6N.js.map} +0 -0
  84. /package/dist/{client-FDKJ4BY7.js.map → client-AGFNR2S4.js.map} +0 -0
  85. /package/dist/{config-HDUFDOQN.js.map → config-IBS6KOLQ.js.map} +0 -0
  86. /package/dist/{detect-providers-I2QQFDJW.js.map → detect-providers-XEP4QA3R.js.map} +0 -0
  87. /package/dist/{digest-PNHFM7JJ.js.map → digest-7HLJXL77.js.map} +0 -0
  88. /package/dist/{init-7N7F6W6U.js.map → init-ARQ53JOR.js.map} +0 -0
  89. /package/dist/{reprocess-PKRDV67L.js.map → reprocess-CDEFGQOV.js.map} +0 -0
  90. /package/dist/{restart-WSJRHRHI.js.map → restart-XCMILOL5.js.map} +0 -0
  91. /package/dist/{search-SWMJ4MZ3.js.map → search-7W25SKCB.js.map} +0 -0
  92. /package/dist/{server-NTRVB5ZM.js.map → server-6UDN35QN.js.map} +0 -0
  93. /package/dist/{session-start-KQ4KCQMZ.js.map → session-start-K6IGAC7H.js.map} +0 -0
  94. /package/dist/{setup-digest-BOYOSM4B.js.map → setup-digest-X5PN27F4.js.map} +0 -0
  95. /package/dist/{setup-llm-PCZ64ALK.js.map → setup-llm-S5OHQJXK.js.map} +0 -0
  96. /package/dist/{stats-2OUQSEZO.js.map → stats-TTSDXGJV.js.map} +0 -0
  97. /package/dist/{verify-MG5O7SBU.js.map → verify-TOWQHPBX.js.map} +0 -0
  98. /package/dist/{version-NKOECSVH.js.map → version-36RVCQA6.js.map} +0 -0
@@ -12,7 +12,7 @@
12
12
  "source": {
13
13
  "source": "npm",
14
14
  "package": "@goondocks/myco",
15
- "version": "0.6.1"
15
+ "version": "0.6.3"
16
16
  },
17
17
  "description": "Collective agent intelligence — captures session knowledge and serves it back via MCP",
18
18
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myco",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Collective agent intelligence — captures session knowledge and serves it back to your team via MCP",
5
5
  "author": {
6
6
  "name": "goondocks-co",
@@ -3,17 +3,17 @@ import {
3
3
  VaultWriter,
4
4
  indexNote,
5
5
  supersedeSpore
6
- } from "./chunk-ALBVNGCF.js";
6
+ } from "./chunk-UP4P4OAA.js";
7
7
  import {
8
8
  generateEmbedding
9
9
  } from "./chunk-RGVBGTD6.js";
10
10
  import {
11
11
  stripFrontmatter
12
- } from "./chunk-RY76WEN3.js";
12
+ } from "./chunk-GENQ5QGP.js";
13
13
  import {
14
14
  DIGEST_TIERS,
15
15
  EMBEDDING_INPUT_LIMIT
16
- } from "./chunk-WBLTISAK.js";
16
+ } from "./chunk-J4D4CROB.js";
17
17
 
18
18
  // src/mcp/tools/context.ts
19
19
  import fs from "fs";
@@ -110,4 +110,4 @@ export {
110
110
  consolidateSpores,
111
111
  handleMycoContext
112
112
  };
113
- //# sourceMappingURL=chunk-LDKXXKF6.js.map
113
+ //# sourceMappingURL=chunk-2ZIBCEYO.js.map
@@ -2,6 +2,7 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  ARTIFACT_TYPES,
4
4
  CONVERSATION_HEADING,
5
+ TURN_HEADING_PREFIX,
5
6
  VaultWriter,
6
7
  bareSessionId,
7
8
  buildClassificationPrompt,
@@ -23,39 +24,32 @@ import {
23
24
  stripReasoningTokens,
24
25
  supersedeSpore,
25
26
  supersededIdsSchema
26
- } from "./chunk-ALBVNGCF.js";
27
+ } from "./chunk-UP4P4OAA.js";
27
28
  import {
28
29
  generateEmbedding
29
30
  } from "./chunk-RGVBGTD6.js";
30
31
  import {
31
32
  stripFrontmatter
32
- } from "./chunk-RY76WEN3.js";
33
+ } from "./chunk-GENQ5QGP.js";
33
34
  import {
34
35
  initFts
35
36
  } from "./chunk-6FQISQNA.js";
36
37
  import {
37
38
  external_exports,
38
39
  require_dist
39
- } from "./chunk-JSK7L46L.js";
40
+ } from "./chunk-ERG2IEWX.js";
40
41
  import {
41
- AgentRegistry,
42
- claudeCodeAdapter,
43
- createPerProjectAdapter
44
- } from "./chunk-RNWALAFP.js";
45
- import {
46
- AI_RESPONSE_PREVIEW_CHARS,
47
42
  CHARS_PER_TOKEN,
48
- COMMAND_PREVIEW_CHARS,
49
43
  CURATION_CLUSTER_SIMILARITY,
50
44
  DIGEST_LLM_REQUEST_TIMEOUT_MS,
51
45
  DIGEST_SUBSTRATE_TYPE_WEIGHTS,
46
+ DIGEST_TIERS,
52
47
  DIGEST_TIER_MIN_CONTEXT,
53
48
  EMBEDDING_INPUT_LIMIT,
54
49
  LLM_REASONING_MODE,
55
- PROMPT_PREVIEW_CHARS,
56
50
  SUPERSESSION_MAX_TOKENS,
57
51
  estimateTokens
58
- } from "./chunk-WBLTISAK.js";
52
+ } from "./chunk-J4D4CROB.js";
59
53
  import {
60
54
  __toESM
61
55
  } from "./chunk-PZUWP5VK.js";
@@ -69,7 +63,7 @@ import crypto from "crypto";
69
63
  // src/daemon/trace.ts
70
64
  import fs from "fs";
71
65
  import path from "path";
72
- function readLastTimestamp(filePath) {
66
+ function readLastRecord(filePath) {
73
67
  let content;
74
68
  try {
75
69
  content = fs.readFileSync(filePath, "utf-8").trim();
@@ -80,12 +74,14 @@ function readLastTimestamp(filePath) {
80
74
  const lines = content.split("\n");
81
75
  const lastLine = lines[lines.length - 1];
82
76
  try {
83
- const record = JSON.parse(lastLine);
84
- return record.timestamp ?? null;
77
+ return JSON.parse(lastLine);
85
78
  } catch {
86
79
  return null;
87
80
  }
88
81
  }
82
+ function readLastTimestamp(filePath) {
83
+ return readLastRecord(filePath)?.timestamp ?? null;
84
+ }
89
85
  function appendTraceRecord(filePath, record) {
90
86
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
91
87
  fs.appendFileSync(filePath, JSON.stringify(record) + "\n", "utf-8");
@@ -103,6 +99,10 @@ var DigestEngine = class {
103
99
  log;
104
100
  lastCycleTimestampCache = void 0;
105
101
  cycleInProgress = false;
102
+ /** Whether a digest cycle is currently running. */
103
+ get isCycleInProgress() {
104
+ return this.cycleInProgress;
105
+ }
106
106
  /** Hooks that run before each digest cycle (e.g., consolidation). */
107
107
  prePassHooks = [];
108
108
  /** Hooks that run after each successful digest cycle. */
@@ -149,7 +149,7 @@ var DigestEngine = class {
149
149
  */
150
150
  getEligibleTiers() {
151
151
  const contextWindow = this.config.digest.intelligence.context_window;
152
- return this.config.digest.tiers.filter((tier) => {
152
+ return DIGEST_TIERS.filter((tier) => {
153
153
  const minContext = DIGEST_TIER_MIN_CONTEXT[tier];
154
154
  return minContext !== void 0 && minContext <= contextWindow;
155
155
  });
@@ -189,7 +189,7 @@ ${note.content}`;
189
189
  * Write a digest extract to the vault with YAML frontmatter.
190
190
  * Uses atomic write pattern (temp file + rename).
191
191
  */
192
- writeExtract(tier, body, cycleId, model, substrateCount) {
192
+ writeExtract(tier, body, cycleId, model, substrateCount, substrateNotes, tokensUsed) {
193
193
  const digestDir = path2.join(this.vaultDir, "digest");
194
194
  fs2.mkdirSync(digestDir, { recursive: true });
195
195
  const frontmatter = {
@@ -200,6 +200,8 @@ ${note.content}`;
200
200
  substrate_count: substrateCount,
201
201
  model
202
202
  };
203
+ if (substrateNotes && substrateNotes.length > 0) frontmatter.substrate_notes = substrateNotes;
204
+ if (tokensUsed !== void 0) frontmatter.tokens_used = tokensUsed;
203
205
  const fmYaml = import_yaml.default.stringify(frontmatter, {
204
206
  defaultStringType: "QUOTE_DOUBLE",
205
207
  defaultKeyType: "PLAIN"
@@ -301,6 +303,7 @@ ${body}
301
303
  }
302
304
  const cycleTimestamp = (/* @__PURE__ */ new Date()).toISOString();
303
305
  const systemPrompt = loadPrompt("digest-system");
306
+ const allSubstrateIds = substrate.map((note) => note.id);
304
307
  for (const tier of eligibleTiers) {
305
308
  const tierPrompt = loadPrompt(`digest-${tier}`);
306
309
  const previousExtract = opts?.cleanSlate ? null : this.readPreviousExtract(tier);
@@ -343,12 +346,34 @@ ${body}
343
346
  const responseTokens = estimateTokens(extractText);
344
347
  totalTokensUsed += promptTokens + responseTokens;
345
348
  this.log("info", `Tier ${tier}: completed`, { durationMs: tierDuration, responseTokens, model: response.model });
346
- this.writeExtract(tier, extractText, cycleId, response.model, substrate.length);
349
+ this.writeExtract(tier, extractText, cycleId, response.model, substrate.length, allSubstrateIds, promptTokens + responseTokens);
347
350
  tiersGenerated.push(tier);
348
351
  } catch (err) {
349
352
  this.log("warn", `Tier ${tier}: failed`, { error: err.message });
350
353
  }
351
354
  }
355
+ if (tiersGenerated.length > 0) {
356
+ const digestDir = path2.join(this.vaultDir, "digest");
357
+ for (const tier of tiersGenerated) {
358
+ const extractPath = path2.join(digestDir, `extract-${tier}.md`);
359
+ try {
360
+ const content = fs2.readFileSync(extractPath, "utf-8");
361
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
362
+ if (fmMatch) {
363
+ const parsed = import_yaml.default.parse(fmMatch[1]);
364
+ parsed.tiers_generated = tiersGenerated;
365
+ const fmYaml = import_yaml.default.stringify(parsed, { defaultStringType: "QUOTE_DOUBLE", defaultKeyType: "PLAIN" }).trim();
366
+ const extractBody = content.slice(fmMatch[0].length);
367
+ const tmpPath = `${extractPath}.tmp`;
368
+ fs2.writeFileSync(tmpPath, `---
369
+ ${fmYaml}
370
+ ---${extractBody}`, "utf-8");
371
+ fs2.renameSync(tmpPath, extractPath);
372
+ }
373
+ } catch {
374
+ }
375
+ }
376
+ }
352
377
  const result = {
353
378
  cycleId,
354
379
  timestamp: cycleTimestamp,
@@ -450,6 +475,7 @@ var Metabolism = class {
450
475
  };
451
476
 
452
477
  // src/daemon/processor.ts
478
+ var EXTRACTION_PROMPT_OVERHEAD_TOKENS = 500;
453
479
  var SUMMARIZATION_FAILED_MARKER = "summarization failed";
454
480
  var ClassificationResponseSchema = external_exports.object({
455
481
  artifacts: external_exports.array(external_exports.object({
@@ -479,11 +505,26 @@ var BufferProcessor = class {
479
505
  const charBudget = available * CHARS_PER_TOKEN;
480
506
  return data.slice(0, charBudget);
481
507
  }
482
- async process(events, sessionId) {
483
- const rawPrompt = this.buildPromptForExtraction(events, sessionId);
484
- const prompt = this.truncateForContext(rawPrompt, this.extractionMaxTokens);
508
+ async process(conversationMarkdown, sessionId) {
509
+ if (!conversationMarkdown.trim()) {
510
+ return { summary: "", observations: [], degraded: false };
511
+ }
512
+ const availableTokens = this.contextWindow - EXTRACTION_PROMPT_OVERHEAD_TOKENS - this.extractionMaxTokens;
513
+ const availableChars = availableTokens * CHARS_PER_TOKEN;
514
+ let truncated = conversationMarkdown;
515
+ if (conversationMarkdown.length > availableChars) {
516
+ truncated = conversationMarkdown.slice(-availableChars);
517
+ const turnBoundary = truncated.indexOf(TURN_HEADING_PREFIX);
518
+ if (turnBoundary > 0) {
519
+ truncated = truncated.slice(turnBoundary);
520
+ }
521
+ }
522
+ const prompt = buildExtractionPrompt(sessionId, truncated, this.extractionMaxTokens);
485
523
  try {
486
- const response = await this.backend.summarize(prompt, { maxTokens: this.extractionMaxTokens, reasoning: LLM_REASONING_MODE });
524
+ const response = await this.backend.summarize(prompt, {
525
+ maxTokens: this.extractionMaxTokens,
526
+ reasoning: LLM_REASONING_MODE
527
+ });
487
528
  const parsed = extractJson(response.text);
488
529
  return {
489
530
  summary: parsed.summary,
@@ -492,16 +533,12 @@ var BufferProcessor = class {
492
533
  };
493
534
  } catch (error) {
494
535
  return {
495
- summary: `LLM processing failed for session ${sessionId}. ${events.length} events captured. Error: ${error.message}`,
536
+ summary: `LLM processing failed for session ${sessionId}. Error: ${error.message}`,
496
537
  observations: [],
497
538
  degraded: true
498
539
  };
499
540
  }
500
541
  }
501
- buildPromptForExtraction(events, sessionId) {
502
- const toolSummary = this.summarizeEvents(events);
503
- return buildExtractionPrompt(sessionId, events.length, toolSummary, this.extractionMaxTokens);
504
- }
505
542
  async summarizeSession(conversationMarkdown, sessionId, user) {
506
543
  const truncatedContent = this.truncateForContext(conversationMarkdown, this.summaryMaxTokens);
507
544
  const summaryPrompt = buildSummaryPrompt(sessionId, user ?? "unknown", truncatedContent, this.summaryMaxTokens);
@@ -533,103 +570,8 @@ var BufferProcessor = class {
533
570
  buildPromptForClassification(candidates, sessionId) {
534
571
  return buildClassificationPrompt(sessionId, candidates, this.classificationMaxTokens);
535
572
  }
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
573
  };
585
574
 
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
575
  // src/vault/observations.ts
634
576
  function writeObservationNotes(observations, sessionId, writer, index, vaultDir) {
635
577
  const results = [];
@@ -722,6 +664,13 @@ ${note.content}`.slice(0, EMBEDDING_INPUT_LIMIT);
722
664
  onProgress
723
665
  }
724
666
  );
667
+ if (ctx.pipeline) {
668
+ for (const note of activeNotes) {
669
+ ctx.pipeline.register(note.id, note.type, note.path);
670
+ ctx.pipeline.advance(note.id, note.type, "capture", "succeeded");
671
+ ctx.pipeline.advance(note.id, note.type, "embedding", "succeeded");
672
+ }
673
+ }
725
674
  return {
726
675
  ftsCount,
727
676
  embeddedCount: result.succeeded,
@@ -733,6 +682,16 @@ async function runDigest(ctx, llmProvider, options) {
733
682
  const { config, vaultDir, index } = ctx;
734
683
  const log = ctx.log ? (level, message, data) => ctx.log(level, message, data) : () => {
735
684
  };
685
+ if (ctx.pipeline && options?.full) {
686
+ const items = ctx.pipeline.listItems({ stage: "digest", status: "succeeded" });
687
+ let reset = 0;
688
+ for (const item of items.items) {
689
+ ctx.pipeline.advance(item.id, item.item_type, "digest", "pending");
690
+ reset++;
691
+ }
692
+ log("info", `Reset ${reset} item(s) to digest:pending for full reprocessing`);
693
+ return null;
694
+ }
736
695
  const engine = new DigestEngine({
737
696
  vaultDir,
738
697
  index,
@@ -806,6 +765,17 @@ async function runCuration(deps, dryRun) {
806
765
  });
807
766
  const allSpores = index.query({ type: "spore" });
808
767
  const activeSpores = allSpores.filter((n) => isActiveSpore(n.frontmatter));
768
+ if (deps.pipeline && !dryRun) {
769
+ let enqueued = 0;
770
+ for (const spore of activeSpores) {
771
+ deps.pipeline.register(spore.id, "spore", spore.path);
772
+ deps.pipeline.advance(spore.id, "spore", "capture", "succeeded");
773
+ deps.pipeline.advance(spore.id, "spore", "consolidation", "pending");
774
+ enqueued++;
775
+ }
776
+ log("info", `Enqueued ${enqueued} spore(s) for pipeline consolidation`);
777
+ return { scanned: activeSpores.length, clustersEvaluated: 0, superseded: 0, enqueued: true };
778
+ }
809
779
  if (activeSpores.length === 0) {
810
780
  return { scanned: 0, clustersEvaluated: 0, superseded: 0 };
811
781
  }
@@ -914,7 +884,14 @@ async function runCuration(deps, dryRun) {
914
884
  function updateTitleAndSummary(body, newTitle, newNarrative) {
915
885
  let updated = body.replace(/^# .*/m, `# ${newTitle}`);
916
886
  const summaryCallout = callout("abstract", "Summary", newNarrative);
917
- updated = updated.replace(/> \[!abstract\] Summary\n(?:> .*\n?)*/m, summaryCallout + "\n");
887
+ const hasExistingCallout = /> \[!abstract\] Summary/.test(updated);
888
+ if (hasExistingCallout) {
889
+ updated = updated.replace(/> \[!abstract\] Summary\n(?:> .*\n?)*/m, summaryCallout + "\n");
890
+ } else {
891
+ updated = updated.replace(/^(# .*\n)/m, `$1
892
+ ${summaryCallout}
893
+ `);
894
+ }
918
895
  return updated;
919
896
  }
920
897
  async function runReprocess(ctx, llmProvider, embeddingProvider, options, onProgress) {
@@ -925,14 +902,6 @@ async function runReprocess(ctx, llmProvider, embeddingProvider, options, onProg
925
902
  const dateFilter = options?.date;
926
903
  const failedOnly = options?.failed ?? false;
927
904
  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
905
  const sessionsDir = path3.join(vaultDir, "sessions");
937
906
  if (!fs3.existsSync(sessionsDir)) {
938
907
  return { sessionsFound: 0, sessionsProcessed: 0, observationsExtracted: 0, summariesRegenerated: 0, embeddingsQueued: 0 };
@@ -946,12 +915,42 @@ async function runReprocess(ctx, llmProvider, embeddingProvider, options, onProg
946
915
  if (!file.startsWith("session-") || !file.endsWith(".md")) continue;
947
916
  const sessionId = file.replace("session-", "").replace(".md", "");
948
917
  if (sessionFilter && !sessionId.includes(sessionFilter)) continue;
949
- sessionFiles.push({ relativePath: path3.join("sessions", dateDir, file), sessionId });
918
+ sessionFiles.push({ relativePath: path3.join("sessions", dateDir, file), sessionId, dateDir });
950
919
  }
951
920
  }
952
921
  if (sessionFiles.length === 0) {
953
922
  return { sessionsFound: 0, sessionsProcessed: 0, observationsExtracted: 0, summariesRegenerated: 0, embeddingsQueued: 0 };
954
923
  }
924
+ if (ctx.pipeline && !skipLlm) {
925
+ let enqueued = 0;
926
+ let eligibleFiles = sessionFiles;
927
+ if (failedOnly) {
928
+ eligibleFiles = sessionFiles.filter(({ relativePath }) => {
929
+ const rawContent = fs3.readFileSync(path3.join(vaultDir, relativePath), "utf-8");
930
+ return rawContent.includes(SUMMARIZATION_FAILED_MARKER);
931
+ });
932
+ }
933
+ for (const { relativePath, sessionId } of eligibleFiles) {
934
+ ctx.pipeline.register(sessionId, "session", relativePath);
935
+ ctx.pipeline.advance(sessionId, "session", "capture", "succeeded");
936
+ ctx.pipeline.advance(sessionId, "session", "extraction", "pending");
937
+ enqueued++;
938
+ }
939
+ log("info", `Enqueued ${enqueued} session(s) for pipeline reprocessing`, {
940
+ filters: { session: sessionFilter, date: dateFilter, failed: failedOnly }
941
+ });
942
+ return {
943
+ sessionsFound: sessionFiles.length,
944
+ sessionsProcessed: enqueued,
945
+ observationsExtracted: 0,
946
+ summariesRegenerated: 0,
947
+ embeddingsQueued: 0,
948
+ enqueued: true
949
+ };
950
+ }
951
+ const effectiveLlm = skipLlm ? null : llmProvider;
952
+ const processor = effectiveLlm ? new BufferProcessor(effectiveLlm, config.intelligence.llm.context_window, config.capture) : null;
953
+ const writer = new VaultWriter(vaultDir);
955
954
  const tasks = [];
956
955
  for (const { relativePath, sessionId } of sessionFiles) {
957
956
  const rawContent = fs3.readFileSync(path3.join(vaultDir, relativePath), "utf-8");
@@ -959,18 +958,10 @@ async function runReprocess(ctx, llmProvider, embeddingProvider, options, onProg
959
958
  if (failedOnly && !hasFailed) continue;
960
959
  const { data: frontmatter, content: body } = (0, import_gray_matter.default)(rawContent);
961
960
  const bare = bareSessionId(sessionId);
962
- const turnsResult = miner.getAllTurnsWithSource(bare);
963
961
  const conversationSection = extractSection(body, CONVERSATION_HEADING);
964
962
  const fmEnd = rawContent.indexOf("---", 4);
965
963
  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 });
964
+ tasks.push({ relativePath, sessionId, bare, frontmatter, frontmatterBlock, body, conversationSection, hasFailed });
974
965
  }
975
966
  if (tasks.length === 0) {
976
967
  return { sessionsFound: sessionFiles.length, sessionsProcessed: 0, observationsExtracted: 0, summariesRegenerated: 0, embeddingsQueued: 0 };
@@ -994,8 +985,8 @@ async function runReprocess(ctx, llmProvider, embeddingProvider, options, onProg
994
985
  tasks,
995
986
  async (task) => {
996
987
  let obs = 0;
997
- if (processor && task.batchEvents) {
998
- const result = await processor.process(task.batchEvents, task.bare);
988
+ if (processor && task.conversationSection.trim()) {
989
+ const result = await processor.process(task.conversationSection, task.bare);
999
990
  if (result.observations.length > 0) {
1000
991
  writeObservationNotes(result.observations, task.bare, writer, index, vaultDir);
1001
992
  obs = result.observations.length;
@@ -1070,18 +1061,18 @@ ${task.frontmatter.summary ?? ""}`.slice(0, EMBEDDING_INPUT_LIMIT);
1070
1061
  }
1071
1062
 
1072
1063
  export {
1064
+ readLastRecord,
1073
1065
  readLastTimestamp,
1074
1066
  appendTraceRecord,
1075
1067
  DigestEngine,
1076
1068
  Metabolism,
1077
1069
  SUMMARIZATION_FAILED_MARKER,
1078
1070
  BufferProcessor,
1079
- TranscriptMiner,
1080
- extractTurnsFromBuffer,
1081
1071
  writeObservationNotes,
1082
1072
  runRebuild,
1083
1073
  runDigest,
1084
1074
  runCuration,
1075
+ updateTitleAndSummary,
1085
1076
  runReprocess
1086
1077
  };
1087
- //# sourceMappingURL=chunk-PQWQC3RF.js.map
1078
+ //# sourceMappingURL=chunk-4XVKZ3WA.js.map