@goondocks/myco 0.3.7 → 0.4.1
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 +9 -4
- package/commands/init.md +63 -39
- package/commands/setup-llm.md +69 -44
- package/commands/status.md +28 -10
- package/dist/{chunk-YFG2O5HR.js → chunk-2GJFTIWX.js} +2 -2
- package/dist/{chunk-ISCT2SI6.js → chunk-6UJWI4IW.js} +7359 -60
- package/dist/chunk-6UJWI4IW.js.map +1 -0
- package/dist/{chunk-PA3VMINE.js → chunk-AK6GNLPV.js} +6 -1
- package/dist/chunk-AK6GNLPV.js.map +1 -0
- package/dist/{chunk-JKOALBZC.js → chunk-BNIYWCST.js} +2 -2
- package/dist/{chunk-AWF3M57N.js → chunk-FPEDTLQ6.js} +9 -9
- package/dist/{chunk-AWF3M57N.js.map → chunk-FPEDTLQ6.js.map} +1 -1
- package/dist/{chunk-QWU7QLZI.js → chunk-I7PNZEBO.js} +10 -10
- package/dist/chunk-I7PNZEBO.js.map +1 -0
- package/dist/{chunk-7WNE22W7.js → chunk-IVS5MYBL.js} +3 -3
- package/dist/{chunk-7WNE22W7.js.map → chunk-IVS5MYBL.js.map} +1 -1
- package/dist/{chunk-7VPJK56U.js → chunk-JBD5KP5G.js} +31 -16
- package/dist/chunk-JBD5KP5G.js.map +1 -0
- package/dist/chunk-MIU3DKLN.js +37 -0
- package/dist/chunk-MIU3DKLN.js.map +1 -0
- package/dist/{chunk-NYAWCMRZ.js → chunk-OUFSLZTX.js} +4 -4
- package/dist/chunk-P7RNAYU7.js +242 -0
- package/dist/chunk-P7RNAYU7.js.map +1 -0
- package/dist/chunk-T7OC6GH5.js +99 -0
- package/dist/chunk-T7OC6GH5.js.map +1 -0
- package/dist/chunk-TBRZAJ7W.js +135 -0
- package/dist/chunk-TBRZAJ7W.js.map +1 -0
- package/dist/chunk-UKWO26VI.js +147 -0
- package/dist/chunk-UKWO26VI.js.map +1 -0
- package/dist/{chunk-FFQNE6CT.js → chunk-V2OWD2VV.js} +45 -31
- package/dist/chunk-V2OWD2VV.js.map +1 -0
- package/dist/chunk-WBT5DWGC.js +49 -0
- package/dist/chunk-WBT5DWGC.js.map +1 -0
- package/dist/{chunk-LR7RQCOB.js → chunk-XCPQHC4X.js} +2 -2
- package/dist/{chunk-CCIV47S4.js → chunk-XHWIIU5D.js} +8 -9
- package/dist/chunk-XHWIIU5D.js.map +1 -0
- package/dist/{chunk-ZBNT6E22.js → chunk-ZCBL5HER.js} +2 -2
- package/dist/{cli-3WQSDSW6.js → cli-IGZA3TZC.js} +23 -17
- package/dist/cli-IGZA3TZC.js.map +1 -0
- package/dist/{client-5T4M42UQ.js → client-5SUO2UYH.js} +5 -5
- package/dist/{config-MD4XMLUS.js → config-5FGLQGCW.js} +4 -4
- package/dist/{detect-providers-LNOLBICR.js → detect-providers-5FU3BN5Q.js} +3 -3
- package/dist/{init-RALMQKOQ.js → init-M3GDZRKI.js} +51 -60
- package/dist/init-M3GDZRKI.js.map +1 -0
- package/dist/{main-S3WSUF5T.js → main-3JSO25IZ.js} +657 -228
- package/dist/main-3JSO25IZ.js.map +1 -0
- package/dist/{rebuild-JW6BCHHZ.js → rebuild-MW4GCY6Z.js} +10 -10
- package/dist/rebuild-MW4GCY6Z.js.map +1 -0
- package/dist/{reprocess-SNXFNKBN.js → reprocess-SWRFIIDZ.js} +18 -18
- package/dist/reprocess-SWRFIIDZ.js.map +1 -0
- package/dist/{restart-YE2IGOYT.js → restart-5UY2KV54.js} +6 -6
- package/dist/{search-2HMG3ON7.js → search-IYVMRZU2.js} +9 -9
- package/dist/{server-JM3TM7D2.js → server-FSUSHJ3Y.js} +77 -54
- package/dist/{server-JM3TM7D2.js.map → server-FSUSHJ3Y.js.map} +1 -1
- package/dist/{session-5GI2YU6R.js → session-QF6MILAC.js} +2 -2
- package/dist/{session-start-2UEEEO52.js → session-start-YB4A4PZB.js} +29 -28
- package/dist/session-start-YB4A4PZB.js.map +1 -0
- package/dist/setup-digest-6TK5SPS6.js +15 -0
- package/dist/setup-llm-UGZBURZJ.js +15 -0
- package/dist/setup-llm-UGZBURZJ.js.map +1 -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/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/mcp/server.js +4 -4
- package/dist/src/prompts/classification.md +1 -0
- package/dist/src/prompts/digest-10000.md +74 -0
- package/dist/src/prompts/digest-1500.md +25 -0
- package/dist/src/prompts/digest-3000.md +32 -0
- package/dist/src/prompts/digest-5000.md +43 -0
- package/dist/src/prompts/digest-system.md +32 -0
- package/dist/src/prompts/extraction.md +11 -10
- package/dist/src/prompts/summary.md +11 -1
- package/dist/src/prompts/title.md +1 -1
- package/dist/{stats-IOWXG576.js → stats-IVIXIKTS.js} +12 -12
- package/dist/stats-IVIXIKTS.js.map +1 -0
- package/dist/{verify-7MWOV72E.js → verify-WEGRM4W2.js} +6 -6
- package/dist/{version-S7MHLD5P.js → version-5B2TWXQJ.js} +4 -4
- package/dist/version-5B2TWXQJ.js.map +1 -0
- package/package.json +1 -1
- package/skills/myco/SKILL.md +20 -20
- package/skills/myco/references/wisdom.md +14 -14
- package/skills/rules/SKILL.md +4 -4
- package/dist/chunk-7VPJK56U.js.map +0 -1
- package/dist/chunk-BA23DROX.js +0 -160
- package/dist/chunk-BA23DROX.js.map +0 -1
- package/dist/chunk-CCIV47S4.js.map +0 -1
- package/dist/chunk-EF4JVH24.js +0 -7299
- package/dist/chunk-EF4JVH24.js.map +0 -1
- package/dist/chunk-FFQNE6CT.js.map +0 -1
- package/dist/chunk-ISCT2SI6.js.map +0 -1
- package/dist/chunk-PA3VMINE.js.map +0 -1
- package/dist/chunk-QWU7QLZI.js.map +0 -1
- package/dist/chunk-YMYJ7FNH.js +0 -19
- package/dist/chunk-YMYJ7FNH.js.map +0 -1
- package/dist/cli-3WQSDSW6.js.map +0 -1
- package/dist/init-RALMQKOQ.js.map +0 -1
- package/dist/main-S3WSUF5T.js.map +0 -1
- package/dist/rebuild-JW6BCHHZ.js.map +0 -1
- package/dist/reprocess-SNXFNKBN.js.map +0 -1
- package/dist/session-start-2UEEEO52.js.map +0 -1
- package/dist/stats-IOWXG576.js.map +0 -1
- /package/dist/{chunk-YFG2O5HR.js.map → chunk-2GJFTIWX.js.map} +0 -0
- /package/dist/{chunk-JKOALBZC.js.map → chunk-BNIYWCST.js.map} +0 -0
- /package/dist/{chunk-NYAWCMRZ.js.map → chunk-OUFSLZTX.js.map} +0 -0
- /package/dist/{chunk-LR7RQCOB.js.map → chunk-XCPQHC4X.js.map} +0 -0
- /package/dist/{chunk-ZBNT6E22.js.map → chunk-ZCBL5HER.js.map} +0 -0
- /package/dist/{client-5T4M42UQ.js.map → client-5SUO2UYH.js.map} +0 -0
- /package/dist/{config-MD4XMLUS.js.map → config-5FGLQGCW.js.map} +0 -0
- /package/dist/{detect-providers-LNOLBICR.js.map → detect-providers-5FU3BN5Q.js.map} +0 -0
- /package/dist/{restart-YE2IGOYT.js.map → restart-5UY2KV54.js.map} +0 -0
- /package/dist/{search-2HMG3ON7.js.map → search-IYVMRZU2.js.map} +0 -0
- /package/dist/{session-5GI2YU6R.js.map → session-QF6MILAC.js.map} +0 -0
- /package/dist/{version-S7MHLD5P.js.map → setup-digest-6TK5SPS6.js.map} +0 -0
- /package/dist/{verify-7MWOV72E.js.map → verify-WEGRM4W2.js.map} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
MycoConfigSchema,
|
|
4
|
+
require_dist
|
|
5
|
+
} from "./chunk-6UJWI4IW.js";
|
|
6
|
+
import {
|
|
7
|
+
__toESM
|
|
8
|
+
} from "./chunk-PZUWP5VK.js";
|
|
9
|
+
|
|
10
|
+
// src/config/loader.ts
|
|
11
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
12
|
+
import fs2 from "fs";
|
|
13
|
+
import path2 from "path";
|
|
14
|
+
|
|
15
|
+
// src/config/migrations.ts
|
|
16
|
+
import fs from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
var MEMORY_TYPE_PATTERN = /type:\s*["']?memory["']?/g;
|
|
19
|
+
var MIGRATIONS = [
|
|
20
|
+
{
|
|
21
|
+
version: 1,
|
|
22
|
+
name: "rename-memories-to-spores",
|
|
23
|
+
migrate: (doc, vaultDir) => {
|
|
24
|
+
const context = doc.context;
|
|
25
|
+
const layers = context?.layers;
|
|
26
|
+
if (layers && "memories" in layers && !("spores" in layers)) {
|
|
27
|
+
layers.spores = layers.memories;
|
|
28
|
+
delete layers.memories;
|
|
29
|
+
}
|
|
30
|
+
const memoriesDir = path.join(vaultDir, "memories");
|
|
31
|
+
const sporesDir = path.join(vaultDir, "spores");
|
|
32
|
+
if (!fs.existsSync(memoriesDir)) return;
|
|
33
|
+
if (fs.existsSync(sporesDir)) {
|
|
34
|
+
const moveRemaining = (srcDir, destDir) => {
|
|
35
|
+
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
36
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
37
|
+
const destPath = path.join(destDir, entry.name);
|
|
38
|
+
if (entry.isDirectory()) {
|
|
39
|
+
if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });
|
|
40
|
+
moveRemaining(srcPath, destPath);
|
|
41
|
+
} else if (!fs.existsSync(destPath)) {
|
|
42
|
+
fs.renameSync(srcPath, destPath);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
moveRemaining(memoriesDir, sporesDir);
|
|
47
|
+
fs.rmSync(memoriesDir, { recursive: true, force: true });
|
|
48
|
+
} else {
|
|
49
|
+
fs.renameSync(memoriesDir, sporesDir);
|
|
50
|
+
}
|
|
51
|
+
const walkUpdate = (dir) => {
|
|
52
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
53
|
+
const fullPath = path.join(dir, entry.name);
|
|
54
|
+
if (entry.isDirectory()) {
|
|
55
|
+
walkUpdate(fullPath);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!entry.name.endsWith(".md")) continue;
|
|
59
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
60
|
+
MEMORY_TYPE_PATTERN.lastIndex = 0;
|
|
61
|
+
if (MEMORY_TYPE_PATTERN.test(content)) {
|
|
62
|
+
MEMORY_TYPE_PATTERN.lastIndex = 0;
|
|
63
|
+
fs.writeFileSync(fullPath, content.replace(MEMORY_TYPE_PATTERN, "type: spore"));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
walkUpdate(sporesDir);
|
|
68
|
+
const walkLinks = (dir) => {
|
|
69
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
70
|
+
const fullPath = path.join(dir, entry.name);
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
walkLinks(fullPath);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (!entry.name.endsWith(".md")) continue;
|
|
76
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
77
|
+
if (content.includes("memories/")) {
|
|
78
|
+
fs.writeFileSync(fullPath, content.replace(/memories\//g, "spores/"));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
walkLinks(vaultDir);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
var CURRENT_MIGRATION_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
|
|
87
|
+
function runMigrations(doc, vaultDir, log) {
|
|
88
|
+
const currentVersion = doc.config_version ?? 0;
|
|
89
|
+
let ran = false;
|
|
90
|
+
for (const migration of MIGRATIONS) {
|
|
91
|
+
if (migration.version <= currentVersion) continue;
|
|
92
|
+
log?.(`Running migration ${migration.version}: ${migration.name}`);
|
|
93
|
+
migration.migrate(doc, vaultDir);
|
|
94
|
+
doc.config_version = migration.version;
|
|
95
|
+
ran = true;
|
|
96
|
+
}
|
|
97
|
+
return ran;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/config/loader.ts
|
|
101
|
+
var CONFIG_FILENAME = "myco.yaml";
|
|
102
|
+
function loadConfig(vaultDir) {
|
|
103
|
+
const configPath = path2.join(vaultDir, CONFIG_FILENAME);
|
|
104
|
+
if (!fs2.existsSync(configPath)) {
|
|
105
|
+
throw new Error(`myco.yaml not found in ${vaultDir}`);
|
|
106
|
+
}
|
|
107
|
+
const raw = fs2.readFileSync(configPath, "utf-8");
|
|
108
|
+
const parsed = import_yaml.default.parse(raw);
|
|
109
|
+
if (parsed.version === 1 || parsed.intelligence?.backend) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
"Myco config uses v1 format. Run /myco:setup-llm to reconfigure for v2."
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
const intel = parsed.intelligence;
|
|
115
|
+
const llm = intel?.llm;
|
|
116
|
+
if (llm?.provider === "haiku") {
|
|
117
|
+
llm.provider = "anthropic";
|
|
118
|
+
}
|
|
119
|
+
const migrationsRan = runMigrations(parsed, vaultDir, (msg) => {
|
|
120
|
+
process.stderr.write(`[myco migration] ${msg}
|
|
121
|
+
`);
|
|
122
|
+
});
|
|
123
|
+
const config = MycoConfigSchema.parse(parsed);
|
|
124
|
+
const needsWrite = migrationsRan || (parsed.config_version ?? 0) < CURRENT_MIGRATION_VERSION || !("digest" in parsed);
|
|
125
|
+
if (needsWrite) {
|
|
126
|
+
const fullConfig = JSON.parse(JSON.stringify(config));
|
|
127
|
+
fs2.writeFileSync(configPath, import_yaml.default.stringify(fullConfig), "utf-8");
|
|
128
|
+
}
|
|
129
|
+
return config;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
loadConfig
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=chunk-TBRZAJ7W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/loader.ts","../src/config/migrations.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { MycoConfigSchema, type MycoConfig } from './schema.js';\nimport { runMigrations, CURRENT_MIGRATION_VERSION } from './migrations.js';\n\nconst CONFIG_FILENAME = 'myco.yaml';\n\nexport function loadConfig(vaultDir: string): MycoConfig {\n const configPath = path.join(vaultDir, CONFIG_FILENAME);\n\n if (!fs.existsSync(configPath)) {\n throw new Error(`myco.yaml not found in ${vaultDir}`);\n }\n\n const raw = fs.readFileSync(configPath, 'utf-8');\n const parsed = YAML.parse(raw) as Record<string, unknown>;\n\n // Detect v1 config and guide migration\n if (parsed.version === 1 || (parsed.intelligence as Record<string, unknown>)?.backend) {\n throw new Error(\n 'Myco config uses v1 format. Run /myco:setup-llm to reconfigure for v2.',\n );\n }\n\n // Auto-map legacy 'haiku' provider name to 'anthropic'\n const intel = parsed.intelligence as Record<string, unknown> | undefined;\n const llm = intel?.llm as Record<string, unknown> | undefined;\n if (llm?.provider === 'haiku') {\n llm.provider = 'anthropic';\n }\n\n // Run numbered migrations\n const migrationsRan = runMigrations(parsed, vaultDir, (msg) => {\n // Log to stderr since this runs during config loading (before logger is available)\n process.stderr.write(`[myco migration] ${msg}\\n`);\n });\n\n // Parse with Zod to fill in defaults for new config sections\n const config = MycoConfigSchema.parse(parsed);\n\n // Write back if migrations ran or new defaults were added\n const needsWrite = migrationsRan\n || (parsed.config_version as number ?? 0) < CURRENT_MIGRATION_VERSION\n || !('digest' in parsed);\n\n if (needsWrite) {\n const fullConfig = JSON.parse(JSON.stringify(config)) as Record<string, unknown>;\n fs.writeFileSync(configPath, YAML.stringify(fullConfig), 'utf-8');\n }\n\n return config;\n}\n\nexport function saveConfig(vaultDir: string, config: MycoConfig): void {\n // Validate before writing — OAK lesson: validate on write, not just read\n const validated = MycoConfigSchema.parse(config);\n\n const configPath = path.join(vaultDir, CONFIG_FILENAME);\n fs.mkdirSync(vaultDir, { recursive: true });\n fs.writeFileSync(configPath, YAML.stringify(validated), 'utf-8');\n}\n","/**\n * Config and vault migrations — run once per version, tracked by config_version.\n *\n * Each migration has a version number, a name, and a function that receives\n * the raw parsed YAML doc and the vault directory. Migrations run in order\n * and are skipped if config_version is already past them.\n *\n * To add a new migration:\n * 1. Add an entry to MIGRATIONS with the next version number\n * 2. Write the migrate function — it receives the mutable doc and vaultDir\n * 3. The framework handles version tracking and writing the config back\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface Migration {\n version: number;\n name: string;\n migrate: (doc: Record<string, unknown>, vaultDir: string) => void;\n}\n\n/** Regex matching both quoted and unquoted YAML: type: memory, type: \"memory\", type: 'memory' */\nconst MEMORY_TYPE_PATTERN = /type:\\s*[\"']?memory[\"']?/g;\n\nexport const MIGRATIONS: Migration[] = [\n {\n version: 1,\n name: 'rename-memories-to-spores',\n migrate: (doc, vaultDir) => {\n // Config: rename context.layers.memories → context.layers.spores\n const context = doc.context as Record<string, unknown> | undefined;\n const layers = context?.layers as Record<string, unknown> | undefined;\n if (layers && 'memories' in layers && !('spores' in layers)) {\n layers.spores = layers.memories;\n delete layers.memories;\n }\n\n // Vault: rename memories/ directory → spores/\n const memoriesDir = path.join(vaultDir, 'memories');\n const sporesDir = path.join(vaultDir, 'spores');\n\n if (!fs.existsSync(memoriesDir)) return;\n\n if (fs.existsSync(sporesDir)) {\n // Both exist (interrupted migration) — merge remaining files\n const moveRemaining = (srcDir: string, destDir: string): void => {\n for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {\n const srcPath = path.join(srcDir, entry.name);\n const destPath = path.join(destDir, entry.name);\n if (entry.isDirectory()) {\n if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });\n moveRemaining(srcPath, destPath);\n } else if (!fs.existsSync(destPath)) {\n fs.renameSync(srcPath, destPath);\n }\n }\n };\n moveRemaining(memoriesDir, sporesDir);\n fs.rmSync(memoriesDir, { recursive: true, force: true });\n } else {\n fs.renameSync(memoriesDir, sporesDir);\n }\n\n // Update frontmatter type: memory → type: spore (handles quoted and unquoted)\n const walkUpdate = (dir: string): void => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) { walkUpdate(fullPath); continue; }\n if (!entry.name.endsWith('.md')) continue;\n const content = fs.readFileSync(fullPath, 'utf-8');\n MEMORY_TYPE_PATTERN.lastIndex = 0;\n if (MEMORY_TYPE_PATTERN.test(content)) {\n MEMORY_TYPE_PATTERN.lastIndex = 0;\n fs.writeFileSync(fullPath, content.replace(MEMORY_TYPE_PATTERN, 'type: spore'));\n }\n }\n };\n walkUpdate(sporesDir);\n\n // Update wikilinks in ALL vault files: [[memories/...]] → [[spores/...]]\n const walkLinks = (dir: string): void => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) { walkLinks(fullPath); continue; }\n if (!entry.name.endsWith('.md')) continue;\n const content = fs.readFileSync(fullPath, 'utf-8');\n if (content.includes('memories/')) {\n fs.writeFileSync(fullPath, content.replace(/memories\\//g, 'spores/'));\n }\n }\n };\n walkLinks(vaultDir);\n },\n },\n];\n\n/** Current migration version — the highest version in MIGRATIONS. */\nexport const CURRENT_MIGRATION_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;\n\n/**\n * Run all pending migrations on the raw config doc.\n * Returns true if any migrations ran (caller should reindex).\n */\nexport function runMigrations(\n doc: Record<string, unknown>,\n vaultDir: string,\n log?: (message: string) => void,\n): boolean {\n const currentVersion = (doc.config_version as number) ?? 0;\n let ran = false;\n\n for (const migration of MIGRATIONS) {\n if (migration.version <= currentVersion) continue;\n\n log?.(`Running migration ${migration.version}: ${migration.name}`);\n migration.migrate(doc, vaultDir);\n doc.config_version = migration.version;\n ran = true;\n }\n\n return ran;\n}\n"],"mappings":"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","names":["fs","path","path","fs","YAML"]}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
parseStringFlag
|
|
4
|
+
} from "./chunk-SAKJMNSR.js";
|
|
5
|
+
import {
|
|
6
|
+
MycoConfigSchema,
|
|
7
|
+
require_dist
|
|
8
|
+
} from "./chunk-6UJWI4IW.js";
|
|
9
|
+
import {
|
|
10
|
+
__toESM
|
|
11
|
+
} from "./chunk-PZUWP5VK.js";
|
|
12
|
+
|
|
13
|
+
// src/cli/setup-digest.ts
|
|
14
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
import path from "path";
|
|
17
|
+
var CONFIG_FILENAME = "myco.yaml";
|
|
18
|
+
var DAEMON_STATE_FILENAME = "daemon.json";
|
|
19
|
+
var USAGE = `Usage: myco setup-digest [options]
|
|
20
|
+
|
|
21
|
+
Configure digest (continuous reasoning) settings.
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--enabled <true|false> Enable/disable digest (default: true)
|
|
25
|
+
--tiers <1500,3000,...> Comma-separated tier list
|
|
26
|
+
--inject-tier <number|null> Tier to auto-inject at session start
|
|
27
|
+
--provider <name> LLM provider for digest (null = inherit)
|
|
28
|
+
--model <name> Model for digest (null = inherit)
|
|
29
|
+
--base-url <url> Provider base URL (null = inherit)
|
|
30
|
+
--context-window <number> Context window for digest operations
|
|
31
|
+
--keep-alive <duration> Keep model loaded (Ollama, e.g. "30m")
|
|
32
|
+
--gpu-kv-cache <true|false> Offload KV cache to GPU (LM Studio)
|
|
33
|
+
--active-interval <seconds> Metabolism active interval
|
|
34
|
+
--dormancy-threshold <seconds> Time before dormancy
|
|
35
|
+
--max-notes <number> Max substrate notes per cycle
|
|
36
|
+
--extraction-tokens <number> Max tokens for spore extraction
|
|
37
|
+
--summary-tokens <number> Max tokens for session summaries
|
|
38
|
+
--title-tokens <number> Max tokens for session titles
|
|
39
|
+
--classification-tokens <number> Max tokens for artifact classification
|
|
40
|
+
--show Show current settings and exit
|
|
41
|
+
`;
|
|
42
|
+
async function run(args, vaultDir) {
|
|
43
|
+
const configPath = path.join(vaultDir, CONFIG_FILENAME);
|
|
44
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
45
|
+
const doc = import_yaml.default.parse(raw);
|
|
46
|
+
if (args.includes("--show")) {
|
|
47
|
+
const config = MycoConfigSchema.parse(doc);
|
|
48
|
+
console.log(JSON.stringify({
|
|
49
|
+
digest: config.digest,
|
|
50
|
+
capture: {
|
|
51
|
+
extraction_max_tokens: config.capture.extraction_max_tokens,
|
|
52
|
+
summary_max_tokens: config.capture.summary_max_tokens,
|
|
53
|
+
title_max_tokens: config.capture.title_max_tokens,
|
|
54
|
+
classification_max_tokens: config.capture.classification_max_tokens
|
|
55
|
+
}
|
|
56
|
+
}, null, 2));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (args.length === 0) {
|
|
60
|
+
console.log(USAGE);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!doc.digest || typeof doc.digest !== "object") {
|
|
64
|
+
doc.digest = {};
|
|
65
|
+
}
|
|
66
|
+
const digest = doc.digest;
|
|
67
|
+
if (!digest.intelligence || typeof digest.intelligence !== "object") {
|
|
68
|
+
digest.intelligence = {};
|
|
69
|
+
}
|
|
70
|
+
if (!digest.metabolism || typeof digest.metabolism !== "object") {
|
|
71
|
+
digest.metabolism = {};
|
|
72
|
+
}
|
|
73
|
+
if (!digest.substrate || typeof digest.substrate !== "object") {
|
|
74
|
+
digest.substrate = {};
|
|
75
|
+
}
|
|
76
|
+
if (!doc.capture || typeof doc.capture !== "object") {
|
|
77
|
+
doc.capture = {};
|
|
78
|
+
}
|
|
79
|
+
const intelligence = digest.intelligence;
|
|
80
|
+
const metabolism = digest.metabolism;
|
|
81
|
+
const substrate = digest.substrate;
|
|
82
|
+
const capture = doc.capture;
|
|
83
|
+
const enabled = parseStringFlag(args, "--enabled");
|
|
84
|
+
if (enabled !== void 0) digest.enabled = enabled === "true";
|
|
85
|
+
const tiers = parseStringFlag(args, "--tiers");
|
|
86
|
+
if (tiers !== void 0) {
|
|
87
|
+
digest.tiers = tiers.split(",").map((t) => parseInt(t.trim(), 10));
|
|
88
|
+
}
|
|
89
|
+
const injectTier = parseStringFlag(args, "--inject-tier");
|
|
90
|
+
if (injectTier !== void 0) {
|
|
91
|
+
digest.inject_tier = injectTier === "null" ? null : parseInt(injectTier, 10);
|
|
92
|
+
}
|
|
93
|
+
const provider = parseStringFlag(args, "--provider");
|
|
94
|
+
if (provider !== void 0) intelligence.provider = provider === "null" ? null : provider;
|
|
95
|
+
const model = parseStringFlag(args, "--model");
|
|
96
|
+
if (model !== void 0) intelligence.model = model === "null" ? null : model;
|
|
97
|
+
const baseUrl = parseStringFlag(args, "--base-url");
|
|
98
|
+
if (baseUrl !== void 0) intelligence.base_url = baseUrl === "null" ? null : baseUrl;
|
|
99
|
+
const contextWindow = parseStringFlag(args, "--context-window");
|
|
100
|
+
if (contextWindow !== void 0) intelligence.context_window = parseInt(contextWindow, 10);
|
|
101
|
+
const keepAlive = parseStringFlag(args, "--keep-alive");
|
|
102
|
+
if (keepAlive !== void 0) intelligence.keep_alive = keepAlive === "null" ? null : keepAlive;
|
|
103
|
+
const gpuKvCache = parseStringFlag(args, "--gpu-kv-cache");
|
|
104
|
+
if (gpuKvCache !== void 0) intelligence.gpu_kv_cache = gpuKvCache === "true";
|
|
105
|
+
const activeInterval = parseStringFlag(args, "--active-interval");
|
|
106
|
+
if (activeInterval !== void 0) metabolism.active_interval = parseInt(activeInterval, 10);
|
|
107
|
+
const dormancyThreshold = parseStringFlag(args, "--dormancy-threshold");
|
|
108
|
+
if (dormancyThreshold !== void 0) metabolism.dormancy_threshold = parseInt(dormancyThreshold, 10);
|
|
109
|
+
const maxNotes = parseStringFlag(args, "--max-notes");
|
|
110
|
+
if (maxNotes !== void 0) substrate.max_notes_per_cycle = parseInt(maxNotes, 10);
|
|
111
|
+
const extractionTokens = parseStringFlag(args, "--extraction-tokens");
|
|
112
|
+
if (extractionTokens !== void 0) capture.extraction_max_tokens = parseInt(extractionTokens, 10);
|
|
113
|
+
const summaryTokens = parseStringFlag(args, "--summary-tokens");
|
|
114
|
+
if (summaryTokens !== void 0) capture.summary_max_tokens = parseInt(summaryTokens, 10);
|
|
115
|
+
const titleTokens = parseStringFlag(args, "--title-tokens");
|
|
116
|
+
if (titleTokens !== void 0) capture.title_max_tokens = parseInt(titleTokens, 10);
|
|
117
|
+
const classificationTokens = parseStringFlag(args, "--classification-tokens");
|
|
118
|
+
if (classificationTokens !== void 0) capture.classification_max_tokens = parseInt(classificationTokens, 10);
|
|
119
|
+
const result = MycoConfigSchema.safeParse(doc);
|
|
120
|
+
if (!result.success) {
|
|
121
|
+
console.error("Validation error:");
|
|
122
|
+
for (const issue of result.error.issues) {
|
|
123
|
+
console.error(` ${issue.path.join(".")}: ${issue.message}`);
|
|
124
|
+
}
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
fs.writeFileSync(configPath, import_yaml.default.stringify(doc), "utf-8");
|
|
128
|
+
console.log("Digest configuration updated.");
|
|
129
|
+
const updated = MycoConfigSchema.parse(doc);
|
|
130
|
+
console.log(JSON.stringify({
|
|
131
|
+
digest: updated.digest,
|
|
132
|
+
capture: {
|
|
133
|
+
extraction_max_tokens: updated.capture.extraction_max_tokens,
|
|
134
|
+
summary_max_tokens: updated.capture.summary_max_tokens,
|
|
135
|
+
title_max_tokens: updated.capture.title_max_tokens,
|
|
136
|
+
classification_max_tokens: updated.capture.classification_max_tokens
|
|
137
|
+
}
|
|
138
|
+
}, null, 2));
|
|
139
|
+
if (fs.existsSync(path.join(vaultDir, DAEMON_STATE_FILENAME))) {
|
|
140
|
+
console.log("\nNote: restart the daemon for changes to take effect (myco restart)");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export {
|
|
145
|
+
run
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=chunk-UKWO26VI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/setup-digest.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { MycoConfigSchema } from '../config/schema.js';\nimport { parseStringFlag } from './shared.js';\n\nconst CONFIG_FILENAME = 'myco.yaml';\nconst DAEMON_STATE_FILENAME = 'daemon.json';\n\nconst USAGE = `Usage: myco setup-digest [options]\n\nConfigure digest (continuous reasoning) settings.\n\nOptions:\n --enabled <true|false> Enable/disable digest (default: true)\n --tiers <1500,3000,...> Comma-separated tier list\n --inject-tier <number|null> Tier to auto-inject at session start\n --provider <name> LLM provider for digest (null = inherit)\n --model <name> Model for digest (null = inherit)\n --base-url <url> Provider base URL (null = inherit)\n --context-window <number> Context window for digest operations\n --keep-alive <duration> Keep model loaded (Ollama, e.g. \"30m\")\n --gpu-kv-cache <true|false> Offload KV cache to GPU (LM Studio)\n --active-interval <seconds> Metabolism active interval\n --dormancy-threshold <seconds> Time before dormancy\n --max-notes <number> Max substrate notes per cycle\n --extraction-tokens <number> Max tokens for spore extraction\n --summary-tokens <number> Max tokens for session summaries\n --title-tokens <number> Max tokens for session titles\n --classification-tokens <number> Max tokens for artifact classification\n --show Show current settings and exit\n`;\n\nexport async function run(args: string[], vaultDir: string): Promise<void> {\n const configPath = path.join(vaultDir, CONFIG_FILENAME);\n const raw = fs.readFileSync(configPath, 'utf-8');\n const doc = YAML.parse(raw) as Record<string, unknown>;\n\n // Show current settings\n if (args.includes('--show')) {\n const config = MycoConfigSchema.parse(doc);\n console.log(JSON.stringify({\n digest: config.digest,\n capture: {\n extraction_max_tokens: config.capture.extraction_max_tokens,\n summary_max_tokens: config.capture.summary_max_tokens,\n title_max_tokens: config.capture.title_max_tokens,\n classification_max_tokens: config.capture.classification_max_tokens,\n },\n }, null, 2));\n return;\n }\n\n // No flags = show usage\n if (args.length === 0) {\n console.log(USAGE);\n return;\n }\n\n // Ensure digest section exists\n if (!doc.digest || typeof doc.digest !== 'object') {\n doc.digest = {};\n }\n const digest = doc.digest as Record<string, unknown>;\n\n // Ensure nested sections exist\n if (!digest.intelligence || typeof digest.intelligence !== 'object') {\n digest.intelligence = {};\n }\n if (!digest.metabolism || typeof digest.metabolism !== 'object') {\n digest.metabolism = {};\n }\n if (!digest.substrate || typeof digest.substrate !== 'object') {\n digest.substrate = {};\n }\n if (!doc.capture || typeof doc.capture !== 'object') {\n doc.capture = {};\n }\n\n const intelligence = digest.intelligence as Record<string, unknown>;\n const metabolism = digest.metabolism as Record<string, unknown>;\n const substrate = digest.substrate as Record<string, unknown>;\n const capture = doc.capture as Record<string, unknown>;\n\n // Parse and apply flags\n const enabled = parseStringFlag(args, '--enabled');\n if (enabled !== undefined) digest.enabled = enabled === 'true';\n\n const tiers = parseStringFlag(args, '--tiers');\n if (tiers !== undefined) {\n digest.tiers = tiers.split(',').map((t) => parseInt(t.trim(), 10));\n }\n\n const injectTier = parseStringFlag(args, '--inject-tier');\n if (injectTier !== undefined) {\n digest.inject_tier = injectTier === 'null' ? null : parseInt(injectTier, 10);\n }\n\n const provider = parseStringFlag(args, '--provider');\n if (provider !== undefined) intelligence.provider = provider === 'null' ? null : provider;\n\n const model = parseStringFlag(args, '--model');\n if (model !== undefined) intelligence.model = model === 'null' ? null : model;\n\n const baseUrl = parseStringFlag(args, '--base-url');\n if (baseUrl !== undefined) intelligence.base_url = baseUrl === 'null' ? null : baseUrl;\n\n const contextWindow = parseStringFlag(args, '--context-window');\n if (contextWindow !== undefined) intelligence.context_window = parseInt(contextWindow, 10);\n\n const keepAlive = parseStringFlag(args, '--keep-alive');\n if (keepAlive !== undefined) intelligence.keep_alive = keepAlive === 'null' ? null : keepAlive;\n\n const gpuKvCache = parseStringFlag(args, '--gpu-kv-cache');\n if (gpuKvCache !== undefined) intelligence.gpu_kv_cache = gpuKvCache === 'true';\n\n const activeInterval = parseStringFlag(args, '--active-interval');\n if (activeInterval !== undefined) metabolism.active_interval = parseInt(activeInterval, 10);\n\n const dormancyThreshold = parseStringFlag(args, '--dormancy-threshold');\n if (dormancyThreshold !== undefined) metabolism.dormancy_threshold = parseInt(dormancyThreshold, 10);\n\n const maxNotes = parseStringFlag(args, '--max-notes');\n if (maxNotes !== undefined) substrate.max_notes_per_cycle = parseInt(maxNotes, 10);\n\n const extractionTokens = parseStringFlag(args, '--extraction-tokens');\n if (extractionTokens !== undefined) capture.extraction_max_tokens = parseInt(extractionTokens, 10);\n\n const summaryTokens = parseStringFlag(args, '--summary-tokens');\n if (summaryTokens !== undefined) capture.summary_max_tokens = parseInt(summaryTokens, 10);\n\n const titleTokens = parseStringFlag(args, '--title-tokens');\n if (titleTokens !== undefined) capture.title_max_tokens = parseInt(titleTokens, 10);\n\n const classificationTokens = parseStringFlag(args, '--classification-tokens');\n if (classificationTokens !== undefined) capture.classification_max_tokens = parseInt(classificationTokens, 10);\n\n // Validate the full config\n const result = MycoConfigSchema.safeParse(doc);\n if (!result.success) {\n console.error('Validation error:');\n for (const issue of result.error.issues) {\n console.error(` ${issue.path.join('.')}: ${issue.message}`);\n }\n process.exit(1);\n }\n\n // Write back\n fs.writeFileSync(configPath, YAML.stringify(doc), 'utf-8');\n console.log('Digest configuration updated.');\n\n // Show what was set\n const updated = MycoConfigSchema.parse(doc);\n console.log(JSON.stringify({\n digest: updated.digest,\n capture: {\n extraction_max_tokens: updated.capture.extraction_max_tokens,\n summary_max_tokens: updated.capture.summary_max_tokens,\n title_max_tokens: updated.capture.title_max_tokens,\n classification_max_tokens: updated.capture.classification_max_tokens,\n },\n }, null, 2));\n\n if (fs.existsSync(path.join(vaultDir, DAEMON_STATE_FILENAME))) {\n console.log('\\nNote: restart the daemon for changes to take effect (myco restart)');\n }\n}\n"],"mappings":"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","names":["YAML"]}
|
|
@@ -1,29 +1,26 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
formatSporeBody,
|
|
4
4
|
sessionNoteId
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-I7PNZEBO.js";
|
|
6
6
|
import {
|
|
7
7
|
ARTIFACT_TYPES,
|
|
8
8
|
indexNote
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-FPEDTLQ6.js";
|
|
10
10
|
import {
|
|
11
11
|
external_exports
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6UJWI4IW.js";
|
|
13
13
|
import {
|
|
14
14
|
AgentRegistry
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BNIYWCST.js";
|
|
16
16
|
import {
|
|
17
17
|
AI_RESPONSE_PREVIEW_CHARS,
|
|
18
18
|
CANDIDATE_CONTENT_PREVIEW,
|
|
19
19
|
CHARS_PER_TOKEN,
|
|
20
|
-
CLASSIFICATION_MAX_TOKENS,
|
|
21
20
|
COMMAND_PREVIEW_CHARS,
|
|
22
|
-
EXTRACTION_MAX_TOKENS,
|
|
23
21
|
PROMPT_PREVIEW_CHARS,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from "./chunk-7VPJK56U.js";
|
|
22
|
+
estimateTokens
|
|
23
|
+
} from "./chunk-JBD5KP5G.js";
|
|
27
24
|
|
|
28
25
|
// src/prompts/index.ts
|
|
29
26
|
import fs from "fs";
|
|
@@ -59,18 +56,20 @@ function interpolate(template, vars) {
|
|
|
59
56
|
}
|
|
60
57
|
return result;
|
|
61
58
|
}
|
|
62
|
-
function buildExtractionPrompt(sessionId, eventCount, toolSummary) {
|
|
59
|
+
function buildExtractionPrompt(sessionId, eventCount, toolSummary, maxTokens) {
|
|
63
60
|
return interpolate(loadPrompt("extraction"), {
|
|
64
61
|
sessionId,
|
|
65
62
|
eventCount: String(eventCount),
|
|
66
|
-
toolSummary
|
|
63
|
+
toolSummary,
|
|
64
|
+
maxTokens: String(maxTokens ?? 2048)
|
|
67
65
|
});
|
|
68
66
|
}
|
|
69
|
-
function buildSummaryPrompt(sessionId, user, content) {
|
|
67
|
+
function buildSummaryPrompt(sessionId, user, content, maxTokens) {
|
|
70
68
|
return interpolate(loadPrompt("summary"), {
|
|
71
69
|
sessionId,
|
|
72
70
|
user,
|
|
73
|
-
content
|
|
71
|
+
content,
|
|
72
|
+
maxTokens: String(maxTokens ?? 1024)
|
|
74
73
|
});
|
|
75
74
|
}
|
|
76
75
|
function buildTitlePrompt(summary, sessionId) {
|
|
@@ -92,7 +91,7 @@ function buildSimilarityPrompt(currentSummary, candidateSummary) {
|
|
|
92
91
|
candidateSummary
|
|
93
92
|
});
|
|
94
93
|
}
|
|
95
|
-
function buildClassificationPrompt(sessionId, candidates) {
|
|
94
|
+
function buildClassificationPrompt(sessionId, candidates, maxTokens) {
|
|
96
95
|
const fileList = candidates.map((c) => {
|
|
97
96
|
const truncated = c.content.slice(0, CANDIDATE_CONTENT_PREVIEW);
|
|
98
97
|
return `### ${c.path}
|
|
@@ -104,7 +103,8 @@ ${truncated}
|
|
|
104
103
|
sessionId,
|
|
105
104
|
fileList,
|
|
106
105
|
artifactTypes: ARTIFACT_TYPE_DESCRIPTIONS.map((d) => `- ${d}`).join("\n"),
|
|
107
|
-
validTypes: ARTIFACT_TYPES.join("|")
|
|
106
|
+
validTypes: ARTIFACT_TYPES.join("|"),
|
|
107
|
+
maxTokens: String(maxTokens ?? 1024)
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -117,7 +117,11 @@ var REASONING_PATTERNS = [
|
|
|
117
117
|
// <reasoning>...</reasoning>answer
|
|
118
118
|
/<reasoning>[\s\S]*?<\/reasoning>\s*/gi,
|
|
119
119
|
// <|thinking|>...<|/thinking|>answer
|
|
120
|
-
/<\|thinking\|>[\s\S]*?<\|\/thinking\|>\s*/gi
|
|
120
|
+
/<\|thinking\|>[\s\S]*?<\|\/thinking\|>\s*/gi,
|
|
121
|
+
// Plain-text "Thinking Process:" block followed by actual content
|
|
122
|
+
// (Qwen 3.5 via LM Studio without native thinking mode)
|
|
123
|
+
// Matches from "Thinking Process:" up to the last numbered step, then the synthesis follows
|
|
124
|
+
/^Thinking Process:[\s\S]*?(?=\n(?:## |# |\*\*[A-Z]))/i
|
|
121
125
|
];
|
|
122
126
|
function stripReasoningTokens(text) {
|
|
123
127
|
if (!text) return text;
|
|
@@ -158,22 +162,30 @@ var ClassificationResponseSchema = external_exports.object({
|
|
|
158
162
|
})).default([])
|
|
159
163
|
});
|
|
160
164
|
var BufferProcessor = class {
|
|
161
|
-
constructor(backend, contextWindow = 8192) {
|
|
165
|
+
constructor(backend, contextWindow = 8192, captureConfig) {
|
|
162
166
|
this.backend = backend;
|
|
163
167
|
this.contextWindow = contextWindow;
|
|
168
|
+
this.extractionMaxTokens = captureConfig?.extraction_max_tokens ?? 2048;
|
|
169
|
+
this.summaryMaxTokens = captureConfig?.summary_max_tokens ?? 512;
|
|
170
|
+
this.titleMaxTokens = captureConfig?.title_max_tokens ?? 32;
|
|
171
|
+
this.classificationMaxTokens = captureConfig?.classification_max_tokens ?? 1024;
|
|
164
172
|
}
|
|
173
|
+
extractionMaxTokens;
|
|
174
|
+
summaryMaxTokens;
|
|
175
|
+
titleMaxTokens;
|
|
176
|
+
classificationMaxTokens;
|
|
165
177
|
truncateForContext(data, maxTokens) {
|
|
166
178
|
const available = this.contextWindow - maxTokens;
|
|
167
|
-
const dataTokens =
|
|
179
|
+
const dataTokens = estimateTokens(data);
|
|
168
180
|
if (dataTokens <= available) return data;
|
|
169
181
|
const charBudget = available * CHARS_PER_TOKEN;
|
|
170
182
|
return data.slice(0, charBudget);
|
|
171
183
|
}
|
|
172
184
|
async process(events, sessionId) {
|
|
173
185
|
const rawPrompt = this.buildPromptForExtraction(events, sessionId);
|
|
174
|
-
const prompt = this.truncateForContext(rawPrompt,
|
|
186
|
+
const prompt = this.truncateForContext(rawPrompt, this.extractionMaxTokens);
|
|
175
187
|
try {
|
|
176
|
-
const response = await this.backend.summarize(prompt, { maxTokens:
|
|
188
|
+
const response = await this.backend.summarize(prompt, { maxTokens: this.extractionMaxTokens });
|
|
177
189
|
const parsed = extractJson(response.text);
|
|
178
190
|
return {
|
|
179
191
|
summary: parsed.summary,
|
|
@@ -190,14 +202,14 @@ var BufferProcessor = class {
|
|
|
190
202
|
}
|
|
191
203
|
buildPromptForExtraction(events, sessionId) {
|
|
192
204
|
const toolSummary = this.summarizeEvents(events);
|
|
193
|
-
return buildExtractionPrompt(sessionId, events.length, toolSummary);
|
|
205
|
+
return buildExtractionPrompt(sessionId, events.length, toolSummary, this.extractionMaxTokens);
|
|
194
206
|
}
|
|
195
207
|
async summarizeSession(conversationMarkdown, sessionId, user) {
|
|
196
|
-
const truncatedContent = this.truncateForContext(conversationMarkdown,
|
|
197
|
-
const summaryPrompt = buildSummaryPrompt(sessionId, user ?? "unknown", truncatedContent);
|
|
208
|
+
const truncatedContent = this.truncateForContext(conversationMarkdown, this.summaryMaxTokens);
|
|
209
|
+
const summaryPrompt = buildSummaryPrompt(sessionId, user ?? "unknown", truncatedContent, this.summaryMaxTokens);
|
|
198
210
|
let summaryText;
|
|
199
211
|
try {
|
|
200
|
-
const response = await this.backend.summarize(summaryPrompt, { maxTokens:
|
|
212
|
+
const response = await this.backend.summarize(summaryPrompt, { maxTokens: this.summaryMaxTokens });
|
|
201
213
|
summaryText = stripReasoningTokens(response.text);
|
|
202
214
|
} catch (error) {
|
|
203
215
|
summaryText = `Session ${sessionId} \u2014 summarization failed: ${error.message}`;
|
|
@@ -205,7 +217,7 @@ var BufferProcessor = class {
|
|
|
205
217
|
const titlePrompt = buildTitlePrompt(summaryText, sessionId);
|
|
206
218
|
let title;
|
|
207
219
|
try {
|
|
208
|
-
const response = await this.backend.summarize(titlePrompt, { maxTokens:
|
|
220
|
+
const response = await this.backend.summarize(titlePrompt, { maxTokens: this.titleMaxTokens });
|
|
209
221
|
title = stripReasoningTokens(response.text).trim();
|
|
210
222
|
} catch {
|
|
211
223
|
title = `Session ${sessionId}`;
|
|
@@ -215,13 +227,13 @@ var BufferProcessor = class {
|
|
|
215
227
|
async classifyArtifacts(candidates, sessionId) {
|
|
216
228
|
if (candidates.length === 0) return [];
|
|
217
229
|
const prompt = this.buildPromptForClassification(candidates, sessionId);
|
|
218
|
-
const response = await this.backend.summarize(prompt, { maxTokens:
|
|
230
|
+
const response = await this.backend.summarize(prompt, { maxTokens: this.classificationMaxTokens });
|
|
219
231
|
const raw = extractJson(response.text);
|
|
220
232
|
const parsed = ClassificationResponseSchema.parse(raw);
|
|
221
233
|
return parsed.artifacts;
|
|
222
234
|
}
|
|
223
235
|
buildPromptForClassification(candidates, sessionId) {
|
|
224
|
-
return buildClassificationPrompt(sessionId, candidates);
|
|
236
|
+
return buildClassificationPrompt(sessionId, candidates, this.classificationMaxTokens);
|
|
225
237
|
}
|
|
226
238
|
summarizeEvents(events) {
|
|
227
239
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
@@ -325,7 +337,7 @@ function writeObservationNotes(observations, sessionId, writer, index, vaultDir)
|
|
|
325
337
|
const results = [];
|
|
326
338
|
for (const obs of observations) {
|
|
327
339
|
const obsId = `${obs.type}-${sessionId.slice(-6)}-${Date.now()}`;
|
|
328
|
-
const body =
|
|
340
|
+
const body = formatSporeBody({
|
|
329
341
|
title: obs.title,
|
|
330
342
|
observationType: obs.type,
|
|
331
343
|
content: obs.content,
|
|
@@ -338,7 +350,7 @@ function writeObservationNotes(observations, sessionId, writer, index, vaultDir)
|
|
|
338
350
|
sacrificed: obs.sacrificed,
|
|
339
351
|
tags: obs.tags
|
|
340
352
|
});
|
|
341
|
-
const relativePath = writer.
|
|
353
|
+
const relativePath = writer.writeSpore({
|
|
342
354
|
id: obsId,
|
|
343
355
|
observation_type: obs.type,
|
|
344
356
|
session: sessionNoteId(sessionId),
|
|
@@ -352,11 +364,13 @@ function writeObservationNotes(observations, sessionId, writer, index, vaultDir)
|
|
|
352
364
|
}
|
|
353
365
|
|
|
354
366
|
export {
|
|
367
|
+
loadPrompt,
|
|
355
368
|
buildSimilarityPrompt,
|
|
369
|
+
stripReasoningTokens,
|
|
356
370
|
extractNumber,
|
|
357
371
|
BufferProcessor,
|
|
358
372
|
TranscriptMiner,
|
|
359
373
|
extractTurnsFromBuffer,
|
|
360
374
|
writeObservationNotes
|
|
361
375
|
};
|
|
362
|
-
//# sourceMappingURL=chunk-
|
|
376
|
+
//# sourceMappingURL=chunk-V2OWD2VV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/prompts/index.ts","../src/intelligence/response.ts","../src/daemon/processor.ts","../src/capture/transcript-miner.ts","../src/vault/observations.ts"],"sourcesContent":["/**\n * Prompt loader — reads .md templates from disk and interpolates variables.\n * Prompts are markdown files in this directory, not TypeScript strings.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { ARTIFACT_TYPES } from '../vault/types.js';\nimport { CANDIDATE_CONTENT_PREVIEW } from '../constants.js';\n\n/**\n * Resolve the prompts directory. With tsup code-splitting, import.meta.url\n * points to a chunk file (dist/chunk-XXXX.js), not dist/src/prompts/.\n * Walk up from the current file to find package.json, then use dist/src/prompts/.\n */\nfunction resolvePromptsDir(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 5; i++) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n return path.join(dir, 'dist', 'src', 'prompts');\n }\n // Also check if we're already in the right place (tsc output or dev mode)\n if (fs.existsSync(path.join(dir, 'extraction.md'))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n // Final fallback: adjacent to current file (works with tsc)\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nconst PROMPTS_DIR = resolvePromptsDir();\n\nconst promptCache = new Map<string, string>();\n\nexport function loadPrompt(name: string): string {\n let cached = promptCache.get(name);\n if (!cached) {\n cached = fs.readFileSync(path.join(PROMPTS_DIR, `${name}.md`), 'utf-8').trim();\n promptCache.set(name, cached);\n }\n return cached;\n}\n\nfunction interpolate(template: string, vars: Record<string, string>): string {\n let result = template;\n for (const [key, value] of Object.entries(vars)) {\n result = result.replaceAll(`{{${key}}}`, value);\n }\n return result;\n}\n\n// --- Prompt builders ---\n\nexport function buildExtractionPrompt(\n sessionId: string,\n eventCount: number,\n toolSummary: string,\n maxTokens?: number,\n): string {\n return interpolate(loadPrompt('extraction'), {\n sessionId,\n eventCount: String(eventCount),\n toolSummary,\n maxTokens: String(maxTokens ?? 2048),\n });\n}\n\nexport function buildSummaryPrompt(\n sessionId: string,\n user: string,\n content: string,\n maxTokens?: number,\n): string {\n return interpolate(loadPrompt('summary'), {\n sessionId,\n user,\n content,\n maxTokens: String(maxTokens ?? 1024),\n });\n}\n\nexport function buildTitlePrompt(\n summary: string,\n sessionId: string,\n): string {\n return interpolate(loadPrompt('title'), {\n summary,\n sessionId,\n });\n}\n\nconst ARTIFACT_TYPE_DESCRIPTIONS = [\n '\"spec\" — Design specifications, architecture documents',\n '\"plan\" — Implementation plans, roadmaps',\n '\"rfc\" — Requests for comment, proposals',\n '\"doc\" — Documentation, guides, READMEs',\n '\"other\" — Other substantive documents',\n];\n\nexport function buildSimilarityPrompt(\n currentSummary: string,\n candidateSummary: string,\n): string {\n return interpolate(loadPrompt('session-similarity'), {\n currentSummary,\n candidateSummary,\n });\n}\n\nexport function buildClassificationPrompt(\n sessionId: string,\n candidates: Array<{ path: string; content: string }>,\n maxTokens?: number,\n): string {\n const fileList = candidates\n .map((c) => {\n const truncated = c.content.slice(0, CANDIDATE_CONTENT_PREVIEW);\n return `### ${c.path}\\n\\`\\`\\`\\n${truncated}\\n\\`\\`\\``;\n })\n .join('\\n\\n');\n\n return interpolate(loadPrompt('classification'), {\n sessionId,\n fileList,\n artifactTypes: ARTIFACT_TYPE_DESCRIPTIONS.map((d) => `- ${d}`).join('\\n'),\n validTypes: ARTIFACT_TYPES.join('|'),\n maxTokens: String(maxTokens ?? 1024),\n });\n}\n","/**\n * Clean LLM response text before parsing.\n *\n * Reasoning models (DeepSeek, Qwen, GLM, etc.) embed chain-of-thought\n * in the response using special tags. These must be stripped before\n * JSON parsing or value extraction.\n */\n\n// Patterns for reasoning model chain-of-thought tokens.\n// Order matters: most specific patterns first.\nconst REASONING_PATTERNS = [\n // <think>...</think>answer (DeepSeek, Qwen, GLM, many others)\n /<think>[\\s\\S]*?<\\/think>\\s*/gi,\n // Implicit opening: reasoning...</think>answer (GLM-4.7 observed)\n /^[\\s\\S]*?<\\/think>\\s*/i,\n // <reasoning>...</reasoning>answer\n /<reasoning>[\\s\\S]*?<\\/reasoning>\\s*/gi,\n // <|thinking|>...<|/thinking|>answer\n /<\\|thinking\\|>[\\s\\S]*?<\\|\\/thinking\\|>\\s*/gi,\n // Plain-text \"Thinking Process:\" block followed by actual content\n // (Qwen 3.5 via LM Studio without native thinking mode)\n // Matches from \"Thinking Process:\" up to the last numbered step, then the synthesis follows\n /^Thinking Process:[\\s\\S]*?(?=\\n(?:## |# |\\*\\*[A-Z]))/i,\n];\n\n/**\n * Strip reasoning/chain-of-thought tokens from LLM response text.\n * Returns the final answer without the thinking process.\n */\nexport function stripReasoningTokens(text: string): string {\n if (!text) return text;\n\n for (const pattern of REASONING_PATTERNS) {\n const stripped = text.replace(pattern, '').trim();\n if (stripped && stripped !== text.trim()) {\n return stripped;\n }\n }\n\n return text;\n}\n\n/**\n * Extract JSON from an LLM response that may contain markdown fences,\n * reasoning tokens, or other wrapper text.\n *\n * Tries in order:\n * 1. Strip reasoning tokens\n * 2. Extract from ```json ... ``` code fences\n * 3. Find bare {...} JSON object\n * 4. Parse the cleaned text directly\n */\nexport function extractJson(text: string): unknown {\n const cleaned = stripReasoningTokens(text);\n\n // Try code fence extraction\n const fenceMatch = cleaned.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?```/);\n if (fenceMatch) {\n return JSON.parse(fenceMatch[1].trim());\n }\n\n // Try bare JSON object\n const objectMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (objectMatch) {\n return JSON.parse(objectMatch[0]);\n }\n\n // Try direct parse\n return JSON.parse(cleaned);\n}\n\n/**\n * Extract a numeric value from an LLM response that may contain\n * reasoning tokens or extra text around the number.\n */\nexport function extractNumber(text: string): number {\n const cleaned = stripReasoningTokens(text).trim();\n const match = cleaned.match(/(\\d+\\.?\\d*)/);\n if (match) return parseFloat(match[1]);\n return parseFloat(cleaned);\n}\n","import { z } from 'zod';\nimport type { LlmProvider } from '../intelligence/llm.js';\nimport { ARTIFACT_TYPES } from '../vault/types.js';\nimport { estimateTokens, CHARS_PER_TOKEN, PROMPT_PREVIEW_CHARS, AI_RESPONSE_PREVIEW_CHARS, COMMAND_PREVIEW_CHARS } from '../constants.js';\nimport type { MycoConfig } from '../config/schema.js';\nimport type { ObservationType, ArtifactType } from '../vault/types.js';\nimport { buildExtractionPrompt, buildSummaryPrompt, buildTitlePrompt, buildClassificationPrompt } from '../prompts/index.js';\nimport { extractJson, stripReasoningTokens } from '../intelligence/response.js';\n\nexport interface Observation {\n type: ObservationType;\n title: string;\n content: string;\n tags: string[];\n root_cause?: string;\n fix?: string;\n rationale?: string;\n alternatives_rejected?: string;\n gained?: string;\n sacrificed?: string;\n}\n\nexport interface ProcessorResult {\n summary: string;\n observations: Observation[];\n degraded: boolean;\n}\n\nexport interface ClassifiedArtifact {\n source_path: string;\n artifact_type: ArtifactType;\n title: string;\n tags: string[];\n}\n\nconst ClassificationResponseSchema = z.object({\n artifacts: z.array(z.object({\n source_path: z.string(),\n artifact_type: z.enum(ARTIFACT_TYPES),\n title: z.string(),\n tags: z.array(z.string()).default([]),\n })).default([]),\n});\n\nexport class BufferProcessor {\n private extractionMaxTokens: number;\n private summaryMaxTokens: number;\n private titleMaxTokens: number;\n private classificationMaxTokens: number;\n\n constructor(private backend: LlmProvider, private contextWindow: number = 8192, captureConfig?: MycoConfig['capture']) {\n this.extractionMaxTokens = captureConfig?.extraction_max_tokens ?? 2048;\n this.summaryMaxTokens = captureConfig?.summary_max_tokens ?? 512;\n this.titleMaxTokens = captureConfig?.title_max_tokens ?? 32;\n this.classificationMaxTokens = captureConfig?.classification_max_tokens ?? 1024;\n }\n\n private truncateForContext(data: string, maxTokens: number): string {\n const available = this.contextWindow - maxTokens;\n const dataTokens = estimateTokens(data);\n if (dataTokens <= available) return data;\n const charBudget = available * CHARS_PER_TOKEN;\n return data.slice(0, charBudget);\n }\n\n async process(\n events: Array<Record<string, unknown>>,\n sessionId: string,\n ): Promise<ProcessorResult> {\n const rawPrompt = this.buildPromptForExtraction(events, sessionId);\n const prompt = this.truncateForContext(rawPrompt, this.extractionMaxTokens);\n\n try {\n const response = await this.backend.summarize(prompt, { maxTokens: this.extractionMaxTokens });\n const parsed = extractJson(response.text) as {\n summary: string;\n observations: Observation[];\n };\n\n return {\n summary: parsed.summary,\n observations: parsed.observations ?? [],\n degraded: false,\n };\n } catch (error) {\n return {\n summary: `LLM processing failed for session ${sessionId}. ${events.length} events captured. Error: ${(error as Error).message}`,\n observations: [],\n degraded: true,\n };\n }\n }\n\n private buildPromptForExtraction(\n events: Array<Record<string, unknown>>,\n sessionId: string,\n ): string {\n const toolSummary = this.summarizeEvents(events);\n return buildExtractionPrompt(sessionId, events.length, toolSummary, this.extractionMaxTokens);\n }\n\n async summarizeSession(\n conversationMarkdown: string,\n sessionId: string,\n user?: string,\n ): Promise<{ summary: string; title: string }> {\n const truncatedContent = this.truncateForContext(conversationMarkdown, this.summaryMaxTokens);\n const summaryPrompt = buildSummaryPrompt(sessionId, user ?? 'unknown', truncatedContent, this.summaryMaxTokens);\n\n let summaryText: string;\n try {\n const response = await this.backend.summarize(summaryPrompt, { maxTokens: this.summaryMaxTokens });\n summaryText = stripReasoningTokens(response.text);\n } catch (error) {\n summaryText = `Session ${sessionId} — summarization failed: ${(error as Error).message}`;\n }\n\n const titlePrompt = buildTitlePrompt(summaryText, sessionId);\n let title: string;\n try {\n const response = await this.backend.summarize(titlePrompt, { maxTokens: this.titleMaxTokens });\n title = stripReasoningTokens(response.text).trim();\n } catch {\n title = `Session ${sessionId}`;\n }\n\n return { summary: summaryText, title };\n }\n\n async classifyArtifacts(\n candidates: Array<{ path: string; content: string }>,\n sessionId: string,\n ): Promise<ClassifiedArtifact[]> {\n if (candidates.length === 0) return [];\n\n const prompt = this.buildPromptForClassification(candidates, sessionId);\n const response = await this.backend.summarize(prompt, { maxTokens: this.classificationMaxTokens });\n const raw = extractJson(response.text);\n const parsed = ClassificationResponseSchema.parse(raw);\n return parsed.artifacts;\n }\n\n private buildPromptForClassification(\n candidates: Array<{ path: string; content: string }>,\n sessionId: string,\n ): string {\n return buildClassificationPrompt(sessionId, candidates, this.classificationMaxTokens);\n }\n\n private summarizeEvents(events: Array<Record<string, unknown>>): string {\n const toolCounts = new Map<string, number>();\n const filesAccessed = new Set<string>();\n const prompts: string[] = [];\n const aiResponses: string[] = [];\n\n for (const event of events) {\n if (event.type === 'user_prompt') {\n const prompt = String(event.prompt ?? '');\n if (prompt) prompts.push(prompt.slice(0, PROMPT_PREVIEW_CHARS));\n continue;\n }\n\n if (event.type === 'ai_response') {\n const content = String(event.content ?? '');\n if (content) aiResponses.push(content.slice(0, AI_RESPONSE_PREVIEW_CHARS));\n continue;\n }\n\n // Hooks send tool_name/tool_input; also support legacy tool/input\n const tool = String(event.tool_name ?? event.tool ?? 'unknown');\n toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);\n\n const input = (event.tool_input ?? event.input) as Record<string, unknown> | undefined;\n if (input?.path) filesAccessed.add(String(input.path));\n if (input?.file_path) filesAccessed.add(String(input.file_path));\n if (input?.command) filesAccessed.add(`[cmd] ${String(input.command).slice(0, COMMAND_PREVIEW_CHARS)}`);\n }\n\n const lines: string[] = [];\n\n if (prompts.length > 0) {\n lines.push('### User Prompts');\n for (const p of prompts) {\n lines.push(`- \"${p}\"`);\n }\n }\n\n lines.push('\\n### Tool Usage');\n for (const [tool, count] of toolCounts) {\n lines.push(`- ${tool}: ${count} calls`);\n }\n\n if (filesAccessed.size > 0) {\n lines.push('\\n### Files Accessed');\n for (const file of filesAccessed) {\n lines.push(`- ${file}`);\n }\n }\n\n if (aiResponses.length > 0) {\n lines.push('\\n### AI Responses');\n for (const r of aiResponses) {\n lines.push(`- \"${r}\"`);\n }\n }\n\n return lines.join('\\n');\n }\n}\n","import { AgentRegistry } from '../agents/registry.js';\nimport type { AgentAdapter } from '../agents/adapter.js';\nimport { PROMPT_PREVIEW_CHARS } from '../constants.js';\nimport fs from 'node:fs';\n\n// Re-export TranscriptTurn from its canonical home in agents/adapter.ts\nexport type { TranscriptTurn } from '../agents/adapter.js';\nimport type { TranscriptTurn } from '../agents/adapter.js';\n\ninterface TranscriptConfig {\n /** Additional agent adapters to register (useful for testing or custom agents) */\n additionalAdapters?: AgentAdapter[];\n}\n\nexport class TranscriptMiner {\n private registry: AgentRegistry;\n\n constructor(config?: TranscriptConfig) {\n this.registry = new AgentRegistry(config?.additionalAdapters);\n }\n\n /**\n * Extract all conversation turns for a session.\n * Convenience wrapper — delegates to getAllTurnsWithSource.\n */\n getAllTurns(sessionId: string): TranscriptTurn[] {\n return this.getAllTurnsWithSource(sessionId).turns;\n }\n\n /**\n * Extract turns using the hook-provided transcript path first (fast, no scanning),\n * then fall back to adapter registry scanning if the path isn't provided.\n */\n getAllTurnsWithSource(sessionId: string, transcriptPath?: string): { turns: TranscriptTurn[]; source: string } {\n // Primary: use the path provided by the hook (no directory scanning needed)\n if (transcriptPath) {\n const result = this.registry.parseTurnsFromPath(transcriptPath);\n if (result) return result;\n }\n\n // Fallback: scan known agent directories\n const result = this.registry.getTranscriptTurns(sessionId);\n if (result) return result;\n return { turns: [], source: 'none' };\n }\n}\n\n/**\n * Build turns from buffer events — the fallback when no agent transcript is available.\n * Buffer events come from hooks (user_prompt, tool_use) and lack AI responses.\n * Turns will have prompts and tool counts but no aiResponse.\n */\nexport function extractTurnsFromBuffer(events: Array<Record<string, unknown>>): TranscriptTurn[] {\n const turns: TranscriptTurn[] = [];\n let current: TranscriptTurn | null = null;\n\n for (const event of events) {\n const type = event.type as string;\n if (type === 'user_prompt') {\n if (current) turns.push(current);\n current = {\n prompt: String(event.prompt ?? '').slice(0, PROMPT_PREVIEW_CHARS),\n toolCount: 0,\n timestamp: String(event.timestamp ?? new Date().toISOString()),\n };\n } else if (type === 'tool_use') {\n if (current) current.toolCount++;\n }\n }\n if (current) turns.push(current);\n return turns;\n}\n","import { formatSporeBody } from '../obsidian/formatter.js';\nimport { sessionNoteId } from './session-id.js';\nimport { indexNote } from '../index/rebuild.js';\nimport type { Observation } from '../daemon/processor.js';\nimport type { VaultWriter } from './writer.js';\nimport type { MycoIndex } from '../index/sqlite.js';\n\nexport interface WrittenNote {\n id: string;\n path: string;\n observation: Observation;\n}\n\nexport function writeObservationNotes(\n observations: Observation[],\n sessionId: string,\n writer: VaultWriter,\n index: MycoIndex,\n vaultDir: string,\n): WrittenNote[] {\n const results: WrittenNote[] = [];\n\n for (const obs of observations) {\n const obsId = `${obs.type}-${sessionId.slice(-6)}-${Date.now()}`;\n const body = formatSporeBody({\n title: obs.title,\n observationType: obs.type,\n content: obs.content,\n sessionId,\n root_cause: obs.root_cause,\n fix: obs.fix,\n rationale: obs.rationale,\n alternatives_rejected: obs.alternatives_rejected,\n gained: obs.gained,\n sacrificed: obs.sacrificed,\n tags: obs.tags,\n });\n const relativePath = writer.writeSpore({\n id: obsId,\n observation_type: obs.type,\n session: sessionNoteId(sessionId),\n tags: obs.tags,\n content: body,\n });\n indexNote(index, vaultDir, relativePath);\n results.push({ id: obsId, path: relativePath, observation: obs });\n }\n\n return results;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAKA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAS9B,SAAS,oBAA4B;AACnC,MAAI,MAAM,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AACrD,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,GAAG,WAAW,KAAK,KAAK,KAAK,cAAc,CAAC,GAAG;AACjD,aAAO,KAAK,KAAK,KAAK,QAAQ,OAAO,SAAS;AAAA,IAChD;AAEA,QAAI,GAAG,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,GAAG;AAClD,aAAO;AAAA,IACT;AACA,UAAM,KAAK,QAAQ,GAAG;AAAA,EACxB;AAEA,SAAO,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AACpD;AAEA,IAAM,cAAc,kBAAkB;AAEtC,IAAM,cAAc,oBAAI,IAAoB;AAErC,SAAS,WAAW,MAAsB;AAC/C,MAAI,SAAS,YAAY,IAAI,IAAI;AACjC,MAAI,CAAC,QAAQ;AACX,aAAS,GAAG,aAAa,KAAK,KAAK,aAAa,GAAG,IAAI,KAAK,GAAG,OAAO,EAAE,KAAK;AAC7E,gBAAY,IAAI,MAAM,MAAM;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,YAAY,UAAkB,MAAsC;AAC3E,MAAI,SAAS;AACb,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,aAAS,OAAO,WAAW,KAAK,GAAG,MAAM,KAAK;AAAA,EAChD;AACA,SAAO;AACT;AAIO,SAAS,sBACd,WACA,YACA,aACA,WACQ;AACR,SAAO,YAAY,WAAW,YAAY,GAAG;AAAA,IAC3C;AAAA,IACA,YAAY,OAAO,UAAU;AAAA,IAC7B;AAAA,IACA,WAAW,OAAO,aAAa,IAAI;AAAA,EACrC,CAAC;AACH;AAEO,SAAS,mBACd,WACA,MACA,SACA,WACQ;AACR,SAAO,YAAY,WAAW,SAAS,GAAG;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,OAAO,aAAa,IAAI;AAAA,EACrC,CAAC;AACH;AAEO,SAAS,iBACd,SACA,WACQ;AACR,SAAO,YAAY,WAAW,OAAO,GAAG;AAAA,IACtC;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,IAAM,6BAA6B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,sBACd,gBACA,kBACQ;AACR,SAAO,YAAY,WAAW,oBAAoB,GAAG;AAAA,IACnD;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEO,SAAS,0BACd,WACA,YACA,WACQ;AACR,QAAM,WAAW,WACd,IAAI,CAAC,MAAM;AACV,UAAM,YAAY,EAAE,QAAQ,MAAM,GAAG,yBAAyB;AAC9D,WAAO,OAAO,EAAE,IAAI;AAAA;AAAA,EAAa,SAAS;AAAA;AAAA,EAC5C,CAAC,EACA,KAAK,MAAM;AAEd,SAAO,YAAY,WAAW,gBAAgB,GAAG;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,eAAe,2BAA2B,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI;AAAA,IACxE,YAAY,eAAe,KAAK,GAAG;AAAA,IACnC,WAAW,OAAO,aAAa,IAAI;AAAA,EACrC,CAAC;AACH;;;ACxHA,IAAM,qBAAqB;AAAA;AAAA,EAEzB;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA,EAIA;AACF;AAMO,SAAS,qBAAqB,MAAsB;AACzD,MAAI,CAAC,KAAM,QAAO;AAElB,aAAW,WAAW,oBAAoB;AACxC,UAAM,WAAW,KAAK,QAAQ,SAAS,EAAE,EAAE,KAAK;AAChD,QAAI,YAAY,aAAa,KAAK,KAAK,GAAG;AACxC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,YAAY,MAAuB;AACjD,QAAM,UAAU,qBAAqB,IAAI;AAGzC,QAAM,aAAa,QAAQ,MAAM,oCAAoC;AACrE,MAAI,YAAY;AACd,WAAO,KAAK,MAAM,WAAW,CAAC,EAAE,KAAK,CAAC;AAAA,EACxC;AAGA,QAAM,cAAc,QAAQ,MAAM,aAAa;AAC/C,MAAI,aAAa;AACf,WAAO,KAAK,MAAM,YAAY,CAAC,CAAC;AAAA,EAClC;AAGA,SAAO,KAAK,MAAM,OAAO;AAC3B;AAMO,SAAS,cAAc,MAAsB;AAClD,QAAM,UAAU,qBAAqB,IAAI,EAAE,KAAK;AAChD,QAAM,QAAQ,QAAQ,MAAM,aAAa;AACzC,MAAI,MAAO,QAAO,WAAW,MAAM,CAAC,CAAC;AACrC,SAAO,WAAW,OAAO;AAC3B;;;AC7CA,IAAM,+BAA+B,iBAAE,OAAO;AAAA,EAC5C,WAAW,iBAAE,MAAM,iBAAE,OAAO;AAAA,IAC1B,aAAa,iBAAE,OAAO;AAAA,IACtB,eAAe,iBAAE,KAAK,cAAc;AAAA,IACpC,OAAO,iBAAE,OAAO;AAAA,IAChB,MAAM,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACtC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAChB,CAAC;AAEM,IAAM,kBAAN,MAAsB;AAAA,EAM3B,YAAoB,SAA8B,gBAAwB,MAAM,eAAuC;AAAnG;AAA8B;AAChD,SAAK,sBAAsB,eAAe,yBAAyB;AACnE,SAAK,mBAAmB,eAAe,sBAAsB;AAC7D,SAAK,iBAAiB,eAAe,oBAAoB;AACzD,SAAK,0BAA0B,eAAe,6BAA6B;AAAA,EAC7E;AAAA,EAVQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EASA,mBAAmB,MAAc,WAA2B;AAClE,UAAM,YAAY,KAAK,gBAAgB;AACvC,UAAM,aAAa,eAAe,IAAI;AACtC,QAAI,cAAc,UAAW,QAAO;AACpC,UAAM,aAAa,YAAY;AAC/B,WAAO,KAAK,MAAM,GAAG,UAAU;AAAA,EACjC;AAAA,EAEA,MAAM,QACJ,QACA,WAC0B;AAC1B,UAAM,YAAY,KAAK,yBAAyB,QAAQ,SAAS;AACjE,UAAM,SAAS,KAAK,mBAAmB,WAAW,KAAK,mBAAmB;AAE1E,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,UAAU,QAAQ,EAAE,WAAW,KAAK,oBAAoB,CAAC;AAC7F,YAAM,SAAS,YAAY,SAAS,IAAI;AAKxC,aAAO;AAAA,QACL,SAAS,OAAO;AAAA,QAChB,cAAc,OAAO,gBAAgB,CAAC;AAAA,QACtC,UAAU;AAAA,MACZ;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS,qCAAqC,SAAS,KAAK,OAAO,MAAM,4BAA6B,MAAgB,OAAO;AAAA,QAC7H,cAAc,CAAC;AAAA,QACf,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,yBACN,QACA,WACQ;AACR,UAAM,cAAc,KAAK,gBAAgB,MAAM;AAC/C,WAAO,sBAAsB,WAAW,OAAO,QAAQ,aAAa,KAAK,mBAAmB;AAAA,EAC9F;AAAA,EAEA,MAAM,iBACJ,sBACA,WACA,MAC6C;AAC7C,UAAM,mBAAmB,KAAK,mBAAmB,sBAAsB,KAAK,gBAAgB;AAC5F,UAAM,gBAAgB,mBAAmB,WAAW,QAAQ,WAAW,kBAAkB,KAAK,gBAAgB;AAE9G,QAAI;AACJ,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,UAAU,eAAe,EAAE,WAAW,KAAK,iBAAiB,CAAC;AACjG,oBAAc,qBAAqB,SAAS,IAAI;AAAA,IAClD,SAAS,OAAO;AACd,oBAAc,WAAW,SAAS,iCAA6B,MAAgB,OAAO;AAAA,IACxF;AAEA,UAAM,cAAc,iBAAiB,aAAa,SAAS;AAC3D,QAAI;AACJ,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,UAAU,aAAa,EAAE,WAAW,KAAK,eAAe,CAAC;AAC7F,cAAQ,qBAAqB,SAAS,IAAI,EAAE,KAAK;AAAA,IACnD,QAAQ;AACN,cAAQ,WAAW,SAAS;AAAA,IAC9B;AAEA,WAAO,EAAE,SAAS,aAAa,MAAM;AAAA,EACvC;AAAA,EAEA,MAAM,kBACJ,YACA,WAC+B;AAC/B,QAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AAErC,UAAM,SAAS,KAAK,6BAA6B,YAAY,SAAS;AACtE,UAAM,WAAW,MAAM,KAAK,QAAQ,UAAU,QAAQ,EAAE,WAAW,KAAK,wBAAwB,CAAC;AACjG,UAAM,MAAM,YAAY,SAAS,IAAI;AACrC,UAAM,SAAS,6BAA6B,MAAM,GAAG;AACrD,WAAO,OAAO;AAAA,EAChB;AAAA,EAEQ,6BACN,YACA,WACQ;AACR,WAAO,0BAA0B,WAAW,YAAY,KAAK,uBAAuB;AAAA,EACtF;AAAA,EAEQ,gBAAgB,QAAgD;AACtE,UAAM,aAAa,oBAAI,IAAoB;AAC3C,UAAM,gBAAgB,oBAAI,IAAY;AACtC,UAAM,UAAoB,CAAC;AAC3B,UAAM,cAAwB,CAAC;AAE/B,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,SAAS,eAAe;AAChC,cAAM,SAAS,OAAO,MAAM,UAAU,EAAE;AACxC,YAAI,OAAQ,SAAQ,KAAK,OAAO,MAAM,GAAG,oBAAoB,CAAC;AAC9D;AAAA,MACF;AAEA,UAAI,MAAM,SAAS,eAAe;AAChC,cAAM,UAAU,OAAO,MAAM,WAAW,EAAE;AAC1C,YAAI,QAAS,aAAY,KAAK,QAAQ,MAAM,GAAG,yBAAyB,CAAC;AACzE;AAAA,MACF;AAGA,YAAM,OAAO,OAAO,MAAM,aAAa,MAAM,QAAQ,SAAS;AAC9D,iBAAW,IAAI,OAAO,WAAW,IAAI,IAAI,KAAK,KAAK,CAAC;AAEpD,YAAM,QAAS,MAAM,cAAc,MAAM;AACzC,UAAI,OAAO,KAAM,eAAc,IAAI,OAAO,MAAM,IAAI,CAAC;AACrD,UAAI,OAAO,UAAW,eAAc,IAAI,OAAO,MAAM,SAAS,CAAC;AAC/D,UAAI,OAAO,QAAS,eAAc,IAAI,SAAS,OAAO,MAAM,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAAC,EAAE;AAAA,IACxG;AAEA,UAAM,QAAkB,CAAC;AAEzB,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,KAAK,kBAAkB;AAC7B,iBAAW,KAAK,SAAS;AACvB,cAAM,KAAK,MAAM,CAAC,GAAG;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,KAAK,kBAAkB;AAC7B,eAAW,CAAC,MAAM,KAAK,KAAK,YAAY;AACtC,YAAM,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ;AAAA,IACxC;AAEA,QAAI,cAAc,OAAO,GAAG;AAC1B,YAAM,KAAK,sBAAsB;AACjC,iBAAW,QAAQ,eAAe;AAChC,cAAM,KAAK,KAAK,IAAI,EAAE;AAAA,MACxB;AAAA,IACF;AAEA,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,KAAK,oBAAoB;AAC/B,iBAAW,KAAK,aAAa;AAC3B,cAAM,KAAK,MAAM,CAAC,GAAG;AAAA,MACvB;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACF;;;AClMO,IAAM,kBAAN,MAAsB;AAAA,EACnB;AAAA,EAER,YAAY,QAA2B;AACrC,SAAK,WAAW,IAAI,cAAc,QAAQ,kBAAkB;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,WAAqC;AAC/C,WAAO,KAAK,sBAAsB,SAAS,EAAE;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAAsB,WAAmB,gBAAsE;AAE7G,QAAI,gBAAgB;AAClB,YAAMA,UAAS,KAAK,SAAS,mBAAmB,cAAc;AAC9D,UAAIA,QAAQ,QAAOA;AAAA,IACrB;AAGA,UAAM,SAAS,KAAK,SAAS,mBAAmB,SAAS;AACzD,QAAI,OAAQ,QAAO;AACnB,WAAO,EAAE,OAAO,CAAC,GAAG,QAAQ,OAAO;AAAA,EACrC;AACF;AAOO,SAAS,uBAAuB,QAA0D;AAC/F,QAAM,QAA0B,CAAC;AACjC,MAAI,UAAiC;AAErC,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,MAAM;AACnB,QAAI,SAAS,eAAe;AAC1B,UAAI,QAAS,OAAM,KAAK,OAAO;AAC/B,gBAAU;AAAA,QACR,QAAQ,OAAO,MAAM,UAAU,EAAE,EAAE,MAAM,GAAG,oBAAoB;AAAA,QAChE,WAAW;AAAA,QACX,WAAW,OAAO,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,MAC/D;AAAA,IACF,WAAW,SAAS,YAAY;AAC9B,UAAI,QAAS,SAAQ;AAAA,IACvB;AAAA,EACF;AACA,MAAI,QAAS,OAAM,KAAK,OAAO;AAC/B,SAAO;AACT;;;AC1DO,SAAS,sBACd,cACA,WACA,QACA,OACA,UACe;AACf,QAAM,UAAyB,CAAC;AAEhC,aAAW,OAAO,cAAc;AAC9B,UAAM,QAAQ,GAAG,IAAI,IAAI,IAAI,UAAU,MAAM,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC;AAC9D,UAAM,OAAO,gBAAgB;AAAA,MAC3B,OAAO,IAAI;AAAA,MACX,iBAAiB,IAAI;AAAA,MACrB,SAAS,IAAI;AAAA,MACb;AAAA,MACA,YAAY,IAAI;AAAA,MAChB,KAAK,IAAI;AAAA,MACT,WAAW,IAAI;AAAA,MACf,uBAAuB,IAAI;AAAA,MAC3B,QAAQ,IAAI;AAAA,MACZ,YAAY,IAAI;AAAA,MAChB,MAAM,IAAI;AAAA,IACZ,CAAC;AACD,UAAM,eAAe,OAAO,WAAW;AAAA,MACrC,IAAI;AAAA,MACJ,kBAAkB,IAAI;AAAA,MACtB,SAAS,cAAc,SAAS;AAAA,MAChC,MAAM,IAAI;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AACD,cAAU,OAAO,UAAU,YAAY;AACvC,YAAQ,KAAK,EAAE,IAAI,OAAO,MAAM,cAAc,aAAa,IAAI,CAAC;AAAA,EAClE;AAEA,SAAO;AACT;","names":["result"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
stripFrontmatter
|
|
4
|
+
} from "./chunk-MIU3DKLN.js";
|
|
5
|
+
import {
|
|
6
|
+
DIGEST_TIERS
|
|
7
|
+
} from "./chunk-JBD5KP5G.js";
|
|
8
|
+
|
|
9
|
+
// src/mcp/tools/context.ts
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
var DEFAULT_CONTEXT_TIER = 3e3;
|
|
13
|
+
function tryReadExtract(filePath, tier, fallback) {
|
|
14
|
+
let raw;
|
|
15
|
+
try {
|
|
16
|
+
raw = fs.readFileSync(filePath, "utf-8");
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const { body, frontmatter } = stripFrontmatter(raw);
|
|
21
|
+
const generated = frontmatter.generated;
|
|
22
|
+
return {
|
|
23
|
+
content: body,
|
|
24
|
+
tier,
|
|
25
|
+
fallback,
|
|
26
|
+
generated
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function handleMycoContext(vaultDir, input) {
|
|
30
|
+
const requestedTier = input.tier ?? DEFAULT_CONTEXT_TIER;
|
|
31
|
+
const digestDir = path.join(vaultDir, "digest");
|
|
32
|
+
const exact = tryReadExtract(path.join(digestDir, `extract-${requestedTier}.md`), requestedTier, false);
|
|
33
|
+
if (exact) return exact;
|
|
34
|
+
const candidates = [...DIGEST_TIERS].sort((a, b) => Math.abs(a - requestedTier) - Math.abs(b - requestedTier));
|
|
35
|
+
for (const tier of candidates) {
|
|
36
|
+
const result = tryReadExtract(path.join(digestDir, `extract-${tier}.md`), tier, true);
|
|
37
|
+
if (result) return result;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
content: "Digest context is not yet available. The first digest cycle has not completed.",
|
|
41
|
+
tier: requestedTier,
|
|
42
|
+
fallback: false
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
handleMycoContext
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=chunk-WBT5DWGC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/tools/context.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { stripFrontmatter } from '../../vault/frontmatter.js';\nimport { DIGEST_TIERS } from '../../constants.js';\n\n/** Default tier when none is requested. */\nconst DEFAULT_CONTEXT_TIER = 3000;\n\ninterface ContextInput {\n tier?: number;\n}\n\nexport interface ContextResult {\n content: string;\n tier: number;\n fallback: boolean;\n generated?: string;\n}\n\n/**\n * Try to read a digest extract file. Returns null if the file doesn't exist.\n * Strips YAML frontmatter and extracts the generated timestamp.\n */\nfunction tryReadExtract(filePath: string, tier: number, fallback: boolean): ContextResult | null {\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n\n const { body, frontmatter } = stripFrontmatter(raw);\n const generated = frontmatter.generated as string | undefined;\n\n return {\n content: body,\n tier,\n fallback,\n generated,\n };\n}\n\nexport function handleMycoContext(vaultDir: string, input: ContextInput): ContextResult {\n const requestedTier = input.tier ?? DEFAULT_CONTEXT_TIER;\n const digestDir = path.join(vaultDir, 'digest');\n\n // Try exact tier first\n const exact = tryReadExtract(path.join(digestDir, `extract-${requestedTier}.md`), requestedTier, false);\n if (exact) return exact;\n\n // Fall back to nearest available tier\n const candidates = [...DIGEST_TIERS]\n .sort((a, b) => Math.abs(a - requestedTier) - Math.abs(b - requestedTier));\n\n for (const tier of candidates) {\n const result = tryReadExtract(path.join(digestDir, `extract-${tier}.md`), tier, true);\n if (result) return result;\n }\n\n return {\n content: 'Digest context is not yet available. The first digest cycle has not completed.',\n tier: requestedTier,\n fallback: false,\n };\n}\n"],"mappings":";;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAKjB,IAAM,uBAAuB;AAiB7B,SAAS,eAAe,UAAkB,MAAc,UAAyC;AAC/F,MAAI;AACJ,MAAI;AACF,UAAM,GAAG,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,MAAM,YAAY,IAAI,iBAAiB,GAAG;AAClD,QAAM,YAAY,YAAY;AAE9B,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,kBAAkB,UAAkB,OAAoC;AACtF,QAAM,gBAAgB,MAAM,QAAQ;AACpC,QAAM,YAAY,KAAK,KAAK,UAAU,QAAQ;AAG9C,QAAM,QAAQ,eAAe,KAAK,KAAK,WAAW,WAAW,aAAa,KAAK,GAAG,eAAe,KAAK;AACtG,MAAI,MAAO,QAAO;AAGlB,QAAM,aAAa,CAAC,GAAG,YAAY,EAChC,KAAK,CAAC,GAAG,MAAM,KAAK,IAAI,IAAI,aAAa,IAAI,KAAK,IAAI,IAAI,aAAa,CAAC;AAE3E,aAAW,QAAQ,YAAY;AAC7B,UAAM,SAAS,eAAe,KAAK,KAAK,WAAW,WAAW,IAAI,KAAK,GAAG,MAAM,IAAI;AACpF,QAAI,OAAQ,QAAO;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AACF;","names":[]}
|