@goondocks/myco 0.9.0 → 0.11.0
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/CONTRIBUTING.md +3 -19
- package/README.md +35 -11
- package/dist/{agent-run-EFICNTAU.js → agent-run-CGM75RS6.js} +7 -7
- package/dist/{agent-tasks-RXJ7Z5NG.js → agent-tasks-3RQKPRSW.js} +7 -7
- package/dist/{chunk-RJ6ZQKG5.js → chunk-5QERXFH7.js} +2 -2
- package/dist/{chunk-UBZPD4HN.js → chunk-5SDH75YC.js} +2 -2
- package/dist/{chunk-BUSP3OJB.js → chunk-6LL2MQHP.js} +6 -6
- package/dist/{chunk-5VZ52A4T.js → chunk-76ZO5RGT.js} +16 -2
- package/dist/{chunk-5VZ52A4T.js.map → chunk-76ZO5RGT.js.map} +1 -1
- package/dist/{chunk-46PWOKSI.js → chunk-AEJS57ZK.js} +2 -2
- package/dist/{chunk-DCXRSSBP.js → chunk-C3AEZ3BZ.js} +3 -3
- package/dist/{chunk-QIK2XSDQ.js → chunk-CHG652UO.js} +4 -4
- package/dist/{chunk-4LPQ26CK.js → chunk-CUDM5YJY.js} +25 -8
- package/dist/chunk-CUDM5YJY.js.map +1 -0
- package/dist/{chunk-YDN4OM33.js → chunk-D6DXYAFK.js} +20 -7
- package/dist/chunk-D6DXYAFK.js.map +1 -0
- package/dist/chunk-ENWBFX7F.js +50 -0
- package/dist/chunk-ENWBFX7F.js.map +1 -0
- package/dist/{chunk-OXZSXYAT.js → chunk-FFQES5MC.js} +48 -21
- package/dist/chunk-FFQES5MC.js.map +1 -0
- package/dist/{chunk-KYLDNM7H.js → chunk-FPMEIN2W.js} +2 -2
- package/dist/{chunk-U3IBO3O3.js → chunk-IXOHLPH7.js} +9 -8
- package/dist/chunk-IXOHLPH7.js.map +1 -0
- package/dist/{chunk-PB6TOLRQ.js → chunk-JYXMRW3T.js} +2 -2
- package/dist/chunk-K2UZNK25.js +83 -0
- package/dist/chunk-K2UZNK25.js.map +1 -0
- package/dist/chunk-LYFDTF7G.js +792 -0
- package/dist/chunk-LYFDTF7G.js.map +1 -0
- package/dist/{chunk-MHSCMET3.js → chunk-MAZOVVDU.js} +33 -3
- package/dist/chunk-MAZOVVDU.js.map +1 -0
- package/dist/{chunk-JYOOJCPQ.js → chunk-MKKXCCQ5.js} +5 -5
- package/dist/{chunk-5PEUFJ6U.js → chunk-QFMBZ72S.js} +24 -8
- package/dist/chunk-QFMBZ72S.js.map +1 -0
- package/dist/{chunk-FFAYUQ5N.js → chunk-RJMXDUMA.js} +2 -1
- package/dist/{chunk-WGTCA2NU.js → chunk-S6I62FAH.js} +10 -2
- package/dist/{chunk-WGTCA2NU.js.map → chunk-S6I62FAH.js.map} +1 -1
- package/dist/{chunk-3K5WGSJ4.js → chunk-U7UUJ4FD.js} +23 -8
- package/dist/chunk-U7UUJ4FD.js.map +1 -0
- package/dist/{chunk-PT5IC642.js → chunk-W6HI4CCS.js} +2 -2
- package/dist/{chunk-KV4OC4H3.js → chunk-WZZH3YXJ.js} +119 -16
- package/dist/chunk-WZZH3YXJ.js.map +1 -0
- package/dist/chunk-XLY3REL3.js +165 -0
- package/dist/chunk-XLY3REL3.js.map +1 -0
- package/dist/{chunk-TRUJLI6K.js → chunk-YKOEMLJJ.js} +9 -5
- package/dist/chunk-YKOEMLJJ.js.map +1 -0
- package/dist/{chunk-JMJJEQ3P.js → chunk-ZAHDA2PQ.js} +9 -9
- package/dist/{chunk-2T7RPVPP.js → chunk-ZESTWGJT.js} +2 -2
- package/dist/{cli-ODLFRIYS.js → cli-FL754H6S.js} +49 -36
- package/dist/cli-FL754H6S.js.map +1 -0
- package/dist/client-4NP7ZMLV.js +15 -0
- package/dist/{config-UR5BSGVX.js → config-G3CSGI7P.js} +2 -2
- package/dist/{detect-H5OPI7GD.js → detect-27DN6UTL.js} +3 -3
- package/dist/{detect-providers-Q42OD4OS.js → detect-providers-AZ6DEQU7.js} +5 -5
- package/dist/{doctor-JLKTXDEH.js → doctor-OFGWOYBC.js} +24 -30
- package/dist/doctor-OFGWOYBC.js.map +1 -0
- package/dist/{executor-ONSDHPGX.js → executor-SWXSN7ZC.js} +38 -25
- package/dist/executor-SWXSN7ZC.js.map +1 -0
- package/dist/{init-6GWY345B.js → init-JZJJKC4G.js} +46 -65
- package/dist/init-JZJJKC4G.js.map +1 -0
- package/dist/{init-wizard-UONLDYLI.js → init-wizard-4VHNOYFO.js} +8 -8
- package/dist/llm-XJFHRFHB.js +17 -0
- package/dist/{loader-SH67XD54.js → loader-DGWP4EFB.js} +6 -6
- package/dist/{loader-XVXKZZDH.js → loader-PZ7ZRSA4.js} +8 -4
- package/dist/{logs-QZVYF6FP.js → logs-LXHPDKUA.js} +3 -3
- package/dist/machine-id-RCM7TXPJ.js +13 -0
- package/dist/{main-BMCL7CPO.js → main-UBUZTMGV.js} +1367 -107
- package/dist/main-UBUZTMGV.js.map +1 -0
- package/dist/{openai-embeddings-C265WRNK.js → openai-embeddings-ST3B6GW7.js} +5 -5
- package/dist/{openrouter-U6VFCRX2.js → openrouter-HJHOO3EO.js} +5 -5
- package/dist/post-compact-O7HMEFKP.js +30 -0
- package/dist/post-compact-O7HMEFKP.js.map +1 -0
- package/dist/{post-tool-use-DOUM7CGQ.js → post-tool-use-OVNMZ3UG.js} +22 -15
- package/dist/post-tool-use-OVNMZ3UG.js.map +1 -0
- package/dist/post-tool-use-failure-HPXTFYBY.js +32 -0
- package/dist/post-tool-use-failure-HPXTFYBY.js.map +1 -0
- package/dist/{pre-compact-3J33CHXQ.js → pre-compact-JD3D4PBB.js} +12 -8
- package/dist/pre-compact-JD3D4PBB.js.map +1 -0
- package/dist/{provider-check-3WBPZADE.js → provider-check-SOTDYLJE.js} +5 -5
- package/dist/{registry-J4XTWARS.js → registry-33MEKDHT.js} +7 -7
- package/dist/remove-XDFMOYUL.js +92 -0
- package/dist/remove-XDFMOYUL.js.map +1 -0
- package/dist/{resolution-events-TFEQPVKS.js → resolution-events-UPHJJLDQ.js} +5 -2
- package/dist/{restart-2VM33WOB.js → restart-JBAMRKRJ.js} +8 -8
- package/dist/{search-ZGQR5MDE.js → search-43TS5RGA.js} +8 -8
- package/dist/{server-6KMBJCHZ.js → server-UBU7NALJ.js} +14 -14
- package/dist/{session-Z2FXDDG6.js → session-CPBLMD7M.js} +9 -8
- package/dist/{session-Z2FXDDG6.js.map → session-CPBLMD7M.js.map} +1 -1
- package/dist/{session-end-FLVX32LE.js → session-end-DUHUYE6J.js} +13 -8
- package/dist/session-end-DUHUYE6J.js.map +1 -0
- package/dist/{session-start-UCLK7PXE.js → session-start-I7XM3CME.js} +19 -15
- package/dist/{session-start-UCLK7PXE.js.map → session-start-I7XM3CME.js.map} +1 -1
- package/dist/{setup-llm-GKMCHURK.js → setup-llm-TTHEUWDA.js} +10 -10
- package/dist/src/cli.js +1 -1
- package/dist/src/daemon/main.js +1 -1
- package/dist/src/hooks/post-tool-use.js +1 -1
- package/dist/src/hooks/session-end.js +1 -1
- package/dist/src/hooks/session-start.js +1 -1
- package/dist/src/hooks/stop.js +1 -1
- package/dist/src/hooks/user-prompt-submit.js +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/symbionts/manifests/claude-code.yaml +8 -4
- package/dist/src/symbionts/manifests/codex.yaml +19 -0
- package/dist/src/symbionts/manifests/cursor.yaml +6 -3
- package/dist/src/symbionts/manifests/gemini.yaml +20 -0
- package/dist/src/symbionts/manifests/vscode-copilot.yaml +17 -0
- package/dist/src/symbionts/manifests/windsurf.yaml +16 -0
- package/dist/src/symbionts/templates/claude-code/hooks.json +134 -0
- package/dist/src/symbionts/templates/claude-code/mcp.json +7 -0
- package/dist/src/symbionts/templates/claude-code/settings.json +10 -0
- package/dist/src/symbionts/templates/codex/hooks.json +46 -0
- package/dist/src/symbionts/templates/codex/mcp.json +6 -0
- package/dist/src/symbionts/templates/cursor/mcp.json +7 -0
- package/dist/src/symbionts/templates/cursor/settings.json +6 -0
- package/dist/src/symbionts/templates/gemini/hooks.json +74 -0
- package/dist/src/symbionts/templates/gemini/mcp.json +6 -0
- package/dist/src/symbionts/templates/gemini/settings.json +6 -0
- package/dist/src/symbionts/templates/instructions-stub.md +9 -0
- package/dist/src/symbionts/templates/vscode-copilot/hooks.json +79 -0
- package/dist/src/symbionts/templates/vscode-copilot/mcp.json +7 -0
- package/dist/src/symbionts/templates/vscode-copilot/settings.json +6 -0
- package/dist/src/symbionts/templates/windsurf/hooks.json +22 -0
- package/dist/src/symbionts/templates/windsurf/settings.json +6 -0
- package/dist/{stats-IUJPZSVZ.js → stats-7CE6GEWE.js} +11 -11
- package/dist/{stop-XRQLLXST.js → stop-BF3AWA7S.js} +18 -12
- package/dist/stop-BF3AWA7S.js.map +1 -0
- package/dist/stop-failure-7Q2LQF2R.js +30 -0
- package/dist/stop-failure-7Q2LQF2R.js.map +1 -0
- package/dist/subagent-start-QG2J3AN4.js +30 -0
- package/dist/{subagent-start-MWWQTZMQ.js.map → subagent-start-QG2J3AN4.js.map} +1 -1
- package/dist/subagent-stop-WVA7RDIM.js +32 -0
- package/dist/subagent-stop-WVA7RDIM.js.map +1 -0
- package/dist/task-completed-AQVQ7GFL.js +31 -0
- package/dist/task-completed-AQVQ7GFL.js.map +1 -0
- package/dist/team-LC3K7UXD.js +251 -0
- package/dist/team-LC3K7UXD.js.map +1 -0
- package/dist/ui/assets/index-BGbil7f1.css +1 -0
- package/dist/ui/assets/index-UFE9l-Hb.js +794 -0
- package/dist/ui/index.html +2 -2
- package/dist/update-3EKXZF3H.js +70 -0
- package/dist/update-3EKXZF3H.js.map +1 -0
- package/dist/{user-prompt-submit-KSM3AR6P.js → user-prompt-submit-22YQD4XM.js} +16 -9
- package/dist/user-prompt-submit-22YQD4XM.js.map +1 -0
- package/dist/{verify-UDAYVX37.js → verify-DVIWHZXA.js} +9 -9
- package/dist/{version-KLBN4HZT.js → version-VPI6ERF7.js} +2 -2
- package/dist/version-VPI6ERF7.js.map +1 -0
- package/package.json +3 -3
- package/skills/rules/SKILL.md +32 -9
- package/.claude-plugin/marketplace.json +0 -29
- package/.claude-plugin/plugin.json +0 -27
- package/dist/chunk-3K5WGSJ4.js.map +0 -1
- package/dist/chunk-4LPQ26CK.js.map +0 -1
- package/dist/chunk-5PEUFJ6U.js.map +0 -1
- package/dist/chunk-KB4DGYIY.js +0 -436
- package/dist/chunk-KB4DGYIY.js.map +0 -1
- package/dist/chunk-KV4OC4H3.js.map +0 -1
- package/dist/chunk-MHSCMET3.js.map +0 -1
- package/dist/chunk-OXZSXYAT.js.map +0 -1
- package/dist/chunk-TRUJLI6K.js.map +0 -1
- package/dist/chunk-U3IBO3O3.js.map +0 -1
- package/dist/chunk-XNOCTDHF.js +0 -21
- package/dist/chunk-XNOCTDHF.js.map +0 -1
- package/dist/chunk-YDN4OM33.js.map +0 -1
- package/dist/cli-ODLFRIYS.js.map +0 -1
- package/dist/client-MXRNQ5FI.js +0 -13
- package/dist/doctor-JLKTXDEH.js.map +0 -1
- package/dist/executor-ONSDHPGX.js.map +0 -1
- package/dist/init-6GWY345B.js.map +0 -1
- package/dist/llm-BV3QNVRD.js +0 -17
- package/dist/main-BMCL7CPO.js.map +0 -1
- package/dist/post-compact-OWFSOITU.js +0 -26
- package/dist/post-compact-OWFSOITU.js.map +0 -1
- package/dist/post-tool-use-DOUM7CGQ.js.map +0 -1
- package/dist/post-tool-use-failure-SG3C7PE6.js +0 -28
- package/dist/post-tool-use-failure-SG3C7PE6.js.map +0 -1
- package/dist/pre-compact-3J33CHXQ.js.map +0 -1
- package/dist/session-end-FLVX32LE.js.map +0 -1
- package/dist/stop-XRQLLXST.js.map +0 -1
- package/dist/stop-failure-2CAJJKRG.js +0 -26
- package/dist/stop-failure-2CAJJKRG.js.map +0 -1
- package/dist/subagent-start-MWWQTZMQ.js +0 -26
- package/dist/subagent-stop-PJXYGRXB.js +0 -28
- package/dist/subagent-stop-PJXYGRXB.js.map +0 -1
- package/dist/task-completed-4LFRJVGI.js +0 -27
- package/dist/task-completed-4LFRJVGI.js.map +0 -1
- package/dist/ui/assets/index-DZrElonz.js +0 -744
- package/dist/ui/assets/index-TkeiYbZB.css +0 -1
- package/dist/user-prompt-submit-KSM3AR6P.js.map +0 -1
- /package/dist/{agent-run-EFICNTAU.js.map → agent-run-CGM75RS6.js.map} +0 -0
- /package/dist/{agent-tasks-RXJ7Z5NG.js.map → agent-tasks-3RQKPRSW.js.map} +0 -0
- /package/dist/{chunk-RJ6ZQKG5.js.map → chunk-5QERXFH7.js.map} +0 -0
- /package/dist/{chunk-UBZPD4HN.js.map → chunk-5SDH75YC.js.map} +0 -0
- /package/dist/{chunk-BUSP3OJB.js.map → chunk-6LL2MQHP.js.map} +0 -0
- /package/dist/{chunk-46PWOKSI.js.map → chunk-AEJS57ZK.js.map} +0 -0
- /package/dist/{chunk-DCXRSSBP.js.map → chunk-C3AEZ3BZ.js.map} +0 -0
- /package/dist/{chunk-QIK2XSDQ.js.map → chunk-CHG652UO.js.map} +0 -0
- /package/dist/{chunk-KYLDNM7H.js.map → chunk-FPMEIN2W.js.map} +0 -0
- /package/dist/{chunk-PB6TOLRQ.js.map → chunk-JYXMRW3T.js.map} +0 -0
- /package/dist/{chunk-JYOOJCPQ.js.map → chunk-MKKXCCQ5.js.map} +0 -0
- /package/dist/{chunk-FFAYUQ5N.js.map → chunk-RJMXDUMA.js.map} +0 -0
- /package/dist/{chunk-PT5IC642.js.map → chunk-W6HI4CCS.js.map} +0 -0
- /package/dist/{chunk-JMJJEQ3P.js.map → chunk-ZAHDA2PQ.js.map} +0 -0
- /package/dist/{chunk-2T7RPVPP.js.map → chunk-ZESTWGJT.js.map} +0 -0
- /package/dist/{client-MXRNQ5FI.js.map → client-4NP7ZMLV.js.map} +0 -0
- /package/dist/{config-UR5BSGVX.js.map → config-G3CSGI7P.js.map} +0 -0
- /package/dist/{detect-H5OPI7GD.js.map → detect-27DN6UTL.js.map} +0 -0
- /package/dist/{detect-providers-Q42OD4OS.js.map → detect-providers-AZ6DEQU7.js.map} +0 -0
- /package/dist/{init-wizard-UONLDYLI.js.map → init-wizard-4VHNOYFO.js.map} +0 -0
- /package/dist/{llm-BV3QNVRD.js.map → llm-XJFHRFHB.js.map} +0 -0
- /package/dist/{loader-SH67XD54.js.map → loader-DGWP4EFB.js.map} +0 -0
- /package/dist/{loader-XVXKZZDH.js.map → loader-PZ7ZRSA4.js.map} +0 -0
- /package/dist/{logs-QZVYF6FP.js.map → logs-LXHPDKUA.js.map} +0 -0
- /package/dist/{openai-embeddings-C265WRNK.js.map → machine-id-RCM7TXPJ.js.map} +0 -0
- /package/dist/{openrouter-U6VFCRX2.js.map → openai-embeddings-ST3B6GW7.js.map} +0 -0
- /package/dist/{provider-check-3WBPZADE.js.map → openrouter-HJHOO3EO.js.map} +0 -0
- /package/dist/{registry-J4XTWARS.js.map → provider-check-SOTDYLJE.js.map} +0 -0
- /package/dist/{resolution-events-TFEQPVKS.js.map → registry-33MEKDHT.js.map} +0 -0
- /package/dist/{version-KLBN4HZT.js.map → resolution-events-UPHJJLDQ.js.map} +0 -0
- /package/dist/{restart-2VM33WOB.js.map → restart-JBAMRKRJ.js.map} +0 -0
- /package/dist/{search-ZGQR5MDE.js.map → search-43TS5RGA.js.map} +0 -0
- /package/dist/{server-6KMBJCHZ.js.map → server-UBU7NALJ.js.map} +0 -0
- /package/dist/{setup-llm-GKMCHURK.js.map → setup-llm-TTHEUWDA.js.map} +0 -0
- /package/dist/{stats-IUJPZSVZ.js.map → stats-7CE6GEWE.js.map} +0 -0
- /package/dist/{verify-UDAYVX37.js.map → verify-DVIWHZXA.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/symbionts/installer.ts","../src/cli/shared.ts"],"sourcesContent":["import type { SymbiontManifest } from './manifest-schema.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/** Prefix used to identify Myco-owned hooks in settings files. */\nconst MYCO_HOOK_COMMAND_PREFIX = 'myco-run';\n\n/**\n * Check if a hook group is Myco-owned.\n * Handles both nested format (Claude Code, Codex, etc.) and flat format (Windsurf).\n *\n * Nested: { hooks: [{ command: \"myco-run ...\" }] }\n * Flat: { command: \"myco-run ...\" }\n */\nfunction isMycoHookGroup(group: Record<string, unknown>): boolean {\n // Nested format: { hooks: [{ command: \"myco-run ...\" }] }\n if (Array.isArray(group.hooks) && group.hooks.some((h: { command?: string }) => h.command?.startsWith(MYCO_HOOK_COMMAND_PREFIX))) return true;\n // Flat format: { command: \"myco-run ...\" }\n if (typeof group.command === 'string' && group.command.startsWith(MYCO_HOOK_COMMAND_PREFIX)) return true;\n return false;\n}\n\n/** Comment header for Myco entries in .gitignore. */\nconst GITIGNORE_SKILLS_COMMENT = '# Myco skill symlinks (machine-specific)';\n\n/** Subdirectory within the package where symbiont templates live. */\nconst TEMPLATES_SUBDIR = 'src/symbionts/templates';\n\n/** Subdirectory within the package where skills live. */\nconst SKILLS_SUBDIR = 'skills';\n\n/** Canonical cross-agent skills directory. */\nconst CANONICAL_SKILLS_DIR = '.agents/skills';\n\n/** MCP server name used by Myco in all symbiont configurations. */\nexport const MYCO_MCP_SERVER_NAME = 'myco';\n\n/** Marker text used to identify unmodified instruction stubs. */\nconst INSTRUCTIONS_STUB_MARKER = 'Edit AGENTS.md, not this file';\n\n/** Start/end markers for the reference block prepended to existing instruction files. */\nconst INSTRUCTIONS_REF_START = '<!-- myco:agents-ref:start -->';\nconst INSTRUCTIONS_REF_END = '<!-- myco:agents-ref:end -->';\n\n/** Reference block prepended to existing instruction files. */\nconst INSTRUCTIONS_REF_BLOCK = `${INSTRUCTIONS_REF_START}\n> **Project intelligence:** This project uses [Myco](https://myco.sh). The canonical project rules are in [\\`AGENTS.md\\`](AGENTS.md) — read and follow it alongside this file.\n${INSTRUCTIONS_REF_END}\n\n`;\n\nexport interface InstallResult {\n hooks: boolean;\n mcp: boolean;\n skills: boolean;\n settings: boolean;\n instructions: boolean;\n}\n\nexport class SymbiontInstaller {\n constructor(\n private manifest: SymbiontManifest,\n private projectRoot: string,\n private packageRoot: string,\n ) {}\n\n /** Load a JSON template file for this symbiont. Returns null if not found. */\n loadTemplate(name: string): Record<string, unknown> | null {\n // Check both source layout and dist layout\n const candidates = [\n path.join(this.packageRoot, TEMPLATES_SUBDIR, this.manifest.name, `${name}.json`),\n // tsup preserves the src/ prefix under dist/, so the same subdir works in both layouts\n path.join(this.packageRoot, 'dist', TEMPLATES_SUBDIR, this.manifest.name, `${name}.json`),\n ];\n for (const filePath of candidates) {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch { /* not found or malformed — try next */ }\n }\n return null;\n }\n\n /** Run all registration steps. */\n install(): InstallResult {\n const reg = this.manifest.registration;\n const result = this.shouldBatchJsonTargets(reg)\n ? this.installBatchedJson(reg!)\n : {\n hooks: this.installHooks(),\n mcp: this.installMcp(),\n skills: this.installSkills(),\n settings: this.installSettings(),\n instructions: this.installInstructions(),\n };\n this.updateGitignore();\n return result;\n }\n\n /**\n * Check if ALL non-null JSON targets share the same file (e.g., Gemini).\n * Only batches when every target resolves to one path — partial overlaps\n * (e.g., Claude Code: hooks+settings share but MCP is separate) use normal path.\n */\n private shouldBatchJsonTargets(reg: typeof this.manifest.registration): boolean {\n if (!reg) return false;\n const mcpFormat = reg.mcpFormat ?? 'json';\n if (mcpFormat !== 'json') return false;\n const targets = [reg.hooksTarget, reg.mcpTarget, reg.settingsTarget].filter(Boolean);\n return targets.length > 1 && new Set(targets).size === 1;\n }\n\n /**\n * Batched install for agents where hooks, MCP, and settings share one JSON file.\n * Single read → apply all transforms in memory → single write.\n */\n private installBatchedJson(reg: NonNullable<typeof this.manifest.registration>): InstallResult {\n const targetPath = path.join(this.projectRoot, reg.hooksTarget ?? reg.mcpTarget ?? reg.settingsTarget!);\n let data = readJsonFile(targetPath);\n let hooks = false, mcp = false, settings = false;\n\n // Apply hooks transform\n const hooksTemplate = reg.hooksTarget ? this.loadTemplate('hooks') : null;\n if (hooksTemplate) {\n const existingHooks = (data.hooks ?? {}) as Record<string, unknown[]>;\n const mergedHooks: Record<string, unknown[]> = {};\n for (const [event, groups] of Object.entries(existingHooks)) {\n const nonMyco = (groups as Array<Record<string, unknown>>).filter((g) => !isMycoHookGroup(g));\n if (nonMyco.length > 0) mergedHooks[event] = nonMyco;\n }\n for (const [event, groups] of Object.entries(hooksTemplate)) {\n mergedHooks[event] = [...(mergedHooks[event] ?? []), ...(groups as unknown[])];\n }\n data.hooks = mergedHooks;\n hooks = true;\n }\n\n // Apply MCP transform\n const mcpTemplate = reg.mcpTarget ? this.loadTemplate('mcp') : null;\n if (mcpTemplate) {\n const servers = (data.mcpServers ?? {}) as Record<string, unknown>;\n for (const [name, def] of Object.entries(mcpTemplate)) {\n servers[name] = def;\n }\n data.mcpServers = servers;\n mcp = true;\n }\n\n // Apply settings transform\n const settingsTemplate = reg.settingsTarget ? this.loadTemplate('settings') : null;\n if (settingsTemplate) {\n data = deepMergeSettings(data, settingsTemplate);\n settings = true;\n }\n\n writeJsonFile(targetPath, data);\n\n return {\n hooks,\n mcp,\n skills: this.installSkills(),\n settings,\n instructions: this.installInstructions(),\n };\n }\n\n /** Remove all Myco registration from this symbiont's project files. */\n uninstall(): InstallResult {\n const reg = this.manifest.registration;\n const result = this.shouldBatchJsonTargets(reg)\n ? this.uninstallBatchedJson(reg!)\n : {\n hooks: this.uninstallHooks(),\n mcp: this.uninstallMcp(),\n skills: this.uninstallSkills(),\n settings: this.uninstallSettings(),\n instructions: this.uninstallInstructions(),\n };\n this.cleanGitignore();\n return result;\n }\n\n /**\n * Batched uninstall for agents where hooks, MCP, and settings share one JSON file.\n */\n private uninstallBatchedJson(reg: NonNullable<typeof this.manifest.registration>): InstallResult {\n const targetPath = path.join(this.projectRoot, reg.hooksTarget ?? reg.mcpTarget ?? reg.settingsTarget!);\n const data = readJsonFile(targetPath);\n if (Object.keys(data).length === 0) {\n return { hooks: false, mcp: false, skills: this.uninstallSkills(), settings: false, instructions: this.uninstallInstructions() };\n }\n\n let hooks = false, mcp = false, settings = false;\n\n // Remove hooks\n if (reg.hooksTarget) {\n const existingHooks = (data.hooks ?? {}) as Record<string, unknown[]>;\n if (Object.keys(existingHooks).length > 0) {\n const cleaned: Record<string, unknown[]> = {};\n for (const [event, groups] of Object.entries(existingHooks)) {\n const nonMyco = (groups as Array<Record<string, unknown>>).filter((g) => !isMycoHookGroup(g));\n if (nonMyco.length > 0) cleaned[event] = nonMyco;\n }\n if (Object.keys(cleaned).length === 0) {\n delete data.hooks;\n } else {\n data.hooks = cleaned;\n }\n hooks = true;\n }\n }\n\n // Remove MCP\n if (reg.mcpTarget) {\n const servers = (data.mcpServers ?? {}) as Record<string, unknown>;\n if (servers[MYCO_MCP_SERVER_NAME]) {\n delete servers[MYCO_MCP_SERVER_NAME];\n if (Object.keys(servers).length === 0) delete data.mcpServers;\n else data.mcpServers = servers;\n mcp = true;\n }\n }\n\n // Remove settings\n const settingsTemplate = reg.settingsTarget ? this.loadTemplate('settings') : null;\n if (settingsTemplate) {\n settings = deepRemoveSettings(data, settingsTemplate);\n }\n\n writeOrDeleteJsonFile(targetPath, data);\n\n return { hooks, mcp, skills: this.uninstallSkills(), settings, instructions: this.uninstallInstructions() };\n }\n\n /**\n * Ensure the instruction file references AGENTS.md.\n * - File doesn't exist: write the full stub template.\n * - File exists without reference: prepend a reference block.\n * - File already has reference: skip (idempotent).\n */\n installInstructions(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.instructionsFile) return false;\n\n const targetPath = path.join(this.projectRoot, reg.instructionsFile);\n\n // Check if file already exists\n let existing: string | null = null;\n try { existing = fs.readFileSync(targetPath, 'utf-8'); } catch { /* doesn't exist */ }\n\n if (existing !== null) {\n // File exists — check if it already has our reference\n if (existing.includes(INSTRUCTIONS_REF_START) || existing.includes(INSTRUCTIONS_STUB_MARKER)) {\n return false; // Already has reference — idempotent\n }\n // Prepend reference block to existing content\n fs.writeFileSync(targetPath, INSTRUCTIONS_REF_BLOCK + existing, 'utf-8');\n return true;\n }\n\n // File doesn't exist — write the full stub template\n const templateCandidates = [\n path.join(this.packageRoot, 'src/symbionts/templates/instructions-stub.md'),\n path.join(this.packageRoot, 'dist/src/symbionts/templates/instructions-stub.md'),\n ];\n let stub: string | null = null;\n for (const p of templateCandidates) {\n try { stub = fs.readFileSync(p, 'utf-8'); break; } catch { /* try next */ }\n }\n if (!stub) return false;\n\n stub = stub.replace('{agentDisplayName}', this.manifest.displayName);\n fs.mkdirSync(path.dirname(targetPath), { recursive: true });\n fs.writeFileSync(targetPath, stub, 'utf-8');\n return true;\n }\n\n /**\n * Remove Myco's instruction file reference.\n * - If file is the full stub (only Myco content): delete it.\n * - If file has user content + prepended reference: remove just the reference block.\n */\n uninstallInstructions(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.instructionsFile) return false;\n\n const targetPath = path.join(this.projectRoot, reg.instructionsFile);\n let content: string;\n try { content = fs.readFileSync(targetPath, 'utf-8'); } catch { return false; }\n\n // Case 1: Full stub — delete the file entirely\n if (content.includes(INSTRUCTIONS_STUB_MARKER)) {\n fs.unlinkSync(targetPath);\n return true;\n }\n\n // Case 2: Prepended reference block — remove just the block\n if (content.includes(INSTRUCTIONS_REF_START)) {\n const startIdx = content.indexOf(INSTRUCTIONS_REF_START);\n const endIdx = content.indexOf(INSTRUCTIONS_REF_END);\n if (endIdx > startIdx) {\n // Remove from start marker through end marker + trailing whitespace\n const afterEnd = endIdx + INSTRUCTIONS_REF_END.length;\n const cleaned = (content.slice(0, startIdx) + content.slice(afterEnd)).replace(/^\\n+/, '');\n fs.writeFileSync(targetPath, cleaned, 'utf-8');\n return true;\n }\n }\n\n return false;\n }\n\n /** List skill directory names from the package root. Returns empty array if not found. */\n private listSkillDirs(): string[] {\n try {\n return fs.readdirSync(path.join(this.packageRoot, SKILLS_SUBDIR), { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch { return []; }\n }\n\n /** Add skill symlink paths to project .gitignore. */\n private updateGitignore(): void {\n const reg = this.manifest.registration;\n if (!reg?.skillsTarget) return;\n\n const skillNames = this.listSkillDirs();\n\n const entries = [\n `${CANONICAL_SKILLS_DIR}/`,\n ...(reg.skillsTarget !== CANONICAL_SKILLS_DIR\n ? skillNames.map((name) => `${reg.skillsTarget}/${name}`)\n : []\n ),\n ];\n\n const gitignorePath = path.join(this.projectRoot, '.gitignore');\n let existing = '';\n try { existing = fs.readFileSync(gitignorePath, 'utf-8'); } catch { /* doesn't exist yet */ }\n\n const newEntries = entries.filter((e) => !existing.includes(e));\n if (newEntries.length === 0) return;\n\n const separator = existing.endsWith('\\n') || existing === '' ? '' : '\\n';\n const block = `${separator}\\n${GITIGNORE_SKILLS_COMMENT}\\n${newEntries.join('\\n')}\\n`;\n fs.writeFileSync(gitignorePath, existing + block, 'utf-8');\n }\n\n /**\n * Merge hooks template into the target settings file.\n * Replaces all Myco-owned hook groups; preserves non-Myco hooks.\n */\n installHooks(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n const template = this.loadTemplate('hooks');\n if (!template) return false;\n\n const targetPath = path.join(this.projectRoot, reg.hooksTarget);\n const settings = readJsonFile(targetPath);\n const existingHooks = (settings.hooks ?? {}) as Record<string, unknown[]>;\n\n // Build merged hooks: for each event, keep non-Myco groups + add template groups\n const mergedHooks: Record<string, unknown[]> = {};\n\n // Preserve non-Myco hooks from existing config\n for (const [event, groups] of Object.entries(existingHooks)) {\n const nonMycoGroups = (groups as Array<Record<string, unknown>>).filter(\n (group) => !isMycoHookGroup(group),\n );\n if (nonMycoGroups.length > 0) {\n mergedHooks[event] = nonMycoGroups;\n }\n }\n\n // Add template hooks\n for (const [event, groups] of Object.entries(template)) {\n mergedHooks[event] = [...(mergedHooks[event] ?? []), ...(groups as unknown[])];\n }\n\n settings.hooks = mergedHooks;\n writeJsonFile(targetPath, settings);\n return true;\n }\n\n /**\n * Merge MCP server template into the target config file.\n * Replaces the `myco` server entry; preserves other servers.\n */\n installMcp(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.mcpTarget) return false;\n\n const template = this.loadTemplate('mcp');\n if (!template) return false;\n\n const targetPath = path.join(this.projectRoot, reg.mcpTarget);\n const mcpFormat = reg.mcpFormat ?? 'json';\n\n if (mcpFormat === 'toml') {\n return this.installMcpToml(targetPath, template);\n }\n return this.installMcpJson(targetPath, template);\n }\n\n /** Write MCP servers to a JSON config file. */\n private installMcpJson(targetPath: string, template: Record<string, unknown>): boolean {\n const config = readJsonFile(targetPath);\n const servers = (config.mcpServers ?? {}) as Record<string, unknown>;\n\n for (const [name, def] of Object.entries(template)) {\n servers[name] = def;\n }\n\n config.mcpServers = servers;\n writeJsonFile(targetPath, config);\n return true;\n }\n\n /** Write MCP servers to a TOML config file. */\n private installMcpToml(targetPath: string, template: Record<string, unknown>): boolean {\n let raw = '';\n try { raw = fs.readFileSync(targetPath, 'utf-8'); } catch { /* doesn't exist */ }\n\n for (const [name, def] of Object.entries(template)) {\n raw = buildTomlMcpSection(raw, name, def as Record<string, unknown>);\n }\n\n fs.mkdirSync(path.dirname(targetPath), { recursive: true });\n fs.writeFileSync(targetPath, raw, 'utf-8');\n return true;\n }\n\n /**\n * Create symlinks for skills through .agents/skills/ canonical layer.\n * Canonical: .agents/skills/<name> -> <packageRoot>/skills/<name>\n * Agent-specific: <skillsTarget>/<name> -> ../../.agents/skills/<name>\n */\n installSkills(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.skillsTarget) return false;\n\n const skillNames = this.listSkillDirs();\n if (skillNames.length === 0) return false;\n\n const skillsSrc = path.join(this.packageRoot, SKILLS_SUBDIR);\n\n // Create canonical symlinks: .agents/skills/<name> -> package skills\n const canonicalDir = path.join(this.projectRoot, CANONICAL_SKILLS_DIR);\n fs.mkdirSync(canonicalDir, { recursive: true });\n\n for (const name of skillNames) {\n const canonicalLink = path.join(canonicalDir, name);\n const target = path.join(skillsSrc, name);\n ensureSymlink(canonicalLink, target);\n }\n\n // Create agent-specific symlinks if skillsTarget differs from canonical\n const agentSkillsDir = path.join(this.projectRoot, reg.skillsTarget);\n const canonicalRel = path.relative(agentSkillsDir, canonicalDir);\n\n if (reg.skillsTarget !== CANONICAL_SKILLS_DIR) {\n fs.mkdirSync(agentSkillsDir, { recursive: true });\n for (const name of skillNames) {\n const agentLink = path.join(agentSkillsDir, name);\n const relTarget = path.join(canonicalRel, name);\n ensureSymlink(agentLink, relTarget);\n }\n }\n\n return true;\n }\n\n /**\n * Merge settings template into the target settings file.\n * Deep merges objects and deduplicates arrays.\n */\n installSettings(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.settingsTarget) return false;\n\n const template = this.loadTemplate('settings');\n if (!template) return false;\n\n const targetPath = path.join(this.projectRoot, reg.settingsTarget);\n const existing = readJsonFile(targetPath);\n const merged = deepMergeSettings(existing, template);\n writeJsonFile(targetPath, merged);\n return true;\n }\n\n /**\n * Remove Myco entries from the target settings file.\n * Template-driven: loads the settings template and removes matching values.\n * Arrays: filter out values present in the template.\n * Objects: delete keys present in the template.\n */\n uninstallSettings(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.settingsTarget) return false;\n\n const template = this.loadTemplate('settings');\n if (!template) return false;\n\n const targetPath = path.join(this.projectRoot, reg.settingsTarget);\n const settings = readJsonFile(targetPath);\n if (Object.keys(settings).length === 0) return false;\n\n const changed = deepRemoveSettings(settings, template);\n if (!changed) return false;\n\n writeOrDeleteJsonFile(targetPath, settings);\n return true;\n }\n\n /** Remove Myco hook groups from the target settings file. */\n uninstallHooks(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n const targetPath = path.join(this.projectRoot, reg.hooksTarget);\n const settings = readJsonFile(targetPath);\n const existingHooks = (settings.hooks ?? {}) as Record<string, unknown[]>;\n if (Object.keys(existingHooks).length === 0) return false;\n\n const cleaned: Record<string, unknown[]> = {};\n for (const [event, groups] of Object.entries(existingHooks)) {\n const nonMyco = (groups as Array<Record<string, unknown>>).filter(\n (group) => !isMycoHookGroup(group),\n );\n if (nonMyco.length > 0) {\n cleaned[event] = nonMyco;\n }\n }\n\n if (Object.keys(cleaned).length === 0) {\n delete settings.hooks;\n } else {\n settings.hooks = cleaned;\n }\n\n writeOrDeleteJsonFile(targetPath, settings);\n return true;\n }\n\n /** Remove Myco MCP server entry from the target config file. */\n uninstallMcp(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.mcpTarget) return false;\n\n const targetPath = path.join(this.projectRoot, reg.mcpTarget);\n const mcpFormat = reg.mcpFormat ?? 'json';\n\n if (mcpFormat === 'toml') {\n return this.uninstallMcpToml(targetPath);\n }\n return this.uninstallMcpJson(targetPath);\n }\n\n private uninstallMcpJson(targetPath: string): boolean {\n const config = readJsonFile(targetPath);\n const servers = (config.mcpServers ?? {}) as Record<string, unknown>;\n if (!servers[MYCO_MCP_SERVER_NAME]) return false;\n\n delete servers[MYCO_MCP_SERVER_NAME];\n\n if (Object.keys(servers).length === 0) {\n delete config.mcpServers;\n } else {\n config.mcpServers = servers;\n }\n\n writeOrDeleteJsonFile(targetPath, config);\n return true;\n }\n\n private uninstallMcpToml(targetPath: string): boolean {\n let raw = '';\n try { raw = fs.readFileSync(targetPath, 'utf-8'); } catch { return false; }\n\n const sectionHeader = `[mcp_servers.${MYCO_MCP_SERVER_NAME}]`;\n if (!raw.includes(sectionHeader)) return false;\n\n const startIdx = raw.indexOf(sectionHeader);\n const endIdx = findTomlSectionEnd(raw, startIdx + sectionHeader.length, MYCO_MCP_SERVER_NAME);\n const before = raw.slice(0, startIdx).trimEnd();\n const after = raw.slice(endIdx).trimStart();\n const updated = (before + (before && after ? '\\n\\n' : '') + after).trimEnd();\n\n if (!updated.trim()) {\n try { fs.unlinkSync(targetPath); } catch { /* ignore */ }\n } else {\n fs.writeFileSync(targetPath, updated + '\\n', 'utf-8');\n }\n return true;\n }\n\n /** Remove skill symlinks (canonical + agent-specific). */\n uninstallSkills(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.skillsTarget) return false;\n\n const skillNames = this.listSkillDirs();\n if (skillNames.length === 0) return false;\n\n let removed = false;\n\n // Remove agent-specific symlinks\n if (reg.skillsTarget !== CANONICAL_SKILLS_DIR) {\n for (const name of skillNames) {\n const link = path.join(this.projectRoot, reg.skillsTarget, name);\n try { fs.unlinkSync(link); removed = true; } catch { /* doesn't exist */ }\n }\n // Remove agent skills dir if now empty (rmdirSync fails atomically if non-empty)\n try { fs.rmdirSync(path.join(this.projectRoot, reg.skillsTarget)); } catch { /* not empty or missing */ }\n }\n\n // Remove canonical symlinks\n const canonicalDir = path.join(this.projectRoot, CANONICAL_SKILLS_DIR);\n for (const name of skillNames) {\n const link = path.join(canonicalDir, name);\n try { fs.unlinkSync(link); removed = true; } catch { /* doesn't exist */ }\n }\n // Remove empty dirs (rmdirSync fails atomically if non-empty)\n try { fs.rmdirSync(canonicalDir); } catch { /* not empty or missing */ }\n try { fs.rmdirSync(path.join(this.projectRoot, '.agents')); } catch { /* not empty or missing */ }\n\n return removed;\n }\n\n /** Remove Myco entries from project .gitignore. */\n private cleanGitignore(): void {\n const gitignorePath = path.join(this.projectRoot, '.gitignore');\n let content = '';\n try { content = fs.readFileSync(gitignorePath, 'utf-8'); } catch { return; }\n\n // Remove the Myco skill symlinks block and individual entries\n const reg = this.manifest.registration;\n const skillNames = reg?.skillsTarget && reg.skillsTarget !== CANONICAL_SKILLS_DIR\n ? this.listSkillDirs()\n : [];\n const lines = content.split('\\n');\n const filtered = lines.filter((line) => {\n if (line === GITIGNORE_SKILLS_COMMENT) return false;\n if (line === `${CANONICAL_SKILLS_DIR}/`) return false;\n if (skillNames.some((name) => line === `${reg!.skillsTarget}/${name}`)) return false;\n return true;\n });\n\n // Clean up consecutive blank lines left by removal\n const cleaned = filtered.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim();\n if (cleaned) {\n fs.writeFileSync(gitignorePath, cleaned + '\\n', 'utf-8');\n } else {\n try { fs.unlinkSync(gitignorePath); } catch { /* ignore */ }\n }\n }\n}\n\n// --- TOML helpers ---\n\n/** TOML section header pattern. */\nconst TOML_SECTION_RE = /^\\[([^\\]]+)\\]/;\n\n/** Find where a [mcp_servers.<name>] section ends in a TOML string. */\nfunction findTomlSectionEnd(raw: string, searchStart: number, serverName: string): number {\n const subsectionPrefix = `mcp_servers.${serverName}.`;\n const rawLines = raw.slice(searchStart).split('\\n');\n let offset = searchStart;\n for (const line of rawLines) {\n offset += line.length + 1;\n const m = line.match(TOML_SECTION_RE);\n if (m && !m[1].startsWith(subsectionPrefix) && m[1] !== `mcp_servers.${serverName}`) {\n return offset - line.length - 1;\n }\n }\n return raw.length;\n}\n\n/**\n * Build/update a specific mcp_servers entry in a TOML string.\n * Pure transformation — returns updated content without writing to disk.\n */\nfunction buildTomlMcpSection(\n raw: string,\n serverName: string,\n server: Record<string, unknown>,\n): string {\n const sectionHeader = `[mcp_servers.${serverName}]`;\n\n // Build the TOML block for this server\n const lines: string[] = [sectionHeader];\n for (const [key, val] of Object.entries(server)) {\n if (key === 'env' && typeof val === 'object' && val !== null) continue; // Handle env as subtable\n if (typeof val === 'string') {\n lines.push(`${key} = \"${val}\"`);\n } else if (Array.isArray(val)) {\n lines.push(`${key} = [${val.map((v: unknown) => `\"${v}\"`).join(', ')}]`);\n } else if (typeof val === 'boolean') {\n lines.push(`${key} = ${val}`);\n }\n }\n\n // Add env subtable if present\n const env = server.env as Record<string, string> | undefined;\n if (env && Object.keys(env).length > 0) {\n lines.push('');\n lines.push(`[mcp_servers.${serverName}.env]`);\n for (const [key, val] of Object.entries(env)) {\n lines.push(`${key} = \"${val}\"`);\n }\n }\n\n const block = lines.join('\\n');\n\n let updated: string;\n if (raw.includes(sectionHeader)) {\n const startIdx = raw.indexOf(sectionHeader);\n const endIdx = findTomlSectionEnd(raw, startIdx + sectionHeader.length, serverName);\n const before = raw.slice(0, startIdx).trimEnd();\n const after = raw.slice(endIdx);\n const separator = before ? '\\n\\n' : '';\n updated = (before + separator + block + after).trimEnd() + '\\n';\n } else {\n // Append new section\n const separator = raw.trim() ? '\\n\\n' : '';\n updated = (raw.trimEnd() + separator + block).trimEnd() + '\\n';\n }\n\n return updated;\n}\n\n// --- Settings merge helpers ---\n\n/** Deep merge two settings objects. Arrays are appended + deduplicated; objects recurse. */\nfunction deepMergeSettings(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...target };\n for (const [key, sourceVal] of Object.entries(source)) {\n const targetVal = result[key];\n if (Array.isArray(sourceVal) && Array.isArray(targetVal)) {\n result[key] = [...new Set([...targetVal, ...sourceVal])];\n } else if (isPlainObject(sourceVal) && isPlainObject(targetVal)) {\n result[key] = deepMergeSettings(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n );\n } else {\n result[key] = sourceVal;\n }\n }\n return result;\n}\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return typeof val === 'object' && val !== null && !Array.isArray(val);\n}\n\n/**\n * Remove values from target that match the template structure.\n * Arrays: filter out values present in the template array.\n * Objects: delete keys present in the template object, recurse into nested objects.\n * Returns true if anything was removed.\n */\nfunction deepRemoveSettings(\n target: Record<string, unknown>,\n template: Record<string, unknown>,\n): boolean {\n let changed = false;\n for (const [key, templateVal] of Object.entries(template)) {\n const targetVal = target[key];\n if (targetVal === undefined) continue;\n\n if (Array.isArray(templateVal) && Array.isArray(targetVal)) {\n // Filter out values that appear in the template array\n const templateSet = new Set(templateVal.map(String));\n const filtered = targetVal.filter((v) => !templateSet.has(String(v)));\n if (filtered.length !== targetVal.length) {\n if (filtered.length > 0) {\n target[key] = filtered;\n } else {\n delete target[key];\n }\n changed = true;\n }\n } else if (isPlainObject(templateVal) && isPlainObject(targetVal)) {\n // Recurse into nested objects, then prune if empty\n if (deepRemoveSettings(targetVal, templateVal)) {\n if (Object.keys(targetVal).length === 0) {\n delete target[key];\n }\n changed = true;\n }\n } else {\n // Scalar: delete if value matches\n if (String(targetVal) === String(templateVal)) {\n delete target[key];\n changed = true;\n }\n }\n }\n return changed;\n}\n\n// --- JSON helpers ---\n\nfunction readJsonFile(filePath: string): Record<string, unknown> {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nfunction writeJsonFile(filePath: string, data: Record<string, unknown>): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n', 'utf-8');\n}\n\n/** Write a JSON file, or delete it if the object is empty. */\nfunction writeOrDeleteJsonFile(filePath: string, data: Record<string, unknown>): void {\n if (Object.keys(data).length === 0) {\n try { fs.unlinkSync(filePath); } catch { /* ignore */ }\n } else {\n writeJsonFile(filePath, data);\n }\n}\n\nfunction ensureSymlink(linkPath: string, target: string): void {\n try {\n if (fs.readlinkSync(linkPath) === target) return;\n } catch { /* does not exist or is not a symlink — proceed */ }\n try { fs.rmSync(linkPath, { recursive: true, force: true }); } catch { /* ignore */ }\n fs.symlinkSync(target, linkPath);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { OllamaBackend } from '../intelligence/ollama.js';\nimport { LmStudioBackend } from '../intelligence/lm-studio.js';\n\nimport { DaemonClient } from '../hooks/client.js';\nimport { initDatabase, closeDatabase, vaultDbPath } from '../db/client.js';\nimport { SymbiontInstaller } from '../symbionts/installer.js';\nimport type { SymbiontManifest } from '../symbionts/manifest-schema.js';\n\nexport { parseStringFlag, parseIntFlag } from '../logs/format.js';\n\n/**\n * Initialize the singleton database for direct CLI reads.\n * Used by CLI commands that only need reads (stats, search, session).\n * Does NOT require the daemon to be running — WAL mode allows concurrent reads.\n *\n * @returns a cleanup function that closes the database.\n */\nexport function initVaultDb(vaultDir: string): () => void {\n initDatabase(vaultDbPath(vaultDir));\n return closeDatabase;\n}\n\n/** Connect to the daemon, ensuring it's running. Exits on failure. */\nexport async function connectToDaemon(vaultDir: string): Promise<DaemonClient> {\n const client = new DaemonClient(vaultDir);\n const healthy = await client.ensureRunning();\n if (!healthy) {\n console.error('Failed to connect to daemon');\n process.exit(1);\n }\n return client;\n}\n\n/** Load .env from cwd (not script location — that's the plugin install dir). */\nexport function loadEnv(): void {\n const envPath = path.resolve(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) return;\n for (const line of fs.readFileSync(envPath, 'utf-8').split('\\n')) {\n const match = line.match(/^\\s*([^#=]+?)\\s*=\\s*(.*?)\\s*$/);\n if (match && !process.env[match[1]]) {\n process.env[match[1]] = match[2];\n }\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try { process.kill(pid, 0); return true; } catch { return false; }\n}\n\n// --- Provider defaults (sourced from backend classes) ---\nexport const PROVIDER_DEFAULTS: Record<string, { base_url: string }> = {\n ollama: { base_url: OllamaBackend.DEFAULT_BASE_URL },\n 'lm-studio': { base_url: LmStudioBackend.DEFAULT_BASE_URL },\n};\n\n\nexport const VAULT_GITIGNORE = `# SQLite database\nmyco.db*\nvectors.db*\n\n# Daemon state — per-machine, ephemeral\ndaemon.json\nbuffer/\nlogs/\n\n# Secrets — API keys for cloud providers\nsecrets.env\n\n# Machine ID\nmachine_id\n\n# Binary attachments — screenshots captured from transcripts\nattachments/\n\n# Team worker deployment — patched wrangler.toml + source copy\n.team-worker/\n`;\n\n/** Collapse an absolute home-dir path to its `~/` form for portable config storage. */\nexport function collapseHomePath(absPath: string): string {\n const home = os.homedir();\n if (absPath.startsWith(home + path.sep) || absPath === home) {\n return '~' + absPath.slice(home.length);\n }\n return absPath;\n}\n\n/**\n * Run the SymbiontInstaller for each symbiont manifest and log results.\n * Shared between myco init and myco update.\n */\nexport function registerSymbionts(\n manifests: SymbiontManifest[],\n projectRoot: string,\n packageRoot: string,\n verb: 'Registered' | 'Updated',\n): number {\n let count = 0;\n for (const manifest of manifests) {\n try {\n const installer = new SymbiontInstaller(manifest, projectRoot, packageRoot);\n const result = installer.install();\n\n const installed = [\n result.hooks && 'hooks',\n result.mcp && 'MCP server',\n result.skills && 'skills',\n result.settings && 'settings',\n result.instructions && 'instructions',\n ].filter(Boolean);\n\n if (installed.length > 0) {\n console.log(` \\u2713 ${verb} ${manifest.displayName}: ${installed.join(', ')}`);\n count++;\n } else {\n console.log(` \\u2013 ${manifest.displayName}: no registration targets configured`);\n }\n } catch (err) {\n console.error(` \\u2717 Failed to register ${manifest.displayName}: ${(err as Error).message}`);\n }\n }\n return count;\n}\n\n"],"mappings":"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","names":["fs","path","path","fs"]}
|
|
@@ -72,6 +72,20 @@ var AgentSchema = external_exports.object({
|
|
|
72
72
|
/** Per-task overrides keyed by task name. */
|
|
73
73
|
tasks: external_exports.record(external_exports.string(), TaskProviderOverrideSchema).optional()
|
|
74
74
|
});
|
|
75
|
+
var BackupSchema = external_exports.object({
|
|
76
|
+
/** Override directory for backup files (absolute path). When unset, defaults to {vaultDir}/backups. */
|
|
77
|
+
dir: external_exports.string().optional()
|
|
78
|
+
});
|
|
79
|
+
var TeamSchema = external_exports.object({
|
|
80
|
+
/** Whether team sync is enabled. */
|
|
81
|
+
enabled: external_exports.boolean().default(false),
|
|
82
|
+
/** Cloudflare Worker URL for team sync. */
|
|
83
|
+
worker_url: external_exports.string().url().optional(),
|
|
84
|
+
/** Team identifier for sync grouping. */
|
|
85
|
+
team_id: external_exports.string().optional(),
|
|
86
|
+
/** Sync interval in minutes. */
|
|
87
|
+
interval_minutes: external_exports.number().int().min(1).max(1440).default(15)
|
|
88
|
+
});
|
|
75
89
|
var MycoConfigSchema = external_exports.preprocess(
|
|
76
90
|
(raw) => {
|
|
77
91
|
if (raw && typeof raw === "object" && "curation" in raw && !("agent" in raw)) {
|
|
@@ -87,7 +101,9 @@ var MycoConfigSchema = external_exports.preprocess(
|
|
|
87
101
|
daemon: DaemonSchema.default(() => DaemonSchema.parse({})),
|
|
88
102
|
capture: CaptureSchema.default(() => CaptureSchema.parse({})),
|
|
89
103
|
agent: AgentSchema.default(() => AgentSchema.parse({})),
|
|
90
|
-
context: ContextSchema.default(() => ContextSchema.parse({}))
|
|
104
|
+
context: ContextSchema.default(() => ContextSchema.parse({})),
|
|
105
|
+
backup: BackupSchema.default(() => BackupSchema.parse({})),
|
|
106
|
+
team: TeamSchema.default(() => TeamSchema.parse({}))
|
|
91
107
|
})
|
|
92
108
|
);
|
|
93
109
|
|
|
@@ -264,12 +280,26 @@ function updateConfig(vaultDir, fn) {
|
|
|
264
280
|
saveConfig(vaultDir, updated);
|
|
265
281
|
return updated;
|
|
266
282
|
}
|
|
283
|
+
function updateBackupConfig(vaultDir, backup) {
|
|
284
|
+
return updateConfig(vaultDir, (config) => ({
|
|
285
|
+
...config,
|
|
286
|
+
backup: { ...config.backup, ...backup }
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
function updateTeamConfig(vaultDir, team) {
|
|
290
|
+
return updateConfig(vaultDir, (config) => ({
|
|
291
|
+
...config,
|
|
292
|
+
team: { ...config.team, ...team }
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
267
295
|
|
|
268
296
|
export {
|
|
269
297
|
MycoConfigSchema,
|
|
270
298
|
CONFIG_FILENAME,
|
|
271
299
|
loadConfig,
|
|
272
300
|
saveConfig,
|
|
273
|
-
updateConfig
|
|
301
|
+
updateConfig,
|
|
302
|
+
updateBackupConfig,
|
|
303
|
+
updateTeamConfig
|
|
274
304
|
};
|
|
275
|
-
//# sourceMappingURL=chunk-
|
|
305
|
+
//# sourceMappingURL=chunk-MAZOVVDU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/loader.ts","../src/config/schema.ts","../src/config/migrations.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { MycoConfigSchema, type MycoConfig, type BackupConfig, type TeamConfig } from './schema.js';\nimport { runMigrations, CURRENT_MIGRATION_VERSION } from './migrations.js';\n\nexport const 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 // --- v2 → v3 migration ---\n let v2Migrated = false;\n if (parsed.version === 2) {\n // Extract intelligence.embedding to top-level embedding\n const intel = parsed.intelligence as Record<string, unknown> | undefined;\n const embeddingConfig = intel?.embedding as Record<string, unknown> | undefined;\n if (embeddingConfig && !parsed.embedding) {\n // Map v2 'lm-studio' to v3 'openai-compatible' for embedding provider\n if (embeddingConfig.provider === 'lm-studio') {\n embeddingConfig.provider = 'openai-compatible';\n }\n parsed.embedding = embeddingConfig;\n }\n\n // Keep daemon.port and daemon.log_level, drop grace_period and max_log_size\n const daemon = parsed.daemon as Record<string, unknown> | undefined;\n if (daemon) {\n const { port, log_level } = daemon;\n parsed.daemon = { port: port ?? null, log_level: log_level ?? 'info' };\n }\n\n // Keep capture basics, drop token-related fields; migrate artifact_watch → plan_dirs\n const capture = parsed.capture as Record<string, unknown> | undefined;\n if (capture) {\n const { transcript_paths, artifact_watch, plan_dirs, artifact_extensions, buffer_max_events } = capture;\n parsed.capture = {\n transcript_paths,\n plan_dirs: plan_dirs ?? artifact_watch,\n artifact_extensions,\n buffer_max_events,\n };\n }\n\n // Drop removed top-level sections\n delete parsed.intelligence;\n delete parsed.context;\n delete parsed.team;\n delete parsed.digest;\n delete parsed.pipeline;\n\n // Set version to 3\n parsed.version = 3;\n v2Migrated = true;\n\n process.stderr.write('[myco migration] Migrated config from v2 to v3\\n');\n }\n\n // Run numbered migrations (for v3+ forward migrations)\n const migrationsRan = runMigrations(parsed, vaultDir, (msg) => {\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 v2→v3 migration ran, numbered migrations ran, or new defaults were added\n const needsWrite = v2Migrated\n || migrationsRan\n || (parsed.config_version as number ?? 0) < CURRENT_MIGRATION_VERSION\n || parsed.version !== config.version;\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\nexport function updateConfig(\n vaultDir: string,\n fn: (config: MycoConfig) => MycoConfig,\n): MycoConfig {\n const current = loadConfig(vaultDir);\n const updated = fn(current);\n saveConfig(vaultDir, updated);\n return updated;\n}\n\nexport function updateBackupConfig(\n vaultDir: string,\n backup: Partial<BackupConfig>,\n): MycoConfig {\n return updateConfig(vaultDir, (config) => ({\n ...config,\n backup: { ...config.backup, ...backup },\n }));\n}\n\nexport function updateTeamConfig(\n vaultDir: string,\n team: Partial<TeamConfig>,\n): MycoConfig {\n return updateConfig(vaultDir, (config) => ({\n ...config,\n team: { ...config.team, ...team },\n }));\n}\n","import { z } from 'zod';\n\nconst EmbeddingProviderSchema = z.object({\n provider: z.enum(['ollama', 'openai-compatible', 'openrouter', 'openai']).default('ollama'),\n model: z.string().default('bge-m3'),\n base_url: z.string().url().optional(),\n});\n\nconst DaemonSchema = z.object({\n port: z.number().int().min(1024).max(65535).nullable().default(null),\n log_level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n log_retention_days: z.number().int().min(1).max(365).default(30),\n});\n\nconst CaptureSchema = z.object({\n transcript_paths: z.array(z.string()).default([]),\n plan_dirs: z.array(z.string()).default([]),\n artifact_extensions: z.array(z.string()).default(['.md']),\n buffer_max_events: z.number().int().positive().default(500),\n});\n\n/** Provider config shape used in both task-level and phase-level overrides. */\nconst ProviderOverrideSchema = z.object({\n type: z.enum(['cloud', 'ollama', 'lmstudio']),\n base_url: z.string().optional(),\n model: z.string().optional(),\n /** Context window size for local models (Ollama num_ctx, LM Studio context_length). */\n context_length: z.number().int().positive().optional(),\n});\n\n/** Per-phase overrides within a task — keyed by phase name. */\nconst PhaseOverrideSchema = z.object({\n provider: ProviderOverrideSchema.optional(),\n model: z.string().optional(),\n maxTurns: z.number().int().positive().optional(),\n});\n\n/** Per-task config override — stored in myco.yaml under agent.tasks. */\nconst TaskProviderOverrideSchema = z.object({\n provider: ProviderOverrideSchema.optional(),\n model: z.string().optional(),\n maxTurns: z.number().int().positive().optional(),\n timeoutSeconds: z.number().int().positive().optional(),\n phases: z.record(z.string(), PhaseOverrideSchema).optional(),\n});\n\nconst ContextSchema = z.object({\n /** Which digest tier to inject at session start. */\n digest_tier: z.number().int().default(5000),\n /** Enable semantic spore search on each user prompt. */\n prompt_search: z.boolean().default(true),\n /** Max spores to inject per prompt (0-10). */\n prompt_max_spores: z.number().int().min(0).max(10).default(3),\n});\n\nconst AgentSchema = z.object({\n /** Whether the daemon automatically runs the agent on unprocessed batches. */\n auto_run: z.boolean().default(true),\n /** Seconds between agent timer checks. */\n interval_seconds: z.number().int().positive().default(300),\n /** Number of batches between event-driven summary triggers (0 to disable). */\n summary_batch_interval: z.number().int().min(0).default(5),\n /** Global default provider — applies to all tasks unless overridden per-task. */\n provider: ProviderOverrideSchema.optional(),\n /** Global default model — applies to all tasks unless overridden per-task. */\n model: z.string().optional(),\n /** Per-task overrides keyed by task name. */\n tasks: z.record(z.string(), TaskProviderOverrideSchema).optional(),\n});\n\nconst BackupSchema = z.object({\n /** Override directory for backup files (absolute path). When unset, defaults to {vaultDir}/backups. */\n dir: z.string().optional(),\n});\n\nconst TeamSchema = z.object({\n /** Whether team sync is enabled. */\n enabled: z.boolean().default(false),\n /** Cloudflare Worker URL for team sync. */\n worker_url: z.string().url().optional(),\n /** Team identifier for sync grouping. */\n team_id: z.string().optional(),\n /** Sync interval in minutes. */\n interval_minutes: z.number().int().min(1).max(1440).default(15),\n});\n\nexport const MycoConfigSchema = z.preprocess(\n (raw: unknown) => {\n if (raw && typeof raw === 'object' && 'curation' in raw && !('agent' in raw)) {\n const { curation, ...rest } = raw as Record<string, unknown>;\n return { ...rest, agent: curation };\n }\n return raw;\n },\n z.object({\n version: z.literal(3),\n config_version: z.number().int().nonnegative().default(0),\n embedding: EmbeddingProviderSchema.default(() => EmbeddingProviderSchema.parse({})),\n daemon: DaemonSchema.default(() => DaemonSchema.parse({})),\n capture: CaptureSchema.default(() => CaptureSchema.parse({})),\n agent: AgentSchema.default(() => AgentSchema.parse({})),\n context: ContextSchema.default(() => ContextSchema.parse({})),\n backup: BackupSchema.default(() => BackupSchema.parse({})),\n team: TeamSchema.default(() => TeamSchema.parse({})),\n }),\n);\n\nexport type MycoConfig = z.output<typeof MycoConfigSchema>;\nexport type EmbeddingProviderConfig = z.infer<typeof EmbeddingProviderSchema>;\nexport type TaskProviderOverride = z.infer<typeof TaskProviderOverrideSchema>;\nexport type PhaseOverride = z.infer<typeof PhaseOverrideSchema>;\nexport type ContextConfig = z.infer<typeof ContextSchema>;\nexport type BackupConfig = z.infer<typeof BackupSchema>;\nexport type TeamConfig = z.infer<typeof TeamSchema>;\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 // Legacy: update wikilink references in Markdown files (pre-SQLite migration): [[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 version: 2,\n name: 'consolidation-boolean-to-object',\n migrate: (doc) => {\n const digest = doc.digest as Record<string, unknown> | undefined;\n if (!digest) return;\n\n const consolidation = digest.consolidation;\n if (typeof consolidation === 'boolean') {\n digest.consolidation = { enabled: consolidation, max_tokens: 2048 };\n }\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 migration.migrate(doc, vaultDir);\n doc.config_version = migration.version;\n ran = true;\n }\n\n if (ran) {\n const from = currentVersion;\n const to = (doc.config_version as number) ?? 0;\n log?.(`Migrated config from v${from} to v${to}`);\n }\n\n return ran;\n}\n"],"mappings":"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","names":["fs","path","path","fs","YAML"]}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
OpenRouterEmbeddingProvider
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AEJS57ZK.js";
|
|
5
5
|
import {
|
|
6
6
|
OpenAIEmbeddingProvider
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5QERXFH7.js";
|
|
8
8
|
import {
|
|
9
9
|
LmStudioBackend,
|
|
10
10
|
OllamaBackend
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-5SDH75YC.js";
|
|
12
12
|
import {
|
|
13
13
|
LLM_REQUEST_TIMEOUT_MS
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-76ZO5RGT.js";
|
|
15
15
|
|
|
16
16
|
// node_modules/@anthropic-ai/sdk/internal/tslib.mjs
|
|
17
17
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
@@ -4929,4 +4929,4 @@ export {
|
|
|
4929
4929
|
createLlmProvider,
|
|
4930
4930
|
createEmbeddingProvider
|
|
4931
4931
|
};
|
|
4932
|
-
//# sourceMappingURL=chunk-
|
|
4932
|
+
//# sourceMappingURL=chunk-MKKXCCQ5.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
findPackageRoot
|
|
4
|
+
} from "./chunk-LPUQPDC2.js";
|
|
2
5
|
import {
|
|
3
6
|
require_dist
|
|
4
7
|
} from "./chunk-D7TYRPRM.js";
|
|
5
8
|
import {
|
|
6
9
|
external_exports
|
|
7
10
|
} from "./chunk-KH64DHOY.js";
|
|
8
|
-
import {
|
|
9
|
-
findPackageRoot
|
|
10
|
-
} from "./chunk-LPUQPDC2.js";
|
|
11
11
|
import {
|
|
12
12
|
__toESM
|
|
13
13
|
} from "./chunk-PZUWP5VK.js";
|
|
@@ -16,21 +16,37 @@ import {
|
|
|
16
16
|
var CaptureManifestSchema = external_exports.object({
|
|
17
17
|
planDirs: external_exports.array(external_exports.string()).default([])
|
|
18
18
|
});
|
|
19
|
+
var RegistrationSchema = external_exports.object({
|
|
20
|
+
hooksTarget: external_exports.string().optional(),
|
|
21
|
+
mcpTarget: external_exports.string().optional(),
|
|
22
|
+
mcpFormat: external_exports.enum(["json", "toml"]).default("json"),
|
|
23
|
+
skillsTarget: external_exports.string().optional(),
|
|
24
|
+
settingsTarget: external_exports.string().optional(),
|
|
25
|
+
/** Instruction file that stubs out to AGENTS.md. Only for agents that don't read AGENTS.md natively. */
|
|
26
|
+
instructionsFile: external_exports.string().optional()
|
|
27
|
+
});
|
|
19
28
|
var SymbiontManifestSchema = external_exports.object({
|
|
20
29
|
name: external_exports.string(),
|
|
21
30
|
displayName: external_exports.string(),
|
|
22
31
|
binary: external_exports.string(),
|
|
23
32
|
configDir: external_exports.string(),
|
|
24
33
|
pluginRootEnvVar: external_exports.string(),
|
|
25
|
-
pluginInstallCommands: external_exports.array(external_exports.string()).default([]),
|
|
26
34
|
settingsPath: external_exports.string().optional(),
|
|
27
|
-
mcpConfigPath: external_exports.string().optional(),
|
|
28
35
|
hookFields: external_exports.object({
|
|
36
|
+
sessionId: external_exports.string(),
|
|
29
37
|
transcriptPath: external_exports.string(),
|
|
30
38
|
lastResponse: external_exports.string(),
|
|
31
|
-
|
|
39
|
+
prompt: external_exports.string().default("prompt"),
|
|
40
|
+
toolName: external_exports.string().default("tool_name"),
|
|
41
|
+
toolInput: external_exports.string().default("tool_input"),
|
|
42
|
+
toolOutput: external_exports.string().default("tool_output"),
|
|
43
|
+
/** Env var fallback for session ID (e.g., GEMINI_SESSION_ID). */
|
|
44
|
+
sessionIdEnv: external_exports.string().optional()
|
|
32
45
|
}),
|
|
33
|
-
|
|
46
|
+
/** Resume command template with {sessionId} placeholder. Omit for IDE-based agents. */
|
|
47
|
+
resumeCommand: external_exports.string().optional(),
|
|
48
|
+
capture: CaptureManifestSchema.optional(),
|
|
49
|
+
registration: RegistrationSchema.optional()
|
|
34
50
|
});
|
|
35
51
|
|
|
36
52
|
// src/symbionts/detect.ts
|
|
@@ -89,4 +105,4 @@ export {
|
|
|
89
105
|
detectSymbionts,
|
|
90
106
|
resolvePackageRoot
|
|
91
107
|
};
|
|
92
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-QFMBZ72S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/symbionts/manifest-schema.ts","../src/symbionts/detect.ts"],"sourcesContent":["import { z } from 'zod';\n\nconst CaptureManifestSchema = z.object({\n planDirs: z.array(z.string()).default([]),\n});\n\nconst RegistrationSchema = z.object({\n hooksTarget: z.string().optional(),\n mcpTarget: z.string().optional(),\n mcpFormat: z.enum(['json', 'toml']).default('json'),\n skillsTarget: z.string().optional(),\n settingsTarget: z.string().optional(),\n /** Instruction file that stubs out to AGENTS.md. Only for agents that don't read AGENTS.md natively. */\n instructionsFile: z.string().optional(),\n});\n\nexport const SymbiontManifestSchema = z.object({\n name: z.string(),\n displayName: z.string(),\n binary: z.string(),\n configDir: z.string(),\n pluginRootEnvVar: z.string(),\n settingsPath: z.string().optional(),\n hookFields: z.object({\n sessionId: z.string(),\n transcriptPath: z.string(),\n lastResponse: z.string(),\n prompt: z.string().default('prompt'),\n toolName: z.string().default('tool_name'),\n toolInput: z.string().default('tool_input'),\n toolOutput: z.string().default('tool_output'),\n /** Env var fallback for session ID (e.g., GEMINI_SESSION_ID). */\n sessionIdEnv: z.string().optional(),\n }),\n /** Resume command template with {sessionId} placeholder. Omit for IDE-based agents. */\n resumeCommand: z.string().optional(),\n capture: CaptureManifestSchema.optional(),\n registration: RegistrationSchema.optional(),\n});\n\nexport type SymbiontManifest = z.infer<typeof SymbiontManifestSchema>;\nexport type SymbiontRegistration = z.infer<typeof RegistrationSchema>;\n","import { SymbiontManifestSchema, type SymbiontManifest } from './manifest-schema.js';\nimport { findPackageRoot } from '../utils/find-package-root.js';\nimport { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\n\nexport interface DetectedSymbiont {\n manifest: SymbiontManifest;\n binaryFound: boolean;\n configDirFound: boolean;\n}\n\nconst MANIFESTS_SUBDIR = 'symbionts/manifests';\n\n/** Cached manifests — static files that never change at runtime. */\nlet manifestCache: SymbiontManifest[] | null = null;\n\n/** Load all symbiont manifests from the package's dist directory. */\nexport function loadManifests(): SymbiontManifest[] {\n if (manifestCache) return manifestCache;\n const candidates = [\n // Source layout: src/symbionts/detect.ts → src/symbionts/manifests/\n path.resolve(import.meta.dirname, MANIFESTS_SUBDIR),\n // Dist layout: dist/src/symbionts/ → dist/src/symbionts/manifests/\n // (or dist/src/daemon/ → dist/src/symbionts/manifests/)\n path.resolve(import.meta.dirname, '..', MANIFESTS_SUBDIR),\n path.resolve(import.meta.dirname, '..', '..', MANIFESTS_SUBDIR),\n // Chunk layout: dist/chunk-*.js → dist/src/symbionts/manifests/\n path.resolve(import.meta.dirname, 'src', MANIFESTS_SUBDIR),\n ];\n\n for (const dir of candidates) {\n if (!fs.existsSync(dir)) continue;\n const files = fs.readdirSync(dir).filter(f => f.endsWith('.yaml'));\n if (files.length === 0) continue;\n manifestCache = files.map(f => {\n const raw = YAML.parse(fs.readFileSync(path.join(dir, f), 'utf-8'));\n return SymbiontManifestSchema.parse(raw);\n });\n return manifestCache;\n }\n return [];\n}\n\n/** Check if a binary is available on PATH. */\nfunction isBinaryOnPath(binary: string): boolean {\n try {\n execFileSync('which', [binary], { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Detect which symbionts are available for a project. */\nexport function detectSymbionts(projectRoot: string): DetectedSymbiont[] {\n const manifests = loadManifests();\n return manifests.map(manifest => ({\n manifest,\n binaryFound: isBinaryOnPath(manifest.binary),\n configDirFound: fs.existsSync(path.join(projectRoot, manifest.configDir)),\n })).filter(d => d.binaryFound || d.configDirFound);\n}\n\n/** Find the Myco package root (where package.json lives). */\nexport function resolvePackageRoot(): string {\n return findPackageRoot(import.meta.dirname) ?? process.cwd();\n}\n"],"mappings":"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","names":["YAML"]}
|
|
@@ -70,7 +70,15 @@ var LOG_KINDS = {
|
|
|
70
70
|
// MCP
|
|
71
71
|
MCP_EVENT: "mcp.event",
|
|
72
72
|
// Log retention
|
|
73
|
-
LOG_RETENTION: "log.retention"
|
|
73
|
+
LOG_RETENTION: "log.retention",
|
|
74
|
+
// Backup
|
|
75
|
+
BACKUP_START: "backup.start",
|
|
76
|
+
BACKUP_COMPLETE: "backup.complete",
|
|
77
|
+
BACKUP_ERROR: "backup.error",
|
|
78
|
+
// Team sync
|
|
79
|
+
TEAM_SYNC_START: "team-sync.start",
|
|
80
|
+
TEAM_SYNC_COMPLETE: "team-sync.complete",
|
|
81
|
+
TEAM_SYNC_ERROR: "team-sync.error"
|
|
74
82
|
};
|
|
75
83
|
function kindToComponent(kind) {
|
|
76
84
|
const dot = kind.indexOf(".");
|
|
@@ -81,4 +89,4 @@ export {
|
|
|
81
89
|
LOG_KINDS,
|
|
82
90
|
kindToComponent
|
|
83
91
|
};
|
|
84
|
-
//# sourceMappingURL=chunk-
|
|
92
|
+
//# sourceMappingURL=chunk-S6I62FAH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants/log-kinds.ts"],"sourcesContent":["/**\n * Structured log entry kinds — every logger call uses one of these.\n *\n * Convention: `{component}.{action}` — the component is derived from the\n * first segment (before the dot) for fast column filtering.\n */\nexport const LOG_KINDS = {\n // Context injection\n CONTEXT_QUERY: 'context.query',\n CONTEXT_SESSION: 'context.session',\n CONTEXT_PROMPT: 'context.prompt',\n CONTEXT_DIGEST: 'context.digest',\n CONTEXT_SEARCH: 'context.search',\n CONTEXT_EMBED: 'context.embed',\n CONTEXT_FILTER: 'context.filter',\n\n // Session lifecycle\n LIFECYCLE_REGISTER: 'lifecycle.register',\n LIFECYCLE_RECONCILE: 'lifecycle.reconcile',\n LIFECYCLE_UNREGISTER: 'lifecycle.unregister',\n LIFECYCLE_CLEANUP: 'lifecycle.cleanup',\n LIFECYCLE_AUTO_REGISTER: 'lifecycle.auto-register',\n\n // Hooks (event ingestion)\n HOOKS_EVENT: 'hooks.event',\n HOOKS_PROMPT: 'hooks.prompt',\n HOOKS_STOP: 'hooks.stop',\n HOOKS_TOOL: 'hooks.tool',\n HOOKS_SUBAGENT: 'hooks.subagent',\n\n // Capture (batch/activity recording)\n CAPTURE_BATCH: 'capture.batch',\n CAPTURE_ACTIVITY: 'capture.activity',\n CAPTURE_PLAN: 'capture.plan',\n CAPTURE_ATTACHMENT: 'capture.attachment',\n CAPTURE_BUFFER: 'capture.buffer',\n\n // Processor (stop-event session processing)\n PROCESSOR_SESSION: 'processor.session',\n PROCESSOR_TRANSCRIPT: 'processor.transcript',\n PROCESSOR_BATCH: 'processor.batch',\n PROCESSOR_TITLE: 'processor.title',\n\n // Agent\n AGENT_RUN: 'agent.run',\n AGENT_PHASE: 'agent.phase',\n AGENT_TASK: 'agent.task',\n AGENT_AUTO_RUN: 'agent.auto-run',\n AGENT_ERROR: 'agent.error',\n\n // Embedding\n EMBEDDING_EMBED: 'embedding.embed',\n EMBEDDING_RECONCILE: 'embedding.reconcile',\n EMBEDDING_SEARCH: 'embedding.search',\n EMBEDDING_REBUILD: 'embedding.rebuild',\n EMBEDDING_CLEANUP: 'embedding.cleanup',\n EMBEDDING_PROVIDER: 'embedding.provider',\n\n // Power management\n POWER_TICK: 'power.tick',\n POWER_STATE: 'power.state',\n POWER_JOB: 'power.job',\n POWER_JOB_ERROR: 'power.job-error',\n\n // Daemon core\n DAEMON_START: 'daemon.start',\n DAEMON_CONFIG: 'daemon.config',\n DAEMON_READY: 'daemon.ready',\n DAEMON_MIGRATION: 'daemon.migration',\n DAEMON_PORT: 'daemon.port',\n DAEMON_RECONCILE: 'daemon.reconcile',\n\n // Server (HTTP)\n SERVER_REQUEST: 'server.request',\n SERVER_STATIC: 'server.static',\n SERVER_ERROR: 'server.error',\n\n // Session maintenance job\n MAINTENANCE_SESSION: 'maintenance.session',\n MAINTENANCE_EMBEDDING: 'maintenance.embedding',\n\n // API operations\n API_SESSION_DELETE: 'api.session-delete',\n\n // MCP\n MCP_EVENT: 'mcp.event',\n\n // Log retention\n LOG_RETENTION: 'log.retention',\n} as const;\n\nexport type LogKind = (typeof LOG_KINDS)[keyof typeof LOG_KINDS];\n\n/**\n * Extract the component (first segment) from a kind string.\n * e.g., 'context.session' -> 'context'\n */\nexport function kindToComponent(kind: string): string {\n const dot = kind.indexOf('.');\n return dot > 0 ? kind.slice(0, dot) : kind;\n}\n"],"mappings":";;;AAMO,IAAM,YAAY;AAAA;AAAA,EAEvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,gBAAgB;AAAA;AAAA,EAGhB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,yBAAyB;AAAA;AAAA,EAGzB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,gBAAgB;AAAA;AAAA,EAGhB,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,aAAa;AAAA;AAAA,EAGb,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA;AAAA,EAGpB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA,EAGjB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA;AAAA,EAGlB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,cAAc;AAAA;AAAA,EAGd,qBAAqB;AAAA,EACrB,uBAAuB;AAAA;AAAA,EAGvB,oBAAoB;AAAA;AAAA,EAGpB,WAAW;AAAA;AAAA,EAGX,eAAe;
|
|
1
|
+
{"version":3,"sources":["../src/constants/log-kinds.ts"],"sourcesContent":["/**\n * Structured log entry kinds — every logger call uses one of these.\n *\n * Convention: `{component}.{action}` — the component is derived from the\n * first segment (before the dot) for fast column filtering.\n */\nexport const LOG_KINDS = {\n // Context injection\n CONTEXT_QUERY: 'context.query',\n CONTEXT_SESSION: 'context.session',\n CONTEXT_PROMPT: 'context.prompt',\n CONTEXT_DIGEST: 'context.digest',\n CONTEXT_SEARCH: 'context.search',\n CONTEXT_EMBED: 'context.embed',\n CONTEXT_FILTER: 'context.filter',\n\n // Session lifecycle\n LIFECYCLE_REGISTER: 'lifecycle.register',\n LIFECYCLE_RECONCILE: 'lifecycle.reconcile',\n LIFECYCLE_UNREGISTER: 'lifecycle.unregister',\n LIFECYCLE_CLEANUP: 'lifecycle.cleanup',\n LIFECYCLE_AUTO_REGISTER: 'lifecycle.auto-register',\n\n // Hooks (event ingestion)\n HOOKS_EVENT: 'hooks.event',\n HOOKS_PROMPT: 'hooks.prompt',\n HOOKS_STOP: 'hooks.stop',\n HOOKS_TOOL: 'hooks.tool',\n HOOKS_SUBAGENT: 'hooks.subagent',\n\n // Capture (batch/activity recording)\n CAPTURE_BATCH: 'capture.batch',\n CAPTURE_ACTIVITY: 'capture.activity',\n CAPTURE_PLAN: 'capture.plan',\n CAPTURE_ATTACHMENT: 'capture.attachment',\n CAPTURE_BUFFER: 'capture.buffer',\n\n // Processor (stop-event session processing)\n PROCESSOR_SESSION: 'processor.session',\n PROCESSOR_TRANSCRIPT: 'processor.transcript',\n PROCESSOR_BATCH: 'processor.batch',\n PROCESSOR_TITLE: 'processor.title',\n\n // Agent\n AGENT_RUN: 'agent.run',\n AGENT_PHASE: 'agent.phase',\n AGENT_TASK: 'agent.task',\n AGENT_AUTO_RUN: 'agent.auto-run',\n AGENT_ERROR: 'agent.error',\n\n // Embedding\n EMBEDDING_EMBED: 'embedding.embed',\n EMBEDDING_RECONCILE: 'embedding.reconcile',\n EMBEDDING_SEARCH: 'embedding.search',\n EMBEDDING_REBUILD: 'embedding.rebuild',\n EMBEDDING_CLEANUP: 'embedding.cleanup',\n EMBEDDING_PROVIDER: 'embedding.provider',\n\n // Power management\n POWER_TICK: 'power.tick',\n POWER_STATE: 'power.state',\n POWER_JOB: 'power.job',\n POWER_JOB_ERROR: 'power.job-error',\n\n // Daemon core\n DAEMON_START: 'daemon.start',\n DAEMON_CONFIG: 'daemon.config',\n DAEMON_READY: 'daemon.ready',\n DAEMON_MIGRATION: 'daemon.migration',\n DAEMON_PORT: 'daemon.port',\n DAEMON_RECONCILE: 'daemon.reconcile',\n\n // Server (HTTP)\n SERVER_REQUEST: 'server.request',\n SERVER_STATIC: 'server.static',\n SERVER_ERROR: 'server.error',\n\n // Session maintenance job\n MAINTENANCE_SESSION: 'maintenance.session',\n MAINTENANCE_EMBEDDING: 'maintenance.embedding',\n\n // API operations\n API_SESSION_DELETE: 'api.session-delete',\n\n // MCP\n MCP_EVENT: 'mcp.event',\n\n // Log retention\n LOG_RETENTION: 'log.retention',\n\n // Backup\n BACKUP_START: 'backup.start',\n BACKUP_COMPLETE: 'backup.complete',\n BACKUP_ERROR: 'backup.error',\n\n // Team sync\n TEAM_SYNC_START: 'team-sync.start',\n TEAM_SYNC_COMPLETE: 'team-sync.complete',\n TEAM_SYNC_ERROR: 'team-sync.error',\n} as const;\n\nexport type LogKind = (typeof LOG_KINDS)[keyof typeof LOG_KINDS];\n\n/**\n * Extract the component (first segment) from a kind string.\n * e.g., 'context.session' -> 'context'\n */\nexport function kindToComponent(kind: string): string {\n const dot = kind.indexOf('.');\n return dot > 0 ? kind.slice(0, dot) : kind;\n}\n"],"mappings":";;;AAMO,IAAM,YAAY;AAAA;AAAA,EAEvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,gBAAgB;AAAA;AAAA,EAGhB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,yBAAyB;AAAA;AAAA,EAGzB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,gBAAgB;AAAA;AAAA,EAGhB,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,aAAa;AAAA;AAAA,EAGb,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA;AAAA,EAGpB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA,EAGjB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA;AAAA,EAGlB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,cAAc;AAAA;AAAA,EAGd,qBAAqB;AAAA,EACrB,uBAAuB;AAAA;AAAA,EAGvB,oBAAoB;AAAA;AAAA,EAGpB,WAAW;AAAA;AAAA,EAGX,eAAe;AAAA;AAAA,EAGf,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,cAAc;AAAA;AAAA,EAGd,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,iBAAiB;AACnB;AAQO,SAAS,gBAAgB,MAAsB;AACpD,QAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,SAAO,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI;AACxC;","names":[]}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
syncRow
|
|
4
|
+
} from "./chunk-XLY3REL3.js";
|
|
2
5
|
import {
|
|
3
6
|
getDatabase
|
|
4
7
|
} from "./chunk-MYX5NCRH.js";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_MACHINE_ID
|
|
10
|
+
} from "./chunk-76ZO5RGT.js";
|
|
5
11
|
|
|
6
12
|
// src/db/queries/spores.ts
|
|
7
13
|
var DEFAULT_LIST_LIMIT = 100;
|
|
@@ -23,7 +29,9 @@ var SPORE_COLUMNS = [
|
|
|
23
29
|
"properties",
|
|
24
30
|
"embedded",
|
|
25
31
|
"created_at",
|
|
26
|
-
"updated_at"
|
|
32
|
+
"updated_at",
|
|
33
|
+
"machine_id",
|
|
34
|
+
"synced_at"
|
|
27
35
|
];
|
|
28
36
|
var SELECT_COLUMNS = SPORE_COLUMNS.join(", ");
|
|
29
37
|
function toSporeRow(row) {
|
|
@@ -43,7 +51,9 @@ function toSporeRow(row) {
|
|
|
43
51
|
properties: row.properties ?? null,
|
|
44
52
|
embedded: row.embedded ?? 0,
|
|
45
53
|
created_at: row.created_at,
|
|
46
|
-
updated_at: row.updated_at ?? null
|
|
54
|
+
updated_at: row.updated_at ?? null,
|
|
55
|
+
machine_id: row.machine_id ?? DEFAULT_MACHINE_ID,
|
|
56
|
+
synced_at: row.synced_at ?? null
|
|
47
57
|
};
|
|
48
58
|
}
|
|
49
59
|
function insertSpore(data) {
|
|
@@ -53,12 +63,12 @@ function insertSpore(data) {
|
|
|
53
63
|
id, agent_id, session_id, prompt_batch_id,
|
|
54
64
|
observation_type, status, content, context,
|
|
55
65
|
importance, file_path, tags, content_hash,
|
|
56
|
-
properties, created_at, updated_at
|
|
66
|
+
properties, created_at, updated_at, machine_id
|
|
57
67
|
) VALUES (
|
|
58
68
|
?, ?, ?, ?,
|
|
59
69
|
?, ?, ?, ?,
|
|
60
70
|
?, ?, ?, ?,
|
|
61
|
-
?, ?, ?
|
|
71
|
+
?, ?, ?, ?
|
|
62
72
|
)`
|
|
63
73
|
).run(
|
|
64
74
|
data.id,
|
|
@@ -75,11 +85,14 @@ function insertSpore(data) {
|
|
|
75
85
|
data.content_hash ?? null,
|
|
76
86
|
data.properties ?? null,
|
|
77
87
|
data.created_at,
|
|
78
|
-
data.updated_at ?? null
|
|
88
|
+
data.updated_at ?? null,
|
|
89
|
+
data.machine_id ?? DEFAULT_MACHINE_ID
|
|
79
90
|
);
|
|
80
|
-
|
|
91
|
+
const row = toSporeRow(
|
|
81
92
|
db.prepare(`SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`).get(data.id)
|
|
82
93
|
);
|
|
94
|
+
syncRow("spores", row);
|
|
95
|
+
return row;
|
|
83
96
|
}
|
|
84
97
|
function getSpore(id) {
|
|
85
98
|
const db = getDatabase();
|
|
@@ -149,9 +162,11 @@ function updateSporeStatus(id, status, updatedAt) {
|
|
|
149
162
|
WHERE id = ?`
|
|
150
163
|
).run(status, updatedAt, id);
|
|
151
164
|
if (info.changes === 0) return null;
|
|
152
|
-
|
|
165
|
+
const row = toSporeRow(
|
|
153
166
|
db.prepare(`SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`).get(id)
|
|
154
167
|
);
|
|
168
|
+
syncRow("spores", row);
|
|
169
|
+
return row;
|
|
155
170
|
}
|
|
156
171
|
|
|
157
172
|
export {
|
|
@@ -162,4 +177,4 @@ export {
|
|
|
162
177
|
countSpores,
|
|
163
178
|
updateSporeStatus
|
|
164
179
|
};
|
|
165
|
-
//# sourceMappingURL=chunk-
|
|
180
|
+
//# sourceMappingURL=chunk-U7UUJ4FD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/db/queries/spores.ts"],"sourcesContent":["/**\n * Spore CRUD query helpers.\n *\n * All functions obtain the SQLite instance internally via `getDatabase()`.\n * Queries use positional `?` placeholders throughout (better-sqlite3).\n */\n\nimport { getDatabase } from '@myco/db/client.js';\nimport { DEFAULT_MACHINE_ID } from '@myco/constants.js';\nimport { syncRow } from '@myco/db/queries/team-outbox.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Default number of spores returned by listSpores when no limit given. */\nconst DEFAULT_LIST_LIMIT = 100;\n\n/** Default spore status for new spores. */\nconst DEFAULT_STATUS = 'active';\n\n/** Default importance score for new spores. */\nexport const DEFAULT_IMPORTANCE = 5;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Fields required (or optional) when inserting a spore. */\nexport interface SporeInsert {\n id: string;\n agent_id: string;\n observation_type: string;\n content: string;\n created_at: number;\n session_id?: string | null;\n prompt_batch_id?: number | null;\n status?: string;\n context?: string | null;\n importance?: number;\n file_path?: string | null;\n tags?: string | null;\n content_hash?: string | null;\n properties?: string | null;\n updated_at?: number | null;\n machine_id?: string;\n}\n\n/** Row shape returned from spore queries (all columns). */\nexport interface SporeRow {\n id: string;\n agent_id: string;\n session_id: string | null;\n prompt_batch_id: number | null;\n observation_type: string;\n status: string;\n content: string;\n context: string | null;\n importance: number;\n file_path: string | null;\n tags: string | null;\n content_hash: string | null;\n properties: string | null;\n embedded: number;\n created_at: number;\n updated_at: number | null;\n machine_id: string;\n synced_at: number | null;\n}\n\n/** Filter options for `listSpores`. */\nexport interface ListSporesOptions {\n agent_id?: string;\n observation_type?: string;\n status?: string;\n session_id?: string;\n search?: string;\n limit?: number;\n offset?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Column list\n// ---------------------------------------------------------------------------\n\nconst SPORE_COLUMNS = [\n 'id',\n 'agent_id',\n 'session_id',\n 'prompt_batch_id',\n 'observation_type',\n 'status',\n 'content',\n 'context',\n 'importance',\n 'file_path',\n 'tags',\n 'content_hash',\n 'properties',\n 'embedded',\n 'created_at',\n 'updated_at',\n 'machine_id',\n 'synced_at',\n] as const;\n\nconst SELECT_COLUMNS = SPORE_COLUMNS.join(', ');\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Normalize a SQLite result row into a typed SporeRow. */\nfunction toSporeRow(row: Record<string, unknown>): SporeRow {\n return {\n id: row.id as string,\n agent_id: row.agent_id as string,\n session_id: (row.session_id as string) ?? null,\n prompt_batch_id: (row.prompt_batch_id as number) ?? null,\n observation_type: row.observation_type as string,\n status: row.status as string,\n content: row.content as string,\n context: (row.context as string) ?? null,\n importance: row.importance as number,\n file_path: (row.file_path as string) ?? null,\n tags: (row.tags as string) ?? null,\n content_hash: (row.content_hash as string) ?? null,\n properties: (row.properties as string) ?? null,\n embedded: (row.embedded as number) ?? 0,\n created_at: row.created_at as number,\n updated_at: (row.updated_at as number) ?? null,\n machine_id: (row.machine_id as string) ?? DEFAULT_MACHINE_ID,\n synced_at: (row.synced_at as number) ?? null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Insert a new spore.\n *\n * Requires a valid `agent_id` (foreign key to agents table).\n */\nexport function insertSpore(data: SporeInsert): SporeRow {\n const db = getDatabase();\n\n db.prepare(\n `INSERT INTO spores (\n id, agent_id, session_id, prompt_batch_id,\n observation_type, status, content, context,\n importance, file_path, tags, content_hash,\n properties, created_at, updated_at, machine_id\n ) VALUES (\n ?, ?, ?, ?,\n ?, ?, ?, ?,\n ?, ?, ?, ?,\n ?, ?, ?, ?\n )`,\n ).run(\n data.id,\n data.agent_id,\n data.session_id ?? null,\n data.prompt_batch_id ?? null,\n data.observation_type,\n data.status ?? DEFAULT_STATUS,\n data.content,\n data.context ?? null,\n data.importance ?? DEFAULT_IMPORTANCE,\n data.file_path ?? null,\n data.tags ?? null,\n data.content_hash ?? null,\n data.properties ?? null,\n data.created_at,\n data.updated_at ?? null,\n data.machine_id ?? DEFAULT_MACHINE_ID,\n );\n\n const row = toSporeRow(\n db.prepare(`SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`).get(data.id) as Record<string, unknown>,\n );\n\n syncRow('spores', row);\n\n return row;\n}\n\n/**\n * Retrieve a single spore by id.\n *\n * @returns the spore row, or null if not found.\n */\nexport function getSpore(id: string): SporeRow | null {\n const db = getDatabase();\n\n const row = db.prepare(\n `SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`,\n ).get(id) as Record<string, unknown> | undefined;\n\n if (!row) return null;\n return toSporeRow(row);\n}\n\n/**\n * List spores with optional filters, ordered by created_at DESC.\n */\n/** Build WHERE clause and bound params from spore filter options. */\nfunction buildSporeWhere(\n options: Omit<ListSporesOptions, 'limit' | 'offset'>,\n): { where: string; params: unknown[] } {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent_id !== undefined) {\n conditions.push(`agent_id = ?`);\n params.push(options.agent_id);\n }\n if (options.observation_type !== undefined) {\n conditions.push(`observation_type = ?`);\n params.push(options.observation_type);\n }\n if (options.status !== undefined) {\n conditions.push(`status = ?`);\n params.push(options.status);\n }\n if (options.session_id !== undefined) {\n conditions.push(`session_id = ?`);\n params.push(options.session_id);\n }\n if (options.search !== undefined && options.search.length > 0) {\n conditions.push(`(content LIKE ? OR observation_type LIKE ?)`);\n const pattern = `%${options.search}%`;\n params.push(pattern, pattern);\n }\n\n return {\n where: conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '',\n params,\n };\n}\n\n/**\n * List spores with optional filters, ordered by created_at DESC.\n */\nexport function listSpores(\n options: ListSporesOptions = {},\n): SporeRow[] {\n const db = getDatabase();\n const { where, params } = buildSporeWhere(options);\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n const offset = options.offset ?? 0;\n\n const rows = db.prepare(\n `SELECT ${SELECT_COLUMNS}\n FROM spores\n ${where}\n ORDER BY created_at DESC\n LIMIT ?\n OFFSET ?`,\n ).all(...params, limit, offset) as Record<string, unknown>[];\n\n return rows.map(toSporeRow);\n}\n\n/**\n * Count spores matching optional filters (for pagination totals).\n */\nexport function countSpores(\n options: Omit<ListSporesOptions, 'limit' | 'offset'> = {},\n): number {\n const db = getDatabase();\n const { where, params } = buildSporeWhere(options);\n\n const row = db.prepare(\n `SELECT COUNT(*) as count FROM spores ${where}`,\n ).get(...params) as { count: number };\n\n return row.count;\n}\n\n/**\n * Update the status and updated_at timestamp of a spore.\n *\n * @returns the updated row, or null if the spore does not exist.\n */\nexport function updateSporeStatus(\n id: string,\n status: string,\n updatedAt: number,\n): SporeRow | null {\n const db = getDatabase();\n\n const info = db.prepare(\n `UPDATE spores\n SET status = ?, updated_at = ?\n WHERE id = ?`,\n ).run(status, updatedAt, id);\n\n if (info.changes === 0) return null;\n\n const row = toSporeRow(\n db.prepare(`SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`).get(id) as Record<string, unknown>,\n );\n\n syncRow('spores', row);\n\n return row;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
SEARCH_PREVIEW_CHARS,
|
|
7
7
|
SEARCH_RESULTS_DEFAULT_LIMIT
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-76ZO5RGT.js";
|
|
9
9
|
|
|
10
10
|
// src/db/queries/search.ts
|
|
11
11
|
function fullTextSearch(query, options = {}) {
|
|
@@ -159,4 +159,4 @@ export {
|
|
|
159
159
|
fullTextSearch,
|
|
160
160
|
hydrateSearchResults
|
|
161
161
|
};
|
|
162
|
-
//# sourceMappingURL=chunk-
|
|
162
|
+
//# sourceMappingURL=chunk-W6HI4CCS.js.map
|