@goondocks/myco 0.17.2 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/README.md +14 -22
  2. package/bin/myco-run +15 -2
  3. package/dist/{agent-run-7AYHXIEF.js → agent-run-I4O2K2CK.js} +7 -7
  4. package/dist/{agent-tasks-UUIFKBD4.js → agent-tasks-UOW5BQIB.js} +7 -7
  5. package/dist/{chunk-XD3NEN3Q.js → chunk-2V7HR7HB.js} +2 -2
  6. package/dist/chunk-44PZCAYS.js +107 -0
  7. package/dist/chunk-44PZCAYS.js.map +1 -0
  8. package/dist/{chunk-DT42247G.js → chunk-75AZFBFW.js} +3 -3
  9. package/dist/{chunk-RMJPQZGF.js → chunk-C3EGL5JX.js} +755 -266
  10. package/dist/chunk-C3EGL5JX.js.map +1 -0
  11. package/dist/{chunk-7DAH5GLC.js → chunk-CKJAWZQE.js} +5 -1
  12. package/dist/chunk-CKJAWZQE.js.map +1 -0
  13. package/dist/{chunk-ML6GTPZU.js → chunk-CML4MCYF.js} +2 -2
  14. package/dist/{chunk-UTLWSKDV.js → chunk-CURS2TNP.js} +45 -4
  15. package/dist/chunk-CURS2TNP.js.map +1 -0
  16. package/dist/{chunk-EBIYONNZ.js → chunk-DPSLJ242.js} +34 -2
  17. package/dist/chunk-DPSLJ242.js.map +1 -0
  18. package/dist/{chunk-BZDZORVP.js → chunk-LSP5HYOO.js} +19 -16
  19. package/dist/chunk-LSP5HYOO.js.map +1 -0
  20. package/dist/{chunk-NUSTG3BH.js → chunk-N75GMQGA.js} +3 -3
  21. package/dist/{chunk-F6C4IC6R.js → chunk-NI23QCHB.js} +3 -3
  22. package/dist/{chunk-C3C5QVLK.js → chunk-O3TRN3RC.js} +2 -2
  23. package/dist/{chunk-3NCVCGUZ.js → chunk-RAV5YMRU.js} +3 -3
  24. package/dist/{chunk-25WHTV4N.js → chunk-RIDSOQDR.js} +21 -7
  25. package/dist/chunk-RIDSOQDR.js.map +1 -0
  26. package/dist/{chunk-HPZ7YAMA.js → chunk-TCSVDQF5.js} +1130 -195
  27. package/dist/chunk-TCSVDQF5.js.map +1 -0
  28. package/dist/{chunk-CTF7TQMJ.js → chunk-TLK46KKD.js} +14 -4
  29. package/dist/chunk-TLK46KKD.js.map +1 -0
  30. package/dist/{chunk-IGBHLFV5.js → chunk-TOER6RNC.js} +22 -2
  31. package/dist/chunk-TOER6RNC.js.map +1 -0
  32. package/dist/{chunk-ZSJPI5MS.js → chunk-TZAXQKO6.js} +6 -2
  33. package/dist/chunk-TZAXQKO6.js.map +1 -0
  34. package/dist/{chunk-RKPTMHED.js → chunk-U3J2DDSR.js} +2 -2
  35. package/dist/{chunk-SI5BBQAT.js → chunk-W7WENJ6F.js} +2 -2
  36. package/dist/{chunk-VVGZL2HX.js → chunk-WYOE4IAX.js} +153 -15
  37. package/dist/{chunk-VVGZL2HX.js.map → chunk-WYOE4IAX.js.map} +1 -1
  38. package/dist/{chunk-XZWFMMJR.js → chunk-XWOQL4XN.js} +3 -3
  39. package/dist/{chunk-5ZISXCDC.js → chunk-YZPI2Y3E.js} +39 -5
  40. package/dist/chunk-YZPI2Y3E.js.map +1 -0
  41. package/dist/{cli-WJVYP2QT.js → cli-D3TJYJ2U.js} +40 -40
  42. package/dist/{client-LZ3ZR4HC.js → client-4LLEXLVK.js} +4 -4
  43. package/dist/{config-ZQIMG3FB.js → config-DA4IUVFL.js} +3 -3
  44. package/dist/{detect-NJ2OREDP.js → detect-SZ2KDUF4.js} +2 -2
  45. package/dist/{detect-providers-C64L3QET.js → detect-providers-PSVKXTWE.js} +4 -4
  46. package/dist/{doctor-XEPBNHM3.js → doctor-KCTXPX5D.js} +12 -12
  47. package/dist/{executor-NXKJU5KW.js → executor-UYIZC3L5.js} +93 -285
  48. package/dist/executor-UYIZC3L5.js.map +1 -0
  49. package/dist/{init-BHVQAQ27.js → init-QFNBKKDC.js} +13 -13
  50. package/dist/{installer-45ZLP2RP.js → installer-BWJED3ED.js} +2 -2
  51. package/dist/{llm-KTD6SR55.js → llm-SMA5ZEAW.js} +4 -4
  52. package/dist/{loader-SHRKUKOS.js → loader-Q3P3R4UP.js} +3 -3
  53. package/dist/{loader-NEX3UF6U.js → loader-SKKUMT5C.js} +3 -3
  54. package/dist/{main-YFVBIRRK.js → main-5THODR77.js} +751 -257
  55. package/dist/main-5THODR77.js.map +1 -0
  56. package/dist/{open-2U7ZRGA3.js → open-7737CSPN.js} +7 -7
  57. package/dist/{post-compact-QIBMEWL3.js → post-compact-2TJ5FPZH.js} +7 -7
  58. package/dist/{post-tool-use-ICGFXDVY.js → post-tool-use-FRTSICC3.js} +6 -6
  59. package/dist/{post-tool-use-failure-C7TLH3XQ.js → post-tool-use-failure-KYO2NCNB.js} +7 -7
  60. package/dist/{pre-compact-IF7K4TQK.js → pre-compact-J6GCJEJR.js} +7 -7
  61. package/dist/{provider-check-LTLQ6BUZ.js → provider-check-AE3L5Z6R.js} +4 -4
  62. package/dist/{registry-TFQ22Z7N.js → registry-O2NZLO3V.js} +4 -4
  63. package/dist/{remove-FBGM2QVJ.js → remove-3WZZC7AX.js} +9 -9
  64. package/dist/{resolution-events-HGKIJOTA.js → resolution-events-XWYLLDRK.js} +4 -4
  65. package/dist/{restart-TQEECRNW.js → restart-HUHEFOXU.js} +8 -8
  66. package/dist/{search-NN5FC4Z6.js → search-ZGN3LDXG.js} +8 -8
  67. package/dist/{server-XMWJ4GF7.js → server-PTXLVVEE.js} +4 -4
  68. package/dist/{session-GLPAFYPO.js → session-7VV3IQMO.js} +9 -9
  69. package/dist/{session-end-TI3ILRBC.js → session-end-SMU55UCM.js} +6 -6
  70. package/dist/{session-start-PJLJDVJJ.js → session-start-NIMWEOIZ.js} +29 -13
  71. package/dist/session-start-NIMWEOIZ.js.map +1 -0
  72. package/dist/{setup-llm-AQSWLXCZ.js → setup-llm-7S3VPAPN.js} +8 -8
  73. package/dist/src/agent/definitions/tasks/extract-only.yaml +1 -1
  74. package/dist/src/agent/definitions/tasks/full-intelligence.yaml +10 -0
  75. package/dist/src/agent/definitions/tasks/skill-evolve.yaml +163 -49
  76. package/dist/src/agent/definitions/tasks/skill-generate.yaml +44 -27
  77. package/dist/src/agent/definitions/tasks/skill-survey.yaml +132 -138
  78. package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +1 -1
  79. package/dist/src/cli.js +1 -1
  80. package/dist/src/daemon/main.js +1 -1
  81. package/dist/src/hooks/post-tool-use.js +1 -1
  82. package/dist/src/hooks/session-end.js +1 -1
  83. package/dist/src/hooks/session-start.js +1 -1
  84. package/dist/src/hooks/stop.js +1 -1
  85. package/dist/src/hooks/user-prompt-submit.js +1 -1
  86. package/dist/src/mcp/server.js +1 -1
  87. package/dist/src/symbionts/manifests/codex.yaml +85 -0
  88. package/dist/src/symbionts/templates/claude-code/hooks.json +12 -12
  89. package/dist/src/symbionts/templates/claude-code/settings.json +3 -3
  90. package/dist/src/symbionts/templates/codex/hooks.json +4 -4
  91. package/dist/src/symbionts/templates/cursor/hooks.json +9 -9
  92. package/dist/src/symbionts/templates/cursor/settings.json +2 -2
  93. package/dist/src/symbionts/templates/gemini/hooks.json +6 -6
  94. package/dist/src/symbionts/templates/gemini/settings.json +2 -2
  95. package/dist/src/symbionts/templates/myco-run.cjs +44 -0
  96. package/dist/src/symbionts/templates/opencode/settings.json +2 -2
  97. package/dist/src/symbionts/templates/vscode-copilot/hooks.json +7 -7
  98. package/dist/src/symbionts/templates/vscode-copilot/settings.json +2 -2
  99. package/dist/src/symbionts/templates/windsurf/hooks.json +4 -4
  100. package/dist/src/symbionts/templates/windsurf/settings.json +2 -2
  101. package/dist/src/worker/package-lock.json +4338 -0
  102. package/dist/src/worker/package.json +5 -0
  103. package/dist/src/worker/src/index.ts +58 -65
  104. package/dist/src/worker/src/mcp/auth.ts +65 -0
  105. package/dist/src/worker/src/mcp/server.ts +53 -0
  106. package/dist/src/worker/src/mcp/tools/context.ts +13 -0
  107. package/dist/src/worker/src/mcp/tools/get.ts +15 -0
  108. package/dist/src/worker/src/mcp/tools/graph.ts +35 -0
  109. package/dist/src/worker/src/mcp/tools/search.ts +32 -0
  110. package/dist/src/worker/src/mcp/tools/sessions.ts +24 -0
  111. package/dist/src/worker/src/mcp/tools/skills.ts +16 -0
  112. package/dist/src/worker/src/mcp/tools/team.ts +9 -0
  113. package/dist/src/worker/src/schema.ts +5 -1
  114. package/dist/src/worker/src/search-helpers.ts +70 -0
  115. package/dist/src/worker/wrangler.toml +9 -0
  116. package/dist/{stats-BISBIBXZ.js → stats-GEOQ2DFF.js} +9 -9
  117. package/dist/{stop-47BJ42EO.js → stop-7AKYBJJ2.js} +6 -6
  118. package/dist/{stop-failure-VU5BTLWX.js → stop-failure-NLE2EURG.js} +7 -7
  119. package/dist/{subagent-start-SPTKQRHU.js → subagent-start-LBNZF2TG.js} +7 -7
  120. package/dist/{subagent-stop-UU75BYLC.js → subagent-stop-B2Z5GYAB.js} +7 -7
  121. package/dist/{task-completed-MVDO7TZF.js → task-completed-PO5TETJ7.js} +7 -7
  122. package/dist/{team-7X64J4Y6.js → team-DPNP2RN7.js} +97 -14
  123. package/dist/team-DPNP2RN7.js.map +1 -0
  124. package/dist/ui/assets/{index-rpmSpJpm.js → index-CiI1fwas.js} +120 -120
  125. package/dist/ui/index.html +1 -1
  126. package/dist/{update-DA7VEXOS.js → update-WBWB5URU.js} +18 -9
  127. package/dist/update-WBWB5URU.js.map +1 -0
  128. package/dist/{user-prompt-submit-ADZ4NTVO.js → user-prompt-submit-IZJC3NV7.js} +30 -7
  129. package/dist/user-prompt-submit-IZJC3NV7.js.map +1 -0
  130. package/dist/{verify-QYSERHF7.js → verify-FNSP62I3.js} +5 -5
  131. package/dist/{version-A72TAL2J.js → version-QEVU66NT.js} +2 -2
  132. package/package.json +7 -7
  133. package/dist/chunk-25WHTV4N.js.map +0 -1
  134. package/dist/chunk-5ZISXCDC.js.map +0 -1
  135. package/dist/chunk-7DAH5GLC.js.map +0 -1
  136. package/dist/chunk-BZDZORVP.js.map +0 -1
  137. package/dist/chunk-CTF7TQMJ.js.map +0 -1
  138. package/dist/chunk-EBIYONNZ.js.map +0 -1
  139. package/dist/chunk-HPZ7YAMA.js.map +0 -1
  140. package/dist/chunk-IGBHLFV5.js.map +0 -1
  141. package/dist/chunk-RMJPQZGF.js.map +0 -1
  142. package/dist/chunk-UTLWSKDV.js.map +0 -1
  143. package/dist/chunk-ZSJPI5MS.js.map +0 -1
  144. package/dist/executor-NXKJU5KW.js.map +0 -1
  145. package/dist/main-YFVBIRRK.js.map +0 -1
  146. package/dist/session-start-PJLJDVJJ.js.map +0 -1
  147. package/dist/src/symbionts/templates/hook-guard.cjs +0 -19
  148. package/dist/team-7X64J4Y6.js.map +0 -1
  149. package/dist/update-DA7VEXOS.js.map +0 -1
  150. package/dist/user-prompt-submit-ADZ4NTVO.js.map +0 -1
  151. /package/dist/{agent-run-7AYHXIEF.js.map → agent-run-I4O2K2CK.js.map} +0 -0
  152. /package/dist/{agent-tasks-UUIFKBD4.js.map → agent-tasks-UOW5BQIB.js.map} +0 -0
  153. /package/dist/{chunk-XD3NEN3Q.js.map → chunk-2V7HR7HB.js.map} +0 -0
  154. /package/dist/{chunk-DT42247G.js.map → chunk-75AZFBFW.js.map} +0 -0
  155. /package/dist/{chunk-ML6GTPZU.js.map → chunk-CML4MCYF.js.map} +0 -0
  156. /package/dist/{chunk-NUSTG3BH.js.map → chunk-N75GMQGA.js.map} +0 -0
  157. /package/dist/{chunk-F6C4IC6R.js.map → chunk-NI23QCHB.js.map} +0 -0
  158. /package/dist/{chunk-C3C5QVLK.js.map → chunk-O3TRN3RC.js.map} +0 -0
  159. /package/dist/{chunk-3NCVCGUZ.js.map → chunk-RAV5YMRU.js.map} +0 -0
  160. /package/dist/{chunk-RKPTMHED.js.map → chunk-U3J2DDSR.js.map} +0 -0
  161. /package/dist/{chunk-SI5BBQAT.js.map → chunk-W7WENJ6F.js.map} +0 -0
  162. /package/dist/{chunk-XZWFMMJR.js.map → chunk-XWOQL4XN.js.map} +0 -0
  163. /package/dist/{cli-WJVYP2QT.js.map → cli-D3TJYJ2U.js.map} +0 -0
  164. /package/dist/{client-LZ3ZR4HC.js.map → client-4LLEXLVK.js.map} +0 -0
  165. /package/dist/{config-ZQIMG3FB.js.map → config-DA4IUVFL.js.map} +0 -0
  166. /package/dist/{detect-NJ2OREDP.js.map → detect-SZ2KDUF4.js.map} +0 -0
  167. /package/dist/{detect-providers-C64L3QET.js.map → detect-providers-PSVKXTWE.js.map} +0 -0
  168. /package/dist/{doctor-XEPBNHM3.js.map → doctor-KCTXPX5D.js.map} +0 -0
  169. /package/dist/{init-BHVQAQ27.js.map → init-QFNBKKDC.js.map} +0 -0
  170. /package/dist/{installer-45ZLP2RP.js.map → installer-BWJED3ED.js.map} +0 -0
  171. /package/dist/{llm-KTD6SR55.js.map → llm-SMA5ZEAW.js.map} +0 -0
  172. /package/dist/{loader-NEX3UF6U.js.map → loader-Q3P3R4UP.js.map} +0 -0
  173. /package/dist/{loader-SHRKUKOS.js.map → loader-SKKUMT5C.js.map} +0 -0
  174. /package/dist/{open-2U7ZRGA3.js.map → open-7737CSPN.js.map} +0 -0
  175. /package/dist/{post-compact-QIBMEWL3.js.map → post-compact-2TJ5FPZH.js.map} +0 -0
  176. /package/dist/{post-tool-use-ICGFXDVY.js.map → post-tool-use-FRTSICC3.js.map} +0 -0
  177. /package/dist/{post-tool-use-failure-C7TLH3XQ.js.map → post-tool-use-failure-KYO2NCNB.js.map} +0 -0
  178. /package/dist/{pre-compact-IF7K4TQK.js.map → pre-compact-J6GCJEJR.js.map} +0 -0
  179. /package/dist/{provider-check-LTLQ6BUZ.js.map → provider-check-AE3L5Z6R.js.map} +0 -0
  180. /package/dist/{registry-TFQ22Z7N.js.map → registry-O2NZLO3V.js.map} +0 -0
  181. /package/dist/{remove-FBGM2QVJ.js.map → remove-3WZZC7AX.js.map} +0 -0
  182. /package/dist/{resolution-events-HGKIJOTA.js.map → resolution-events-XWYLLDRK.js.map} +0 -0
  183. /package/dist/{restart-TQEECRNW.js.map → restart-HUHEFOXU.js.map} +0 -0
  184. /package/dist/{search-NN5FC4Z6.js.map → search-ZGN3LDXG.js.map} +0 -0
  185. /package/dist/{server-XMWJ4GF7.js.map → server-PTXLVVEE.js.map} +0 -0
  186. /package/dist/{session-GLPAFYPO.js.map → session-7VV3IQMO.js.map} +0 -0
  187. /package/dist/{session-end-TI3ILRBC.js.map → session-end-SMU55UCM.js.map} +0 -0
  188. /package/dist/{setup-llm-AQSWLXCZ.js.map → setup-llm-7S3VPAPN.js.map} +0 -0
  189. /package/dist/{stats-BISBIBXZ.js.map → stats-GEOQ2DFF.js.map} +0 -0
  190. /package/dist/{stop-47BJ42EO.js.map → stop-7AKYBJJ2.js.map} +0 -0
  191. /package/dist/{stop-failure-VU5BTLWX.js.map → stop-failure-NLE2EURG.js.map} +0 -0
  192. /package/dist/{subagent-start-SPTKQRHU.js.map → subagent-start-LBNZF2TG.js.map} +0 -0
  193. /package/dist/{subagent-stop-UU75BYLC.js.map → subagent-stop-B2Z5GYAB.js.map} +0 -0
  194. /package/dist/{task-completed-MVDO7TZF.js.map → task-completed-PO5TETJ7.js.map} +0 -0
  195. /package/dist/{verify-QYSERHF7.js.map → verify-FNSP62I3.js.map} +0 -0
  196. /package/dist/{version-A72TAL2J.js.map → version-QEVU66NT.js.map} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
