@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.
Files changed (112) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +10 -11
  4. package/dist/{chunk-2YBUL3IL.js → chunk-25DJSF2K.js} +3 -3
  5. package/dist/{chunk-24DOZEUJ.js → chunk-ALBVNGCF.js} +591 -27
  6. package/dist/chunk-ALBVNGCF.js.map +1 -0
  7. package/dist/{chunk-E7OBRBCQ.js → chunk-CK24O5YQ.js} +12 -2
  8. package/dist/chunk-CK24O5YQ.js.map +1 -0
  9. package/dist/{chunk-2GSX3BK2.js → chunk-CPVXNRGW.js} +4 -4
  10. package/dist/{chunk-L25U7PIG.js → chunk-CQ4RKK67.js} +2 -2
  11. package/dist/{chunk-ZMYNRTTD.js → chunk-HRGHDMYI.js} +4 -3
  12. package/dist/chunk-HRGHDMYI.js.map +1 -0
  13. package/dist/{chunk-5FNZ7AMX.js → chunk-IWBWZQK6.js} +2 -2
  14. package/dist/{chunk-MQSYSQ6T.js → chunk-JSK7L46L.js} +11 -6
  15. package/dist/{chunk-MQSYSQ6T.js.map → chunk-JSK7L46L.js.map} +1 -1
  16. package/dist/{chunk-KUMVJIJW.js → chunk-LDKXXKF6.js} +6 -10
  17. package/dist/{chunk-KUMVJIJW.js.map → chunk-LDKXXKF6.js.map} +1 -1
  18. package/dist/{chunk-QGJ2ZIUZ.js → chunk-MWW62YZP.js} +37 -5
  19. package/dist/chunk-MWW62YZP.js.map +1 -0
  20. package/dist/{chunk-2ZBB3MQT.js → chunk-PQWQC3RF.js} +444 -21
  21. package/dist/chunk-PQWQC3RF.js.map +1 -0
  22. package/dist/{chunk-5QWZT4AB.js → chunk-RNWALAFP.js} +2 -2
  23. package/dist/{chunk-3EM23DMD.js → chunk-RXJHB7W4.js} +2 -2
  24. package/dist/{chunk-GNR3QAER.js → chunk-RY76WEN3.js} +2 -2
  25. package/dist/{chunk-GDYYJTTT.js → chunk-V5R6O6RP.js} +3 -3
  26. package/dist/{chunk-6BSDCZ5Q.js → chunk-WBLTISAK.js} +8 -3
  27. package/dist/chunk-WBLTISAK.js.map +1 -0
  28. package/dist/{chunk-YTANWAGE.js → chunk-XNAM6Z4O.js} +2 -2
  29. package/dist/{chunk-P3WO3N3I.js → chunk-YG6MLLGL.js} +19 -3
  30. package/dist/{chunk-P3WO3N3I.js.map → chunk-YG6MLLGL.js.map} +1 -1
  31. package/dist/{cli-K7SUTP7A.js → cli-LMBBPV2D.js} +20 -20
  32. package/dist/{client-YJMNTITQ.js → client-FDKJ4BY7.js} +5 -5
  33. package/dist/{config-G5GGT5A6.js → config-HDUFDOQN.js} +3 -3
  34. package/dist/{curate-6T5NKVXK.js → curate-DYE4VCBJ.js} +10 -11
  35. package/dist/{curate-6T5NKVXK.js.map → curate-DYE4VCBJ.js.map} +1 -1
  36. package/dist/{detect-providers-S3M5TAMW.js → detect-providers-I2QQFDJW.js} +3 -3
  37. package/dist/{digest-O35VHYFP.js → digest-PNHFM7JJ.js} +11 -13
  38. package/dist/{digest-O35VHYFP.js.map → digest-PNHFM7JJ.js.map} +1 -1
  39. package/dist/{init-TFLSATB3.js → init-7N7F6W6U.js} +8 -8
  40. package/dist/{main-JEUQS3BY.js → main-3JZDUJLU.js} +177 -40
  41. package/dist/main-3JZDUJLU.js.map +1 -0
  42. package/dist/{rebuild-7SH5GSNX.js → rebuild-WXKQ5HZO.js} +10 -11
  43. package/dist/{rebuild-7SH5GSNX.js.map → rebuild-WXKQ5HZO.js.map} +1 -1
  44. package/dist/reprocess-PKRDV67L.js +79 -0
  45. package/dist/reprocess-PKRDV67L.js.map +1 -0
  46. package/dist/{restart-NLJLB52D.js → restart-WSJRHRHI.js} +6 -6
  47. package/dist/{search-2BVRF54H.js → search-SWMJ4MZ3.js} +6 -6
  48. package/dist/{server-4AMZNP4F.js → server-NTRVB5ZM.js} +14 -18
  49. package/dist/{server-4AMZNP4F.js.map → server-NTRVB5ZM.js.map} +1 -1
  50. package/dist/{session-start-AZAF3DTE.js → session-start-KQ4KCQMZ.js} +9 -9
  51. package/dist/setup-digest-BOYOSM4B.js +15 -0
  52. package/dist/setup-llm-PCZ64ALK.js +15 -0
  53. package/dist/src/cli.js +4 -4
  54. package/dist/src/daemon/main.js +4 -4
  55. package/dist/src/hooks/post-tool-use.js +5 -5
  56. package/dist/src/hooks/session-end.js +5 -5
  57. package/dist/src/hooks/session-start.js +4 -4
  58. package/dist/src/hooks/stop.js +7 -7
  59. package/dist/src/hooks/user-prompt-submit.js +5 -5
  60. package/dist/src/mcp/server.js +4 -4
  61. package/dist/src/prompts/consolidation.md +2 -0
  62. package/dist/src/prompts/digest-7500.md +68 -0
  63. package/dist/{stats-MKDIZFIQ.js → stats-2OUQSEZO.js} +6 -6
  64. package/dist/ui/assets/index-Bk4X_8-Z.css +1 -0
  65. package/dist/ui/assets/index-D3SY7ZHY.js +299 -0
  66. package/dist/ui/index.html +2 -2
  67. package/dist/{verify-7DW7LAND.js → verify-MG5O7SBU.js} +6 -6
  68. package/dist/{version-RQLD7VBP.js → version-NKOECSVH.js} +4 -4
  69. package/package.json +3 -3
  70. package/dist/chunk-24DOZEUJ.js.map +0 -1
  71. package/dist/chunk-2ZBB3MQT.js.map +0 -1
  72. package/dist/chunk-3JCXYLHD.js +0 -33
  73. package/dist/chunk-3JCXYLHD.js.map +0 -1
  74. package/dist/chunk-6BSDCZ5Q.js.map +0 -1
  75. package/dist/chunk-B5UZSHQV.js +0 -250
  76. package/dist/chunk-B5UZSHQV.js.map +0 -1
  77. package/dist/chunk-E7OBRBCQ.js.map +0 -1
  78. package/dist/chunk-KC7ENQTN.js +0 -436
  79. package/dist/chunk-KC7ENQTN.js.map +0 -1
  80. package/dist/chunk-QGJ2ZIUZ.js.map +0 -1
  81. package/dist/chunk-UVGAVYWZ.js +0 -157
  82. package/dist/chunk-UVGAVYWZ.js.map +0 -1
  83. package/dist/chunk-ZMYNRTTD.js.map +0 -1
  84. package/dist/main-JEUQS3BY.js.map +0 -1
  85. package/dist/reprocess-Q4YH2ZBK.js +0 -268
  86. package/dist/reprocess-Q4YH2ZBK.js.map +0 -1
  87. package/dist/setup-digest-YLZZGSSR.js +0 -15
  88. package/dist/setup-llm-JOXBSLXC.js +0 -15
  89. package/dist/ui/assets/index-D37IoDXS.css +0 -1
  90. package/dist/ui/assets/index-DA61Ial2.js +0 -289
  91. /package/dist/{chunk-2YBUL3IL.js.map → chunk-25DJSF2K.js.map} +0 -0
  92. /package/dist/{chunk-2GSX3BK2.js.map → chunk-CPVXNRGW.js.map} +0 -0
  93. /package/dist/{chunk-L25U7PIG.js.map → chunk-CQ4RKK67.js.map} +0 -0
  94. /package/dist/{chunk-5FNZ7AMX.js.map → chunk-IWBWZQK6.js.map} +0 -0
  95. /package/dist/{chunk-5QWZT4AB.js.map → chunk-RNWALAFP.js.map} +0 -0
  96. /package/dist/{chunk-3EM23DMD.js.map → chunk-RXJHB7W4.js.map} +0 -0
  97. /package/dist/{chunk-GNR3QAER.js.map → chunk-RY76WEN3.js.map} +0 -0
  98. /package/dist/{chunk-GDYYJTTT.js.map → chunk-V5R6O6RP.js.map} +0 -0
  99. /package/dist/{chunk-YTANWAGE.js.map → chunk-XNAM6Z4O.js.map} +0 -0
  100. /package/dist/{cli-K7SUTP7A.js.map → cli-LMBBPV2D.js.map} +0 -0
  101. /package/dist/{client-YJMNTITQ.js.map → client-FDKJ4BY7.js.map} +0 -0
  102. /package/dist/{config-G5GGT5A6.js.map → config-HDUFDOQN.js.map} +0 -0
  103. /package/dist/{detect-providers-S3M5TAMW.js.map → detect-providers-I2QQFDJW.js.map} +0 -0
  104. /package/dist/{init-TFLSATB3.js.map → init-7N7F6W6U.js.map} +0 -0
  105. /package/dist/{restart-NLJLB52D.js.map → restart-WSJRHRHI.js.map} +0 -0
  106. /package/dist/{search-2BVRF54H.js.map → search-SWMJ4MZ3.js.map} +0 -0
  107. /package/dist/{session-start-AZAF3DTE.js.map → session-start-KQ4KCQMZ.js.map} +0 -0
  108. /package/dist/{setup-digest-YLZZGSSR.js.map → setup-digest-BOYOSM4B.js.map} +0 -0
  109. /package/dist/{setup-llm-JOXBSLXC.js.map → setup-llm-PCZ64ALK.js.map} +0 -0
  110. /package/dist/{stats-MKDIZFIQ.js.map → stats-2OUQSEZO.js.map} +0 -0
  111. /package/dist/{verify-7DW7LAND.js.map → verify-MG5O7SBU.js.map} +0 -0
  112. /package/dist/{version-RQLD7VBP.js.map → version-NKOECSVH.js.map} +0 -0
