@goondocks/myco 0.21.0 → 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/bin/myco-run +68 -7
  2. package/dist/{agent-eval-RJSQI5S2.js → agent-eval-2MQKTXX3.js} +7 -6
  3. package/dist/{agent-eval-RJSQI5S2.js.map → agent-eval-2MQKTXX3.js.map} +1 -1
  4. package/dist/{agent-run-2JSYFOKU.js → agent-run-XJBTSVJR.js} +5 -5
  5. package/dist/{agent-tasks-APFJIM2T.js → agent-tasks-7MWBZOC7.js} +5 -5
  6. package/dist/{chunk-75Z7UKDY.js → chunk-4D22KTXY.js} +2 -2
  7. package/dist/{chunk-P66DLD6G.js → chunk-6FBLL7MD.js} +8 -2
  8. package/dist/chunk-6FBLL7MD.js.map +1 -0
  9. package/dist/{chunk-JZS6GZ6T.js → chunk-AUIXX33A.js} +10 -3
  10. package/dist/chunk-AUIXX33A.js.map +1 -0
  11. package/dist/{chunk-F3OEQYLS.js → chunk-DBBO6FHE.js} +33 -30
  12. package/dist/{chunk-F3OEQYLS.js.map → chunk-DBBO6FHE.js.map} +1 -1
  13. package/dist/{chunk-CESKJD44.js → chunk-DMPCC7V6.js} +19 -11
  14. package/dist/chunk-DMPCC7V6.js.map +1 -0
  15. package/dist/{chunk-RL5R4CQU.js → chunk-DTWUHHFI.js} +39 -2
  16. package/dist/{chunk-RL5R4CQU.js.map → chunk-DTWUHHFI.js.map} +1 -1
  17. package/dist/{chunk-XL75KZGI.js → chunk-EKZG2MCD.js} +7 -3
  18. package/dist/chunk-EKZG2MCD.js.map +1 -0
  19. package/dist/{chunk-NGH7U6A3.js → chunk-HCT7RMM2.js} +487 -98
  20. package/dist/chunk-HCT7RMM2.js.map +1 -0
  21. package/dist/{chunk-G6QIBNZM.js → chunk-IMW5TJ3O.js} +7 -6
  22. package/dist/chunk-IMW5TJ3O.js.map +1 -0
  23. package/dist/chunk-LQIPXVDH.js +17 -0
  24. package/dist/chunk-LQIPXVDH.js.map +1 -0
  25. package/dist/{chunk-5ZG4RMUH.js → chunk-N2DGFACQ.js} +2 -2
  26. package/dist/{chunk-VHNRMM4O.js → chunk-OTQH5KZW.js} +87 -37
  27. package/dist/chunk-OTQH5KZW.js.map +1 -0
  28. package/dist/{chunk-6LB7XELY.js → chunk-QATYARI5.js} +15 -13
  29. package/dist/chunk-QATYARI5.js.map +1 -0
  30. package/dist/{chunk-LVIY7P35.js → chunk-QLLBJEM7.js} +5 -1
  31. package/dist/chunk-QLLBJEM7.js.map +1 -0
  32. package/dist/{chunk-DJ3IHNYO.js → chunk-TFRUDNLI.js} +2 -2
  33. package/dist/{chunk-R2JIJBCL.js → chunk-TMAXWERS.js} +87 -4
  34. package/dist/chunk-TMAXWERS.js.map +1 -0
  35. package/dist/chunk-TSM6VESW.js +25 -0
  36. package/dist/chunk-TSM6VESW.js.map +1 -0
  37. package/dist/{chunk-ILJPRYES.js → chunk-USVFEWYL.js} +2 -2
  38. package/dist/{chunk-JR54LTPP.js → chunk-W5L5IHP5.js} +3 -3
  39. package/dist/{chunk-BUTL6IFS.js → chunk-Z55WGA2J.js} +2 -2
  40. package/dist/{chunk-NGROSFOH.js → chunk-Z66IT5KL.js} +14 -9
  41. package/dist/chunk-Z66IT5KL.js.map +1 -0
  42. package/dist/{cli-LNYSTDQM.js → cli-DDHTHU2J.js} +37 -37
  43. package/dist/{client-NWE4TCNO.js → client-PQU53UQU.js} +5 -3
  44. package/dist/{detect-PXNM6TA7.js → detect-7NUD5B5R.js} +2 -2
  45. package/dist/{doctor-TI7EZ3RW.js → doctor-QK6KFY6H.js} +6 -6
  46. package/dist/{executor-F2YU7HXJ.js → executor-FJCMNSXM.js} +11 -10
  47. package/dist/{init-KG3TYVGE.js → init-GQPD6HHX.js} +9 -9
  48. package/dist/{installer-UMH7OJ5A.js → installer-N4UTEACX.js} +2 -2
  49. package/dist/{loader-NAVVZK63.js → loader-UDNUMEDA.js} +3 -2
  50. package/dist/{main-5PRQNEEE.js → main-4HKTZFIM.js} +469 -187
  51. package/dist/main-4HKTZFIM.js.map +1 -0
  52. package/dist/{open-5A27BCSB.js → open-3P3DDAOA.js} +5 -5
  53. package/dist/{post-compact-USAODKPQ.js → post-compact-QA5LME2J.js} +7 -7
  54. package/dist/{post-tool-use-GMMSYBII.js → post-tool-use-QRZMPNYL.js} +6 -6
  55. package/dist/{post-tool-use-failure-NZVSL2PO.js → post-tool-use-failure-XNHIKBZG.js} +7 -7
  56. package/dist/{pre-compact-LZ57DLUS.js → pre-compact-HDV6X5QM.js} +7 -7
  57. package/dist/{registry-M2Z5QBWH.js → registry-F3THYC5M.js} +4 -3
  58. package/dist/{remove-T3KE6C5N.js → remove-USQDLGTJ.js} +7 -7
  59. package/dist/{restart-YWDEVZUJ.js → restart-FQLZE2TW.js} +6 -6
  60. package/dist/{search-GKFDGELR.js → search-5COKV6TD.js} +6 -6
  61. package/dist/{server-AHUR6CWF.js → server-KRMBRW4T.js} +23 -7
  62. package/dist/{server-AHUR6CWF.js.map → server-KRMBRW4T.js.map} +1 -1
  63. package/dist/{session-2ZEPLWW6.js → session-NJCUW3OX.js} +5 -5
  64. package/dist/{session-end-LWJYQAXX.js → session-end-XD27GRYF.js} +6 -6
  65. package/dist/{session-start-WTA6GCOQ.js → session-start-RDTXUSYL.js} +11 -11
  66. package/dist/{setup-llm-E7UU5IO7.js → setup-llm-FYPPJI6W.js} +5 -5
  67. package/dist/src/agent/definitions/tasks/cortex-instructions.yaml +63 -41
  68. package/dist/src/agent/definitions/tasks/skill-evolve.yaml +178 -22
  69. package/dist/src/agent/definitions/tasks/skill-generate.yaml +20 -6
  70. package/dist/src/agent/definitions/tasks/vault-evolve.yaml +65 -55
  71. package/dist/src/cli.js +1 -1
  72. package/dist/src/daemon/main.js +1 -1
  73. package/dist/src/hooks/post-tool-use.js +1 -1
  74. package/dist/src/hooks/session-end.js +1 -1
  75. package/dist/src/hooks/session-start.js +1 -1
  76. package/dist/src/hooks/stop.js +1 -1
  77. package/dist/src/hooks/user-prompt-submit.js +1 -1
  78. package/dist/src/mcp/server.js +1 -1
  79. package/dist/src/symbionts/manifests/opencode.yaml +7 -0
  80. package/dist/src/symbionts/templates/agents-starter.md +1 -1
  81. package/dist/src/symbionts/templates/opencode/plugin.ts +41 -1
  82. package/dist/src/symbionts/templates/pi/plugin.ts +12 -1
  83. package/dist/{stats-DFG6S23S.js → stats-JCLZLA5G.js} +6 -6
  84. package/dist/{stop-WRBTXEVT.js → stop-B7XCXEM5.js} +6 -6
  85. package/dist/{stop-failure-32MGIG2Q.js → stop-failure-R6QZCUOZ.js} +7 -7
  86. package/dist/{subagent-start-VFGHQFVL.js → subagent-start-N7A622F3.js} +7 -7
  87. package/dist/{subagent-stop-663FXG3P.js → subagent-stop-SVOG5MZJ.js} +7 -7
  88. package/dist/{task-completed-ZCQYEFMZ.js → task-completed-3DL5LJXF.js} +7 -7
  89. package/dist/{team-JTI5CDUO.js → team-VJ3M263F.js} +3 -3
  90. package/dist/ui/assets/{index-DGf1h-Ha.js → index-O1kNWlWM.js} +119 -119
  91. package/dist/ui/assets/index-z2Jm8i4A.css +1 -0
  92. package/dist/ui/index.html +2 -2
  93. package/dist/{update-3NBQTG32.js → update-TVXAUJMZ.js} +45 -11
  94. package/dist/update-TVXAUJMZ.js.map +1 -0
  95. package/dist/{user-prompt-submit-ME2TBKOS.js → user-prompt-submit-KYO2VGLB.js} +10 -9
  96. package/dist/user-prompt-submit-KYO2VGLB.js.map +1 -0
  97. package/dist/{version-GQAFBBPX.js → version-LDFEALUJ.js} +2 -2
  98. package/package.json +1 -1
  99. package/skills/myco-rules/SKILL.md +94 -0
  100. package/skills/{rules → myco-rules}/references/rules-bad-example.md +1 -1
  101. package/skills/{rules → myco-rules}/references/rules-good-example.md +1 -1
  102. package/dist/chunk-6LB7XELY.js.map +0 -1
  103. package/dist/chunk-CESKJD44.js.map +0 -1
  104. package/dist/chunk-CUDIZJY7.js +0 -36
  105. package/dist/chunk-CUDIZJY7.js.map +0 -1
  106. package/dist/chunk-G6QIBNZM.js.map +0 -1
  107. package/dist/chunk-JZS6GZ6T.js.map +0 -1
  108. package/dist/chunk-LVIY7P35.js.map +0 -1
  109. package/dist/chunk-NGH7U6A3.js.map +0 -1
  110. package/dist/chunk-NGROSFOH.js.map +0 -1
  111. package/dist/chunk-P66DLD6G.js.map +0 -1
  112. package/dist/chunk-R2JIJBCL.js.map +0 -1
  113. package/dist/chunk-VHNRMM4O.js.map +0 -1
  114. package/dist/chunk-XL75KZGI.js.map +0 -1
  115. package/dist/main-5PRQNEEE.js.map +0 -1
  116. package/dist/ui/assets/index-_OP4ifzH.css +0 -1
  117. package/dist/update-3NBQTG32.js.map +0 -1
  118. package/dist/user-prompt-submit-ME2TBKOS.js.map +0 -1
  119. package/skills/myco-curate/SKILL.md +0 -86
  120. package/skills/rules/SKILL.md +0 -214
  121. /package/dist/{agent-run-2JSYFOKU.js.map → agent-run-XJBTSVJR.js.map} +0 -0
  122. /package/dist/{agent-tasks-APFJIM2T.js.map → agent-tasks-7MWBZOC7.js.map} +0 -0
  123. /package/dist/{chunk-75Z7UKDY.js.map → chunk-4D22KTXY.js.map} +0 -0
  124. /package/dist/{chunk-5ZG4RMUH.js.map → chunk-N2DGFACQ.js.map} +0 -0
  125. /package/dist/{chunk-DJ3IHNYO.js.map → chunk-TFRUDNLI.js.map} +0 -0
  126. /package/dist/{chunk-ILJPRYES.js.map → chunk-USVFEWYL.js.map} +0 -0
  127. /package/dist/{chunk-JR54LTPP.js.map → chunk-W5L5IHP5.js.map} +0 -0
  128. /package/dist/{chunk-BUTL6IFS.js.map → chunk-Z55WGA2J.js.map} +0 -0
  129. /package/dist/{cli-LNYSTDQM.js.map → cli-DDHTHU2J.js.map} +0 -0
  130. /package/dist/{client-NWE4TCNO.js.map → client-PQU53UQU.js.map} +0 -0
  131. /package/dist/{detect-PXNM6TA7.js.map → detect-7NUD5B5R.js.map} +0 -0
  132. /package/dist/{doctor-TI7EZ3RW.js.map → doctor-QK6KFY6H.js.map} +0 -0
  133. /package/dist/{executor-F2YU7HXJ.js.map → executor-FJCMNSXM.js.map} +0 -0
  134. /package/dist/{init-KG3TYVGE.js.map → init-GQPD6HHX.js.map} +0 -0
  135. /package/dist/{installer-UMH7OJ5A.js.map → installer-N4UTEACX.js.map} +0 -0
  136. /package/dist/{loader-NAVVZK63.js.map → loader-UDNUMEDA.js.map} +0 -0
  137. /package/dist/{open-5A27BCSB.js.map → open-3P3DDAOA.js.map} +0 -0
  138. /package/dist/{post-compact-USAODKPQ.js.map → post-compact-QA5LME2J.js.map} +0 -0
  139. /package/dist/{post-tool-use-GMMSYBII.js.map → post-tool-use-QRZMPNYL.js.map} +0 -0
  140. /package/dist/{post-tool-use-failure-NZVSL2PO.js.map → post-tool-use-failure-XNHIKBZG.js.map} +0 -0
  141. /package/dist/{pre-compact-LZ57DLUS.js.map → pre-compact-HDV6X5QM.js.map} +0 -0
  142. /package/dist/{registry-M2Z5QBWH.js.map → registry-F3THYC5M.js.map} +0 -0
  143. /package/dist/{remove-T3KE6C5N.js.map → remove-USQDLGTJ.js.map} +0 -0
  144. /package/dist/{restart-YWDEVZUJ.js.map → restart-FQLZE2TW.js.map} +0 -0
  145. /package/dist/{search-GKFDGELR.js.map → search-5COKV6TD.js.map} +0 -0
  146. /package/dist/{session-2ZEPLWW6.js.map → session-NJCUW3OX.js.map} +0 -0
  147. /package/dist/{session-end-LWJYQAXX.js.map → session-end-XD27GRYF.js.map} +0 -0
  148. /package/dist/{session-start-WTA6GCOQ.js.map → session-start-RDTXUSYL.js.map} +0 -0
  149. /package/dist/{setup-llm-E7UU5IO7.js.map → setup-llm-FYPPJI6W.js.map} +0 -0
  150. /package/dist/{stats-DFG6S23S.js.map → stats-JCLZLA5G.js.map} +0 -0
  151. /package/dist/{stop-WRBTXEVT.js.map → stop-B7XCXEM5.js.map} +0 -0
  152. /package/dist/{stop-failure-32MGIG2Q.js.map → stop-failure-R6QZCUOZ.js.map} +0 -0
  153. /package/dist/{subagent-start-VFGHQFVL.js.map → subagent-start-N7A622F3.js.map} +0 -0
  154. /package/dist/{subagent-stop-663FXG3P.js.map → subagent-stop-SVOG5MZJ.js.map} +0 -0
  155. /package/dist/{task-completed-ZCQYEFMZ.js.map → task-completed-3DL5LJXF.js.map} +0 -0
  156. /package/dist/{team-JTI5CDUO.js.map → team-VJ3M263F.js.map} +0 -0
  157. /package/dist/{version-GQAFBBPX.js.map → version-LDFEALUJ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/symbionts/manifest-schema.ts","../src/symbionts/detect.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Declarative capture rules owned per-symbiont in its YAML manifest.\n *\n * Rules let each symbiont describe how Myco should filter or rewrite\n * captured events *without* adding symbiont-specific branches inside\n * the generic hook handlers. The hook loads the rules, a generic\n * evaluator decides the action, and the hook acts on the result.\n *\n * Condition types (in `when`):\n * - `transcript_path_missing`: structural. Fires when the hook's\n * transcript_path field is absent/empty. A legitimate user-facing\n * session records a transcript; an ephemeral sub-invocation (e.g.,\n * an agent's internal title-generation call) does not. Preferred\n * over text matching because it doesn't drift as UIs evolve.\n * - `transcript_meta_field_equals`: structural. Fires when a dot-path\n * field in the transcript's first JSON line equals a specific scalar\n * value (for example, `source = \"exec\"`). Use for source-kind or mode\n * filters that are stable in transcript metadata but not represented\n * by field presence alone.\n * - `prompt_starts_with` / `prompt_contains`: text fallback. Use\n * when no structural signal is available. Document the upgrade path\n * in the YAML so future maintainers can replace it when a better\n * signal appears.\n *\n * Scope semantics:\n * - `this_agent` (default): rule fires only when the detected agent\n * matches the manifest that owns the rule. Use for behavior that\n * is specific to the symbiont and can rely on detection working.\n * - `any_agent`: rule fires regardless of detected agent. Use for\n * patterns where detection itself might fail — e.g., an internal\n * sub-invocation that omits the fields agent detection keys on.\n *\n * Events:\n * - `session_start`: fires on SessionStart, before any prompts or\n * tools are captured. The same rules are also reusable at later\n * lifecycle boundaries that could still materialize a session row\n * (for example, transcript-backed stop processing after a missed\n * SessionStart). This is the durable \"session capture rules\"\n * contract for every symbiont.\n * - `user_prompt`: fires on UserPromptSubmit. Safety net for anything\n * that slips past session_start, and the only layer where\n * `rewrite_prompt` makes sense (prompt text doesn't exist until\n * the prompt is submitted).\n *\n * Actions:\n * - `drop`: discard the event entirely. For session_start, the hook\n * skips registering the session row. For user_prompt, the hook\n * skips posting the event and cascade-deletes any session row that\n * may have been registered before the drop rule could fire.\n * - `rewrite_prompt`: replace the captured prompt with the substring\n * after `extract_after`. Only valid for `user_prompt` events.\n */\nconst CaptureRuleSchema = z.object({\n event: z.enum(['session_start', 'user_prompt']),\n scope: z.enum(['this_agent', 'any_agent']).default('this_agent'),\n when: z.object({\n prompt_starts_with: z.string().optional(),\n prompt_contains: z.string().optional(),\n /** Structural: fires when transcript_path is absent or empty. */\n transcript_path_missing: z.boolean().optional(),\n /**\n * Structural: fires when a dot-path field exists (and is truthy) in the\n * transcript's first JSON line (session_meta). Use for detecting sub-agent\n * sessions that have real transcript files but are not user-initiated.\n *\n * Example: `source.subagent` matches a Codex thread-spawn session whose\n * session_meta has `\"source\": {\"subagent\": {...}}` but would NOT match\n * a user session with `\"source\": \"vscode\"`.\n *\n * The hook handler reads the transcript and passes the parsed meta to\n * the evaluator — the evaluator itself does no file I/O.\n */\n transcript_meta_field_exists: z.string().optional(),\n /**\n * Structural: fires when a dot-path field in session_meta exactly equals\n * a scalar value (string / number / boolean / null). Use for stable\n * source-kind markers like `source = \"exec\"`.\n */\n transcript_meta_field_equals: z.object({\n path: z.string(),\n value: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n }).optional(),\n }),\n action: z.enum(['drop', 'rewrite_prompt']),\n /** Short audit string logged when the rule matches (e.g., \"codex-internal-title-gen\"). */\n reason: z.string().optional(),\n /** For rewrite_prompt: keep only the substring after this marker (first occurrence). */\n extract_after: z.string().optional(),\n /** For rewrite_prompt: trim whitespace from the extracted substring. Default true. */\n trim: z.boolean().default(true),\n});\n\nexport type CaptureRule = z.infer<typeof CaptureRuleSchema>;\n\nconst CaptureManifestSchema = z.object({\n planDirs: z.array(z.string()).default([]),\n planTags: z.array(z.string()).default([]),\n rules: z.array(CaptureRuleSchema).default([]),\n});\n\nconst RegistrationSchema = z.object({\n hooksTarget: z.string().optional(),\n /**\n * Format of the hooks target.\n * - 'json' (default): hooks template is merged into a JSON settings file.\n * - 'plugin-file': the hooks template is a verbatim file (e.g., an opencode TS plugin)\n * copied to hooksTarget without JSON parsing. Used for agents with plugin-based hook\n * systems rather than JSON hook entries.\n */\n hooksFormat: z.enum(['json', 'plugin-file']).default('json'),\n /**\n * Optional file path for a plugin deps package.json. When set, the installer writes\n * a package.json declaring the plugin SDK dependency so the agent's package manager\n * (e.g., opencode's Bun) can install it at startup. Preserved on uninstall so\n * contributors can keep their own deps.\n */\n pluginPackageTarget: z.string().optional(),\n mcpTarget: z.string().optional(),\n mcpFormat: z.enum(['json', 'toml']).default('json'),\n /**\n * Optional working directory injected into the Myco MCP server entry. Values\n * may use `{projectRoot}` and `{vaultDir}` placeholders, or remain relative\n * (for example `.` in a project-local config file) when the host agent\n * resolves paths against the config file location.\n */\n mcpCwd: z.string().optional(),\n /**\n * Optional env vars injected into the Myco MCP server entry. Values may use\n * `{projectRoot}` and `{vaultDir}` placeholders so symbionts whose MCP child\n * starts outside the repo can still anchor Myco to the correct project.\n */\n mcpEnv: z.record(z.string(), z.string()).default({}),\n /**\n * JSON key under which MCP server entries are stored in the MCP config file.\n * Defaults to 'mcpServers' (used by Claude Code, Cursor, etc.). opencode uses 'mcp'.\n */\n mcpServersKey: z.string().default('mcpServers'),\n skillsTarget: z.string().optional(),\n settingsTarget: z.string().optional(),\n /** Format of the settings file. TOML-format agents (e.g., Codex) emit top-level template keys as TOML sections. */\n settingsFormat: z.enum(['json', 'toml']).default('json'),\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"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/client.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { DAEMON_CLIENT_TIMEOUT_MS, DAEMON_HEALTH_CHECK_TIMEOUT_MS, DAEMON_HEALTH_RETRY_DELAYS, DAEMON_STALE_GRACE_PERIOD_MS } from '../constants.js';\nimport { getPluginVersion } from '../version.js';\n\ninterface DaemonInfo {\n pid: number;\n port: number;\n}\n\n/**\n * Resolve the CLI entry point for spawning daemon processes.\n * Uses process.argv[1] so the daemon restarts from the same binary\n * (myco-dev vs global myco) that launched the current process.\n */\nexport function resolveCliEntryPath(): { execPath: string; cliEntry: string } {\n return { execPath: process.execPath, cliEntry: process.argv[1] };\n}\n\ninterface HealthResponse {\n myco: boolean;\n version?: string;\n}\n\ninterface ClientResult {\n ok: boolean;\n data?: any;\n}\n\n/**\n * Attempt to parse a non-ok response body as JSON so callers can surface\n * the daemon's structured error envelope (e.g. `{error: {code, message}}`).\n * Returns `undefined` if the body is empty, not JSON, or otherwise fails to\n * parse — callers that ignore `data` on failure still work unchanged.\n */\nasync function parseErrorBody(res: Response): Promise<unknown> {\n try {\n return await res.json();\n } catch {\n return undefined;\n }\n}\n\nexport class DaemonClient {\n private vaultDir: string;\n\n constructor(vaultDir: string) {\n this.vaultDir = vaultDir;\n }\n\n async post(endpoint: string, body: unknown): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false, data: await parseErrorBody(res) };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async put(endpoint: string, body: unknown): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false, data: await parseErrorBody(res) };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async get(endpoint: string): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false, data: await parseErrorBody(res) };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async delete(endpoint: string, body?: unknown): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const init: RequestInit = {\n method: 'DELETE',\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n };\n if (body !== undefined) {\n init.headers = { 'Content-Type': 'application/json' };\n init.body = JSON.stringify(body);\n }\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, init);\n\n if (!res.ok) return { ok: false, data: await parseErrorBody(res) };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async isHealthy(cachedInfo?: DaemonInfo | null): Promise<boolean> {\n try {\n const info = cachedInfo ?? this.readDaemonJson();\n if (!info) return false;\n\n const res = await fetch(`http://127.0.0.1:${info.port}/health`, {\n signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS),\n });\n if (!res.ok) return false;\n const data = await res.json() as HealthResponse;\n return data.myco === true;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if the daemon is running a stale version.\n * Returns true if the daemon's version doesn't match the current plugin version.\n * Skips the check if daemon.json was written recently (grace period) to prevent\n * rapid restart loops from concurrent hooks or session reloads.\n */\n private async isStale(info: DaemonInfo): Promise<boolean> {\n try {\n const jsonPath = path.join(this.vaultDir, 'daemon.json');\n const stat = fs.statSync(jsonPath);\n if (Date.now() - stat.mtimeMs < DAEMON_STALE_GRACE_PERIOD_MS) {\n return false;\n }\n\n const res = await fetch(`http://127.0.0.1:${info.port}/health`, {\n signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS),\n });\n if (!res.ok) return false;\n const data = await res.json() as HealthResponse;\n if (!data.myco) return false;\n\n // No version in response = old daemon that predates this check\n if (!data.version) return true;\n\n return data.version !== getPluginVersion();\n } catch {\n return false;\n }\n }\n\n /**\n * Kill the running daemon process.\n */\n private killDaemon(info: DaemonInfo | null): void {\n try {\n if (!info) return;\n process.kill(info.pid, 'SIGTERM');\n } catch { /* already dead */ }\n try {\n fs.unlinkSync(path.join(this.vaultDir, 'daemon.json'));\n } catch { /* already gone */ }\n }\n\n /**\n * Ensure the daemon is running. Spawns it if unhealthy.\n * When checkStale is true (default), also restarts a healthy daemon if its\n * version doesn't match the current plugin version. Use checkStale: false\n * for hooks that just need the daemon alive (e.g., stop) without triggering\n * version-driven restarts.\n */\n async ensureRunning(opts?: { checkStale?: boolean }): Promise<boolean> {\n const checkStale = opts?.checkStale ?? true;\n const info = this.readDaemonJson();\n\n if (checkStale && info && await this.isStale(info)) {\n this.killDaemon(info);\n // Brief pause for port release\n await new Promise((r) => setTimeout(r, 200));\n } else if (await this.isHealthy(info)) {\n return true;\n }\n\n this.spawnDaemon();\n\n for (const delay of DAEMON_HEALTH_RETRY_DELAYS) {\n await new Promise((r) => setTimeout(r, delay));\n if (await this.isHealthy()) return true;\n }\n return false;\n }\n\n spawnDaemon(): void {\n const { execPath, cliEntry } = resolveCliEntryPath();\n const child = spawn(execPath, [cliEntry, 'daemon', '--vault', this.vaultDir], {\n detached: true,\n stdio: 'ignore',\n });\n child.unref();\n }\n\n private readDaemonJson(): DaemonInfo | null {\n try {\n const jsonPath = path.join(this.vaultDir, 'daemon.json');\n const content = fs.readFileSync(jsonPath, 'utf-8');\n const info = JSON.parse(content);\n if (typeof info.port !== 'number') return null;\n return info as DaemonInfo;\n } catch {\n return null;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,aAAa;AAcf,SAAS,sBAA8D;AAC5E,SAAO,EAAE,UAAU,QAAQ,UAAU,UAAU,QAAQ,KAAK,CAAC,EAAE;AACjE;AAkBA,eAAe,eAAe,KAAiC;AAC7D,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EAER,YAAY,UAAkB;AAC5B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,KAAK,UAAkB,MAAsC;AACjE,QAAI;AACF,YAAM,OAAO,KAAK,eAAe;AACjC,UAAI,CAAC,KAAM,QAAO,EAAE,IAAI,MAAM;AAE9B,YAAM,MAAM,MAAM,MAAM,oBAAoB,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,QAClE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,QACzB,QAAQ,YAAY,QAAQ,wBAAwB;AAAA,MACtD,CAAC;AAED,UAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,MAAM,MAAM,eAAe,GAAG,EAAE;AACjE,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,EAAE,IAAI,MAAM,KAAK;AAAA,IAC1B,QAAQ;AACN,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,UAAkB,MAAsC;AAChE,QAAI;AACF,YAAM,OAAO,KAAK,eAAe;AACjC,UAAI,CAAC,KAAM,QAAO,EAAE,IAAI,MAAM;AAE9B,YAAM,MAAM,MAAM,MAAM,oBAAoB,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,QAClE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,QACzB,QAAQ,YAAY,QAAQ,wBAAwB;AAAA,MACtD,CAAC;AAED,UAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,MAAM,MAAM,eAAe,GAAG,EAAE;AACjE,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,EAAE,IAAI,MAAM,KAAK;AAAA,IAC1B,QAAQ;AACN,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,UAAyC;AACjD,QAAI;AACF,YAAM,OAAO,KAAK,eAAe;AACjC,UAAI,CAAC,KAAM,QAAO,EAAE,IAAI,MAAM;AAE9B,YAAM,MAAM,MAAM,MAAM,oBAAoB,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,QAClE,QAAQ,YAAY,QAAQ,wBAAwB;AAAA,MACtD,CAAC;AAED,UAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,MAAM,MAAM,eAAe,GAAG,EAAE;AACjE,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,EAAE,IAAI,MAAM,KAAK;AAAA,IAC1B,QAAQ;AACN,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,UAAkB,MAAuC;AACpE,QAAI;AACF,YAAM,OAAO,KAAK,eAAe;AACjC,UAAI,CAAC,KAAM,QAAO,EAAE,IAAI,MAAM;AAE9B,YAAM,OAAoB;AAAA,QACxB,QAAQ;AAAA,QACR,QAAQ,YAAY,QAAQ,wBAAwB;AAAA,MACtD;AACA,UAAI,SAAS,QAAW;AACtB,aAAK,UAAU,EAAE,gBAAgB,mBAAmB;AACpD,aAAK,OAAO,KAAK,UAAU,IAAI;AAAA,MACjC;AAEA,YAAM,MAAM,MAAM,MAAM,oBAAoB,KAAK,IAAI,GAAG,QAAQ,IAAI,IAAI;AAExE,UAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,MAAM,MAAM,eAAe,GAAG,EAAE;AACjE,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,EAAE,IAAI,MAAM,KAAK;AAAA,IAC1B,QAAQ;AACN,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,YAAkD;AAChE,QAAI;AACF,YAAM,OAAO,cAAc,KAAK,eAAe;AAC/C,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,MAAM,MAAM,MAAM,oBAAoB,KAAK,IAAI,WAAW;AAAA,QAC9D,QAAQ,YAAY,QAAQ,8BAA8B;AAAA,MAC5D,CAAC;AACD,UAAI,CAAC,IAAI,GAAI,QAAO;AACpB,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO,KAAK,SAAS;AAAA,IACvB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,QAAQ,MAAoC;AACxD,QAAI;AACF,YAAM,WAAW,KAAK,KAAK,KAAK,UAAU,aAAa;AACvD,YAAM,OAAO,GAAG,SAAS,QAAQ;AACjC,UAAI,KAAK,IAAI,IAAI,KAAK,UAAU,8BAA8B;AAC5D,eAAO;AAAA,MACT;AAEA,YAAM,MAAM,MAAM,MAAM,oBAAoB,KAAK,IAAI,WAAW;AAAA,QAC9D,QAAQ,YAAY,QAAQ,8BAA8B;AAAA,MAC5D,CAAC;AACD,UAAI,CAAC,IAAI,GAAI,QAAO;AACpB,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,CAAC,KAAK,KAAM,QAAO;AAGvB,UAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,aAAO,KAAK,YAAY,iBAAiB;AAAA,IAC3C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,MAA+B;AAChD,QAAI;AACF,UAAI,CAAC,KAAM;AACX,cAAQ,KAAK,KAAK,KAAK,SAAS;AAAA,IAClC,QAAQ;AAAA,IAAqB;AAC7B,QAAI;AACF,SAAG,WAAW,KAAK,KAAK,KAAK,UAAU,aAAa,CAAC;AAAA,IACvD,QAAQ;AAAA,IAAqB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,cAAc,MAAmD;AACrE,UAAM,aAAa,MAAM,cAAc;AACvC,UAAM,OAAO,KAAK,eAAe;AAEjC,QAAI,cAAc,QAAQ,MAAM,KAAK,QAAQ,IAAI,GAAG;AAClD,WAAK,WAAW,IAAI;AAEpB,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAAA,IAC7C,WAAW,MAAM,KAAK,UAAU,IAAI,GAAG;AACrC,aAAO;AAAA,IACT;AAEA,SAAK,YAAY;AAEjB,eAAW,SAAS,4BAA4B;AAC9C,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAC7C,UAAI,MAAM,KAAK,UAAU,EAAG,QAAO;AAAA,IACrC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,cAAoB;AAClB,UAAM,EAAE,UAAU,SAAS,IAAI,oBAAoB;AACnD,UAAM,QAAQ,MAAM,UAAU,CAAC,UAAU,UAAU,WAAW,KAAK,QAAQ,GAAG;AAAA,MAC5E,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AACD,UAAM,MAAM;AAAA,EACd;AAAA,EAEQ,iBAAoC;AAC1C,QAAI;AACF,YAAM,WAAW,KAAK,KAAK,KAAK,UAAU,aAAa;AACvD,YAAM,UAAU,GAAG,aAAa,UAAU,OAAO;AACjD,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,UAAI,OAAO,KAAK,SAAS,SAAU,QAAO;AAC1C,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../myco-team/src/cli.ts","../src/config/secrets.ts","../../myco-deploy/src/cloudflare.ts","../../myco-deploy/src/local-config.ts"],"sourcesContent":["/**\n * CLI team commands — provision and manage Cloudflare team sync infrastructure.\n *\n * `myco team init` — Provision D1 database, Vectorize index, deploy worker.\n * `myco team upgrade` — Redeploy worker with updated source.\n */\n\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { CONFIG_FILENAME, loadConfig, updateTeamConfig } from '@myco/config/loader.js';\nimport { writeSecret, readSecrets } from '@myco/config/secrets.js';\nimport { WRANGLER_COMMAND_TIMEOUT_MS, TEAM_API_KEY_SECRET, TEAM_MCP_TOKEN_SECRET } from '@myco/constants.js';\nimport { SCHEMA_VERSION } from '@myco/db/schema.js';\nimport {\n extractJsonArray,\n installDeploymentDeps,\n maskSecret,\n parseD1Id,\n parseKvNamespaceId,\n parseWorkerUrl,\n readJsonConfig,\n resolveHomeConfigPath,\n resolveVaultConfigPath,\n runWrangler,\n stageDeploymentDir,\n writeJsonConfig,\n} from '@myco-deploy/index.js';\n\ndeclare const __MYCO_TEAM_VERSION__: string;\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Number of random bytes for API key generation. */\nconst API_KEY_BYTES = 32;\n\n/** Vectorize index dimensions (must match the embedding model). */\nconst VECTORIZE_DIMENSIONS = '1024';\n\n/** Vectorize distance metric. */\nconst VECTORIZE_METRIC = 'cosine';\n\n/** Prefix for team resource names. */\nconst TEAM_RESOURCE_PREFIX = 'myco-team';\n\n/** Length of the project hash suffix for unique resource naming. */\nconst PROJECT_HASH_LENGTH = 8;\n\n\n/** Source directory for worker files (relative to package root). */\nconst WORKER_SOURCE_DIR = 'worker';\n\n/** Team sync state directory within the vault. */\nconst TEAM_STATE_DIR = 'team';\nconst TEAM_DEPLOY_DIR = 'worker';\nconst TEAM_CONFIG_FILE = 'config.json';\nconst LEGACY_TEAM_CONFIG_DIR = '.myco-team';\nconst LEGACY_TEAM_DEPLOY_DIR = '.team-worker';\nconst TEAM_CONFIG_VERSION = 1;\nconst TEAM_MCP_ROTATION_RETRY_ATTEMPTS = 10;\nconst TEAM_MCP_ROTATION_RETRY_DELAY_MS = 1500;\n\n/** Regex to match wrangler.toml name field. */\nconst TOML_NAME_REGEX = /^name\\s*=\\s*\"[^\"]*\"/m;\n\n/** Regex to match wrangler.toml D1 placeholder. */\nconst TOML_D1_PLACEHOLDER_REGEX = /<YOUR_D1_DATABASE_ID>/g;\n\n/** Regex to match wrangler.toml database_name field. */\nconst TOML_DB_NAME_REGEX = /database_name\\s*=\\s*\"[^\"]*\"/g;\n\n/** Regex to match wrangler.toml index_name field. */\nconst TOML_INDEX_NAME_REGEX = /index_name\\s*=\\s*\"[^\"]*\"/g;\n\n/** Regex to match wrangler.toml team package version placeholder. */\nconst TOML_TEAM_PACKAGE_VERSION_REGEX = /MYCO_TEAM_PACKAGE_VERSION\\s*=\\s*\"[^\"]*\"/g;\n\n/** Regex to match wrangler.toml Myco schema version placeholder. */\nconst TOML_MYCO_SCHEMA_VERSION_REGEX = /MYCO_SCHEMA_VERSION\\s*=\\s*\"[^\"]*\"/g;\n\n/** Regex to match database_id in existing wrangler.toml. */\nconst TOML_DB_ID_REGEX = /database_id\\s*=\\s*\"([^\"]+)\"/;\n\n/** Regex to match wrangler.toml KV namespace placeholder. */\nconst TOML_KV_PLACEHOLDER_REGEX = /<YOUR_KV_NAMESPACE_ID>/g;\n\n/** Regex to extract the KV namespace ID from an existing wrangler.toml. */\nconst TOML_KV_ID_REGEX = /\\[\\[kv_namespaces\\]\\][\\s\\S]*?id\\s*=\\s*\"([0-9a-f]+)\"/;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Generate a project hash from vault dir for unique resource naming. */\nfunction projectHash(vaultDir: string): string {\n const hash = crypto.createHash('sha256').update(vaultDir).digest('hex');\n return hash.slice(0, PROJECT_HASH_LENGTH);\n}\n\n/** Build the unique resource name for this project's team infrastructure. */\nfunction resourceName(vaultDir: string): string {\n return `${TEAM_RESOURCE_PREFIX}-${projectHash(vaultDir)}`;\n}\n\nfunction resolvePackageRoot(): string {\n const override = process.env.MYCO_TEAM_PACKAGE_ROOT?.trim();\n if (override) return override;\n return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');\n}\n\nexport function getTeamPackageVersion(): string {\n if (typeof __MYCO_TEAM_VERSION__ !== 'undefined') {\n return __MYCO_TEAM_VERSION__;\n }\n\n const packageRoot = resolvePackageRoot();\n const candidatePaths = [\n path.join(packageRoot, 'package.json'),\n path.join(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'), 'package.json'),\n ];\n\n for (const candidatePath of candidatePaths) {\n if (!fs.existsSync(candidatePath)) continue;\n const packageJson = JSON.parse(fs.readFileSync(candidatePath, 'utf-8')) as { version?: string };\n if (packageJson.version) return packageJson.version;\n }\n\n return '0.1.0';\n}\n\nfunction getMycoSchemaVersion(): string {\n return String(SCHEMA_VERSION);\n}\n\nexport interface TeamLocalConfig {\n worker_name: string;\n worker_url: string;\n package_version: string;\n created_at: string;\n last_upgraded: string;\n config_version: number;\n}\n\ninterface LegacyTeamLocalConfig extends TeamLocalConfig {\n api_key?: string;\n mcp_token?: string | null;\n vault_dir?: string;\n}\n\nfunction resolveLocalConfigPath(vaultDir: string): string {\n return resolveVaultConfigPath(vaultDir, TEAM_STATE_DIR, TEAM_CONFIG_FILE);\n}\n\nfunction resolveLegacyLocalConfigPath(): string {\n return resolveHomeConfigPath(LEGACY_TEAM_CONFIG_DIR, TEAM_CONFIG_FILE);\n}\n\nfunction resolveDeployDir(vaultDir: string): string {\n return path.join(vaultDir, TEAM_STATE_DIR, TEAM_DEPLOY_DIR);\n}\n\nfunction resolveLegacyDeployDir(vaultDir: string): string {\n return path.join(vaultDir, LEGACY_TEAM_DEPLOY_DIR);\n}\n\nfunction writeLocalConfig(vaultDir: string, config: TeamLocalConfig): void {\n writeJsonConfig(resolveLocalConfigPath(vaultDir), config);\n}\n\nfunction migrateLegacyDeployDir(vaultDir: string): void {\n const legacyDeployDir = resolveLegacyDeployDir(vaultDir);\n const nextDeployDir = resolveDeployDir(vaultDir);\n if (!fs.existsSync(legacyDeployDir) || fs.existsSync(nextDeployDir)) return;\n\n fs.mkdirSync(path.dirname(nextDeployDir), { recursive: true });\n fs.renameSync(legacyDeployDir, nextDeployDir);\n}\n\nfunction readLocalConfig(vaultDir: string): TeamLocalConfig | null {\n const config = readJsonConfig<TeamLocalConfig>(resolveLocalConfigPath(vaultDir));\n if (config) {\n migrateLegacyDeployDir(vaultDir);\n return config;\n }\n\n const legacyConfig = readJsonConfig<LegacyTeamLocalConfig>(resolveLegacyLocalConfigPath());\n if (!legacyConfig) return null;\n if (legacyConfig.vault_dir && legacyConfig.vault_dir !== vaultDir) return null;\n\n const migrated: TeamLocalConfig = {\n worker_name: legacyConfig.worker_name,\n worker_url: legacyConfig.worker_url,\n package_version: legacyConfig.package_version,\n created_at: legacyConfig.created_at,\n last_upgraded: legacyConfig.last_upgraded,\n config_version: legacyConfig.config_version ?? TEAM_CONFIG_VERSION,\n };\n writeLocalConfig(vaultDir, migrated);\n if (legacyConfig.api_key) writeSecret(vaultDir, TEAM_API_KEY_SECRET, legacyConfig.api_key);\n if (legacyConfig.mcp_token) writeSecret(vaultDir, TEAM_MCP_TOKEN_SECRET, legacyConfig.mcp_token);\n migrateLegacyDeployDir(vaultDir);\n return migrated;\n}\n\nfunction requireLocalConfig(vaultDir: string): TeamLocalConfig {\n const config = readLocalConfig(vaultDir);\n if (config) return config;\n\n console.error(`No local myco-team config found at ${resolveLocalConfigPath(vaultDir)}`);\n process.exit(1);\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function rotateMcpTokenWithRetry(workerUrl: string, apiKey: string): Promise<string> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= TEAM_MCP_ROTATION_RETRY_ATTEMPTS; attempt += 1) {\n try {\n return await rotateMcpTokenForWorker(workerUrl, apiKey);\n } catch (error) {\n lastError = error as Error;\n const isRetryable =\n lastError.message.includes('401') &&\n lastError.message.includes('Invalid API key') &&\n attempt < TEAM_MCP_ROTATION_RETRY_ATTEMPTS;\n if (!isRetryable) {\n throw lastError;\n }\n await delay(TEAM_MCP_ROTATION_RETRY_DELAY_MS);\n }\n }\n\n throw lastError ?? new Error('MCP token rotation failed');\n}\n\n/** Run a wrangler command and return stdout. Throws on failure, surfacing stderr. */\nfunction wrangler(args: string[], options?: { cwd?: string }): string {\n return runWrangler(args, { cwd: options?.cwd, timeoutMs: WRANGLER_COMMAND_TIMEOUT_MS });\n}\n\n/** Find the worker source directory. Checks dist layout first (installed), then source layout (dev). */\nfunction locateWorkerSource(): string {\n const root = resolvePackageRoot();\n const distPath = path.join(root, 'dist', WORKER_SOURCE_DIR);\n if (fs.existsSync(distPath)) return distPath;\n const srcPath = path.join(root, WORKER_SOURCE_DIR);\n if (fs.existsSync(srcPath)) return srcPath;\n throw new Error(`Cannot find ${WORKER_SOURCE_DIR} — are you running from the myco-team package?`);\n}\n\n/**\n * Copy worker source to the vault deployment directory and patch wrangler.toml\n * with actual D1 database ID and resource names.\n */\nfunction prepareDeployDir(vaultDir: string, d1Id: string, kvId: string): string {\n const srcDir = locateWorkerSource();\n const deployDir = resolveDeployDir(vaultDir);\n const name = resourceName(vaultDir);\n return stageDeploymentDir({\n sourceDir: srcDir,\n deployDir,\n reset: true,\n textPatches: [{\n filePath: 'wrangler.toml',\n transforms: [\n (toml) => toml.replace(TOML_NAME_REGEX, `name = \"${name}\"`),\n (toml) => toml.replace(TOML_D1_PLACEHOLDER_REGEX, d1Id),\n (toml) => toml.replace(TOML_DB_NAME_REGEX, `database_name = \"${name}\"`),\n (toml) => toml.replace(TOML_INDEX_NAME_REGEX, `index_name = \"${name}-vectors\"`),\n (toml) => toml.replace(TOML_KV_PLACEHOLDER_REGEX, kvId),\n (toml) => toml.replace(TOML_TEAM_PACKAGE_VERSION_REGEX, `MYCO_TEAM_PACKAGE_VERSION = \"${getTeamPackageVersion()}\"`),\n (toml) => toml.replace(TOML_MYCO_SCHEMA_VERSION_REGEX, `MYCO_SCHEMA_VERSION = \"${getMycoSchemaVersion()}\"`),\n ],\n }],\n installDepsTimeoutMs: WRANGLER_COMMAND_TIMEOUT_MS * 3,\n });\n}\n\n/** Ensure a KV namespace exists for this project. Returns the namespace ID. */\nfunction ensureKvNamespace(name: string): string {\n const kvName = `${name}-secrets`;\n const lookupExisting = (): string => {\n const listOutput = wrangler(['kv', 'namespace', 'list']);\n const namespaces = extractJsonArray(listOutput) as Array<{ id: string; title: string }>;\n // Wrangler sometimes rewrites hyphens to underscores in titles\n const normalize = (s: string) => s.replace(/[-_]/g, '');\n const target = normalize(kvName);\n const existing = namespaces.find((ns) => normalize(ns.title) === target || normalize(ns.title).endsWith(target));\n if (!existing) throw new Error(`KV namespace \"${kvName}\" not found in list of ${namespaces.length} namespaces`);\n return existing.id;\n };\n\n try {\n const output = wrangler(['kv', 'namespace', 'create', kvName]);\n return parseKvNamespaceId(output);\n // Created successfully but we couldn't parse — fall back to list lookup\n } catch (err) {\n const errMsg = (err as Error).message;\n if (errMsg.includes('already exists') || errMsg.includes('duplicate') || errMsg.includes('same title')) {\n return lookupExisting();\n }\n throw err;\n }\n}\n\nasync function rotateMcpTokenForWorker(workerUrl: string, apiKey: string): Promise<string> {\n const response = await fetch(`${workerUrl}/mcp/rotate`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n });\n if (!response.ok) {\n throw new Error(`MCP token rotation failed: ${response.status} ${await response.text()}`);\n }\n const body = await response.json() as { token?: string };\n if (!body.token) {\n throw new Error('MCP token rotation response did not include a token');\n }\n return body.token;\n}\n\n// ---------------------------------------------------------------------------\n// Commands\n// ---------------------------------------------------------------------------\n\nexport async function teamInit(vaultDir: string): Promise<void> {\n console.log('Provisioning team sync infrastructure...\\n');\n\n // 1. Check for wrangler\n try {\n const version = wrangler(['--version']).trim();\n console.log(`wrangler: ${version}`);\n } catch {\n console.error('Error: wrangler CLI not found. Install it with: npm install -g wrangler');\n process.exit(1);\n }\n\n // 2. Check auth\n try {\n wrangler(['whoami']);\n console.log('Cloudflare auth: OK\\n');\n } catch {\n console.error('Error: Not authenticated with Cloudflare. Run: wrangler login');\n process.exit(1);\n }\n\n const name = resourceName(vaultDir);\n console.log(`Resource name: ${name}\\n`);\n\n // 3. Create D1 database (or reuse existing)\n console.log('Creating D1 database...');\n let d1Id: string;\n try {\n const d1Output = wrangler(['d1', 'create', name]);\n d1Id = parseD1Id(d1Output);\n console.log(`D1 database created: ${d1Id}\\n`);\n } catch (err) {\n const errMsg = (err as Error).message;\n if (errMsg.includes('already exists')) {\n console.log('D1 database already exists, looking up ID...');\n const listOutput = wrangler(['d1', 'list', '--json']);\n const databases = JSON.parse(listOutput) as Array<{ name: string; uuid: string }>;\n const existing = databases.find((db) => db.name === name);\n if (!existing) {\n console.error(`D1 database \"${name}\" reported as existing but not found in list`);\n process.exit(1);\n }\n d1Id = existing.uuid;\n console.log(`Reusing D1 database: ${d1Id}\\n`);\n } else {\n console.error(`Failed to create D1 database: ${errMsg}`);\n process.exit(1);\n }\n }\n\n // 4. Create Vectorize index (or reuse existing)\n console.log('Creating Vectorize index...');\n try {\n wrangler(['vectorize', 'create', `${name}-vectors`, '--dimensions', VECTORIZE_DIMENSIONS, '--metric', VECTORIZE_METRIC]);\n console.log('Vectorize index created\\n');\n } catch (err) {\n const errMsg = (err as Error).message;\n if (errMsg.includes('already exists') || errMsg.includes('duplicate_name')) {\n console.log('Vectorize index already exists, reusing\\n');\n } else {\n console.error(`Failed to create Vectorize index: ${errMsg}`);\n process.exit(1);\n }\n }\n\n // 5. Create KV namespace for runtime secrets (MCP tokens)\n console.log('Creating KV namespace for secrets...');\n let kvId: string;\n try {\n kvId = ensureKvNamespace(name);\n console.log(`KV namespace ready: ${kvId}\\n`);\n } catch (err) {\n console.error(`Failed to create KV namespace: ${(err as Error).message}`);\n process.exit(1);\n }\n\n // 6. Generate API key\n const apiKey = crypto.randomBytes(API_KEY_BYTES).toString('hex');\n\n // 7. Prepare deployment directory\n console.log('Preparing worker deployment...');\n const deployDir = prepareDeployDir(vaultDir, d1Id, kvId);\n\n // 7. Set API key secret via wrangler\n console.log('Setting API key secret...');\n try {\n runWrangler(['secret', 'put', TEAM_API_KEY_SECRET, '--name', name], {\n cwd: deployDir,\n input: apiKey,\n timeoutMs: WRANGLER_COMMAND_TIMEOUT_MS,\n });\n console.log('Secret set\\n');\n } catch (err) {\n console.error(`Failed to set API key secret: ${(err as Error).message}`);\n process.exit(1);\n }\n\n // 8. Deploy worker\n console.log('Deploying worker...');\n let workerUrl: string;\n try {\n const deployOutput = wrangler(['deploy'], { cwd: deployDir });\n workerUrl = parseWorkerUrl(deployOutput);\n console.log(`Worker deployed: ${workerUrl}\\n`);\n } catch (err) {\n console.error(`Failed to deploy worker: ${(err as Error).message}`);\n process.exit(1);\n }\n\n // 9. Seed team config in the Worker\n console.log('Setting team configuration...');\n try {\n const { getMachineId } = await import('@myco/daemon/machine-id.js');\n const creatorMachineId = await getMachineId(vaultDir);\n await fetch(`${workerUrl}/config`, {\n method: 'PUT',\n headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n team_name: name,\n embedding_model: '@cf/baai/bge-m3',\n embedding_dimensions: '1024',\n created_at: String(Math.floor(Date.now() / 1000)),\n created_by: creatorMachineId,\n }),\n });\n console.log('Team config saved\\n');\n } catch {\n console.log('Warning: could not seed team config (non-fatal)\\n');\n }\n\n let mcpToken: string | null = null;\n try {\n mcpToken = await rotateMcpTokenForWorker(workerUrl, apiKey);\n } catch {\n // Non-fatal. The daemon can also fetch the token later through /connect.\n }\n\n // 10. Save config and API key locally\n updateTeamConfig(vaultDir, {\n enabled: true,\n worker_url: workerUrl,\n });\n writeSecret(vaultDir, TEAM_API_KEY_SECRET, apiKey);\n if (mcpToken) writeSecret(vaultDir, TEAM_MCP_TOKEN_SECRET, mcpToken);\n writeLocalConfig(vaultDir, {\n worker_name: name,\n worker_url: workerUrl,\n package_version: getTeamPackageVersion(),\n created_at: new Date().toISOString(),\n last_upgraded: new Date().toISOString(),\n config_version: TEAM_CONFIG_VERSION,\n });\n\n console.log('Team sync configured!\\n');\n console.log(` URL: ${workerUrl}`);\n console.log(` API Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`);\n if (mcpToken) {\n console.log(` MCP: ${mcpToken.slice(0, 8)}...${mcpToken.slice(-4)}`);\n }\n console.log('\\nShare the URL and API key with teammates so they can connect.');\n}\n\n// ---------------------------------------------------------------------------\n// Shared upgrade logic (used by CLI and daemon API)\n// ---------------------------------------------------------------------------\n\nexport interface UpgradeResult {\n success: boolean;\n worker_url?: string;\n version?: string;\n error?: string;\n}\n\n/**\n * Upgrade the team sync worker: re-copy source, patch config, redeploy.\n * Returns a result instead of calling process.exit — safe for both CLI and daemon.\n */\nexport function upgradeWorker(vaultDir: string): UpgradeResult {\n const config = loadConfig(vaultDir);\n if (!config.team.worker_url) {\n return { success: false, error: 'No team sync configured. Run: myco team init' };\n }\n\n migrateLegacyDeployDir(vaultDir);\n const deployDir = resolveDeployDir(vaultDir);\n const tomlPath = path.join(deployDir, 'wrangler.toml');\n\n if (!fs.existsSync(tomlPath)) {\n return { success: false, error: 'No deployment directory found. Run: myco team init' };\n }\n\n // Read ALL existing resource identifiers from current wrangler.toml.\n const existingToml = fs.readFileSync(tomlPath, 'utf-8');\n const d1Match = existingToml.match(TOML_DB_ID_REGEX);\n if (!d1Match || d1Match[1] === '<YOUR_D1_DATABASE_ID>') {\n return { success: false, error: 'Cannot determine D1 database ID from existing deployment. Run: myco team init' };\n }\n const d1Id = d1Match[1];\n\n const nameMatch = existingToml.match(/^name\\s*=\\s*\"([^\"]*)\"/m);\n const dbNameMatch = existingToml.match(/database_name\\s*=\\s*\"([^\"]*)\"/);\n const indexNameMatch = existingToml.match(/index_name\\s*=\\s*\"([^\"]*)\"/);\n const workerName = nameMatch?.[1] ?? resourceName(vaultDir);\n\n // KV namespace may not exist on older deployments — create or reuse.\n const kvMatch = existingToml.match(TOML_KV_ID_REGEX);\n let kvId: string;\n if (kvMatch) {\n kvId = kvMatch[1];\n } else {\n try {\n kvId = ensureKvNamespace(workerName);\n } catch (err) {\n return { success: false, error: `Failed to provision KV namespace: ${(err as Error).message}` };\n }\n }\n\n try {\n stageDeploymentDir({\n sourceDir: locateWorkerSource(),\n deployDir,\n textPatches: [{\n filePath: 'wrangler.toml',\n transforms: [\n (toml) => toml.replace(TOML_NAME_REGEX, `name = \"${workerName}\"`),\n (toml) => toml.replace(TOML_D1_PLACEHOLDER_REGEX, d1Id),\n (toml) => toml.replace(TOML_DB_NAME_REGEX, `database_name = \"${dbNameMatch?.[1] ?? workerName}\"`),\n (toml) => toml.replace(TOML_INDEX_NAME_REGEX, `index_name = \"${indexNameMatch?.[1] ?? `${workerName}-vectors`}\"`),\n (toml) => toml.replace(TOML_KV_PLACEHOLDER_REGEX, kvId),\n (toml) => toml.replace(TOML_TEAM_PACKAGE_VERSION_REGEX, `MYCO_TEAM_PACKAGE_VERSION = \"${getTeamPackageVersion()}\"`),\n (toml) => toml.replace(TOML_MYCO_SCHEMA_VERSION_REGEX, `MYCO_SCHEMA_VERSION = \"${getMycoSchemaVersion()}\"`),\n ],\n }],\n installDepsTimeoutMs: WRANGLER_COMMAND_TIMEOUT_MS * 3,\n });\n } catch (err) {\n return { success: false, error: `Failed to install worker dependencies: ${(err as Error).message}` };\n }\n\n // Re-set API key secret before deploy (deploy can wipe secrets)\n const secrets = readSecrets(vaultDir);\n const apiKey = secrets[TEAM_API_KEY_SECRET];\n if (apiKey) {\n try {\n runWrangler(['secret', 'put', TEAM_API_KEY_SECRET, '--name', workerName], {\n cwd: deployDir,\n input: apiKey,\n timeoutMs: WRANGLER_COMMAND_TIMEOUT_MS,\n });\n } catch {\n // Non-fatal — secret may already be set\n }\n }\n\n // Redeploy\n try {\n const deployOutput = wrangler(['deploy'], { cwd: deployDir });\n const workerUrl = parseWorkerUrl(deployOutput);\n const version = getTeamPackageVersion();\n\n updateTeamConfig(vaultDir, {\n worker_url: workerUrl,\n });\n const localConfig = readLocalConfig(vaultDir);\n if (localConfig) {\n writeLocalConfig(vaultDir, {\n ...localConfig,\n worker_name: workerName,\n worker_url: workerUrl,\n package_version: version,\n last_upgraded: new Date().toISOString(),\n });\n }\n\n return { success: true, worker_url: workerUrl, version };\n } catch (err) {\n return { success: false, error: `Failed to deploy worker: ${(err as Error).message}` };\n }\n}\n\n// ---------------------------------------------------------------------------\n// CLI wrapper\n// ---------------------------------------------------------------------------\n\nexport async function teamUpgrade(vaultDir: string): Promise<void> {\n console.log('Upgrading team sync worker...\\n');\n const result = upgradeWorker(vaultDir);\n if (!result.success) {\n console.error(result.error);\n process.exit(1);\n }\n console.log(`Worker deployed: ${result.worker_url}`);\n console.log(`Version: ${result.version}`);\n console.log('\\nUpgrade complete.');\n}\n\nexport async function teamStatus(vaultDir: string): Promise<void> {\n const config = requireLocalConfig(vaultDir);\n const secrets = readSecrets(vaultDir);\n\n console.log(`Worker: ${config.worker_name}`);\n console.log(`URL: ${config.worker_url}`);\n console.log(`API Key: ${maskSecret(secrets[TEAM_API_KEY_SECRET] ?? null)}`);\n console.log(`MCP Token: ${maskSecret(secrets[TEAM_MCP_TOKEN_SECRET] ?? null)}`);\n console.log(`Package v: ${config.package_version}`);\n console.log(`Created: ${config.created_at}`);\n console.log(`Upgraded: ${config.last_upgraded}`);\n console.log(`Config v: ${config.config_version}`);\n}\n\nexport async function teamRotateTokens(vaultDir: string, which: 'api' | 'mcp' | 'all' = 'all'): Promise<void> {\n const config = requireLocalConfig(vaultDir);\n const secrets = readSecrets(vaultDir);\n let currentApiKey = secrets[TEAM_API_KEY_SECRET] ?? '';\n let currentMcpToken = secrets[TEAM_MCP_TOKEN_SECRET] ?? null;\n\n let nextConfig = { ...config };\n\n if (which === 'api' || which === 'all') {\n const apiKey = crypto.randomBytes(API_KEY_BYTES).toString('hex');\n runWrangler(['secret', 'put', TEAM_API_KEY_SECRET, '--name', config.worker_name], {\n cwd: resolveDeployDir(vaultDir),\n input: apiKey,\n timeoutMs: WRANGLER_COMMAND_TIMEOUT_MS,\n });\n writeSecret(vaultDir, TEAM_API_KEY_SECRET, apiKey);\n currentApiKey = apiKey;\n nextConfig = {\n ...nextConfig,\n package_version: getTeamPackageVersion(),\n last_upgraded: new Date().toISOString(),\n };\n writeLocalConfig(vaultDir, nextConfig);\n }\n\n if (which === 'mcp' || which === 'all') {\n try {\n currentMcpToken = await rotateMcpTokenWithRetry(config.worker_url, currentApiKey);\n if (currentMcpToken) writeSecret(vaultDir, TEAM_MCP_TOKEN_SECRET, currentMcpToken);\n } catch (error) {\n writeLocalConfig(vaultDir, {\n ...nextConfig,\n last_upgraded: new Date().toISOString(),\n });\n throw new Error(\n `API key rotation completed, but MCP token rotation failed. Local config was updated to the new API key.\\n${(error as Error).message}`,\n );\n }\n }\n\n nextConfig.last_upgraded = new Date().toISOString();\n writeLocalConfig(vaultDir, nextConfig);\n\n console.log(`API Key: ${maskSecret(currentApiKey)}`);\n console.log(`MCP Token: ${maskSecret(currentMcpToken)}`);\n}\n\nexport async function teamDestroy(vaultDir: string): Promise<void> {\n const config = requireLocalConfig(vaultDir);\n const errors: string[] = [];\n const deployDir = resolveDeployDir(vaultDir);\n\n try {\n wrangler(['delete', config.worker_name], { cwd: deployDir });\n } catch (error) {\n errors.push(`worker delete failed: ${(error as Error).message}`);\n }\n\n try {\n wrangler(['vectorize', 'delete', `${config.worker_name}-vectors`]);\n } catch (error) {\n errors.push(`vectorize delete failed: ${(error as Error).message}`);\n }\n\n try {\n const databases = JSON.parse(wrangler(['d1', 'list', '--json'])) as Array<{ name: string; uuid: string }>;\n const database = databases.find((entry) => entry.name === config.worker_name);\n if (database) {\n wrangler(['d1', 'delete', database.name, '--skip-confirmation']);\n }\n } catch (error) {\n errors.push(`d1 delete failed: ${(error as Error).message}`);\n }\n\n try {\n const namespaces = extractJsonArray(wrangler(['kv', 'namespace', 'list'])) as Array<{ id: string; title: string }>;\n const namespace = namespaces.find((entry) => entry.title === `${config.worker_name}-secrets`);\n if (namespace) {\n wrangler(['kv', 'namespace', 'delete', '--namespace-id', namespace.id, '--skip-confirmation']);\n }\n } catch (error) {\n errors.push(`kv delete failed: ${(error as Error).message}`);\n }\n\n if (errors.length > 0) {\n throw new Error(`Team destroy incomplete. Local state preserved for retry.\\n${errors.join('\\n')}`);\n }\n\n fs.rmSync(path.join(vaultDir, TEAM_STATE_DIR), { recursive: true, force: true });\n console.log(`Destroyed local myco-team state for ${config.worker_name}.`);\n}\n","/**\n * Secrets file utilities for API key storage outside git.\n *\n * Secrets are stored in `secrets.env` inside the vault directory.\n * This file is gitignored (see VAULT_GITIGNORE) and never committed.\n * Format: KEY=value, one per line (same as .env).\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst SECRETS_FILE = 'secrets.env';\n\n/** Read all secrets from <vault>/secrets.env as key-value pairs. */\nexport function readSecrets(vaultDir: string): Record<string, string> {\n const secretsPath = path.join(vaultDir, SECRETS_FILE);\n if (!fs.existsSync(secretsPath)) return {};\n\n const secrets: Record<string, string> = {};\n for (const line of fs.readFileSync(secretsPath, 'utf-8').split('\\n')) {\n const match = line.match(/^\\s*([^#=]+?)\\s*=\\s*(.*?)\\s*$/);\n if (match) {\n secrets[match[1]] = match[2];\n }\n }\n return secrets;\n}\n\n/** Write a secret to <vault>/secrets.env, preserving existing entries. */\nexport function writeSecret(vaultDir: string, key: string, value: string): void {\n const secretsPath = path.join(vaultDir, SECRETS_FILE);\n const existing = readSecrets(vaultDir);\n existing[key] = value;\n\n const content = Object.entries(existing)\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n') + '\\n';\n\n fs.writeFileSync(secretsPath, content, 'utf-8');\n}\n\n/** Remove one or more secrets from <vault>/secrets.env, preserving remaining entries. */\nexport function deleteSecrets(vaultDir: string, keys: string[]): void {\n const secretsPath = path.join(vaultDir, SECRETS_FILE);\n if (!fs.existsSync(secretsPath)) return;\n\n const existing = readSecrets(vaultDir);\n for (const key of keys) delete existing[key];\n\n const entries = Object.entries(existing);\n if (entries.length === 0) {\n fs.rmSync(secretsPath, { force: true });\n return;\n }\n\n const content = entries\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n') + '\\n';\n\n fs.writeFileSync(secretsPath, content, 'utf-8');\n}\n\n/** Load secrets from <vault>/secrets.env into process.env (without overwriting existing vars). */\nexport function loadSecrets(vaultDir: string): void {\n const secrets = readSecrets(vaultDir);\n for (const [key, value] of Object.entries(secrets)) {\n if (!process.env[key]) {\n process.env[key] = value;\n }\n }\n}\n","import { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst WORKER_URL_REGEX = /(https:\\/\\/[^\\s]+\\.workers\\.dev)/;\nconst D1_ID_JSON_REGEX = /\"database_id\"\\s*:\\s*\"([0-9a-f-]{36})\"/i;\nconst D1_ID_TEXT_REGEX = /id:\\s*([0-9a-f-]{36})/i;\nconst KV_ID_REGEX = /\"id\":\\s*\"([0-9a-f]+)\"/i;\n\nexport interface WranglerOptions {\n cwd?: string;\n input?: string;\n timeoutMs: number;\n}\n\nexport interface TextPatch {\n filePath: string;\n transforms: Array<(text: string) => string>;\n}\n\nexport interface StageDeploymentDirOptions {\n sourceDir: string;\n deployDir: string;\n reset?: boolean;\n extraCopies?: Array<{ sourceDir: string; destinationSubdir: string }>;\n textPatches?: TextPatch[];\n installDepsTimeoutMs?: number | null;\n}\n\nexport function buildCommandEnv(): NodeJS.ProcessEnv {\n const nodeBinDir = path.dirname(process.execPath);\n const pathValue = process.env.PATH\n ? `${nodeBinDir}${path.delimiter}${process.env.PATH}`\n : nodeBinDir;\n return { ...process.env, PATH: pathValue };\n}\n\nexport function runWrangler(args: string[], options: WranglerOptions): string {\n try {\n return execFileSync('wrangler', args, {\n cwd: options.cwd,\n env: buildCommandEnv(),\n input: options.input,\n encoding: 'utf-8',\n timeout: options.timeoutMs,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n } catch (error) {\n const execError = error as Error & { stderr?: Buffer | string; stdout?: Buffer | string };\n const stderr = execError.stderr?.toString() ?? '';\n const stdout = execError.stdout?.toString() ?? '';\n const detail = [stderr, stdout].filter(Boolean).join('\\n').trim();\n throw new Error(detail || execError.message);\n }\n}\n\nexport function installDeploymentDeps(deployDir: string, timeoutMs: number): void {\n const packageJsonPath = path.join(deployDir, 'package.json');\n if (!fs.existsSync(packageJsonPath)) return;\n\n execFileSync('npm', ['install', '--silent', '--no-audit', '--no-fund'], {\n cwd: deployDir,\n env: buildCommandEnv(),\n encoding: 'utf-8',\n timeout: timeoutMs,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n}\n\nexport function parseWorkerUrl(output: string): string {\n const workerUrl = output.match(WORKER_URL_REGEX)?.[1];\n if (!workerUrl) {\n throw new Error(`Could not parse worker URL from deploy output:\\n${output}`);\n }\n return workerUrl;\n}\n\nexport function parseD1Id(output: string): string {\n const jsonMatch = output.match(D1_ID_JSON_REGEX);\n if (jsonMatch) return jsonMatch[1];\n\n const textMatch = output.match(D1_ID_TEXT_REGEX);\n if (textMatch) return textMatch[1];\n\n throw new Error(`Could not parse D1 database ID from wrangler output:\\n${output}`);\n}\n\nexport function parseKvNamespaceId(output: string): string {\n const kvId = output.match(KV_ID_REGEX)?.[1];\n if (!kvId) {\n throw new Error(`Could not parse KV namespace ID from wrangler output:\\n${output}`);\n }\n return kvId;\n}\n\nexport function extractJsonArray(output: string): unknown[] {\n const start = output.indexOf('[');\n const end = output.lastIndexOf(']');\n if (start === -1 || end === -1 || end < start) {\n throw new Error(`No JSON array found in output:\\n${output}`);\n }\n return JSON.parse(output.slice(start, end + 1)) as unknown[];\n}\n\nexport function stageDeploymentDir(options: StageDeploymentDirOptions): string {\n if (options.reset) {\n fs.rmSync(options.deployDir, { recursive: true, force: true });\n }\n fs.mkdirSync(options.deployDir, { recursive: true });\n fs.cpSync(options.sourceDir, options.deployDir, { recursive: true });\n\n for (const copy of options.extraCopies ?? []) {\n fs.cpSync(copy.sourceDir, path.join(options.deployDir, copy.destinationSubdir), { recursive: true });\n }\n\n for (const patch of options.textPatches ?? []) {\n const absolutePath = path.join(options.deployDir, patch.filePath);\n let nextText = fs.readFileSync(absolutePath, 'utf-8');\n for (const transform of patch.transforms) {\n nextText = transform(nextText);\n }\n fs.writeFileSync(absolutePath, nextText, 'utf-8');\n }\n\n if (options.installDepsTimeoutMs) {\n installDeploymentDeps(options.deployDir, options.installDepsTimeoutMs);\n }\n\n return options.deployDir;\n}\n","import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nconst MYCO_HOME_OVERRIDE_ENV = 'MYCO_HOME_OVERRIDE';\n\nexport function resolveHomeDir(): string {\n return process.env[MYCO_HOME_OVERRIDE_ENV]?.trim() || os.homedir();\n}\n\nexport function resolveHomeConfigPath(configDir: string, fileName: string): string {\n return path.join(resolveHomeDir(), configDir, fileName);\n}\n\nexport function resolveNamedHomeConfigPath(configDir: string, name: string, fileName: string): string {\n return path.join(resolveHomeDir(), configDir, name, fileName);\n}\n\nexport function resolveVaultConfigPath(vaultDir: string, configDir: string, fileName: string): string {\n return path.join(vaultDir, configDir, fileName);\n}\n\nexport function readJsonConfig<T>(configPath: string): T | null {\n if (!fs.existsSync(configPath)) return null;\n return JSON.parse(fs.readFileSync(configPath, 'utf-8')) as T;\n}\n\nexport function writeJsonConfig(configPath: string, value: unknown): void {\n fs.mkdirSync(path.dirname(configPath), { recursive: true });\n fs.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}\\n`, { encoding: 'utf-8', mode: 0o600 });\n fs.chmodSync(configPath, 0o600);\n}\n\nexport function maskSecret(secret: string | null): string | null {\n if (!secret) return null;\n if (secret.length <= 8) return secret;\n return `${secret.slice(0, 4)}...${secret.slice(-4)}`;\n}\n\nexport function createHexToken(byteLength: number): string {\n return crypto.randomBytes(byteLength).toString('hex');\n}\n"],"mappings":"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","names":["crypto","fs","path","fs","path","fs","path","path","fs","crypto","path","fs","path","fs","crypto"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/symbionts/installer.ts","../src/symbionts/toml-helpers.ts","../src/symbionts/settings-merge.ts","../src/symbionts/json-helpers.ts","../src/symbionts/install-helpers.ts"],"sourcesContent":["import type { SymbiontManifest } from './manifest-schema.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { findTomlSectionEnd, buildTomlMcpSection, upsertTomlSection, removeTomlSectionKeys } from './toml-helpers.js';\nimport { deepMergeSettings, deepRemoveSettings } from './settings-merge.js';\nimport { readJsonFile, writeJsonFile, writeOrDeleteJsonFile } from './json-helpers.js';\nimport { ensureAgentsMd, ensureSymlink, isMycoHookGroup } from './install-helpers.js';\nimport { loadMergedConfig } from '../config/loader.js';\n\n/** Current comment header for Myco-managed .gitignore block. */\nconst GITIGNORE_COMMENT = '# Myco managed (machine-specific)';\n\n/** Legacy comment header — recognized for cleanup during reconciliation. */\nconst GITIGNORE_SKILLS_COMMENT_LEGACY = '# Myco skill symlinks (machine-specific)';\n\n/** Wrangler cache directory created by team sync operations. */\nconst WRANGLER_CACHE_DIR = '.wrangler/';\nconst AGENTS_MANAGED_START = '<!-- myco:managed:start -->';\nconst AGENTS_MANAGED_END = '<!-- myco:managed:end -->';\nconst AGENTS_MANAGED_BLOCK = `${AGENTS_MANAGED_START}\n## Myco Managed Guidance\n\n- When \\`capture.ignore_plan_dirs_in_git\\` is enabled, custom directories in \\`capture.plan_dirs\\` may be intentionally gitignored after capture into Myco.\n- Do not force-add files from intentionally gitignored custom plan directories unless the user explicitly asks.\n${AGENTS_MANAGED_END}\n`;\n\n/** Subdirectory within the package where symbiont templates live. */\nconst TEMPLATES_SUBDIR = 'src/symbionts/templates';\n\n/** Filename of the hook guard template in the templates directory. */\nconst HOOK_GUARD_TEMPLATE_FILENAME = 'myco-run.cjs';\n\n/** Filename when installed into the project .agents/ directory. */\nconst HOOK_GUARD_INSTALLED_FILENAME = 'myco-run.cjs';\n\n/** Project-relative path where the hook guard is installed. */\nconst HOOK_GUARD_PROJECT_PATH = `.agents/${HOOK_GUARD_INSTALLED_FILENAME}`;\n\n/**\n * Legacy guard filename we still delete on install to clean up previous\n * installations that used `.agents/myco-hook.cjs` before the rename.\n */\nconst LEGACY_HOOK_GUARD_PATH = '.agents/myco-hook.cjs';\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';\nconst MCP_ENV_PROJECT_ROOT_TOKEN = '{projectRoot}';\nconst MCP_ENV_VAULT_DIR_TOKEN = '{vaultDir}';\n\ninterface McpLaunchOverrides {\n cwd?: string;\n env: Record<string, string>;\n}\n\n/**\n * Marker substring written into plugin-file hook templates (e.g., opencode's plugin.ts).\n * Uninstall only deletes plugin files whose content contains this marker, so\n * contributors who hand-edit a plugin file without removing the marker are protected.\n */\nconst MYCO_PLUGIN_FILE_MARKER = 'myco:plugin-marker';\n\n/** `hooksFormat` value selecting verbatim plugin-file install over JSON merge. */\nconst HOOKS_FORMAT_PLUGIN_FILE = 'plugin-file';\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 * Plugin deps package.json (e.g., .opencode/package.json). Only present for agents\n * with `registration.pluginPackageTarget` set. False otherwise.\n */\n pluginPackage: boolean;\n}\n\nexport class SymbiontInstaller {\n constructor(\n private manifest: SymbiontManifest,\n private projectRoot: string,\n private packageRoot: string,\n ) {}\n\n /**\n * Read a template file as raw text, checking both source and dist layouts.\n * `relPath` is relative to `TEMPLATES_SUBDIR` — e.g. `'hook-guard.cjs'` for\n * a shared template or `'opencode/plugin.ts'` for a per-agent template.\n */\n private readTemplateFile(relPath: string): string | null {\n const candidates = [\n path.join(this.packageRoot, TEMPLATES_SUBDIR, relPath),\n // tsup preserves the src/ prefix under dist/, so the same subdir works in both layouts\n path.join(this.packageRoot, 'dist', TEMPLATES_SUBDIR, relPath),\n ];\n for (const filePath of candidates) {\n try { return fs.readFileSync(filePath, 'utf-8'); } catch { /* try next */ }\n }\n return null;\n }\n\n /**\n * Write a Myco-managed file with a content-diff gate. Creates parent dirs as\n * needed. Returns `true` if the file was written (new or updated), `false` if\n * the on-disk content already matches and the write was skipped.\n */\n private writeManagedFile(absPath: string, content: string): boolean {\n try {\n if (fs.readFileSync(absPath, 'utf-8') === content) return false;\n } catch { /* doesn't exist — proceed */ }\n fs.mkdirSync(path.dirname(absPath), { recursive: true });\n fs.writeFileSync(absPath, content, 'utf-8');\n return true;\n }\n\n /**\n * Copy the hook guard script into .agents/myco-run.cjs and delete the\n * legacy .agents/myco-hook.cjs if present.\n *\n * The guard is the cross-platform entry point for lifecycle hooks.\n * Hook commands invoke `node .agents/myco-run.cjs …`, and the guard\n * resolves which myco binary to exec via `.myco/runtime.command`.\n * MCP server spawn continues to use the published `myco-run` binary.\n * Returns true if the file was written (or updated); false if skipped\n * or N/A.\n */\n installHookGuard(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n const guardTemplate = this.readTemplateFile(HOOK_GUARD_TEMPLATE_FILENAME);\n if (!guardTemplate) return false;\n\n // Sweep legacy guard file on every install — harmless no-op if absent.\n // Prevents the old and new guard files coexisting for projects that\n // were last installed under the `myco-hook.cjs` naming.\n try {\n fs.unlinkSync(path.join(this.projectRoot, LEGACY_HOOK_GUARD_PATH));\n } catch { /* no legacy file present */ }\n\n return this.writeManagedFile(\n path.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH),\n guardTemplate,\n );\n }\n\n /**\n * Remove the hook guard script from .agents/myco-run.cjs.\n * Also deletes the legacy .agents/myco-hook.cjs if present.\n * Returns true if any file was removed; false otherwise.\n */\n uninstallHookGuard(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n let removed = false;\n for (const relPath of [HOOK_GUARD_PROJECT_PATH, LEGACY_HOOK_GUARD_PATH]) {\n try {\n fs.unlinkSync(path.join(this.projectRoot, relPath));\n removed = true;\n } catch { /* not present */ }\n }\n return removed;\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 const raw = this.readTemplateFile(path.join(this.manifest.name, `${name}.json`));\n if (raw === null) return null;\n try { return JSON.parse(raw); } catch { return null; }\n }\n\n /**\n * Load a template file verbatim (no JSON parsing).\n * Used for plugin-file hook templates (e.g., opencode's plugin.ts) and any\n * other template that is copied to the project without structural merging.\n */\n loadTemplateRaw(filename: string): string | null {\n return this.readTemplateFile(path.join(this.manifest.name, filename));\n }\n\n /** Run all registration steps. */\n install(): InstallResult {\n const reg = this.manifest.registration;\n this.reconcileAgentsMd();\n // Install hook guard before hooks so the guard script is in place when hooks reference it\n this.installHookGuard();\n // One-time migration: sweep legacy MYCO_CMD / myco-run entries that\n // the pre-runtime.command dispatch pattern wrote into symbiont config\n // files. Idempotent — no-op on clean files. Runs before installSettings\n // so the stale entries don't survive a deep-merge into the new template.\n this.cleanupLegacyMycoCmdEntries();\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 pluginPackage: this.installPluginPackage(),\n };\n this.updateGitignore();\n return result;\n }\n\n private reconcileAgentsMd(): void {\n ensureAgentsMd(this.projectRoot, this.packageRoot);\n const agentsPath = path.join(this.projectRoot, 'AGENTS.md');\n let content = '';\n try {\n content = fs.readFileSync(agentsPath, 'utf-8');\n } catch {\n return;\n }\n\n const stripped = this.stripManagedAgentsBlock(content);\n const separator = stripped.length > 0 && !stripped.endsWith('\\n') ? '\\n' : '';\n const spacer = stripped.trimEnd().length > 0 ? '\\n\\n' : '';\n const result = `${stripped}${separator}${spacer}${AGENTS_MANAGED_BLOCK}`;\n if (result === content) return;\n fs.writeFileSync(agentsPath, result, 'utf-8');\n }\n\n private stripManagedAgentsBlock(content: string): string {\n const startIdx = content.indexOf(AGENTS_MANAGED_START);\n if (startIdx === -1) return content.trimEnd();\n const endIdx = content.indexOf(AGENTS_MANAGED_END, startIdx);\n if (endIdx === -1) return content.trimEnd();\n const afterEnd = endIdx + AGENTS_MANAGED_END.length;\n return (content.slice(0, startIdx) + content.slice(afterEnd)).trimEnd();\n }\n\n private getCustomPlanGitignoreEntries(): string[] {\n const config = this.loadProjectConfig();\n if (!config?.capture.ignore_plan_dirs_in_git) return [];\n\n return [...new Set(\n config.capture.plan_dirs\n .map((dir) => this.normalizeProjectRelativeDir(dir))\n .filter((dir): dir is string => dir !== null),\n )];\n }\n\n private loadProjectConfig() {\n try {\n return loadMergedConfig(path.join(this.projectRoot, '.myco'));\n } catch {\n return null;\n }\n }\n\n private normalizeProjectRelativeDir(dir: string): string | null {\n const slashNormalized = dir.trim().replaceAll('\\\\', '/');\n if (!slashNormalized) return null;\n if (slashNormalized.startsWith('~/')) return null;\n if (path.posix.isAbsolute(slashNormalized) || path.win32.isAbsolute(slashNormalized)) return null;\n\n const withoutDotPrefix = slashNormalized.replace(/^\\.\\//, '');\n const normalized = path.posix.normalize(withoutDotPrefix);\n if (normalized === '.' || normalized === '..' || normalized.startsWith('../')) return null;\n return normalized.endsWith('/') ? normalized : `${normalized}/`;\n }\n\n /**\n * Sweep legacy `MYCO_CMD` env-var writes and `myco-run` command-name\n * entries from this symbiont's installed config files.\n *\n * Background: prior to the `.myco/runtime.command` refactor, `make\n * dev-link` injected `MYCO_CMD=myco-dev` into each symbiont's env\n * block (`.claude/settings.json` → `env`, `.cursor/mcp.json` →\n * `mcp.myco.env`, `.codex/config.toml` →\n * `[shell_environment_policy.set]`), and each symbiont's template\n * permission allowlist listed `myco-run` as a callable command. The\n * env-var pattern is now obsolete — `.myco/runtime.command` is the\n * hook-side source of truth — while the old allowlist entries remain\n * legacy noise after the permissions refactor.\n *\n * This cleanup runs automatically on every install/update pass so\n * contributors upgrading across this refactor don't need to manually\n * edit any config file. Idempotent: a second run after cleanup is a\n * no-op. Safe to remove from the install pipeline once every known\n * contributor has updated at least once.\n */\n private cleanupLegacyMycoCmdEntries(): void {\n const reg = this.manifest.registration;\n if (!reg) return;\n\n if (reg.settingsTarget) {\n const settingsPath = path.join(this.projectRoot, reg.settingsTarget);\n const format = reg.settingsFormat ?? 'json';\n if (format === 'toml') {\n this.stripLegacyFromToml(settingsPath);\n } else {\n this.stripLegacyFromJson(settingsPath);\n }\n }\n\n if (reg.mcpTarget && reg.mcpFormat !== 'toml') {\n // MCP server env blocks — cursor writes MYCO_CMD here under\n // `mcp.myco.env` / `mcpServers.myco.env`. TOML MCP targets live\n // inside the same config.toml already handled above.\n this.stripLegacyFromJson(path.join(this.projectRoot, reg.mcpTarget));\n }\n }\n\n /**\n * Walk a JSON settings/MCP file and delete legacy MYCO_CMD + myco-run\n * entries. Writes back only if something changed.\n *\n * Removes:\n * - `MYCO_CMD` key from any object named `env` anywhere in the tree\n * - `myco-run` / `myco-run *` / `myco-run:*` / `Bash(myco-run *)` /\n * `Bash(myco-run:*)` / `ShellTool(myco-run *)` from string arrays\n * - `myco-run` / `myco-run *` keys from object-boolean maps like\n * `chat.tools.terminal.autoApprove`\n */\n private stripLegacyFromJson(filePath: string): void {\n let raw: string;\n try { raw = fs.readFileSync(filePath, 'utf-8'); } catch { return; }\n let data: unknown;\n try { data = JSON.parse(raw); } catch { return; }\n\n let changed = false;\n const LEGACY_STRINGS = new Set([\n 'myco-run',\n 'myco-run *',\n 'myco-run:*',\n 'Bash(myco-run *)',\n 'Bash(myco-run:*)',\n 'ShellTool(myco-run *)',\n ]);\n const LEGACY_OBJECT_KEYS = ['myco-run', 'myco-run *'];\n // Fields whose array values are exec argvs (process invocation arrays),\n // NOT allowlist tokens. The cleanup sweep must not touch these because\n // `myco-run` remains the PUBLISHED MCP launcher command — stripping it\n // from an opencode-style `command: [\"myco-run\", \"mcp\"]` array would\n // corrupt the MCP spawn. Only works today because installMcp() deep-\n // merges the template back in after cleanup; don't rely on that mask.\n const EXEC_ARGV_KEYS = new Set(['command', 'args']);\n\n const walk = (node: unknown, parentKey?: string): void => {\n if (node === null || typeof node !== 'object') return;\n if (Array.isArray(node)) {\n // Exec argv arrays are process invocations (e.g. opencode's\n // `command: [\"myco-run\", \"mcp\"]`). Never strip tokens from these\n // — `myco-run` is the intended MCP command.\n if (parentKey !== undefined && EXEC_ARGV_KEYS.has(parentKey)) return;\n // String arrays: filter out legacy allowlist tokens in place.\n for (let i = node.length - 1; i >= 0; i--) {\n if (typeof node[i] === 'string' && LEGACY_STRINGS.has(node[i] as string)) {\n node.splice(i, 1);\n changed = true;\n } else {\n walk(node[i]);\n }\n }\n return;\n }\n const obj = node as Record<string, unknown>;\n // Env blocks: strip MYCO_CMD specifically. We check by key name so\n // we match any `env` object at any nesting level.\n if (parentKey === 'env' && 'MYCO_CMD' in obj) {\n delete obj.MYCO_CMD;\n changed = true;\n }\n // Object-boolean maps keyed on command name: strip legacy keys.\n // Skip inside exec argv scalar fields (e.g. `command: \"myco-run\"`)\n // would be caught by the LEGACY_OBJECT_KEYS lookup only when the\n // key is literally `myco-run`, which is a command-name key in\n // allowlist objects — exec argv scalars are fine because the\n // scalar value `\"myco-run\"` is walked as a string and skipped.\n for (const key of LEGACY_OBJECT_KEYS) {\n if (key in obj) {\n delete obj[key];\n changed = true;\n }\n }\n for (const [k, v] of Object.entries(obj)) {\n walk(v, k);\n }\n };\n\n walk(data);\n\n if (changed) {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n', 'utf-8');\n }\n }\n\n /**\n * Strip `MYCO_CMD = \"...\"` from the `[shell_environment_policy.set]`\n * section of a TOML settings file. Leaves the rest of the file\n * untouched. Drops the `[shell_environment_policy.set]` header entirely\n * when the section becomes empty.\n */\n private stripLegacyFromToml(filePath: string): void {\n let raw: string;\n try { raw = fs.readFileSync(filePath, 'utf-8'); } catch { return; }\n const next = removeTomlSectionKeys(raw, 'shell_environment_policy.set', ['MYCO_CMD']);\n if (next !== raw) {\n fs.writeFileSync(filePath, next, 'utf-8');\n }\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 * Plugin-file hooks (e.g., opencode) naturally fall out of batching because their\n * hooksTarget is a distinct .ts file path, yielding a Set size ≥ 2.\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 serversKey = reg.mcpServersKey ?? 'mcpServers';\n const servers = (data[serversKey] ?? {}) as Record<string, unknown>;\n for (const [name, def] of Object.entries(mcpTemplate)) {\n servers[name] = def;\n }\n data[serversKey] = 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 pluginPackage: this.installPluginPackage(),\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 pluginPackage: false,\n };\n // Remove hook guard after hooks/settings so the file is cleaned up last\n this.uninstallHookGuard();\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 {\n hooks: false,\n mcp: false,\n skills: this.uninstallSkills(),\n settings: false,\n instructions: this.uninstallInstructions(),\n pluginPackage: false,\n };\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 serversKey = reg.mcpServersKey ?? 'mcpServers';\n const servers = (data[serversKey] ?? {}) 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[serversKey];\n else data[serversKey] = 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 {\n hooks,\n mcp,\n skills: this.uninstallSkills(),\n settings,\n instructions: this.uninstallInstructions(),\n pluginPackage: false,\n };\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 * Also ensures AGENTS.md exists — creates a starter if missing.\n */\n installInstructions(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.instructionsFile) return false;\n\n // Ensure AGENTS.md exists before creating stubs that reference it\n ensureAgentsMd(this.projectRoot, this.packageRoot);\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 /**\n * Reconcile Myco-owned skill entries in project .gitignore.\n * Computes the desired entry set, strips any existing Myco block\n * (and legacy entries), then writes the current block if changed.\n */\n private updateGitignore(): void {\n const reg = this.manifest.registration;\n if (!reg?.skillsTarget) return;\n\n const skillNames = this.listSkillDirs();\n\n // Desired state: canonical per-skill entries + infrastructure artifacts.\n // Agent-specific targets (e.g. .claude/skills/) use local .gitignore files\n // instead of polluting the project-level .gitignore.\n const desired = [\n ...skillNames.map((name) => `${CANONICAL_SKILLS_DIR}/${name}`),\n ...this.getCustomPlanGitignoreEntries(),\n WRANGLER_CACHE_DIR,\n ];\n\n const gitignorePath = path.join(this.projectRoot, '.gitignore');\n let content = '';\n try { content = fs.readFileSync(gitignorePath, 'utf-8'); } catch { /* doesn't exist yet */ }\n\n // Strip existing Myco block and any legacy entries\n const stripped = this.stripMycoGitignoreBlock(content, skillNames);\n\n // Build the new block\n const desiredBlock = desired.length > 0\n ? `${GITIGNORE_COMMENT}\\n${desired.join('\\n')}\\n`\n : '';\n\n // Check if anything changed\n if (stripped === content && desiredBlock === '') return;\n const separator = stripped.length > 0 && !stripped.endsWith('\\n') ? '\\n' : '';\n const spacer = stripped.length > 0 && desiredBlock.length > 0 ? '\\n' : '';\n const result = stripped + separator + spacer + desiredBlock;\n if (result === content) return;\n\n fs.writeFileSync(gitignorePath, result, 'utf-8');\n }\n\n /**\n * Remove all Myco-owned gitignore entries: the comment header, per-skill\n * entries for both canonical and agent-specific paths, and legacy blanket\n * directory entries. Returns the cleaned content.\n */\n private stripMycoGitignoreBlock(content: string, skillNames: string[]): string {\n let stripped = content;\n\n const managedStart = stripped.indexOf(GITIGNORE_COMMENT);\n if (managedStart !== -1) {\n const managedEndMatch = stripped.slice(managedStart).match(/\\n\\n/);\n const managedEnd = managedEndMatch\n ? managedStart + managedEndMatch.index! + managedEndMatch[0].length\n : stripped.length;\n stripped = stripped.slice(0, managedStart) + stripped.slice(managedEnd);\n }\n\n const reg = this.manifest.registration;\n const legacyOwnedLines = new Set<string>([\n GITIGNORE_SKILLS_COMMENT_LEGACY,\n `${CANONICAL_SKILLS_DIR}/`,\n WRANGLER_CACHE_DIR,\n ]);\n for (const name of skillNames) {\n legacyOwnedLines.add(`${CANONICAL_SKILLS_DIR}/${name}`);\n if (reg?.skillsTarget && reg.skillsTarget !== CANONICAL_SKILLS_DIR) {\n legacyOwnedLines.add(`${reg.skillsTarget}/${name}`);\n }\n }\n\n const filtered = stripped\n .split('\\n')\n .filter((line) => !legacyOwnedLines.has(line));\n return filtered.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trimEnd() + (filtered.length > 0 ? '\\n' : '');\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 * For plugin-file agents (e.g., opencode) this dispatches to `installPluginHookFile()`\n * which writes a verbatim .ts plugin source to hooksTarget instead of merging JSON.\n */\n installHooks(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n if (reg.hooksFormat === HOOKS_FORMAT_PLUGIN_FILE) return this.installPluginHookFile();\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 * Install a plugin-file hook target by copying a verbatim template.\n * Used for agents whose hook system is plugin-based rather than JSON entry-based\n * (e.g., opencode's TypeScript plugin system).\n */\n private installPluginHookFile(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n const templateContent = this.loadTemplateRaw('plugin.ts');\n if (templateContent === null) return false;\n\n return this.writeManagedFile(\n path.join(this.projectRoot, reg.hooksTarget),\n templateContent,\n );\n }\n\n /**\n * Remove a plugin-file hook target.\n * Only deletes files whose content contains the Myco plugin marker — contributors\n * who hand-edit the plugin file without removing the marker are protected.\n */\n private uninstallPluginHookFile(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n const targetPath = path.join(this.projectRoot, reg.hooksTarget);\n let content: string;\n try { content = fs.readFileSync(targetPath, 'utf-8'); } catch { return false; }\n\n if (!content.includes(MYCO_PLUGIN_FILE_MARKER)) return false;\n\n try {\n fs.unlinkSync(targetPath);\n // Remove parent plugins dir if now empty\n try { fs.rmdirSync(path.dirname(targetPath)); } catch { /* not empty or missing */ }\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Install a plugin deps package.json for plugin-file agents (e.g., opencode).\n * Writes the template verbatim so the agent's package manager can install the SDK.\n */\n private installPluginPackage(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.pluginPackageTarget) return false;\n\n const templateContent = this.loadTemplateRaw('package.json');\n if (templateContent === null) return false;\n\n return this.writeManagedFile(\n path.join(this.projectRoot, reg.pluginPackageTarget),\n templateContent,\n );\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.buildMcpTemplate(this.loadTemplate('mcp'));\n if (!template) return false;\n\n const targetPath = path.join(this.projectRoot, reg.mcpTarget);\n if (reg.mcpFormat === 'toml') {\n return this.installMcpToml(targetPath, template);\n }\n return this.installMcpJson(targetPath, template);\n }\n\n private buildMcpTemplate(\n template: Record<string, unknown> | null,\n ): Record<string, unknown> | null {\n if (!template) return null;\n\n const overrides = this.resolveMcpLaunchOverrides();\n if (!overrides.cwd && Object.keys(overrides.env).length === 0) return template;\n\n return Object.fromEntries(\n Object.entries(template).map(([name, def]) => {\n if (!def || typeof def !== 'object' || Array.isArray(def)) return [name, def];\n const server = def as Record<string, unknown>;\n const mergedEnv = {\n ...(\n server.env && typeof server.env === 'object' && !Array.isArray(server.env)\n ? server.env\n : {}\n ),\n ...overrides.env,\n } as Record<string, unknown>;\n return [\n name,\n {\n ...server,\n ...(overrides.cwd ? { cwd: overrides.cwd } : {}),\n ...(Object.keys(mergedEnv).length > 0 ? { env: mergedEnv } : {}),\n },\n ];\n }),\n );\n }\n\n private resolveMcpLaunchOverrides(): McpLaunchOverrides {\n const vaultDir = path.join(this.projectRoot, '.myco');\n const registration = this.manifest.registration;\n const envEntries = Object.entries(registration?.mcpEnv ?? {});\n return {\n cwd: this.resolveMcpPlaceholderValue(registration?.mcpCwd, vaultDir),\n env: Object.fromEntries(\n envEntries.flatMap(([key, value]) => {\n const resolved = this.resolveMcpPlaceholderValue(value, vaultDir);\n return resolved ? [[key, resolved] as const] : [];\n }),\n ),\n };\n }\n\n private resolveMcpPlaceholderValue(\n value: string | undefined,\n vaultDir: string,\n ): string | undefined {\n if (!value) return value;\n return value\n .replaceAll(MCP_ENV_PROJECT_ROOT_TOKEN, this.projectRoot)\n .replaceAll(MCP_ENV_VAULT_DIR_TOKEN, vaultDir);\n }\n\n /**\n * Write MCP servers to a JSON config file under the manifest-configured key.\n * Most agents use the canonical `mcpServers` key; opencode uses `mcp`.\n *\n * The `?? 'mcpServers'` fallback protects against test fixtures that construct\n * manifests as plain object literals and bypass the schema's default.\n */\n private installMcpJson(targetPath: string, template: Record<string, unknown>): boolean {\n const serversKey = this.manifest.registration!.mcpServersKey ?? 'mcpServers';\n const config = readJsonFile(targetPath);\n const servers = (config[serversKey] ?? {}) as Record<string, unknown>;\n\n for (const [name, def] of Object.entries(template)) {\n servers[name] = def;\n }\n\n config[serversKey] = 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 ensureLocalSkillsGitignore(agentSkillsDir);\n }\n\n return true;\n }\n\n /**\n * Merge settings template into the target settings file.\n * JSON targets: deep-merges objects and deduplicates arrays.\n * TOML targets: emits each top-level template key as a [section] with scalar children.\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 settingsFormat = reg.settingsFormat ?? 'json';\n\n if (settingsFormat === 'toml') {\n return this.installSettingsToml(targetPath, template);\n }\n\n const existing = readJsonFile(targetPath);\n const merged = deepMergeSettings(existing, template);\n writeJsonFile(targetPath, merged);\n return true;\n }\n\n /**\n * Merge a settings template into a TOML config file.\n * Each top-level key in the template becomes a [section] header, with its\n * children written as scalar key = value lines. Existing sections and keys\n * outside the template (including unrelated sections like [mcp_servers.*])\n * are preserved.\n */\n private installSettingsToml(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 [sectionName, values] of Object.entries(template)) {\n if (!values || typeof values !== 'object' || Array.isArray(values)) continue;\n raw = upsertTomlSection(raw, sectionName, values 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 * Remove Myco entries from the target settings file.\n * Template-driven: loads the settings template and removes matching values.\n * JSON: arrays filtered by template values, object keys deleted by name.\n * TOML: removes each template key from its section; empty sections are dropped.\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 settingsFormat = reg.settingsFormat ?? 'json';\n\n if (settingsFormat === 'toml') {\n return this.uninstallSettingsToml(targetPath, template);\n }\n\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 /**\n * Remove template-defined keys from TOML settings file.\n * For each section in the template, deletes only the keys the template owns;\n * other keys and unrelated sections stay intact. Empty sections are stripped.\n * Deletes the file entirely if no TOML content remains.\n */\n private uninstallSettingsToml(targetPath: string, template: Record<string, unknown>): boolean {\n let raw = '';\n try { raw = fs.readFileSync(targetPath, 'utf-8'); } catch { return false; }\n if (!raw.trim()) return false;\n\n let changed = false;\n for (const [sectionName, values] of Object.entries(template)) {\n if (!values || typeof values !== 'object' || Array.isArray(values)) continue;\n const keys = Object.keys(values as Record<string, unknown>);\n const next = removeTomlSectionKeys(raw, sectionName, keys);\n if (next !== raw) {\n raw = next;\n changed = true;\n }\n }\n\n if (!changed) return false;\n\n if (!raw.trim()) {\n try { fs.unlinkSync(targetPath); } catch { /* ignore */ }\n } else {\n fs.writeFileSync(targetPath, raw, 'utf-8');\n }\n return true;\n }\n\n /**\n * Remove Myco hook groups from the target settings file.\n *\n * For plugin-file agents (e.g., opencode) this dispatches to `uninstallPluginHookFile()`\n * which deletes the verbatim plugin file (guarded by the Myco plugin marker).\n */\n uninstallHooks(): boolean {\n const reg = this.manifest.registration;\n if (!reg?.hooksTarget) return false;\n\n if (reg.hooksFormat === HOOKS_FORMAT_PLUGIN_FILE) return this.uninstallPluginHookFile();\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 if (reg.mcpFormat === 'toml') {\n return this.uninstallMcpToml(targetPath);\n }\n return this.uninstallMcpJson(targetPath);\n }\n\n private uninstallMcpJson(targetPath: string): boolean {\n // Fallback matches the schema default; protects test fixtures that bypass .parse().\n const serversKey = this.manifest.registration!.mcpServersKey ?? 'mcpServers';\n const config = readJsonFile(targetPath);\n const servers = (config[serversKey] ?? {}) 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[serversKey];\n } else {\n config[serversKey] = 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, `mcp_servers.${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 const cleaned = this.stripMycoGitignoreBlock(content, this.listSkillDirs()).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/**\n * Create agent-specific symlinks for a skill in `.agents/skills/<name>`.\n *\n * Reads all symbiont manifests to find skillsTarget paths that differ\n * from the canonical `.agents/skills/` directory, then creates relative\n * symlinks from each target to the canonical location.\n *\n * Called by vault_write_skill after writing a generated skill to disk.\n * Also handles removal: when `remove` is true, deletes the symlinks.\n */\nexport function syncSkillSymlinks(\n projectRoot: string,\n skillName: string,\n opts?: { remove?: boolean },\n): void {\n // Resolve manifests dir — try sibling (source layout) then dist layout\n // (tsup bundles into dist/chunk-*.js, but manifests are at dist/src/symbionts/manifests/)\n const selfDir = path.dirname(new URL(import.meta.url).pathname);\n const candidates = [\n path.join(selfDir, 'manifests'),\n path.join(selfDir, 'src', 'symbionts', 'manifests'),\n ];\n const manifestDir = candidates.find((d) => fs.existsSync(d));\n if (!manifestDir) return;\n\n const targets = new Set<string>();\n for (const file of fs.readdirSync(manifestDir).filter((f) => f.endsWith('.yaml'))) {\n try {\n const content = fs.readFileSync(path.join(manifestDir, file), 'utf-8');\n const match = content.match(/skillsTarget:\\s*(.+)/);\n if (match) targets.add(match[1].trim());\n } catch { /* skip unreadable manifests */ }\n }\n\n for (const target of targets) {\n if (target === CANONICAL_SKILLS_DIR) continue; // canonical is the source, not a link target\n\n const agentSkillsDir = path.join(projectRoot, target);\n const linkPath = path.join(agentSkillsDir, skillName);\n\n if (opts?.remove) {\n try { fs.unlinkSync(linkPath); } catch { /* doesn't exist */ }\n try { fs.rmdirSync(agentSkillsDir); } catch { /* not empty or missing */ }\n } else {\n fs.mkdirSync(agentSkillsDir, { recursive: true });\n const canonicalDir = path.join(projectRoot, CANONICAL_SKILLS_DIR);\n const relTarget = path.join(path.relative(agentSkillsDir, canonicalDir), skillName);\n ensureSymlink(linkPath, relTarget);\n // Ensure a local .gitignore ignores all symlinks in this directory.\n // Localized to the agent's skills dir — doesn't pollute the project .gitignore.\n ensureLocalSkillsGitignore(agentSkillsDir);\n }\n }\n}\n\n/** Content for the local .gitignore that ignores Myco-created symlinks. */\nconst LOCAL_SKILLS_GITIGNORE = `# Myco-managed symlinks — generated skills are symlinked here automatically.\n# The canonical location for all skills is .agents/skills/.\n#\n# To add your own skill to this directory, un-ignore it:\n# !my-skill\n*\n!.gitignore\n`;\n\n/**\n * Write a .gitignore inside an agent's skills directory that ignores all\n * symlinks Myco creates there. Idempotent — skips if already present.\n */\nfunction ensureLocalSkillsGitignore(agentSkillsDir: string): void {\n const gitignorePath = path.join(agentSkillsDir, '.gitignore');\n try {\n if (fs.readFileSync(gitignorePath, 'utf-8') === LOCAL_SKILLS_GITIGNORE) return;\n } catch { /* doesn't exist — proceed */ }\n fs.writeFileSync(gitignorePath, LOCAL_SKILLS_GITIGNORE, 'utf-8');\n}\n","/** TOML section header pattern. */\nconst TOML_SECTION_RE = /^\\[([^\\]]+)\\]/;\n\n/**\n * Find where a named TOML section ends.\n *\n * Walks forward from `searchStart` until it hits a section header that is\n * NEITHER the named section itself NOR any of its subtables (headers that\n * start with `${sectionName}.`). Returns `raw.length` if the section extends\n * to the end of the file.\n */\nexport function findTomlSectionEnd(\n raw: string,\n searchStart: number,\n sectionName: string,\n): number {\n const subsectionPrefix = `${sectionName}.`;\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] !== sectionName) {\n return offset - line.length - 1;\n }\n }\n return raw.length;\n}\n\n/** Format a single TOML key = value line from a JS value. Skips unsupported types. */\nfunction formatTomlScalarLine(key: string, val: unknown): string | null {\n if (typeof val === 'string') return `${key} = \"${val}\"`;\n if (typeof val === 'boolean') return `${key} = ${val}`;\n if (typeof val === 'number' && Number.isFinite(val)) return `${key} = ${val}`;\n if (Array.isArray(val)) {\n return `${key} = [${val.map((v: unknown) => `\"${v}\"`).join(', ')}]`;\n }\n return null;\n}\n\n/**\n * Insert or replace a top-level TOML section with the given scalar key/value pairs.\n *\n * - Scalar values (string, boolean, number, string[]) are written as `key = value`.\n * - Nested objects are ignored — use {@link buildTomlMcpSection} or call\n * `upsertTomlSection` once per subtable if you need nested tables.\n * - Idempotent: running twice with the same inputs produces identical output.\n * - Preserves content before and after the section.\n */\nexport function upsertTomlSection(\n raw: string,\n sectionName: string,\n values: Record<string, unknown>,\n): string {\n const sectionHeader = `[${sectionName}]`;\n\n const lines: string[] = [sectionHeader];\n for (const [key, val] of Object.entries(values)) {\n const line = formatTomlScalarLine(key, val);\n if (line !== null) lines.push(line);\n }\n const block = lines.join('\\n');\n\n if (raw.includes(sectionHeader)) {\n const startIdx = raw.indexOf(sectionHeader);\n const endIdx = findTomlSectionEnd(raw, startIdx + sectionHeader.length, sectionName);\n const before = raw.slice(0, startIdx).trimEnd();\n const after = raw.slice(endIdx);\n const separator = before ? '\\n\\n' : '';\n return (before + separator + block + after).trimEnd() + '\\n';\n }\n\n const separator = raw.trim() ? '\\n\\n' : '';\n return (raw.trimEnd() + separator + block).trimEnd() + '\\n';\n}\n\n/**\n * Remove specific keys from a top-level TOML section.\n *\n * - Only the listed keys are removed. Other keys in the section are preserved.\n * - If the section ends up with no content after removal, the whole section\n * (header and body) is stripped.\n * - Returns the updated string; equal to the input if no changes were made.\n */\nexport function removeTomlSectionKeys(\n raw: string,\n sectionName: string,\n keys: string[],\n): string {\n const sectionHeader = `[${sectionName}]`;\n if (!raw.includes(sectionHeader)) return raw;\n\n const startIdx = raw.indexOf(sectionHeader);\n const endIdx = findTomlSectionEnd(raw, startIdx + sectionHeader.length, sectionName);\n const sectionBody = raw.slice(startIdx + sectionHeader.length, endIdx);\n\n const keyRes = keys.map((k) => new RegExp(`^\\\\s*${escapeRegExp(k)}\\\\s*=`));\n const bodyLines = sectionBody.split('\\n');\n const kept: string[] = [];\n let removedAny = false;\n let subtableSeen = false;\n for (const line of bodyLines) {\n // Once we hit a subtable header, everything after stays (keys belong to the parent)\n if (subtableSeen || TOML_SECTION_RE.test(line.trim())) {\n subtableSeen = true;\n kept.push(line);\n continue;\n }\n if (keyRes.some((re) => re.test(line))) {\n removedAny = true;\n continue;\n }\n kept.push(line);\n }\n if (!removedAny) return raw;\n\n // Determine whether the parent section still has any key = value lines.\n const hasRemainingKeys = kept.some((line) => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) return false;\n if (TOML_SECTION_RE.test(trimmed)) return false;\n return /=/.test(trimmed);\n });\n\n const before = raw.slice(0, startIdx).trimEnd();\n let rebuilt: string;\n if (hasRemainingKeys) {\n const newBody = kept.join('\\n');\n const separator = before ? '\\n\\n' : '';\n rebuilt = before + separator + sectionHeader + newBody;\n } else {\n // Drop the header entirely; keep any trailing subtables we preserved above.\n const trailing = kept.join('\\n').trimStart();\n const separator = before && trailing ? '\\n\\n' : '';\n rebuilt = before + separator + trailing;\n }\n return rebuilt.trimEnd() + (rebuilt.trim() ? '\\n' : '');\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\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 *\n * Handles the MCP-specific `env` subtable pattern; for plain sections use\n * {@link upsertTomlSection}.\n */\nexport function buildTomlMcpSection(\n raw: string,\n serverName: string,\n server: Record<string, unknown>,\n): string {\n const sectionName = `mcp_servers.${serverName}`;\n const sectionHeader = `[${sectionName}]`;\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 const line = formatTomlScalarLine(key, val);\n if (line !== null) lines.push(line);\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(`[${sectionName}.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, sectionName);\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","import { deepMerge, isPlainObject } from '../utils/deep-merge.js';\n\n/** Symbiont settings merge uses union semantics: arrays are concatenated and deduped. */\nexport function deepMergeSettings(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n return deepMerge(target, source, { arrayStrategy: 'union' });\n}\n\nexport { isPlainObject };\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 */\nexport function 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","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport function readJsonFile(filePath: string): Record<string, unknown> {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nexport function 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. */\nexport function 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","import fs from 'node:fs';\nimport path from 'node:path';\n\nconst DEFAULT_AGENTS_STARTER = `# Project Rules\n\n<!-- This starter file was created by Myco. Replace it with your project's rules and conventions. -->\n\nRules haven't been defined yet. Use the /rules skill to generate project rules, or edit this file directly.\n`;\n\n/**\n * Check if a command string belongs to Myco.\n *\n * Three legacy shapes we still need to recognize so uninstall / re-install\n * can strip old entries cleanly:\n * 1. `.agents/myco-run.cjs` — current hook guard entry point\n * 2. `.agents/myco-hook.cjs` — prior cross-platform guard (pre-rename)\n * 3. `myco-run` bare — published MCP entry point and old shell shim\n *\n * Any of these signals \"this is our group, safe to replace on reinstall.\"\n */\nexport function isMycoHookCommand(command: string): boolean {\n return (\n command.includes('.agents/myco-run.cjs') ||\n command.includes('.agents/myco-hook.cjs') ||\n command.startsWith('myco-run')\n );\n}\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: \"cd \\\"$(git rev-parse ...)\\\" && node .agents/myco-run.cjs ...\" }] }\n * Flat: { command: \"cd \\\"$(git rev-parse ...)\\\" && node .agents/myco-run.cjs ...\" }\n */\nexport function isMycoHookGroup(group: Record<string, unknown>): boolean {\n // Nested format: { hooks: [{ command: \"...\" }] }\n if (Array.isArray(group.hooks) && group.hooks.some((h: { command?: string }) => h.command && isMycoHookCommand(h.command))) return true;\n // Flat format: { command: \"...\" }\n if (typeof group.command === 'string' && isMycoHookCommand(group.command)) return true;\n return false;\n}\n\n/**\n * Create a starter AGENTS.md if the project doesn't have one.\n * Idempotent — skips if AGENTS.md already exists.\n */\nexport function ensureAgentsMd(projectRoot: string, packageRoot: string): void {\n const agentsMdPath = path.join(projectRoot, 'AGENTS.md');\n if (fs.existsSync(agentsMdPath)) return;\n\n const candidates = [\n path.join(packageRoot, 'src/symbionts/templates/agents-starter.md'),\n path.join(packageRoot, 'dist/src/symbionts/templates/agents-starter.md'),\n ];\n for (const p of candidates) {\n try {\n const content = fs.readFileSync(p, 'utf-8');\n fs.writeFileSync(agentsMdPath, content, 'utf-8');\n return;\n } catch { /* try next */ }\n }\n\n fs.writeFileSync(agentsMdPath, DEFAULT_AGENTS_STARTER, 'utf-8');\n}\n\nexport function 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"],"mappings":"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","names":["fs","path","separator","fs","path","path","fs"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/capture-rules.ts","../src/hooks/transcript-meta.ts"],"sourcesContent":["/**\n * Generic capture-rule evaluator.\n *\n * Each symbiont manifest declares `capture.rules` — a list of `{ event,\n * when, action }` records that describe how Myco should filter captured\n * events for that agent. This module loads rules from every manifest\n * in one place and exposes a pure evaluator the hook handlers call\n * without knowing anything symbiont-specific.\n *\n * Adding a new symbiont's capture behavior is a YAML-only change: edit\n * that agent's manifest file, no hook or evaluator changes needed.\n *\n * Rule scope (`this_agent` vs `any_agent`) lets rules opt into running\n * even when agent detection itself fails — useful for ephemeral\n * sub-invocations that legitimately lack the signals we key on.\n *\n * Conditions should prefer structural signals (e.g.,\n * `transcript_path_missing`) over text matching so rules stay robust\n * across upstream agent updates.\n */\n\nimport type { CaptureRule, SymbiontManifest } from '../symbionts/manifest-schema.js';\nimport { getAtPath } from '../utils/dot-path.js';\n\n/** Structured context a rule can match against at UserPromptSubmit time. */\nexport interface UserPromptRuleContext {\n /** The user prompt text as received from the hook. */\n prompt: string;\n /** Transcript path from the hook payload, if any. Empty/undefined signals an ephemeral session. */\n transcriptPath?: string;\n /** Parsed first JSON line (session_meta) from the transcript, if available. */\n transcriptMeta?: Record<string, unknown>;\n}\n\n/** Structured context a rule can match against at SessionStart time. */\nexport interface SessionStartRuleContext {\n /** Transcript path from the hook payload, if any. Empty/undefined signals an ephemeral session. */\n transcriptPath?: string;\n /** Parsed first JSON line (session_meta) from the transcript, if available. */\n transcriptMeta?: Record<string, unknown>;\n}\n\n/** Outcome of evaluating user_prompt rules. */\nexport type UserPromptDecision =\n | { action: 'pass'; prompt: string }\n | { action: 'rewrite'; prompt: string; reason?: string }\n | { action: 'drop'; reason?: string };\n\n/** Outcome of evaluating session capture rules. No rewrite — there's no prompt text yet. */\nexport type SessionStartDecision =\n | { action: 'pass' }\n | { action: 'drop'; reason?: string };\n\n/**\n * Evaluate all user_prompt rules from every manifest against one context.\n *\n * Rules are checked in declaration order, first-match-wins. A rule only\n * fires when:\n * 1. its `event` is `user_prompt`,\n * 2. its scope permits it (see scope semantics in manifest-schema.ts),\n * 3. every condition in its `when` block matches the context.\n *\n * If no rule matches, the prompt passes through unchanged.\n */\nexport function evaluateUserPromptRules(\n manifests: SymbiontManifest[],\n detectedAgent: string,\n ctx: UserPromptRuleContext,\n): UserPromptDecision {\n for (const manifest of manifests) {\n const rules = manifest.capture?.rules ?? [];\n for (const rule of rules) {\n if (rule.event !== 'user_prompt') continue;\n if (!scopePermits(rule, manifest.name, detectedAgent)) continue;\n if (!whenMatches(rule, ctx)) continue;\n return applyAction(rule, ctx);\n }\n }\n return { action: 'pass', prompt: ctx.prompt };\n}\n\n/**\n * Evaluate all session_start rules from every manifest.\n *\n * Same first-match-wins semantics as user_prompt rules. The only action\n * session_start rules can take is `drop` — text rewriting doesn't apply\n * because there's no prompt text at SessionStart time. Rules that\n * specify prompt-based conditions (prompt_starts_with / prompt_contains)\n * match against an empty prompt here, so they'll never fire on the\n * session_start pass.\n *\n * Callers should skip session registration when the result is `drop`.\n */\nexport function evaluateSessionStartRules(\n manifests: SymbiontManifest[],\n detectedAgent: string,\n ctx: SessionStartRuleContext,\n): SessionStartDecision {\n for (const manifest of manifests) {\n const rules = manifest.capture?.rules ?? [];\n for (const rule of rules) {\n if (rule.event !== 'session_start') continue;\n if (!scopePermits(rule, manifest.name, detectedAgent)) continue;\n if (!whenMatches(rule, { prompt: '', transcriptPath: ctx.transcriptPath, transcriptMeta: ctx.transcriptMeta })) continue;\n if (rule.action === 'drop') {\n return { action: 'drop', reason: rule.reason };\n }\n // rewrite_prompt is meaningless at session_start — skip and let\n // later rules have a chance to match.\n }\n }\n return { action: 'pass' };\n}\n\n/**\n * Evaluate whether a session should be materialized at a lifecycle boundary.\n *\n * SessionStart uses this before registering a session row. Stop processing uses\n * the same decision before transcript-backed capture or stop-driven\n * auto-registration. Keeping both boundaries on the same manifest-driven\n * evaluator makes the rule sustainable for every symbiont, not just the one\n * that first exposed the gap.\n */\nexport function evaluateSessionCaptureRules(\n manifests: SymbiontManifest[],\n detectedAgent: string,\n ctx: SessionStartRuleContext,\n): SessionStartDecision {\n return evaluateSessionStartRules(manifests, detectedAgent, ctx);\n}\n\nfunction scopePermits(rule: CaptureRule, owningAgent: string, detectedAgent: string): boolean {\n if (rule.scope === 'any_agent') return true;\n return owningAgent === detectedAgent;\n}\n\nfunction whenMatches(rule: CaptureRule, ctx: UserPromptRuleContext): boolean {\n const {\n prompt_starts_with,\n prompt_contains,\n transcript_path_missing,\n transcript_meta_field_exists,\n transcript_meta_field_equals,\n } = rule.when;\n\n // Refuse rules with no conditions — prevents a mistyped YAML file from\n // accidentally creating a blanket \"drop everything\" rule.\n const hasAnyCondition =\n prompt_starts_with !== undefined ||\n prompt_contains !== undefined ||\n transcript_path_missing !== undefined ||\n transcript_meta_field_exists !== undefined ||\n transcript_meta_field_equals !== undefined;\n if (!hasAnyCondition) return false;\n\n if (prompt_starts_with && !ctx.prompt.startsWith(prompt_starts_with)) return false;\n if (prompt_contains && !ctx.prompt.includes(prompt_contains)) return false;\n\n if (transcript_path_missing !== undefined) {\n const missing = !ctx.transcriptPath || ctx.transcriptPath.length === 0;\n if (transcript_path_missing && !missing) return false;\n if (!transcript_path_missing && missing) return false;\n }\n\n if (transcript_meta_field_exists !== undefined) {\n if (!ctx.transcriptMeta) return false;\n if (!getAtPath(ctx.transcriptMeta, transcript_meta_field_exists)) return false;\n }\n\n if (transcript_meta_field_equals !== undefined) {\n if (!ctx.transcriptMeta) return false;\n if (getAtPath(ctx.transcriptMeta, transcript_meta_field_equals.path) !== transcript_meta_field_equals.value) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction applyAction(rule: CaptureRule, ctx: UserPromptRuleContext): UserPromptDecision {\n if (rule.action === 'drop') {\n return { action: 'drop', reason: rule.reason };\n }\n // rewrite_prompt — keep only the substring after the extract_after marker.\n // If the marker isn't in the prompt, fall through to `pass` so we don't\n // accidentally blank out a prompt that turned out not to match after all.\n const marker = rule.extract_after;\n if (!marker) return { action: 'pass', prompt: ctx.prompt };\n const idx = ctx.prompt.indexOf(marker);\n if (idx === -1) return { action: 'pass', prompt: ctx.prompt };\n const after = ctx.prompt.slice(idx + marker.length);\n const next = rule.trim ? after.trim() : after;\n if (!next) return { action: 'pass', prompt: ctx.prompt };\n return { action: 'rewrite', prompt: next, reason: rule.reason };\n}\n","/**\n * Read the first JSON line (session_meta) from an agent's transcript file.\n *\n * Every supported agent writes a JSONL transcript where the first entry\n * is a `session_meta` record containing session identity, source info,\n * model, and other structural signals. This reader extracts that record\n * so capture rules can make decisions based on it — e.g., detecting\n * sub-agent thread spawns that have real transcript files but aren't\n * user-initiated sessions.\n *\n * Returns the parsed `payload` object from the session_meta entry, or\n * null if the file doesn't exist, isn't readable, or doesn't contain\n * valid session_meta JSON.\n */\n\nimport fs from 'node:fs';\n\n/**\n * Read and parse the session_meta payload from a transcript file.\n *\n * @param transcriptPath - Absolute path to the JSONL transcript.\n * @returns The session_meta payload object, or null on any failure.\n */\nexport function readTranscriptMeta(transcriptPath: string): Record<string, unknown> | null {\n try {\n const fd = fs.openSync(transcriptPath, 'r');\n try {\n // Read enough bytes for the first line. Session meta can be large\n // when it embeds the full system prompt (base_instructions) — Codex\n // sessions routinely exceed 16 KB. 128 KB covers all known cases.\n const buf = Buffer.alloc(131072);\n const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);\n if (bytesRead === 0) return null;\n\n const chunk = buf.toString('utf-8', 0, bytesRead);\n const newlineIdx = chunk.indexOf('\\n');\n const firstLine = newlineIdx >= 0 ? chunk.slice(0, newlineIdx) : chunk;\n if (!firstLine) return null;\n\n const entry = JSON.parse(firstLine);\n\n // session_meta entries have { type: \"session_meta\", payload: {...} }\n if (entry?.type === 'session_meta' && typeof entry.payload === 'object') {\n return entry.payload as Record<string, unknown>;\n }\n\n // Some agents may write the meta directly without the wrapper\n if (typeof entry === 'object' && entry !== null) {\n return entry as Record<string, unknown>;\n }\n\n return null;\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}