3
  SymbiontInstaller
4
- } from "./chunk-VVGZL2HX.js";
4
+ } from "./chunk-WYOE4IAX.js";
5
5
  import {
6
6
  LmStudioBackend,
7
7
  OllamaBackend
8
- } from "./chunk-ML6GTPZU.js";
8
+ } from "./chunk-CML4MCYF.js";
9
9
  import {
10
10
  closeDatabase,
11
11
  initDatabase,
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-MYX5NCRH.js";
14
14
  import {
15
15
  DaemonClient
16
- } from "./chunk-XZWFMMJR.js";
16
+ } from "./chunk-XWOQL4XN.js";
17
17
 
18
18
  // src/cli/shared.ts
19
19
  import fs from "fs";
@@ -69,11 +69,21 @@ secrets.env
69
69
  # Machine ID
70
70
  machine_id
71
71
 
72
+ # Update tracking \u2014 per-machine state
73
+ last-update-version
74
+ restart-reason.json
75
+
72
76
  # Binary attachments \u2014 screenshots captured from transcripts
73
77
  attachments/
74
78
 
75
79
  # Team worker deployment \u2014 patched wrangler.toml + source copy
76
80
  .team-worker/
81
+
82
+ # Runtime command alias \u2014 per-contributor override for which myco binary
83
+ # the hook guard invokes. Default (file absent) is \`myco\`; \`make dev-link\`
84
+ # writes \`myco-dev\`; users can hand-edit for PATH conflicts or pinning.
85
+ # Never committed \u2014 different contributors use different aliases.
86
+ runtime.command
77
87
  `;
78
88
  function registerSymbionts(manifests, projectRoot, packageRoot, verb) {
79
89
  let count = 0;
@@ -110,4 +120,4 @@ export {
110
120
  VAULT_GITIGNORE,
111
121
  registerSymbionts
112
122
  };
113
- //# sourceMappingURL=chunk-CTF7TQMJ.js.map
123
+ //# sourceMappingURL=chunk-TLK46KKD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/shared.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { OllamaBackend } from '../intelligence/ollama.js';\nimport { LmStudioBackend } from '../intelligence/lm-studio.js';\n\nimport { DaemonClient } from '../hooks/client.js';\nimport { initDatabase, closeDatabase, vaultDbPath } from '../db/client.js';\nimport { SymbiontInstaller } from '../symbionts/installer.js';\nimport type { SymbiontManifest } from '../symbionts/manifest-schema.js';\n\nexport { parseStringFlag, parseIntFlag } from '../logs/format.js';\n\n/**\n * Initialize the singleton database for direct CLI reads.\n * Used by CLI commands that only need reads (stats, search, session).\n * Does NOT require the daemon to be running — WAL mode allows concurrent reads.\n *\n * @returns a cleanup function that closes the database.\n */\nexport function initVaultDb(vaultDir: string): () => void {\n initDatabase(vaultDbPath(vaultDir));\n return closeDatabase;\n}\n\n/** Connect to the daemon, ensuring it's running. Exits on failure. */\nexport async function connectToDaemon(vaultDir: string): Promise<DaemonClient> {\n const client = new DaemonClient(vaultDir);\n const healthy = await client.ensureRunning();\n if (!healthy) {\n console.error('Failed to connect to daemon');\n process.exit(1);\n }\n return client;\n}\n\n/** Load .env from cwd (not script location — that's the plugin install dir). */\nexport function loadEnv(): void {\n const envPath = path.resolve(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) return;\n for (const line of fs.readFileSync(envPath, 'utf-8').split('\\n')) {\n const match = line.match(/^\\s*([^#=]+?)\\s*=\\s*(.*?)\\s*$/);\n if (match && !process.env[match[1]]) {\n process.env[match[1]] = match[2];\n }\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try { process.kill(pid, 0); return true; } catch { return false; }\n}\n\n// --- Provider defaults (sourced from backend classes) ---\nexport const PROVIDER_DEFAULTS: Record<string, { base_url: string }> = {\n ollama: { base_url: OllamaBackend.DEFAULT_BASE_URL },\n 'lm-studio': { base_url: LmStudioBackend.DEFAULT_BASE_URL },\n};\n\n\nexport const VAULT_GITIGNORE = `# SQLite database\nmyco.db*\nvectors.db*\n\n# Daemon state — per-machine, ephemeral\ndaemon.json\nbuffer/\nlogs/\n\n# Secrets — API keys for cloud providers\nsecrets.env\n\n# Machine ID\nmachine_id\n\n# Update tracking — per-machine state\nlast-update-version\nrestart-reason.json\n\n# Binary attachments — screenshots captured from transcripts\nattachments/\n\n# Team worker deployment — patched wrangler.toml + source copy\n.team-worker/\n\n# Runtime command alias — per-contributor override for which myco binary\n# the hook guard invokes. Default (file absent) is \\`myco\\`; \\`make dev-link\\`\n# writes \\`myco-dev\\`; users can hand-edit for PATH conflicts or pinning.\n# Never committed — different contributors use different aliases.\nruntime.command\n`;\n\n/** Collapse an absolute home-dir path to its `~/` form for portable config storage. */\nexport function collapseHomePath(absPath: string): string {\n const home = os.homedir();\n if (absPath.startsWith(home + path.sep) || absPath === home) {\n return '~' + absPath.slice(home.length);\n }\n return absPath;\n}\n\n/**\n * Run the SymbiontInstaller for each symbiont manifest and log results.\n * Shared between myco init and myco update.\n */\nexport function registerSymbionts(\n manifests: SymbiontManifest[],\n projectRoot: string,\n packageRoot: string,\n verb: 'Registered' | 'Updated',\n): number {\n let count = 0;\n for (const manifest of manifests) {\n try {\n const installer = new SymbiontInstaller(manifest, projectRoot, packageRoot);\n const result = installer.install();\n\n const installed = [\n result.hooks && 'hooks',\n result.mcp && 'MCP server',\n result.skills && 'skills',\n result.settings && 'settings',\n result.instructions && 'instructions',\n result.pluginPackage && 'plugin deps',\n ].filter(Boolean);\n\n if (installed.length > 0) {\n console.log(` \\u2713 ${verb} ${manifest.displayName}: ${installed.join(', ')}`);\n count++;\n } else {\n console.log(` \\u2013 ${manifest.displayName}: no registration targets configured`);\n }\n } catch (err) {\n console.error(` \\u2717 Failed to register ${manifest.displayName}: ${(err as Error).message}`);\n }\n }\n return count;\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AAkBR,SAAS,YAAY,UAA8B;AACxD,eAAa,YAAY,QAAQ,CAAC;AAClC,SAAO;AACT;AAGA,eAAsB,gBAAgB,UAAyC;AAC7E,QAAM,SAAS,IAAI,aAAa,QAAQ;AACxC,QAAM,UAAU,MAAM,OAAO,cAAc;AAC3C,MAAI,CAAC,SAAS;AACZ,YAAQ,MAAM,6BAA6B;AAC3C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAGO,SAAS,UAAgB;AAC9B,QAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM;AAClD,MAAI,CAAC,GAAG,WAAW,OAAO,EAAG;AAC7B,aAAW,QAAQ,GAAG,aAAa,SAAS,OAAO,EAAE,MAAM,IAAI,GAAG;AAChE,UAAM,QAAQ,KAAK,MAAM,+BAA+B;AACxD,QAAI,SAAS,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC,GAAG;AACnC,cAAQ,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC;AAAA,IACjC;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAAsB;AACnD,MAAI;AAAE,YAAQ,KAAK,KAAK,CAAC;AAAG,WAAO;AAAA,EAAM,QAAQ;AAAE,WAAO;AAAA,EAAO;AACnE;AAGO,IAAM,oBAA0D;AAAA,EACrE,QAAQ,EAAE,UAAU,cAAc,iBAAiB;AAAA,EACnD,aAAa,EAAE,UAAU,gBAAgB,iBAAiB;AAC5D;AAGO,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CxB,SAAS,kBACd,WACA,aACA,aACA,MACQ;AACR,MAAI,QAAQ;AACZ,aAAW,YAAY,WAAW;AAChC,QAAI;AACF,YAAM,YAAY,IAAI,kBAAkB,UAAU,aAAa,WAAW;AAC1E,YAAM,SAAS,UAAU,QAAQ;AAEjC,YAAM,YAAY;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,OAAO,OAAO;AAAA,QACd,OAAO,UAAU;AAAA,QACjB,OAAO,YAAY;AAAA,QACnB,OAAO,gBAAgB;AAAA,QACvB,OAAO,iBAAiB;AAAA,MAC1B,EAAE,OAAO,OAAO;AAEhB,UAAI,UAAU,SAAS,GAAG;AACxB,gBAAQ,IAAI,YAAY,IAAI,IAAI,SAAS,WAAW,KAAK,UAAU,KAAK,IAAI,CAAC,EAAE;AAC/E;AAAA,MACF,OAAO;AACL,gBAAQ,IAAI,YAAY,SAAS,WAAW,sCAAsC;AAAA,MACpF;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,+BAA+B,SAAS,WAAW,KAAM,IAAc,OAAO,EAAE;AAAA,IAChG;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  SEARCH_PREVIEW_CHARS,
7
7
  SEARCH_RESULTS_DEFAULT_LIMIT