@@ -1,157 +0,0 @@
1
- import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
- import {
3
- formatNoteForPrompt,
4
- formatNotesForPrompt,
5
- indexNote,
6
- loadPrompt,
7
- stripReasoningTokens
8
- } from "./chunk-24DOZEUJ.js";
9
- import {
10
- generateEmbedding
11
- } from "./chunk-RGVBGTD6.js";
12
- import {
13
- external_exports,
14
- require_dist
15
- } from "./chunk-MQSYSQ6T.js";
16
- import {
17
- EMBEDDING_INPUT_LIMIT,
18
- LLM_REASONING_MODE,
19
- SUPERSESSION_CANDIDATE_LIMIT,
20
- SUPERSESSION_MAX_TOKENS,
21
- SUPERSESSION_VECTOR_FETCH_LIMIT
22
- } from "./chunk-6BSDCZ5Q.js";
23
- import {
24
- __toESM
25
- } from "./chunk-PZUWP5VK.js";
26
-
27
- // src/vault/curation.ts
28
- var import_yaml = __toESM(require_dist(), 1);
29
- import fs from "fs";
30
- import path from "path";
31
- var supersededIdsSchema = external_exports.array(external_exports.string());
32
- var SUPERSESSION_NOTICE_MARKER = "Superseded by::";
33
- function isActiveSpore(frontmatter) {
34
- const status = frontmatter.status;
35
- return !status || status === "active";
36
- }
37
- function supersedeSpore(targetId, newSporeId, targetPath, deps) {
38
- const fullPath = path.join(deps.vaultDir, targetPath);
39
- let fileContent;
40
- try {
41
- fileContent = fs.readFileSync(fullPath, "utf-8");
42
- } catch {
43
- return false;
44
- }
45
- const fmMatch = fileContent.match(/^---\n([\s\S]*?)\n---/);
46
- if (!fmMatch) return false;
47
- const parsed = import_yaml.default.parse(fmMatch[1]);
48
- parsed.status = "superseded";
49
- parsed.superseded_by = newSporeId;
50
- const fmYaml = import_yaml.default.stringify(parsed, { defaultStringType: "QUOTE_DOUBLE", defaultKeyType: "PLAIN" }).trim();
51
- let body = fileContent.slice(fmMatch[0].length);
52
- if (!body.includes(SUPERSESSION_NOTICE_MARKER)) {
53
- const notice = `
54
-
55
- > [!warning] Superseded
56
- > This observation has been superseded.
57
-
58
- ${SUPERSESSION_NOTICE_MARKER} [[${newSporeId}]]`;
59
- body = body.trimEnd() + notice + "\n";
60
- }
61
- const tmp = `${fullPath}.tmp`;
62
- fs.writeFileSync(tmp, `---
63
- ${fmYaml}
64
- ---${body}`, "utf-8");
65
- fs.renameSync(tmp, fullPath);
66
- indexNote(deps.index, deps.vaultDir, targetPath);
67
- deps.vectorIndex?.delete(targetId);
68
- return true;
69
- }
70
- async function checkSupersession(newSporeId, deps) {
71
- const { index, vectorIndex, embeddingProvider, llmProvider, vaultDir, log } = deps;
72
- if (!vectorIndex || !llmProvider) {
73
- log?.("debug", "checkSupersession: skipped \u2014 vectorIndex or llmProvider unavailable", { newSporeId });
74
- return [];
75
- }
76
- const newSporeResults = index.queryByIds([newSporeId]);
77
- if (newSporeResults.length === 0) {
78
- log?.("warn", "checkSupersession: new spore not found in index", { newSporeId });
79
- return [];
80
- }
81
- const newSpore = newSporeResults[0];
82
- const observationType = newSpore.frontmatter["observation_type"];
83
- const embeddingText = newSpore.content.slice(0, EMBEDDING_INPUT_LIMIT);
84
- const embeddingResult = await generateEmbedding(embeddingProvider, embeddingText);
85
- const vectorResults = vectorIndex.search(embeddingResult.embedding, {
86
- type: "spore",
87
- limit: SUPERSESSION_VECTOR_FETCH_LIMIT
88
- });
89
- if (vectorResults.length === 0) {
90
- log?.("debug", "checkSupersession: no vector results", { newSporeId });
91
- return [];
92
- }
93
- const candidateIds = vectorResults.map((r) => r.id);
94
- const candidateNotes = index.queryByIds(candidateIds);
95
- const filtered = candidateNotes.filter((note) => {
96
- if (note.id === newSporeId) return false;
97
- if (!isActiveSpore(note.frontmatter)) return false;
98
- if (observationType && note.frontmatter["observation_type"] !== observationType) return false;
99
- return true;
100
- }).slice(0, SUPERSESSION_CANDIDATE_LIMIT);
101
- if (filtered.length === 0) {
102
- log?.("debug", "checkSupersession: no candidates after filtering", { newSporeId, observationType });
103
- return [];
104
- }
105
- const template = loadPrompt("supersession");
106
- const newSporeText = formatNoteForPrompt(newSpore);
107
- const candidatesText = formatNotesForPrompt(filtered);
108
- const prompt = template.replace("{{new_spore}}", newSporeText).replace("{{candidates}}", candidatesText);
109
- let responseText;
110
- try {
111
- const response = await llmProvider.summarize(prompt, {
112
- maxTokens: SUPERSESSION_MAX_TOKENS,
113
- reasoning: LLM_REASONING_MODE
114
- });
115
- responseText = stripReasoningTokens(response.text);
116
- } catch (err) {
117
- log?.("warn", "checkSupersession: LLM call failed", { newSporeId, error: String(err) });
118
- return [];
119
- }
120
- let rawIds;
121
- try {
122
- rawIds = JSON.parse(responseText);
123
- } catch {
124
- log?.("warn", "checkSupersession: failed to parse LLM response", { newSporeId, responseText });
125
- return [];
126
- }
127
- const parsed = supersededIdsSchema.safeParse(rawIds);
128
- if (!parsed.success) {
129
- log?.("warn", "checkSupersession: LLM response failed schema validation", { newSporeId });
130
- return [];
131
- }
132
- const candidateMap = new Map(filtered.map((c) => [c.id, c]));
133
- const validIds = parsed.data.filter((id) => candidateMap.has(id));
134
- if (validIds.length === 0) {
135
- return [];
136
- }
137
- const supersededIds = [];
138
- for (const id of validIds) {
139
- const candidate = candidateMap.get(id);
140
- const wrote = supersedeSpore(id, newSporeId, candidate.path, { index, vectorIndex, vaultDir });
141
- if (!wrote) {
142
- log?.("warn", "checkSupersession: file not found for candidate, skipping", { id, path: candidate.path });
143
- continue;
144
- }
145
- supersededIds.push(id);
146
- log?.("info", "checkSupersession: marked superseded", { supersededId: id, newSporeId });
147
- }
148
- return supersededIds;
149
- }
150
-
151
- export {
152
- supersededIdsSchema,
153
- isActiveSpore,
154
- supersedeSpore,
155
- checkSupersession
156
- };
157
- //# sourceMappingURL=chunk-UVGAVYWZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/vault/curation.ts"],"sourcesContent":["/**\n * Vault curation — supersession detection pipeline.\n *\n * Given a newly written spore ID, finds older spores of the same observation_type\n * that have been rendered outdated, and marks them as superseded.\n */\n\nimport { z } from 'zod';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport type { MycoIndex, IndexedNote } from '../index/sqlite.js';\nimport type { VectorIndex } from '../index/vectors.js';\nimport type { LlmProvider, EmbeddingProvider } from '../intelligence/llm.js';\nimport { generateEmbedding } from '../intelligence/embeddings.js';\nimport { stripReasoningTokens } from '../intelligence/response.js';\nimport { indexNote } from '../index/rebuild.js';\nimport { loadPrompt, formatNoteForPrompt, formatNotesForPrompt } from '../prompts/index.js';\nimport {\n SUPERSESSION_CANDIDATE_LIMIT,\n SUPERSESSION_VECTOR_FETCH_LIMIT,\n SUPERSESSION_MAX_TOKENS,\n EMBEDDING_INPUT_LIMIT,\n LLM_REASONING_MODE,\n} from '../constants.js';\n\ntype LogLevel = 'debug' | 'info' | 'warn';\ntype LogFn = (level: LogLevel, message: string, data?: Record<string, unknown>) => void;\n\n/** Zod schema for validating LLM supersession responses. */\nexport const supersededIdsSchema = z.array(z.string());\n\n/** Marker string used to detect whether a supersession notice has already been appended. */\nexport const SUPERSESSION_NOTICE_MARKER = 'Superseded by::';\n\n/** Returns true if a spore should be considered active (including legacy spores without status). */\nexport function isActiveSpore(frontmatter: Record<string, unknown>): boolean {\n const status = frontmatter.status as string | undefined;\n return !status || status === 'active';\n}\n\n/**\n * Mark a single spore as superseded: update frontmatter + append notice in a\n * single read-modify-write, then re-index and remove from vector index.\n * Returns true if the write succeeded, false if the file was not found.\n */\nexport function supersedeSpore(\n targetId: string,\n newSporeId: string,\n targetPath: string,\n deps: { index: MycoIndex; vectorIndex: VectorIndex | null; vaultDir: string },\n): boolean {\n const fullPath = path.join(deps.vaultDir, targetPath);\n let fileContent: string;\n try {\n fileContent = fs.readFileSync(fullPath, 'utf-8');\n } catch {\n return false;\n }\n\n // Parse and update frontmatter\n const fmMatch = fileContent.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!fmMatch) return false;\n\n const parsed = YAML.parse(fmMatch[1]) as Record<string, unknown>;\n parsed.status = 'superseded';\n parsed.superseded_by = newSporeId;\n\n const fmYaml = YAML.stringify(parsed, { defaultStringType: 'QUOTE_DOUBLE', defaultKeyType: 'PLAIN' }).trim();\n let body = fileContent.slice(fmMatch[0].length);\n\n // Append supersession notice (idempotent: skip if already present)\n if (!body.includes(SUPERSESSION_NOTICE_MARKER)) {\n const notice = `\\n\\n> [!warning] Superseded\\n> This observation has been superseded.\\n\\n${SUPERSESSION_NOTICE_MARKER} [[${newSporeId}]]`;\n body = body.trimEnd() + notice + '\\n';\n }\n\n // Atomic write (temp file + rename)\n const tmp = `${fullPath}.tmp`;\n fs.writeFileSync(tmp, `---\\n${fmYaml}\\n---${body}`, 'utf-8');\n fs.renameSync(tmp, fullPath);\n\n // Re-index the updated file and remove stale vector\n indexNote(deps.index, deps.vaultDir, targetPath);\n deps.vectorIndex?.delete(targetId);\n\n return true;\n}\n\n/**\n * Check whether the newly written spore with `newSporeId` supersedes any\n * existing active spores of the same observation_type.\n *\n * Returns the list of spore IDs that were marked superseded.\n */\nexport async function checkSupersession(\n newSporeId: string,\n deps: {\n index: MycoIndex;\n vectorIndex: VectorIndex | null;\n embeddingProvider: EmbeddingProvider;\n llmProvider: LlmProvider | null;\n vaultDir: string;\n log?: LogFn;\n },\n): Promise<string[]> {\n const { index, vectorIndex, embeddingProvider, llmProvider, vaultDir, log } = deps;\n\n // Early-exit if no vector index or LLM available\n if (!vectorIndex || !llmProvider) {\n log?.('debug', 'checkSupersession: skipped — vectorIndex or llmProvider unavailable', { newSporeId });\n return [];\n }\n\n // Look up the new spore to get its content and observation_type\n const newSporeResults = index.queryByIds([newSporeId]);\n if (newSporeResults.length === 0) {\n log?.('warn', 'checkSupersession: new spore not found in index', { newSporeId });\n return [];\n }\n const newSpore = newSporeResults[0];\n const observationType = newSpore.frontmatter['observation_type'] as string | undefined;\n\n // Embed the spore content for similarity search\n const embeddingText = newSpore.content.slice(0, EMBEDDING_INPUT_LIMIT);\n const embeddingResult = await generateEmbedding(embeddingProvider, embeddingText);\n\n // Fetch candidate spore IDs from vector index\n const vectorResults = vectorIndex.search(embeddingResult.embedding, {\n type: 'spore',\n limit: SUPERSESSION_VECTOR_FETCH_LIMIT,\n });\n\n if (vectorResults.length === 0) {\n log?.('debug', 'checkSupersession: no vector results', { newSporeId });\n return [];\n }\n\n const candidateIds = vectorResults.map((r) => r.id);\n\n // Look up candidate notes and post-filter:\n // - same observation_type as the new spore\n // - active status (including legacy spores without status field)\n // - not the new spore itself\n const candidateNotes = index.queryByIds(candidateIds);\n const filtered = candidateNotes\n .filter((note) => {\n if (note.id === newSporeId) return false;\n if (!isActiveSpore(note.frontmatter)) return false;\n if (observationType && note.frontmatter['observation_type'] !== observationType) return false;\n return true;\n })\n .slice(0, SUPERSESSION_CANDIDATE_LIMIT);\n\n if (filtered.length === 0) {\n log?.('debug', 'checkSupersession: no candidates after filtering', { newSporeId, observationType });\n return [];\n }\n\n // Build the supersession prompt\n const template = loadPrompt('supersession');\n const newSporeText = formatNoteForPrompt(newSpore);\n const candidatesText = formatNotesForPrompt(filtered);\n\n const prompt = template\n .replace('{{new_spore}}', newSporeText)\n .replace('{{candidates}}', candidatesText);\n\n // Ask the LLM which candidates are superseded\n let responseText: string;\n try {\n const response = await llmProvider.summarize(prompt, {\n maxTokens: SUPERSESSION_MAX_TOKENS,\n reasoning: LLM_REASONING_MODE,\n });\n responseText = stripReasoningTokens(response.text);\n } catch (err) {\n log?.('warn', 'checkSupersession: LLM call failed', { newSporeId, error: String(err) });\n return [];\n }\n\n // Parse the LLM response as a JSON array of IDs\n let rawIds: unknown;\n try {\n rawIds = JSON.parse(responseText);\n } catch {\n log?.('warn', 'checkSupersession: failed to parse LLM response', { newSporeId, responseText });\n return [];\n }\n\n const parsed = supersededIdsSchema.safeParse(rawIds);\n if (!parsed.success) {\n log?.('warn', 'checkSupersession: LLM response failed schema validation', { newSporeId });\n return [];\n }\n\n // Filter to IDs that actually exist in the candidate list and are still active\n const candidateMap = new Map<string, IndexedNote>(filtered.map((c) => [c.id, c]));\n const validIds = parsed.data.filter((id) => candidateMap.has(id));\n\n if (validIds.length === 0) {\n return [];\n }\n\n // Mark each validated candidate as superseded\n const supersededIds: string[] = [];\n\n for (const id of validIds) {\n const candidate = candidateMap.get(id)!;\n const wrote = supersedeSpore(id, newSporeId, candidate.path, { index, vectorIndex, vaultDir });\n\n if (!wrote) {\n log?.('warn', 'checkSupersession: file not found for candidate, skipping', { id, path: candidate.path });\n continue;\n }\n\n supersededIds.push(id);\n log?.('info', 'checkSupersession: marked superseded', { supersededId: id, newSporeId });\n }\n\n return supersededIds;\n}\n"],"mappings":"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","names":["YAML"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/services/stats.ts"],"sourcesContent":["import { MycoIndex } from '../index/sqlite.js';\nimport { VectorIndex } from '../index/vectors.js';\nimport { isProcessAlive } from '../cli/shared.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/** Fallback dimension for opening VectorIndex when the actual dimension is unknown. */\nconst VECTOR_FALLBACK_DIMENSION = 1024;\n\nexport interface VaultStats {\n vault: {\n path: string;\n name: string;\n spore_counts: Record<string, number>;\n session_count: number;\n plan_count: number;\n };\n index: {\n fts_entries: number;\n vector_count: number;\n };\n daemon: {\n pid: number;\n port: number;\n started: string;\n active_sessions: string[];\n alive: boolean;\n } | null;\n}\n\nexport function gatherStats(vaultDir: string, index: MycoIndex, vectorIndex?: VectorIndex): VaultStats {\n const typeCounts = index.countByType();\n const spore_counts = index.sporeCountsByObservationType();\n\n let vector_count = 0;\n if (vectorIndex) {\n vector_count = vectorIndex.count();\n } else {\n const vecDb = path.join(vaultDir, 'vectors.db');\n if (fs.existsSync(vecDb)) {\n try {\n const vec = new VectorIndex(vecDb, VECTOR_FALLBACK_DIMENSION);\n vector_count = vec.count();\n vec.close();\n } catch { /* ignore */ }\n }\n }\n\n let daemon: VaultStats['daemon'] = null;\n const daemonPath = path.join(vaultDir, 'daemon.json');\n if (fs.existsSync(daemonPath)) {\n try {\n const info = JSON.parse(fs.readFileSync(daemonPath, 'utf-8'));\n daemon = {\n pid: info.pid,\n port: info.port,\n started: info.started,\n active_sessions: info.sessions || [],\n alive: isProcessAlive(info.pid),\n };\n } catch { /* ignore */ }\n }\n\n return {\n vault: {\n path: vaultDir,\n name: path.basename(vaultDir),\n spore_counts,\n session_count: typeCounts['session'] ?? 0,\n plan_count: typeCounts['plan'] ?? 0,\n },\n index: {\n fts_entries: Object.values(typeCounts).reduce((sum, n) => sum + n, 0),\n vector_count,\n },\n daemon,\n };\n}\n"],"mappings":";;;;;;;;;AAGA,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,IAAM,4BAA4B;AAuB3B,SAAS,YAAY,UAAkB,OAAkB,aAAuC;AACrG,QAAM,aAAa,MAAM,YAAY;AACrC,QAAM,eAAe,MAAM,6BAA6B;AAExD,MAAI,eAAe;AACnB,MAAI,aAAa;AACf,mBAAe,YAAY,MAAM;AAAA,EACnC,OAAO;AACL,UAAM,QAAQ,KAAK,KAAK,UAAU,YAAY;AAC9C,QAAI,GAAG,WAAW,KAAK,GAAG;AACxB,UAAI;AACF,cAAM,MAAM,IAAI,YAAY,OAAO,yBAAyB;AAC5D,uBAAe,IAAI,MAAM;AACzB,YAAI,MAAM;AAAA,MACZ,QAAQ;AAAA,MAAe;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,SAA+B;AACnC,QAAM,aAAa,KAAK,KAAK,UAAU,aAAa;AACpD,MAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAC5D,eAAS;AAAA,QACP,KAAK,KAAK;AAAA,QACV,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,iBAAiB,KAAK,YAAY,CAAC;AAAA,QACnC,OAAO,eAAe,KAAK,GAAG;AAAA,MAChC;AAAA,IACF,QAAQ;AAAA,IAAe;AAAA,EACzB;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,KAAK,SAAS,QAAQ;AAAA,MAC5B;AAAA,MACA,eAAe,WAAW,SAAS,KAAK;AAAA,MACxC,YAAY,WAAW,MAAM,KAAK;AAAA,IACpC;AAAA,IACA,OAAO;AAAA,MACL,aAAa,OAAO,OAAO,UAAU,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,GAAG,CAAC;AAAA,MACpE;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;","names":[]}