@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.
Files changed (121) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +9 -4
  4. package/commands/init.md +63 -39
  5. package/commands/setup-llm.md +69 -44
  6. package/commands/status.md +28 -10
  7. package/dist/{chunk-YFG2O5HR.js → chunk-2GJFTIWX.js} +2 -2
  8. package/dist/{chunk-ISCT2SI6.js → chunk-6UJWI4IW.js} +7359 -60
  9. package/dist/chunk-6UJWI4IW.js.map +1 -0
  10. package/dist/{chunk-PA3VMINE.js → chunk-AK6GNLPV.js} +6 -1
  11. package/dist/chunk-AK6GNLPV.js.map +1 -0
  12. package/dist/{chunk-JKOALBZC.js → chunk-BNIYWCST.js} +2 -2
  13. package/dist/{chunk-AWF3M57N.js → chunk-FPEDTLQ6.js} +9 -9
  14. package/dist/{chunk-AWF3M57N.js.map → chunk-FPEDTLQ6.js.map} +1 -1
  15. package/dist/{chunk-QWU7QLZI.js → chunk-I7PNZEBO.js} +10 -10
  16. package/dist/chunk-I7PNZEBO.js.map +1 -0
  17. package/dist/{chunk-7WNE22W7.js → chunk-IVS5MYBL.js} +3 -3
  18. package/dist/{chunk-7WNE22W7.js.map → chunk-IVS5MYBL.js.map} +1 -1
  19. package/dist/{chunk-7VPJK56U.js → chunk-JBD5KP5G.js} +31 -16
  20. package/dist/chunk-JBD5KP5G.js.map +1 -0
  21. package/dist/chunk-MIU3DKLN.js +37 -0
  22. package/dist/chunk-MIU3DKLN.js.map +1 -0
  23. package/dist/{chunk-NYAWCMRZ.js → chunk-OUFSLZTX.js} +4 -4
  24. package/dist/chunk-P7RNAYU7.js +242 -0
  25. package/dist/chunk-P7RNAYU7.js.map +1 -0
  26. package/dist/chunk-T7OC6GH5.js +99 -0
  27. package/dist/chunk-T7OC6GH5.js.map +1 -0
  28. package/dist/chunk-TBRZAJ7W.js +135 -0
  29. package/dist/chunk-TBRZAJ7W.js.map +1 -0
  30. package/dist/chunk-UKWO26VI.js +147 -0
  31. package/dist/chunk-UKWO26VI.js.map +1 -0
  32. package/dist/{chunk-FFQNE6CT.js → chunk-V2OWD2VV.js} +45 -31
  33. package/dist/chunk-V2OWD2VV.js.map +1 -0
  34. package/dist/chunk-WBT5DWGC.js +49 -0
  35. package/dist/chunk-WBT5DWGC.js.map +1 -0
  36. package/dist/{chunk-LR7RQCOB.js → chunk-XCPQHC4X.js} +2 -2
  37. package/dist/{chunk-CCIV47S4.js → chunk-XHWIIU5D.js} +8 -9
  38. package/dist/chunk-XHWIIU5D.js.map +1 -0
  39. package/dist/{chunk-ZBNT6E22.js → chunk-ZCBL5HER.js} +2 -2
  40. package/dist/{cli-3WQSDSW6.js → cli-IGZA3TZC.js} +23 -17
  41. package/dist/cli-IGZA3TZC.js.map +1 -0
  42. package/dist/{client-5T4M42UQ.js → client-5SUO2UYH.js} +5 -5
  43. package/dist/{config-MD4XMLUS.js → config-5FGLQGCW.js} +4 -4
  44. package/dist/{detect-providers-LNOLBICR.js → detect-providers-5FU3BN5Q.js} +3 -3
  45. package/dist/{init-RALMQKOQ.js → init-M3GDZRKI.js} +51 -60
  46. package/dist/init-M3GDZRKI.js.map +1 -0
  47. package/dist/{main-S3WSUF5T.js → main-3JSO25IZ.js} +657 -228
  48. package/dist/main-3JSO25IZ.js.map +1 -0
  49. package/dist/{rebuild-JW6BCHHZ.js → rebuild-MW4GCY6Z.js} +10 -10
  50. package/dist/rebuild-MW4GCY6Z.js.map +1 -0
  51. package/dist/{reprocess-SNXFNKBN.js → reprocess-SWRFIIDZ.js} +18 -18
  52. package/dist/reprocess-SWRFIIDZ.js.map +1 -0
  53. package/dist/{restart-YE2IGOYT.js → restart-5UY2KV54.js} +6 -6
  54. package/dist/{search-2HMG3ON7.js → search-IYVMRZU2.js} +9 -9
  55. package/dist/{server-JM3TM7D2.js → server-FSUSHJ3Y.js} +77 -54
  56. package/dist/{server-JM3TM7D2.js.map → server-FSUSHJ3Y.js.map} +1 -1
  57. package/dist/{session-5GI2YU6R.js → session-QF6MILAC.js} +2 -2
  58. package/dist/{session-start-2UEEEO52.js → session-start-YB4A4PZB.js} +29 -28
  59. package/dist/session-start-YB4A4PZB.js.map +1 -0
  60. package/dist/setup-digest-6TK5SPS6.js +15 -0
  61. package/dist/setup-llm-UGZBURZJ.js +15 -0
  62. package/dist/setup-llm-UGZBURZJ.js.map +1 -0
  63. package/dist/src/cli.js +4 -4
  64. package/dist/src/daemon/main.js +4 -4
  65. package/dist/src/hooks/post-tool-use.js +5 -5
  66. package/dist/src/hooks/session-end.js +5 -5
  67. package/dist/src/hooks/session-start.js +4 -4
  68. package/dist/src/hooks/stop.js +7 -7
  69. package/dist/src/hooks/user-prompt-submit.js +5 -5
  70. package/dist/src/hooks/user-prompt-submit.js.map +1 -1
  71. package/dist/src/mcp/server.js +4 -4
  72. package/dist/src/prompts/classification.md +1 -0
  73. package/dist/src/prompts/digest-10000.md +74 -0
  74. package/dist/src/prompts/digest-1500.md +25 -0
  75. package/dist/src/prompts/digest-3000.md +32 -0
  76. package/dist/src/prompts/digest-5000.md +43 -0
  77. package/dist/src/prompts/digest-system.md +32 -0
  78. package/dist/src/prompts/extraction.md +11 -10
  79. package/dist/src/prompts/summary.md +11 -1
  80. package/dist/src/prompts/title.md +1 -1
  81. package/dist/{stats-IOWXG576.js → stats-IVIXIKTS.js} +12 -12
  82. package/dist/stats-IVIXIKTS.js.map +1 -0
  83. package/dist/{verify-7MWOV72E.js → verify-WEGRM4W2.js} +6 -6
  84. package/dist/{version-S7MHLD5P.js → version-5B2TWXQJ.js} +4 -4
  85. package/dist/version-5B2TWXQJ.js.map +1 -0
  86. package/package.json +1 -1
  87. package/skills/myco/SKILL.md +20 -20
  88. package/skills/myco/references/wisdom.md +14 -14
  89. package/skills/rules/SKILL.md +4 -4
  90. package/dist/chunk-7VPJK56U.js.map +0 -1
  91. package/dist/chunk-BA23DROX.js +0 -160
  92. package/dist/chunk-BA23DROX.js.map +0 -1
  93. package/dist/chunk-CCIV47S4.js.map +0 -1
  94. package/dist/chunk-EF4JVH24.js +0 -7299
  95. package/dist/chunk-EF4JVH24.js.map +0 -1
  96. package/dist/chunk-FFQNE6CT.js.map +0 -1
  97. package/dist/chunk-ISCT2SI6.js.map +0 -1
  98. package/dist/chunk-PA3VMINE.js.map +0 -1
  99. package/dist/chunk-QWU7QLZI.js.map +0 -1
  100. package/dist/chunk-YMYJ7FNH.js +0 -19
  101. package/dist/chunk-YMYJ7FNH.js.map +0 -1
  102. package/dist/cli-3WQSDSW6.js.map +0 -1
  103. package/dist/init-RALMQKOQ.js.map +0 -1
  104. package/dist/main-S3WSUF5T.js.map +0 -1
  105. package/dist/rebuild-JW6BCHHZ.js.map +0 -1
  106. package/dist/reprocess-SNXFNKBN.js.map +0 -1
  107. package/dist/session-start-2UEEEO52.js.map +0 -1
  108. package/dist/stats-IOWXG576.js.map +0 -1
  109. /package/dist/{chunk-YFG2O5HR.js.map → chunk-2GJFTIWX.js.map} +0 -0
  110. /package/dist/{chunk-JKOALBZC.js.map → chunk-BNIYWCST.js.map} +0 -0
  111. /package/dist/{chunk-NYAWCMRZ.js.map → chunk-OUFSLZTX.js.map} +0 -0
  112. /package/dist/{chunk-LR7RQCOB.js.map → chunk-XCPQHC4X.js.map} +0 -0
  113. /package/dist/{chunk-ZBNT6E22.js.map → chunk-ZCBL5HER.js.map} +0 -0
  114. /package/dist/{client-5T4M42UQ.js.map → client-5SUO2UYH.js.map} +0 -0
  115. /package/dist/{config-MD4XMLUS.js.map → config-5FGLQGCW.js.map} +0 -0
  116. /package/dist/{detect-providers-LNOLBICR.js.map → detect-providers-5FU3BN5Q.js.map} +0 -0
  117. /package/dist/{restart-YE2IGOYT.js.map → restart-5UY2KV54.js.map} +0 -0
  118. /package/dist/{search-2HMG3ON7.js.map → search-IYVMRZU2.js.map} +0 -0
  119. /package/dist/{session-5GI2YU6R.js.map → session-QF6MILAC.js.map} +0 -0
  120. /package/dist/{version-S7MHLD5P.js.map → setup-digest-6TK5SPS6.js.map} +0 -0
  121. /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