8
- } from "./chunk-7DAH5GLC.js";
8
+ } from "./chunk-CKJAWZQE.js";
9
9
 
10
10
  // src/db/queries/search.ts
11
11
  function fullTextSearch(query, options = {}) {
@@ -125,6 +125,9 @@ function hydrateSearchResults(vectorResults) {
125
125
  const artifactStmt = db.prepare(
126
126
  `SELECT id, title, content FROM artifacts WHERE id IN (SELECT value FROM json_each(?))`
127
127
  );
128
+ const skillStmt = db.prepare(
129
+ `SELECT id, name, display_name, description FROM skill_records WHERE id IN (SELECT value FROM json_each(?))`
130
+ );
128
131
  const sessionResults = byNamespace.get("sessions");
129
132
  if (sessionResults && sessionResults.length > 0) {
130
133
  const ids = sessionResults.map((r) => r.id);
@@ -195,6 +198,23 @@ function hydrateSearchResults(vectorResults) {
195
198
  });
196
199
  }
197
200
  }
201
+ const skillResults = byNamespace.get("skill_records");
202
+ if (skillResults && skillResults.length > 0) {
203
+ const ids = skillResults.map((r) => r.id);
204
+ const rows = skillStmt.all(JSON.stringify(ids));
205
+ const rowMap = new Map(rows.map((r) => [r.id, r]));
206
+ for (const vr of skillResults) {
207
+ const row = rowMap.get(vr.id);
208
+ if (!row) continue;
209
+ results.push({
210
+ id: row.id,
211
+ type: "skill",
212
+ title: row.display_name || row.name,
213
+ preview: row.description.slice(0, SEARCH_PREVIEW_CHARS),
214
+ score: vr.similarity
215
+ });
216
+ }
217
+ }
198
218
  results.sort((a, b) => b.score - a.score);
199
219
  return results;
200
220
  }
@@ -203,4 +223,4 @@ export {
203
223
  fullTextSearch,
204
224
  hydrateSearchResults
205
225
  };
206
- //# sourceMappingURL=chunk-IGBHLFV5.js.map
226
+ //# sourceMappingURL=chunk-TOER6RNC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db/queries/search.ts"],"sourcesContent":["/**\n * Full-text search using SQLite FTS5.\n *\n * Searches prompt_batches and activities via their FTS5 virtual tables.\n * Semantic search (vector similarity) is handled by the external VectorStore —\n * this module covers text-based retrieval only.\n *\n * All queries use parameterized placeholders throughout.\n */\n\nimport { getDatabase } from '@myco/db/client.js';\nimport {\n SEARCH_RESULTS_DEFAULT_LIMIT,\n SEARCH_PREVIEW_CHARS,\n} from '@myco/constants.js';\nimport type { VectorSearchResult } from '@myco/daemon/embedding/types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** All result types that can appear in search results. */\nexport type SearchResultType =\n | 'session'\n | 'spore'\n | 'plan'\n | 'artifact'\n | 'prompt_batch'\n | 'activity'\n | 'skill';\n\n/** A single result returned from full-text or semantic search. */\nexport interface SearchResult {\n id: string;\n type: SearchResultType;\n title: string;\n preview: string;\n score: number;\n session_id?: string;\n}\n\n/** Options for fullTextSearch. */\nexport interface SearchOptions {\n /** Restrict results to a single type. */\n type?: string;\n /** Maximum number of results to return (default: SEARCH_RESULTS_DEFAULT_LIMIT). */\n limit?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Full-text search across capture tables using SQLite FTS5.\n *\n * Searches prompt_batches (indexed on user_prompt) and activities (indexed\n * on tool_name, tool_input, file_path). The raw query string is passed\n * directly to FTS5 MATCH — callers should sanitize if needed.\n *\n * FTS5 `rank` values are negative (lower = better match). This function\n * converts them to positive scores via `Math.abs()` so higher = better\n * in the returned results.\n *\n * When `options.type` is specified, only the matching table branch is queried.\n *\n * @param query — search string (FTS5 MATCH syntax)\n * @param options — optional type filter and result limit\n * @returns SearchResult[] ordered by score DESC\n */\nexport function fullTextSearch(\n query: string,\n options: SearchOptions = {},\n): SearchResult[] {\n const db = getDatabase();\n const limit = options.limit ?? SEARCH_RESULTS_DEFAULT_LIMIT;\n const typeFilter = options.type;\n\n const results: SearchResult[] = [];\n\n // -- prompt_batches branch ------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'prompt_batch') {\n const batchRows = db.prepare(\n `SELECT pb.id, pb.prompt_number, pb.session_id,\n substr(COALESCE(pb.user_prompt, '') || ' ' || COALESCE(pb.response_summary, ''), 1, ?) AS preview,\n fts.rank\n FROM prompt_batches_fts fts\n JOIN prompt_batches pb ON pb.id = fts.rowid\n WHERE prompt_batches_fts MATCH ?\n ORDER BY fts.rank\n LIMIT ?`\n ).all(SEARCH_PREVIEW_CHARS, query, limit) as Array<{\n id: number;\n prompt_number: number | null;\n session_id: string | null;\n preview: string;\n rank: number;\n }>;\n\n for (const row of batchRows) {\n results.push({\n id: String(row.id),\n type: 'prompt_batch',\n title: row.prompt_number != null\n ? `Batch #${row.prompt_number}`\n : `Batch ${row.id}`,\n preview: row.preview,\n score: Math.abs(row.rank),\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // -- activities branch ----------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'activity') {\n const activityRows = db.prepare(\n `SELECT a.id, a.tool_name, a.tool_input, a.file_path, a.session_id,\n fts.rank\n FROM activities_fts fts\n JOIN activities a ON a.id = fts.rowid\n WHERE activities_fts MATCH ?\n ORDER BY fts.rank\n LIMIT ?`\n ).all(query, limit) as Array<{\n id: number;\n tool_name: string;\n tool_input: string | null;\n file_path: string | null;\n session_id: string | null;\n rank: number;\n }>;\n\n for (const row of activityRows) {\n const preview = (row.tool_input ?? row.file_path ?? '').slice(0, SEARCH_PREVIEW_CHARS);\n results.push({\n id: String(row.id),\n type: 'activity',\n title: row.tool_name,\n preview,\n score: Math.abs(row.rank),\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // -- spores branch --------------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'spore') {\n const sporeRows = db.prepare(\n `SELECT s.id, s.observation_type, s.session_id,\n substr(COALESCE(s.content, ''), 1, ?) AS preview,\n fts.rank\n FROM spores_fts fts\n JOIN spores s ON s.rowid = fts.rowid\n WHERE spores_fts MATCH ?\n ORDER BY fts.rank\n LIMIT ?`\n ).all(SEARCH_PREVIEW_CHARS, query, limit) as Array<{\n id: string;\n observation_type: string;\n session_id: string | null;\n preview: string;\n rank: number;\n }>;\n\n for (const row of sporeRows) {\n results.push({\n id: String(row.id),\n type: 'spore',\n title: row.observation_type,\n preview: row.preview,\n score: Math.abs(row.rank),\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // -- sessions branch ------------------------------------------------------\n if (typeFilter === undefined || typeFilter === 'session') {\n const sessionRows = db.prepare(\n `SELECT s.id, s.title,\n substr(COALESCE(s.summary, s.title, ''), 1, ?) AS preview,\n fts.rank\n FROM sessions_fts fts\n JOIN sessions s ON s.rowid = fts.rowid\n WHERE sessions_fts MATCH ?\n ORDER BY fts.rank\n LIMIT ?`\n ).all(SEARCH_PREVIEW_CHARS, query, limit) as Array<{\n id: string;\n title: string | null;\n preview: string;\n rank: number;\n }>;\n\n for (const row of sessionRows) {\n results.push({\n id: String(row.id),\n type: 'session',\n title: row.title ?? `Session ${row.id.slice(-6)}`,\n preview: row.preview,\n score: Math.abs(row.rank),\n });\n }\n }\n\n // Sort combined results by score DESC and apply limit.\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, limit);\n}\n\n// ---------------------------------------------------------------------------\n// Hydration — convert VectorSearchResults into SearchResults\n// ---------------------------------------------------------------------------\n\n/** Row shape returned from sessions table for hydration. */\ninterface SessionRow {\n id: string;\n title: string | null;\n summary: string | null;\n session_id?: undefined;\n}\n\n/** Row shape returned from spores table for hydration. */\ninterface SporeRow {\n id: string;\n observation_type: string;\n content: string;\n session_id: string | null;\n}\n\n/** Row shape returned from plans table for hydration. */\ninterface PlanRow {\n id: string;\n title: string | null;\n content: string | null;\n session_id: string | null;\n}\n\n/** Row shape returned from artifacts table for hydration. */\ninterface ArtifactRow {\n id: string;\n title: string;\n content: string | null;\n}\n\n/**\n * Hydrate vector search results into SearchResults by fetching full records\n * from the record store.\n *\n * Groups results by namespace, queries each table for the relevant IDs, then\n * maps them into SearchResult format with titles and previews.\n */\nexport function hydrateSearchResults(\n vectorResults: VectorSearchResult[],\n): SearchResult[] {\n if (vectorResults.length === 0) return [];\n\n const db = getDatabase();\n const results: SearchResult[] = [];\n\n // Group result IDs by namespace\n const byNamespace = new Map<string, VectorSearchResult[]>();\n for (const vr of vectorResults) {\n const group = byNamespace.get(vr.namespace) ?? [];\n group.push(vr);\n byNamespace.set(vr.namespace, group);\n }\n\n // Use json_each so the statement text is stable and SQLite can cache the plan.\n const sessionStmt = db.prepare(\n `SELECT id, title, summary FROM sessions WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const sporeStmt = db.prepare(\n `SELECT id, observation_type, content, session_id FROM spores WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const planStmt = db.prepare(\n `SELECT id, title, content, session_id FROM plans WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const artifactStmt = db.prepare(\n `SELECT id, title, content FROM artifacts WHERE id IN (SELECT value FROM json_each(?))`,\n );\n const skillStmt = db.prepare(\n `SELECT id, name, display_name, description FROM skill_records WHERE id IN (SELECT value FROM json_each(?))`,\n );\n\n // --- sessions ---\n const sessionResults = byNamespace.get('sessions');\n if (sessionResults && sessionResults.length > 0) {\n const ids = sessionResults.map((r) => r.id);\n const rows = sessionStmt.all(JSON.stringify(ids)) as SessionRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of sessionResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'session',\n title: row.title ?? `Session ${row.id.slice(-6)}`,\n preview: (row.summary ?? '').slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n });\n }\n }\n\n // --- spores ---\n const sporeResults = byNamespace.get('spores');\n if (sporeResults && sporeResults.length > 0) {\n const ids = sporeResults.map((r) => r.id);\n const rows = sporeStmt.all(JSON.stringify(ids)) as SporeRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of sporeResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'spore',\n title: row.observation_type,\n preview: row.content.slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // --- plans ---\n const planResults = byNamespace.get('plans');\n if (planResults && planResults.length > 0) {\n const ids = planResults.map((r) => r.id);\n const rows = planStmt.all(JSON.stringify(ids)) as PlanRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of planResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'plan',\n title: row.title ?? `Plan ${row.id.slice(-6)}`,\n preview: (row.content ?? '').slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n ...(row.session_id != null ? { session_id: row.session_id } : {}),\n });\n }\n }\n\n // --- artifacts ---\n const artifactResults = byNamespace.get('artifacts');\n if (artifactResults && artifactResults.length > 0) {\n const ids = artifactResults.map((r) => r.id);\n const rows = artifactStmt.all(JSON.stringify(ids)) as ArtifactRow[];\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of artifactResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'artifact',\n title: row.title,\n preview: (row.content ?? '').slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n });\n }\n }\n\n // --- skill_records ---\n const skillResults = byNamespace.get('skill_records');\n if (skillResults && skillResults.length > 0) {\n const ids = skillResults.map((r) => r.id);\n const rows = skillStmt.all(JSON.stringify(ids)) as Array<{ id: string; name: string; display_name: string; description: string }>;\n\n const rowMap = new Map(rows.map((r) => [r.id, r]));\n for (const vr of skillResults) {\n const row = rowMap.get(vr.id);\n if (!row) continue;\n results.push({\n id: row.id,\n type: 'skill',\n title: row.display_name || row.name,\n preview: row.description.slice(0, SEARCH_PREVIEW_CHARS),\n score: vr.similarity,\n });\n }\n }\n\n // Preserve the original similarity-based ordering from vector search\n results.sort((a, b) => b.score - a.score);\n return results;\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  getTeamMachineId,
4
4
  syncRow