- formatMemoryBody,
3
+ formatSporeBody,
4
4
  sessionNoteId
5
- } from "./chunk-QWU7QLZI.js";
5
+ } from "./chunk-I7PNZEBO.js";
6
6
  import {
7
7
  ARTIFACT_TYPES,
8
8
  indexNote
9
- } from "./chunk-AWF3M57N.js";
9
+ } from "./chunk-FPEDTLQ6.js";
10
10
  import {
11
11
  external_exports
12
- } from "./chunk-ISCT2SI6.js";
12
+ } from "./chunk-6UJWI4IW.js";
13
13
  import {
14
14
  AgentRegistry
15
- } from "./chunk-JKOALBZC.js";
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
- SUMMARY_MAX_TOKENS,
25
- TITLE_MAX_TOKENS
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 = Math.ceil(data.length / CHARS_PER_TOKEN);
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, EXTRACTION_MAX_TOKENS);
186
+ const prompt = this.truncateForContext(rawPrompt, this.extractionMaxTokens);
175
187
  try {
176
- const response = await this.backend.summarize(prompt, { maxTokens: EXTRACTION_MAX_TOKENS });
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, SUMMARY_MAX_TOKENS);
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: SUMMARY_MAX_TOKENS });
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: TITLE_MAX_TOKENS });
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: CLASSIFICATION_MAX_TOKENS });
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 = formatMemoryBody({
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.writeMemory({
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-FFQNE6CT.js.map
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":"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","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":[]}