5
- } from "./chunk-C3C5QVLK.js";
5
+ } from "./chunk-O3TRN3RC.js";
6
6
  import {
7
7
  getDatabase
8
8
  } from "./chunk-MYX5NCRH.js";
@@ -124,6 +124,10 @@ function buildSporeWhere(options) {
124
124
  const pattern = `%${options.search}%`;
125
125
  params.push(pattern, pattern);
126
126
  }
127
+ if (options.since !== void 0) {
128
+ conditions.push("created_at > ?");
129
+ params.push(options.since);
130
+ }
127
131
  return {
128
132
  where: conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "",
129
133
  params
@@ -183,4 +187,4 @@ export {
183
187
  listSporeIdsSince,
184
188
  updateSporeStatus
185
189
  };
186
- //# sourceMappingURL=chunk-ZSJPI5MS.js.map
190
+ //# sourceMappingURL=chunk-TZAXQKO6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db/queries/spores.ts"],"sourcesContent":["/**\n * Spore CRUD query helpers.\n *\n * All functions obtain the SQLite instance internally via `getDatabase()`.\n * Queries use positional `?` placeholders throughout (better-sqlite3).\n */\n\nimport { getDatabase } from '@myco/db/client.js';\nimport { getTeamMachineId } from '@myco/daemon/team-context.js';\nimport { syncRow } from '@myco/db/queries/team-outbox.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Default number of spores returned by listSpores when no limit given. */\nconst DEFAULT_LIST_LIMIT = 100;\n\n/** Default spore status for new spores. */\nconst DEFAULT_STATUS = 'active';\n\n/** Default importance score for new spores. */\nexport const DEFAULT_IMPORTANCE = 5;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Fields required (or optional) when inserting a spore. */\nexport interface SporeInsert {\n id: string;\n agent_id: string;\n observation_type: string;\n content: string;\n created_at: number;\n session_id?: string | null;\n prompt_batch_id?: number | null;\n status?: string;\n context?: string | null;\n importance?: number;\n file_path?: string | null;\n tags?: string | null;\n content_hash?: string | null;\n properties?: string | null;\n updated_at?: number | null;\n machine_id?: string;\n}\n\n/** Row shape returned from spore queries (all columns). */\nexport interface SporeRow {\n id: string;\n agent_id: string;\n session_id: string | null;\n prompt_batch_id: number | null;\n observation_type: string;\n status: string;\n content: string;\n context: string | null;\n importance: number;\n file_path: string | null;\n tags: string | null;\n content_hash: string | null;\n properties: string | null;\n embedded: number;\n created_at: number;\n updated_at: number | null;\n machine_id: string;\n synced_at: number | null;\n}\n\n/** Filter options for `listSpores`. */\nexport interface ListSporesOptions {\n agent_id?: string;\n observation_type?: string;\n status?: string;\n session_id?: string;\n search?: string;\n /** Only return spores created after this epoch-seconds timestamp. */\n since?: number;\n limit?: number;\n offset?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Column list\n// ---------------------------------------------------------------------------\n\nconst SPORE_COLUMNS = [\n 'id',\n 'agent_id',\n 'session_id',\n 'prompt_batch_id',\n 'observation_type',\n 'status',\n 'content',\n 'context',\n 'importance',\n 'file_path',\n 'tags',\n 'content_hash',\n 'properties',\n 'embedded',\n 'created_at',\n 'updated_at',\n 'machine_id',\n 'synced_at',\n] as const;\n\nconst SELECT_COLUMNS = SPORE_COLUMNS.join(', ');\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Normalize a SQLite result row into a typed SporeRow. */\nfunction toSporeRow(row: Record<string, unknown>): SporeRow {\n return {\n id: row.id as string,\n agent_id: row.agent_id as string,\n session_id: (row.session_id as string) ?? null,\n prompt_batch_id: (row.prompt_batch_id as number) ?? null,\n observation_type: row.observation_type as string,\n status: row.status as string,\n content: row.content as string,\n context: (row.context as string) ?? null,\n importance: row.importance as number,\n file_path: (row.file_path as string) ?? null,\n tags: (row.tags as string) ?? null,\n content_hash: (row.content_hash as string) ?? null,\n properties: (row.properties as string) ?? null,\n embedded: (row.embedded as number) ?? 0,\n created_at: row.created_at as number,\n updated_at: (row.updated_at as number) ?? null,\n machine_id: (row.machine_id as string) ?? 'local',\n synced_at: (row.synced_at as number) ?? null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Insert a new spore.\n *\n * Requires a valid `agent_id` (foreign key to agents table).\n */\nexport function insertSpore(data: SporeInsert): SporeRow {\n const db = getDatabase();\n\n db.prepare(\n `INSERT INTO spores (\n id, agent_id, session_id, prompt_batch_id,\n observation_type, status, content, context,\n importance, file_path, tags, content_hash,\n properties, created_at, updated_at, machine_id\n ) VALUES (\n ?, ?, ?, ?,\n ?, ?, ?, ?,\n ?, ?, ?, ?,\n ?, ?, ?, ?\n )`,\n ).run(\n data.id,\n data.agent_id,\n data.session_id ?? null,\n data.prompt_batch_id ?? null,\n data.observation_type,\n data.status ?? DEFAULT_STATUS,\n data.content,\n data.context ?? null,\n data.importance ?? DEFAULT_IMPORTANCE,\n data.file_path ?? null,\n data.tags ?? null,\n data.content_hash ?? null,\n data.properties ?? null,\n data.created_at,\n data.updated_at ?? null,\n data.machine_id ?? getTeamMachineId(),\n );\n\n const row = toSporeRow(\n db.prepare(`SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`).get(data.id) as Record<string, unknown>,\n );\n\n syncRow('spores', row);\n\n return row;\n}\n\n/**\n * Retrieve a single spore by id.\n *\n * @returns the spore row, or null if not found.\n */\nexport function getSpore(id: string): SporeRow | null {\n const db = getDatabase();\n\n const row = db.prepare(\n `SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`,\n ).get(id) as Record<string, unknown> | undefined;\n\n if (!row) return null;\n return toSporeRow(row);\n}\n\n/**\n * List spores with optional filters, ordered by created_at DESC.\n */\n/** Build WHERE clause and bound params from spore filter options. */\nfunction buildSporeWhere(\n options: Omit<ListSporesOptions, 'limit' | 'offset'>,\n): { where: string; params: unknown[] } {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent_id !== undefined) {\n conditions.push(`agent_id = ?`);\n params.push(options.agent_id);\n }\n if (options.observation_type !== undefined) {\n conditions.push(`observation_type = ?`);\n params.push(options.observation_type);\n }\n if (options.status !== undefined) {\n conditions.push(`status = ?`);\n params.push(options.status);\n }\n if (options.session_id !== undefined) {\n conditions.push(`session_id = ?`);\n params.push(options.session_id);\n }\n if (options.search !== undefined && options.search.length > 0) {\n conditions.push(`(content LIKE ? OR observation_type LIKE ?)`);\n const pattern = `%${options.search}%`;\n params.push(pattern, pattern);\n }\n if (options.since !== undefined) {\n conditions.push('created_at > ?');\n params.push(options.since);\n }\n\n return {\n where: conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '',\n params,\n };\n}\n\n/**\n * List spores with optional filters, ordered by created_at DESC.\n */\nexport function listSpores(\n options: ListSporesOptions = {},\n): SporeRow[] {\n const db = getDatabase();\n const { where, params } = buildSporeWhere(options);\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n const offset = options.offset ?? 0;\n\n const rows = db.prepare(\n `SELECT ${SELECT_COLUMNS}\n FROM spores\n ${where}\n ORDER BY created_at DESC\n LIMIT ?\n OFFSET ?`,\n ).all(...params, limit, offset) as Record<string, unknown>[];\n\n return rows.map(toSporeRow);\n}\n\n/**\n * Count spores matching optional filters (for pagination totals).\n */\nexport function countSpores(\n options: Omit<ListSporesOptions, 'limit' | 'offset'> = {},\n): number {\n const db = getDatabase();\n const { where, params } = buildSporeWhere(options);\n\n const row = db.prepare(\n `SELECT COUNT(*) as count FROM spores ${where}`,\n ).get(...params) as { count: number };\n\n return row.count;\n}\n\n/**\n * Count active spores created after a given timestamp.\n * Used by skill-evolve to detect new knowledge since last assessment.\n */\nexport function countSporesSince(sinceEpoch: number): number {\n const db = getDatabase();\n const row = db.prepare(\n `SELECT COUNT(*) as count FROM spores WHERE created_at > ? AND status = 'active'`,\n ).get(sinceEpoch) as { count: number };\n return row.count;\n}\n\n/**\n * List active spore IDs created after a given timestamp, ordered newest first.\n */\nexport function listSporeIdsSince(sinceEpoch: number, limit = 20): string[] {\n const db = getDatabase();\n const rows = db.prepare(\n `SELECT id FROM spores WHERE created_at > ? AND status = 'active' ORDER BY created_at DESC LIMIT ?`,\n ).all(sinceEpoch, limit) as Array<{ id: string }>;\n return rows.map(r => r.id);\n}\n\n/**\n * Update the status and updated_at timestamp of a spore.\n *\n * @returns the updated row, or null if the spore does not exist.\n */\nexport function updateSporeStatus(\n id: string,\n status: string,\n updatedAt: number,\n): SporeRow | null {\n const db = getDatabase();\n\n const info = db.prepare(\n `UPDATE spores\n SET status = ?, updated_at = ?\n WHERE id = ?`,\n ).run(status, updatedAt, id);\n\n if (info.changes === 0) return null;\n\n const row = toSporeRow(\n db.prepare(`SELECT ${SELECT_COLUMNS} FROM spores WHERE id = ?`).get(id) as Record<string, unknown>,\n );\n\n syncRow('spores', row);\n\n return row;\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  getTeamMachineId,
4
4
  syncRow
5
- } from "./chunk-C3C5QVLK.js";
5
+ } from "./chunk-O3TRN3RC.js";
6
6
  import {
7
7
  getDatabase
8
8
  } from "./chunk-MYX5NCRH.js";
@@ -88,4 +88,4 @@ export {
88
88
  insertResolutionEvent,
89
89
  listResolutionEvents
90
90
  };
91
- //# sourceMappingURL=chunk-RKPTMHED.js.map
91
+ //# sourceMappingURL=chunk-U3J2DDSR.js.map
@@ -11,7 +11,7 @@ var cached;
11
11
  function getPluginVersion() {
12
12
  if (cached) return cached;
13
13
  if (true) {
14
- cached = "0.17.2";
14
+ cached = "0.18.1";
15
15
  return cached;
16
16
  }
17
17
  const root = findPackageRoot(path.dirname(fileURLToPath(import.meta.url)));
@@ -32,4 +32,4 @@ function getPluginVersion() {
32
32
  export {
33
33
  getPluginVersion
34
34
  };
35
- //# sourceMappingURL=chunk-SI5BBQAT.js.map
35
+ //# sourceMappingURL=chunk-W7WENJ6F.js.map
@@ -208,9 +208,8 @@ function writeOrDeleteJsonFile(filePath, data) {
208
208
  // src/symbionts/install-helpers.ts
209
209
  import fs2 from "fs";
210
210
  import path2 from "path";
211
- var MYCO_HOOK_COMMAND_PREFIX = "myco-run";
212
211
  function isMycoHookCommand(command) {
213
- return command.startsWith(MYCO_HOOK_COMMAND_PREFIX) || command.includes(".agents/myco-hook.cjs");
212
+ return command.includes(".agents/myco-run.cjs") || command.includes(".agents/myco-hook.cjs") || command.startsWith("myco-run");
214
213
  }
215
214
  function isMycoHookGroup(group) {
216
215
  if (Array.isArray(group.hooks) && group.hooks.some((h) => h.command && isMycoHookCommand(h.command))) return true;
@@ -250,9 +249,10 @@ var GITIGNORE_COMMENT = "# Myco managed (machine-specific)";
250
249
  var GITIGNORE_SKILLS_COMMENT_LEGACY = "# Myco skill symlinks (machine-specific)";
251
250
  var WRANGLER_CACHE_DIR = ".wrangler/";
252
251
  var TEMPLATES_SUBDIR = "src/symbionts/templates";
253
- var HOOK_GUARD_TEMPLATE_FILENAME = "hook-guard.cjs";
254
- var HOOK_GUARD_INSTALLED_FILENAME = "myco-hook.cjs";
252
+ var HOOK_GUARD_TEMPLATE_FILENAME = "myco-run.cjs";
253
+ var HOOK_GUARD_INSTALLED_FILENAME = "myco-run.cjs";
255
254
  var HOOK_GUARD_PROJECT_PATH = `.agents/${HOOK_GUARD_INSTALLED_FILENAME}`;
255
+ var LEGACY_HOOK_GUARD_PATH = ".agents/myco-hook.cjs";
256
256
  var SKILLS_SUBDIR = "skills";
257
257
  var CANONICAL_SKILLS_DIR = ".agents/skills";
258
258
  var MYCO_MCP_SERVER_NAME = "myco";
@@ -306,33 +306,47 @@ var SymbiontInstaller = class {
306
306
  return true;
307
307
  }
308
308
  /**
309
- * Copy the hook-guard script into .agents/myco-hook.cjs.
310
- * Returns true if the file was written (or updated); false if skipped or N/A.
309
+ * Copy the hook guard script into .agents/myco-run.cjs and delete the
310
+ * legacy .agents/myco-hook.cjs if present.
311
+ *
312
+ * The guard is the cross-platform entry point for lifecycle hooks.
313
+ * Hook commands invoke `node .agents/myco-run.cjs …`, and the guard
314
+ * resolves which myco binary to exec via `.myco/runtime.command`.
315
+ * MCP server spawn continues to use the published `myco-run` binary.
316
+ * Returns true if the file was written (or updated); false if skipped
317
+ * or N/A.
311
318
  */
312
319
  installHookGuard() {
313
320
  const reg = this.manifest.registration;
314
321
  if (!reg?.hooksTarget) return false;
315
322
  const guardTemplate = this.readTemplateFile(HOOK_GUARD_TEMPLATE_FILENAME);
316
323
  if (!guardTemplate) return false;
324
+ try {
325
+ fs3.unlinkSync(path3.join(this.projectRoot, LEGACY_HOOK_GUARD_PATH));
326
+ } catch {
327
+ }
317
328
  return this.writeManagedFile(
318
329
  path3.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH),
319
330
  guardTemplate
320
331
  );
321
332
  }
322
333
  /**
323
- * Remove the hook-guard script from .agents/myco-hook.cjs.
324
- * Returns true if the file was removed; false otherwise.
334
+ * Remove the hook guard script from .agents/myco-run.cjs.
335
+ * Also deletes the legacy .agents/myco-hook.cjs if present.
336
+ * Returns true if any file was removed; false otherwise.
325
337
  */
326
338
  uninstallHookGuard() {
327
339
  const reg = this.manifest.registration;
328
340
  if (!reg?.hooksTarget) return false;
329
- const targetPath = path3.join(this.projectRoot, HOOK_GUARD_PROJECT_PATH);
330
- try {
331
- fs3.unlinkSync(targetPath);
332
- return true;
333
- } catch {
334
- return false;
341
+ let removed = false;
342
+ for (const relPath of [HOOK_GUARD_PROJECT_PATH, LEGACY_HOOK_GUARD_PATH]) {
343
+ try {
344
+ fs3.unlinkSync(path3.join(this.projectRoot, relPath));
345
+ removed = true;
346
+ } catch {
347
+ }
335
348
  }
349
+ return removed;
336
350
  }
337
351
  /** Load a JSON template file for this symbiont. Returns null if not found. */
338
352
  loadTemplate(name) {
@@ -356,6 +370,7 @@ var SymbiontInstaller = class {
356
370
  install() {
357
371
  const reg = this.manifest.registration;
358
372
  this.installHookGuard();
373
+ this.cleanupLegacyMycoCmdEntries();
359
374
  const result = this.shouldBatchJsonTargets(reg) ? this.installBatchedJson(reg) : {
360
375
  hooks: this.installHooks(),
361
376
  mcp: this.installMcp(),
@@ -367,6 +382,129 @@ var SymbiontInstaller = class {
367
382
  this.updateGitignore();
368
383
  return result;
369
384
  }
385
+ /**
386
+ * Sweep legacy `MYCO_CMD` env-var writes and `myco-run` command-name
387
+ * entries from this symbiont's installed config files.
388
+ *
389
+ * Background: prior to the `.myco/runtime.command` refactor, `make
390
+ * dev-link` injected `MYCO_CMD=myco-dev` into each symbiont's env
391
+ * block (`.claude/settings.json` → `env`, `.cursor/mcp.json` →
392
+ * `mcp.myco.env`, `.codex/config.toml` →
393
+ * `[shell_environment_policy.set]`), and each symbiont's template
394
+ * permission allowlist listed `myco-run` as a callable command. The
395
+ * env-var pattern is now obsolete — `.myco/runtime.command` is the
396
+ * hook-side source of truth — while the old allowlist entries remain
397
+ * legacy noise after the permissions refactor.
398
+ *
399
+ * This cleanup runs automatically on every install/update pass so
400
+ * contributors upgrading across this refactor don't need to manually
401
+ * edit any config file. Idempotent: a second run after cleanup is a
402
+ * no-op. Safe to remove from the install pipeline once every known
403
+ * contributor has updated at least once.
404
+ */
405
+ cleanupLegacyMycoCmdEntries() {
406
+ const reg = this.manifest.registration;
407
+ if (!reg) return;
408
+ if (reg.settingsTarget) {
409
+ const settingsPath = path3.join(this.projectRoot, reg.settingsTarget);
410
+ const format = reg.settingsFormat ?? "json";
411
+ if (format === "toml") {
412
+ this.stripLegacyFromToml(settingsPath);
413
+ } else {
414
+ this.stripLegacyFromJson(settingsPath);
415
+ }
416
+ }
417
+ if (reg.mcpTarget && reg.mcpFormat !== "toml") {
418
+ this.stripLegacyFromJson(path3.join(this.projectRoot, reg.mcpTarget));
419
+ }
420
+ }
421
+ /**
422
+ * Walk a JSON settings/MCP file and delete legacy MYCO_CMD + myco-run
423
+ * entries. Writes back only if something changed.
424
+ *
425
+ * Removes:
426
+ * - `MYCO_CMD` key from any object named `env` anywhere in the tree
427
+ * - `myco-run` / `myco-run *` / `myco-run:*` / `Bash(myco-run *)` /
428
+ * `Bash(myco-run:*)` / `ShellTool(myco-run *)` from string arrays
429
+ * - `myco-run` / `myco-run *` keys from object-boolean maps like
430
+ * `chat.tools.terminal.autoApprove`
431
+ */
432
+ stripLegacyFromJson(filePath) {
433
+ let raw;
434
+ try {
435
+ raw = fs3.readFileSync(filePath, "utf-8");
436
+ } catch {
437
+ return;
438
+ }
439
+ let data;
440
+ try {
441
+ data = JSON.parse(raw);
442
+ } catch {
443
+ return;
444
+ }
445
+ let changed = false;
446
+ const LEGACY_STRINGS = /* @__PURE__ */ new Set([
447
+ "myco-run",
448
+ "myco-run *",
449
+ "myco-run:*",
450
+ "Bash(myco-run *)",
451
+ "Bash(myco-run:*)",
452
+ "ShellTool(myco-run *)"
453
+ ]);
454
+ const LEGACY_OBJECT_KEYS = ["myco-run", "myco-run *"];
455
+ const EXEC_ARGV_KEYS = /* @__PURE__ */ new Set(["command", "args"]);
456
+ const walk = (node, parentKey) => {
457
+ if (node === null || typeof node !== "object") return;
458
+ if (Array.isArray(node)) {
459
+ if (parentKey !== void 0 && EXEC_ARGV_KEYS.has(parentKey)) return;
460
+ for (let i = node.length - 1; i >= 0; i--) {
461
+ if (typeof node[i] === "string" && LEGACY_STRINGS.has(node[i])) {
462
+ node.splice(i, 1);
463
+ changed = true;
464
+ } else {
465
+ walk(node[i]);
466
+ }
467
+ }
468
+ return;
469
+ }
470
+ const obj = node;
471
+ if (parentKey === "env" && "MYCO_CMD" in obj) {
472
+ delete obj.MYCO_CMD;
473
+ changed = true;
474
+ }
475
+ for (const key of LEGACY_OBJECT_KEYS) {
476
+ if (key in obj) {
477
+ delete obj[key];
478
+ changed = true;
479
+ }
480
+ }
481
+ for (const [k, v] of Object.entries(obj)) {
482
+ walk(v, k);
483
+ }
484
+ };
485
+ walk(data);
486
+ if (changed) {
487
+ fs3.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
488
+ }
489
+ }
490
+ /**
491
+ * Strip `MYCO_CMD = "..."` from the `[shell_environment_policy.set]`
492
+ * section of a TOML settings file. Leaves the rest of the file
493
+ * untouched. Drops the `[shell_environment_policy.set]` header entirely
494
+ * when the section becomes empty.
495
+ */
496
+ stripLegacyFromToml(filePath) {
497
+ let raw;
498
+ try {
499
+ raw = fs3.readFileSync(filePath, "utf-8");
500
+ } catch {
501
+ return;
502
+ }
503
+ const next = removeTomlSectionKeys(raw, "shell_environment_policy.set", ["MYCO_CMD"]);
504
+ if (next !== raw) {
505
+ fs3.writeFileSync(filePath, next, "utf-8");
506
+ }
507
+ }
370
508
  /**
371
509
  * Check if ALL non-null JSON targets share the same file (e.g., Gemini).
372
510
  * Only batches when every target resolves to one path — partial overlaps
@@ -1102,4 +1240,4 @@ export {
1102
1240
  SymbiontInstaller,
1103
1241
  syncSkillSymlinks
1104
1242
  };
1105
- //# sourceMappingURL=chunk-VVGZL2HX.js.map
1243
+ //# sourceMappingURL=chunk-WYOE4IAX.js.map