@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
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Myco</title>
8
- <script type="module" crossorigin src="/assets/index-rpmSpJpm.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CiI1fwas.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-CRmkSi63.css">
10
10
  </head>
11
11
  <body>
@@ -2,26 +2,30 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  VAULT_GITIGNORE,
4
4
  registerSymbionts
5
- } from "./chunk-CTF7TQMJ.js";
5
+ } from "./chunk-TLK46KKD.js";
6
6
  import "./chunk-SAKJMNSR.js";
7
- import "./chunk-VVGZL2HX.js";
8
- import "./chunk-ML6GTPZU.js";
7
+ import "./chunk-WYOE4IAX.js";
8
+ import "./chunk-CML4MCYF.js";
9
9
  import {
10
10
  getEnabledSymbiontNames,
11
11
  loadConfig
12
- } from "./chunk-XD3NEN3Q.js";
12
+ } from "./chunk-2V7HR7HB.js";
13
13
  import "./chunk-MYX5NCRH.js";
14
14
  import {
15
15
  resolveVaultDir
16
16
  } from "./chunk-5ZT2Q6P5.js";
17
- import "./chunk-XZWFMMJR.js";
18
- import "./chunk-SI5BBQAT.js";
17
+ import "./chunk-XWOQL4XN.js";
18
+ import {
19
+ getPluginVersion
20
+ } from "./chunk-W7WENJ6F.js";
19
21
  import {
20
22
  loadManifests,
21
23
  resolvePackageRoot
22
- } from "./chunk-EBIYONNZ.js";
24
+ } from "./chunk-DPSLJ242.js";
23
25
  import "./chunk-LPUQPDC2.js";
24
- import "./chunk-7DAH5GLC.js";
26
+ import {
27
+ UPDATE_STAMP_FILENAME
28
+ } from "./chunk-CKJAWZQE.js";
25
29
  import "./chunk-E7NUADTQ.js";
26
30
  import "./chunk-D7TYRPRM.js";
27
31
  import "./chunk-E4VLWIJC.js";
@@ -78,6 +82,11 @@ async function run(args) {
78
82
  } else {
79
83
  console.log(" \u2013 No configured agents found");
80
84
  }
85
+ try {
86
+ const stampPath = path.join(vaultDir, UPDATE_STAMP_FILENAME);
87
+ fs.writeFileSync(stampPath, getPluginVersion(), "utf-8");
88
+ } catch {
89
+ }
81
90
  console.log("");
82
91
  if (updatedCount > 0) {
83
92
  console.log(`Updated ${updatedCount} item${updatedCount > 1 ? "s" : ""}.`);
@@ -89,4 +98,4 @@ async function run(args) {
89
98
  export {
90
99
  run
91
100
  };
92
- //# sourceMappingURL=update-DA7VEXOS.js.map
101
+ //# sourceMappingURL=update-WBWB5URU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/update.ts"],"sourcesContent":["import { resolveVaultDir } from '../vault/resolve.js';\nimport { VAULT_GITIGNORE, registerSymbionts } from './shared.js';\nimport { loadManifests, resolvePackageRoot } from '../symbionts/detect.js';\nimport { loadConfig, getEnabledSymbiontNames } from '../config/loader.js';\nimport { getPluginVersion } from '../version.js';\nimport { UPDATE_STAMP_FILENAME } from '../constants/update.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport async function run(args: string[]): Promise<void> {\n let projectRoot: string | undefined;\n const projectIdx = args.indexOf('--project');\n if (projectIdx !== -1 && args[projectIdx + 1]) {\n projectRoot = args[projectIdx + 1];\n }\n\n const vaultDir = projectRoot\n ? path.join(projectRoot, '.myco')\n : resolveVaultDir();\n if (!fs.existsSync(path.join(vaultDir, 'myco.yaml'))) {\n console.error(`No myco.yaml found in ${vaultDir}. Run 'myco init' first.`);\n process.exit(1);\n }\n\n console.log(`Updating Myco vault at ${vaultDir}\\n`);\n\n let updatedCount = 0;\n\n // --- Update .gitignore to match current template ---\n\n const gitignorePath = path.join(vaultDir, '.gitignore');\n const currentGitignore = fs.existsSync(gitignorePath)\n ? fs.readFileSync(gitignorePath, 'utf-8')\n : '';\n\n if (currentGitignore !== VAULT_GITIGNORE) {\n fs.writeFileSync(gitignorePath, VAULT_GITIGNORE, 'utf-8');\n console.log(' \\u2713 Updated .gitignore');\n updatedCount++;\n } else {\n console.log(' \\u2013 .gitignore is current');\n }\n\n // --- Update symbiont registration ---\n\n const resolvedProjectRoot = projectRoot ?? path.dirname(vaultDir);\n const allManifests = loadManifests();\n const pkgRoot = resolvePackageRoot();\n\n const config = loadConfig(vaultDir);\n let configured: typeof allManifests;\n\n const enabledNames = getEnabledSymbiontNames(config);\n\n if (enabledNames) {\n // Explicit mode: only update enabled symbionts\n configured = allManifests.filter((m) => enabledNames.has(m.name));\n\n // Warn about registered-but-not-enabled symbionts\n for (const m of allManifests) {\n if (!enabledNames.has(m.name) && fs.existsSync(path.join(resolvedProjectRoot, m.configDir))) {\n console.log(` !! ${m.displayName} is registered but not enabled. Run 'myco remove --symbiont ${m.name}' to clean up.`);\n }\n }\n } else {\n // Fallback: configDir-exists heuristic (pre-existing installs without symbionts config)\n configured = allManifests.filter((m) =>\n fs.existsSync(path.join(resolvedProjectRoot, m.configDir)),\n );\n }\n\n if (configured.length > 0) {\n const registered = registerSymbionts(configured, resolvedProjectRoot, pkgRoot, 'Updated');\n updatedCount += registered;\n } else {\n console.log(' \\u2013 No configured agents found');\n }\n\n // --- Write version stamp ---\n try {\n const stampPath = path.join(vaultDir, UPDATE_STAMP_FILENAME);\n fs.writeFileSync(stampPath, getPluginVersion(), 'utf-8');\n } catch {\n // Non-fatal — stamp write failure shouldn't break the update\n }\n\n // --- Summary ---\n\n console.log('');\n if (updatedCount > 0) {\n console.log(`Updated ${updatedCount} item${updatedCount > 1 ? 's' : ''}.`);\n } else {\n console.log('Everything is up to date.');\n }\n console.log('Run `myco doctor` to verify setup health.');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,IAAI,MAA+B;AACvD,MAAI;AACJ,QAAM,aAAa,KAAK,QAAQ,WAAW;AAC3C,MAAI,eAAe,MAAM,KAAK,aAAa,CAAC,GAAG;AAC7C,kBAAc,KAAK,aAAa,CAAC;AAAA,EACnC;AAEA,QAAM,WAAW,cACb,KAAK,KAAK,aAAa,OAAO,IAC9B,gBAAgB;AACpB,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,UAAU,WAAW,CAAC,GAAG;AACpD,YAAQ,MAAM,yBAAyB,QAAQ,0BAA0B;AACzE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,IAAI,0BAA0B,QAAQ;AAAA,CAAI;AAElD,MAAI,eAAe;AAInB,QAAM,gBAAgB,KAAK,KAAK,UAAU,YAAY;AACtD,QAAM,mBAAmB,GAAG,WAAW,aAAa,IAChD,GAAG,aAAa,eAAe,OAAO,IACtC;AAEJ,MAAI,qBAAqB,iBAAiB;AACxC,OAAG,cAAc,eAAe,iBAAiB,OAAO;AACxD,YAAQ,IAAI,6BAA6B;AACzC;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,gCAAgC;AAAA,EAC9C;AAIA,QAAM,sBAAsB,eAAe,KAAK,QAAQ,QAAQ;AAChE,QAAM,eAAe,cAAc;AACnC,QAAM,UAAU,mBAAmB;AAEnC,QAAM,SAAS,WAAW,QAAQ;AAClC,MAAI;AAEJ,QAAM,eAAe,wBAAwB,MAAM;AAEnD,MAAI,cAAc;AAEhB,iBAAa,aAAa,OAAO,CAAC,MAAM,aAAa,IAAI,EAAE,IAAI,CAAC;AAGhE,eAAW,KAAK,cAAc;AAC5B,UAAI,CAAC,aAAa,IAAI,EAAE,IAAI,KAAK,GAAG,WAAW,KAAK,KAAK,qBAAqB,EAAE,SAAS,CAAC,GAAG;AAC3F,gBAAQ,IAAI,QAAQ,EAAE,WAAW,+DAA+D,EAAE,IAAI,gBAAgB;AAAA,MACxH;AAAA,IACF;AAAA,EACF,OAAO;AAEL,iBAAa,aAAa;AAAA,MAAO,CAAC,MAChC,GAAG,WAAW,KAAK,KAAK,qBAAqB,EAAE,SAAS,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,aAAa,kBAAkB,YAAY,qBAAqB,SAAS,SAAS;AACxF,oBAAgB;AAAA,EAClB,OAAO;AACL,YAAQ,IAAI,qCAAqC;AAAA,EACnD;AAGA,MAAI;AACF,UAAM,YAAY,KAAK,KAAK,UAAU,qBAAqB;AAC3D,OAAG,cAAc,WAAW,iBAAiB,GAAG,OAAO;AAAA,EACzD,QAAQ;AAAA,EAER;AAIA,UAAQ,IAAI,EAAE;AACd,MAAI,eAAe,GAAG;AACpB,YAAQ,IAAI,WAAW,YAAY,QAAQ,eAAe,IAAI,MAAM,EAAE,GAAG;AAAA,EAC3E,OAAO;AACL,YAAQ,IAAI,2BAA2B;AAAA,EACzC;AACA,UAAQ,IAAI,2CAA2C;AACzD;","names":[]}
@@ -2,20 +2,26 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  EventBuffer
4
4
  } from "./chunk-V7XG6V6C.js";
5
+ import {
6
+ evaluateUserPromptRules,
7
+ readTranscriptMeta
8
+ } from "./chunk-44PZCAYS.js";
5
9
  import {
6
10
  normalizeHookInput,
7
11
  readStdin
8
- } from "./chunk-5ZISXCDC.js";
12
+ } from "./chunk-YZPI2Y3E.js";
9
13
  import {
10
14
  resolveVaultDir
11
15
  } from "./chunk-5ZT2Q6P5.js";
12
16
  import {
13
17
  DaemonClient
14
- } from "./chunk-XZWFMMJR.js";
15
- import "./chunk-SI5BBQAT.js";
16
- import "./chunk-EBIYONNZ.js";
18
+ } from "./chunk-XWOQL4XN.js";
19
+ import "./chunk-W7WENJ6F.js";
20
+ import {
21
+ loadManifests
22
+ } from "./chunk-DPSLJ242.js";
17
23
  import "./chunk-LPUQPDC2.js";
18
- import "./chunk-7DAH5GLC.js";
24
+ import "./chunk-CKJAWZQE.js";
19
25
  import "./chunk-E7NUADTQ.js";
20
26
  import "./chunk-D7TYRPRM.js";
21
27
  import "./chunk-E4VLWIJC.js";
@@ -31,12 +37,29 @@ async function main() {
31
37
  try {
32
38
  const rawInput = JSON.parse(await readStdin());
33
39
  const input = normalizeHookInput(rawInput);
34
- const prompt = input.prompt ?? "";
40
+ const rawPrompt = input.prompt ?? "";
35
41
  const sessionId = input.sessionId;
42
+ const transcriptMeta = input.transcriptPath ? readTranscriptMeta(input.transcriptPath) : void 0;
43
+ const decision = evaluateUserPromptRules(loadManifests(), input.agent, {
44
+ prompt: rawPrompt,
45
+ transcriptPath: input.transcriptPath,
46
+ transcriptMeta: transcriptMeta ?? void 0
47
+ });
36
48
  const client = new DaemonClient(VAULT_DIR);
37
49
  if (!await client.isHealthy()) {
38
50
  client.spawnDaemon();
39
51
  }
52
+ if (decision.action === "drop") {
53
+ process.stderr.write(`[myco] user-prompt-submit: dropped (${decision.reason ?? "rule"})
54
+ `);
55
+ await client.delete(`/api/sessions/${sessionId}`);
56
+ return;
57
+ }
58
+ const prompt = decision.action === "rewrite" ? decision.prompt : rawPrompt;
59
+ if (decision.action === "rewrite") {
60
+ process.stderr.write(`[myco] user-prompt-submit: rewritten (${decision.reason ?? "rule"})
61
+ `);
62
+ }
40
63
  const eventResult = await client.post("/events", {
41
64
  type: "user_prompt",
42
65
  prompt,
@@ -63,4 +86,4 @@ ${sessionLine}` : sessionLine;
63
86
  export {
64
87
  main
65
88
  };
66
- //# sourceMappingURL=user-prompt-submit-ADZ4NTVO.js.map
89
+ //# sourceMappingURL=user-prompt-submit-IZJC3NV7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/user-prompt-submit.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { normalizeHookInput } from './normalize.js';\nimport { evaluateUserPromptRules } from './capture-rules.js';\nimport { readTranscriptMeta } from './transcript-meta.js';\nimport { loadManifests } from '../symbionts/detect.js';\nimport { EventBuffer } from '../capture/buffer.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport async function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const rawInput = JSON.parse(await readStdin());\n const input = normalizeHookInput(rawInput);\n const rawPrompt = input.prompt ?? '';\n const sessionId = input.sessionId;\n\n // Apply generic capture rules owned by each symbiont's manifest.\n // The hook stays symbiont-agnostic — per-agent behavior lives in YAML.\n // Pass structural context so rules can key on things like\n // `transcript_path_missing` without doing their own text mining.\n const transcriptMeta = input.transcriptPath ? readTranscriptMeta(input.transcriptPath) : undefined;\n const decision = evaluateUserPromptRules(loadManifests(), input.agent, {\n prompt: rawPrompt,\n transcriptPath: input.transcriptPath,\n transcriptMeta: transcriptMeta ?? undefined,\n });\n\n const client = new DaemonClient(VAULT_DIR);\n // Spawn daemon if needed but don't block on full health check backoff.\n // The event POST will fail fast if daemon isn't ready — buffer absorbs it.\n if (!(await client.isHealthy())) {\n client.spawnDaemon();\n }\n\n if (decision.action === 'drop') {\n // A rule classified this prompt as a phantom sub-invocation (e.g., an\n // agent's internal title-generation call). SessionStart already\n // registered the session row; delete it so it doesn't linger as a\n // zero-prompt ghost in the UI. Silently tolerate failures — the\n // session-maintenance sweep will clean up stragglers within the\n // stale threshold as a safety net.\n process.stderr.write(`[myco] user-prompt-submit: dropped (${decision.reason ?? 'rule'})\\n`);\n await client.delete(`/api/sessions/${sessionId}`);\n return;\n }\n\n const prompt = decision.action === 'rewrite' ? decision.prompt : rawPrompt;\n if (decision.action === 'rewrite') {\n process.stderr.write(`[myco] user-prompt-submit: rewritten (${decision.reason ?? 'rule'})\\n`);\n }\n\n // Forward prompt as event for capture\n const eventResult = await client.post('/events', {\n type: 'user_prompt', prompt, session_id: sessionId, agent: input.agent,\n });\n\n if (!eventResult.ok) {\n // Daemon still unreachable — write directly to buffer for later processing\n const buffer = new EventBuffer(path.join(VAULT_DIR, 'buffer'), sessionId);\n buffer.append({ type: 'user_prompt', prompt });\n }\n\n // Search for relevant spores to inject as context for this prompt.\n // The daemon does a vector search against the prompt text and returns\n // any high-relevance spores. This is fast (~20ms) — no LLM call.\n const contextResult = await client.post('/context/prompt', {\n prompt,\n session_id: sessionId,\n });\n\n // Always include the session ID so the agent can pass it to myco_remember.\n // Uses Session:: format consistent with daemon context injection (Branch::, Session::).\n const sessionLine = `Session:: \\`${sessionId}\\``;\n const contextText = contextResult.ok && contextResult.data?.text\n ? `${contextResult.data.text}\\n${sessionLine}`\n : sessionLine;\n\n process.stdout.write(contextText);\n } catch (error) {\n process.stderr.write(`[myco] user-prompt-submit error: ${(error as Error).message}\\n`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,OAAO;AAC3B,QAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,WAAW,WAAW,CAAC,EAAG;AAEvD,MAAI;AACF,UAAM,WAAW,KAAK,MAAM,MAAM,UAAU,CAAC;AAC7C,UAAM,QAAQ,mBAAmB,QAAQ;AACzC,UAAM,YAAY,MAAM,UAAU;AAClC,UAAM,YAAY,MAAM;AAMxB,UAAM,iBAAiB,MAAM,iBAAiB,mBAAmB,MAAM,cAAc,IAAI;AACzF,UAAM,WAAW,wBAAwB,cAAc,GAAG,MAAM,OAAO;AAAA,MACrE,QAAQ;AAAA,MACR,gBAAgB,MAAM;AAAA,MACtB,gBAAgB,kBAAkB;AAAA,IACpC,CAAC;AAED,UAAM,SAAS,IAAI,aAAa,SAAS;AAGzC,QAAI,CAAE,MAAM,OAAO,UAAU,GAAI;AAC/B,aAAO,YAAY;AAAA,IACrB;AAEA,QAAI,SAAS,WAAW,QAAQ;AAO9B,cAAQ,OAAO,MAAM,uCAAuC,SAAS,UAAU,MAAM;AAAA,CAAK;AAC1F,YAAM,OAAO,OAAO,iBAAiB,SAAS,EAAE;AAChD;AAAA,IACF;AAEA,UAAM,SAAS,SAAS,WAAW,YAAY,SAAS,SAAS;AACjE,QAAI,SAAS,WAAW,WAAW;AACjC,cAAQ,OAAO,MAAM,yCAAyC,SAAS,UAAU,MAAM;AAAA,CAAK;AAAA,IAC9F;AAGA,UAAM,cAAc,MAAM,OAAO,KAAK,WAAW;AAAA,MAC/C,MAAM;AAAA,MAAe;AAAA,MAAQ,YAAY;AAAA,MAAW,OAAO,MAAM;AAAA,IACnE,CAAC;AAED,QAAI,CAAC,YAAY,IAAI;AAEnB,YAAM,SAAS,IAAI,YAAY,KAAK,KAAK,WAAW,QAAQ,GAAG,SAAS;AACxE,aAAO,OAAO,EAAE,MAAM,eAAe,OAAO,CAAC;AAAA,IAC/C;AAKA,UAAM,gBAAgB,MAAM,OAAO,KAAK,mBAAmB;AAAA,MACzD;AAAA,MACA,YAAY;AAAA,IACd,CAAC;AAID,UAAM,cAAc,eAAe,SAAS;AAC5C,UAAM,cAAc,cAAc,MAAM,cAAc,MAAM,OACxD,GAAG,cAAc,KAAK,IAAI;AAAA,EAAK,WAAW,KAC1C;AAEJ,YAAQ,OAAO,MAAM,WAAW;AAAA,EAClC,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,oCAAqC,MAAgB,OAAO;AAAA,CAAI;AAAA,EACvF;AACF;","names":[]}
@@ -1,12 +1,12 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
3
  createEmbeddingProvider
4
- } from "./chunk-HPZ7YAMA.js";
5
- import "./chunk-ML6GTPZU.js";
4
+ } from "./chunk-TCSVDQF5.js";
5
+ import "./chunk-CML4MCYF.js";
6
6
  import {
7
7
  loadConfig
8
- } from "./chunk-XD3NEN3Q.js";
9
- import "./chunk-7DAH5GLC.js";
8
+ } from "./chunk-2V7HR7HB.js";
9
+ import "./chunk-CKJAWZQE.js";
10
10
  import "./chunk-E7NUADTQ.js";
11
11
  import "./chunk-D7TYRPRM.js";
12
12
  import "./chunk-E4VLWIJC.js";
@@ -39,4 +39,4 @@ async function run(_args, vaultDir) {
39
39
  export {
40
40
  run
41
41
  };
42
- //# sourceMappingURL=verify-QYSERHF7.js.map
42
+ //# sourceMappingURL=verify-FNSP62I3.js.map
@@ -1,10 +1,10 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
3
  getPluginVersion
4
- } from "./chunk-SI5BBQAT.js";
4
+ } from "./chunk-W7WENJ6F.js";
5
5
  import "./chunk-LPUQPDC2.js";
6
6
  import "./chunk-PZUWP5VK.js";
7
7
  export {
8
8
  getPluginVersion
9
9
  };
10
- //# sourceMappingURL=version-A72TAL2J.js.map
10
+ //# sourceMappingURL=version-QEVU66NT.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goondocks/myco",
3
- "version": "0.17.2",
3
+ "version": "0.18.1",
4
4
  "description": "Collective agent intelligence — Claude Code plugin",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -38,11 +38,11 @@
38
38
  "url": "https://github.com/goondocks-co/myco.git"
39
39
  },
40
40
  "dependencies": {
41
- "@anthropic-ai/claude-agent-sdk": "^0.2.92",
42
- "@anthropic-ai/sdk": "^0.82.0",
43
- "@inquirer/prompts": "^8.3.2",
41
+ "@anthropic-ai/claude-agent-sdk": "^0.2.104",
42
+ "@anthropic-ai/sdk": "^0.88.0",
43
+ "@inquirer/prompts": "^8.4.1",
44
44
  "@modelcontextprotocol/sdk": "^1.28.0",
45
- "better-sqlite3": "^12.8.0",
45
+ "better-sqlite3": "^12.9.0",
46
46
  "chokidar": "^5.0.0",
47
47
  "gray-matter": "^4.0.3",
48
48
  "semver": "^7.7.4",
@@ -52,11 +52,11 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/better-sqlite3": "^7.6.13",
55
- "@types/node": "^25.5.0",
55
+ "@types/node": "^25.6.0",
56
56
  "@types/semver": "^7.7.1",
57
57
  "tsup": "^8.0.0",
58
58
  "tsx": "^4.0.0",
59
59
  "typescript": "^6.0.2",
60
- "vitest": "^4.1.2"
60
+ "vitest": "^4.1.4"
61
61
  }
62
62
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/db/queries/sessions.ts"],"sourcesContent":["/**\n * Session 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 sessions returned by listSessions when no limit given. */\nconst DEFAULT_LIST_LIMIT = 100;\n\n/** Session status value when a session is closed normally. */\nconst STATUS_COMPLETED = 'completed';\n\n/** Default session status for new sessions. */\nconst DEFAULT_STATUS = 'active';\n\n/** Default prompt count for new sessions. */\nconst DEFAULT_PROMPT_COUNT = 0;\n\n/** Default tool count for new sessions. */\nconst DEFAULT_TOOL_COUNT = 0;\n\n/** Default processed flag for new sessions. */\nconst DEFAULT_PROCESSED = 0;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Fields required (or optional) when inserting/upserting a session. */\nexport interface SessionInsert {\n id: string;\n agent: string;\n started_at: number;\n created_at: number;\n user?: string | null;\n project_root?: string | null;\n branch?: string | null;\n ended_at?: number | null;\n status?: string;\n prompt_count?: number;\n tool_count?: number;\n title?: string | null;\n summary?: string | null;\n transcript_path?: string | null;\n parent_session_id?: string | null;\n parent_session_reason?: string | null;\n processed?: number;\n content_hash?: string | null;\n machine_id?: string;\n}\n\n/** Row shape returned from session queries (all columns). */\nexport interface SessionRow {\n id: string;\n agent: string;\n user: string | null;\n project_root: string | null;\n branch: string | null;\n started_at: number;\n ended_at: number | null;\n status: string;\n prompt_count: number;\n tool_count: number;\n title: string | null;\n summary: string | null;\n transcript_path: string | null;\n parent_session_id: string | null;\n parent_session_reason: string | null;\n processed: number;\n content_hash: string | null;\n embedded: number;\n created_at: number;\n machine_id: string;\n synced_at: number | null;\n}\n\n/** Updatable fields for `updateSession`. */\nexport interface SessionUpdate {\n agent?: string;\n user?: string | null;\n project_root?: string | null;\n branch?: string | null;\n ended_at?: number | null;\n status?: string;\n prompt_count?: number;\n tool_count?: number;\n title?: string | null;\n summary?: string | null;\n transcript_path?: string | null;\n parent_session_id?: string | null;\n parent_session_reason?: string | null;\n processed?: number;\n content_hash?: string | null;\n}\n\n/** Filter options for `listSessions`. */\nexport interface ListSessionsOptions {\n limit?: number;\n offset?: number;\n status?: string;\n agent?: string;\n search?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Column list\n// ---------------------------------------------------------------------------\n\nconst SESSION_COLUMNS = [\n 'id',\n 'agent',\n '\"user\"',\n 'project_root',\n 'branch',\n 'started_at',\n 'ended_at',\n 'status',\n 'prompt_count',\n 'tool_count',\n 'title',\n 'summary',\n 'transcript_path',\n 'parent_session_id',\n 'parent_session_reason',\n 'processed',\n 'content_hash',\n 'embedded',\n 'created_at',\n 'machine_id',\n 'synced_at',\n] as const;\n\nconst SELECT_COLUMNS = SESSION_COLUMNS.join(', ');\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize a SQLite result row into a typed SessionRow.\n *\n * The quoted \"user\" column comes back as `user` in the result object.\n */\nfunction toSessionRow(row: Record<string, unknown>): SessionRow {\n return {\n id: row.id as string,\n agent: row.agent as string,\n user: (row.user as string) ?? null,\n project_root: (row.project_root as string) ?? null,\n branch: (row.branch as string) ?? null,\n started_at: row.started_at as number,\n ended_at: (row.ended_at as number) ?? null,\n status: row.status as string,\n prompt_count: row.prompt_count as number,\n tool_count: row.tool_count as number,\n title: (row.title as string) ?? null,\n summary: (row.summary as string) ?? null,\n transcript_path: (row.transcript_path as string) ?? null,\n parent_session_id: (row.parent_session_id as string) ?? null,\n parent_session_reason: (row.parent_session_reason as string) ?? null,\n processed: row.processed as number,\n content_hash: (row.content_hash as string) ?? null,\n embedded: (row.embedded as number) ?? 0,\n created_at: row.created_at as number,\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 session or update it if the id already exists.\n *\n * On conflict the row is updated with the values from `data`, preserving\n * any columns not supplied via COALESCE with EXCLUDED values.\n */\nexport function upsertSession(data: SessionInsert): SessionRow {\n const db = getDatabase();\n\n db.prepare(\n `INSERT INTO sessions (\n id, agent, \"user\", project_root, branch,\n started_at, ended_at, status, prompt_count, tool_count,\n title, summary, transcript_path,\n parent_session_id, parent_session_reason,\n processed, content_hash, created_at, machine_id\n ) VALUES (\n ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?,\n ?, ?, ?,\n ?, ?,\n ?, ?, ?, ?\n )\n ON CONFLICT (id) DO UPDATE SET\n agent = EXCLUDED.agent,\n \"user\" = EXCLUDED.\"user\",\n project_root = EXCLUDED.project_root,\n branch = EXCLUDED.branch,\n started_at = EXCLUDED.started_at,\n ended_at = COALESCE(EXCLUDED.ended_at, sessions.ended_at),\n status = COALESCE(EXCLUDED.status, sessions.status),\n prompt_count = CASE WHEN ? THEN EXCLUDED.prompt_count ELSE sessions.prompt_count END,\n tool_count = CASE WHEN ? THEN EXCLUDED.tool_count ELSE sessions.tool_count END,\n title = COALESCE(EXCLUDED.title, sessions.title),\n summary = COALESCE(EXCLUDED.summary, sessions.summary),\n transcript_path = COALESCE(EXCLUDED.transcript_path, sessions.transcript_path),\n parent_session_id = EXCLUDED.parent_session_id,\n parent_session_reason = EXCLUDED.parent_session_reason,\n processed = COALESCE(EXCLUDED.processed, sessions.processed),\n content_hash = EXCLUDED.content_hash`,\n ).run(\n data.id,\n data.agent,\n data.user ?? null,\n data.project_root ?? null,\n data.branch ?? null,\n data.started_at,\n data.ended_at ?? null,\n data.status ?? DEFAULT_STATUS,\n data.prompt_count ?? DEFAULT_PROMPT_COUNT,\n data.tool_count ?? DEFAULT_TOOL_COUNT,\n data.title ?? null,\n data.summary ?? null,\n data.transcript_path ?? null,\n data.parent_session_id ?? null,\n data.parent_session_reason ?? null,\n data.processed ?? DEFAULT_PROCESSED,\n data.content_hash ?? null,\n data.created_at,\n data.machine_id ?? getTeamMachineId(),\n data.prompt_count !== undefined ? 1 : 0,\n data.tool_count !== undefined ? 1 : 0,\n );\n\n const row = toSessionRow(\n db.prepare(`SELECT ${SELECT_COLUMNS} FROM sessions WHERE id = ?`).get(data.id) as Record<string, unknown>,\n );\n\n syncRow('sessions', row);\n\n return row;\n}\n\n/**\n * Retrieve a single session by id.\n *\n * @returns the session row, or null if not found.\n */\nexport function getSession(id: string): SessionRow | null {\n const db = getDatabase();\n\n const row = db.prepare(\n `SELECT ${SELECT_COLUMNS} FROM sessions WHERE id = ?`,\n ).get(id) as Record<string, unknown> | undefined;\n\n if (!row) return null;\n return toSessionRow(row);\n}\n\n/** Build WHERE clause and bound params from session filter options. */\nfunction buildSessionsWhere(\n options: Omit<ListSessionsOptions, 'limit' | 'offset'>,\n): { where: string; params: unknown[] } {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (options.status !== undefined) {\n conditions.push(`status = ?`);\n params.push(options.status);\n }\n\n if (options.agent !== undefined) {\n conditions.push(`agent = ?`);\n params.push(options.agent);\n }\n\n if (options.search !== undefined && options.search.length > 0) {\n conditions.push(`(title LIKE ? OR id LIKE ?)`);\n const pattern = `%${options.search}%`;\n params.push(pattern, pattern);\n }\n\n return {\n where: conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '',\n params,\n };\n}\n\n/**\n * List sessions with optional filters, ordered by created_at DESC.\n */\nexport function listSessions(\n options: ListSessionsOptions = {},\n): SessionRow[] {\n const db = getDatabase();\n const { where, params } = buildSessionsWhere(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 sessions\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(toSessionRow);\n}\n\n/**\n * Count sessions matching optional filters (for pagination totals).\n */\nexport function countSessions(\n options: Omit<ListSessionsOptions, 'limit' | 'offset'> = {},\n): number {\n const db = getDatabase();\n const { where, params } = buildSessionsWhere(options);\n\n const row = db.prepare(\n `SELECT COUNT(*) as count FROM sessions ${where}`,\n ).get(...params) as { count: number };\n\n return row.count;\n}\n\n/**\n * Update specific fields on an existing session.\n *\n * @returns the updated row, or null if the session does not exist.\n */\nexport function updateSession(\n id: string,\n updates: SessionUpdate,\n): SessionRow | null {\n const db = getDatabase();\n\n const setClauses: string[] = [];\n const params: unknown[] = [];\n\n const fieldMap: Record<string, string> = {\n agent: 'agent',\n user: '\"user\"',\n project_root: 'project_root',\n branch: 'branch',\n ended_at: 'ended_at',\n status: 'status',\n prompt_count: 'prompt_count',\n tool_count: 'tool_count',\n title: 'title',\n summary: 'summary',\n transcript_path: 'transcript_path',\n parent_session_id: 'parent_session_id',\n parent_session_reason: 'parent_session_reason',\n processed: 'processed',\n content_hash: 'content_hash',\n };\n\n for (const [key, column] of Object.entries(fieldMap)) {\n if (key in updates) {\n setClauses.push(`${column} = ?`);\n params.push((updates as Record<string, unknown>)[key] ?? null);\n }\n }\n\n if (setClauses.length === 0) return getSession(id);\n\n params.push(id);\n\n db.prepare(\n `UPDATE sessions\n SET ${setClauses.join(', ')}\n WHERE id = ?`,\n ).run(...params);\n\n const updated = getSession(id);\n\n if (updated) syncRow('sessions', updated);\n\n return updated;\n}\n\n/**\n * Atomically increment tool_count for a session.\n *\n * Uses SQL `tool_count + 1` to avoid read-modify-write races.\n */\nexport function incrementSessionToolCount(id: string): void {\n const db = getDatabase();\n db.prepare(\n `UPDATE sessions SET tool_count = COALESCE(tool_count, 0) + 1 WHERE id = ?`,\n ).run(id);\n}\n\n/**\n * Close a session — set status to 'completed' and record the end time.\n *\n * @returns the updated row, or null if the session does not exist.\n */\nexport function closeSession(\n id: string,\n endedAt: number,\n): SessionRow | null {\n const db = getDatabase();\n\n db.prepare(\n `UPDATE sessions\n SET status = ?, ended_at = ?\n WHERE id = ?`,\n ).run(STATUS_COMPLETED, endedAt, id);\n\n const closed = getSession(id);\n\n if (closed) syncRow('sessions', closed);\n\n return closed;\n}\n\n/**\n * Delete a session and all its child rows (batches, activities, attachments).\n *\n * No ON DELETE CASCADE in the schema, so we delete children first.\n * Returns true if the session existed and was deleted.\n */\nexport function deleteSession(id: string): boolean {\n const db = getDatabase();\n\n db.prepare(`DELETE FROM activities WHERE session_id = ?`).run(id);\n db.prepare(`DELETE FROM attachments WHERE session_id = ?`).run(id);\n db.prepare(`DELETE FROM prompt_batches WHERE session_id = ?`).run(id);\n const info = db.prepare(`DELETE FROM sessions WHERE id = ?`).run(id);\n\n return info.changes > 0;\n}\n\n// ---------------------------------------------------------------------------\n// Cascade delete + impact query\n// ---------------------------------------------------------------------------\n\n/** Counts of related data that would be affected by a session delete. */\nexport interface SessionImpact {\n promptCount: number;\n sporeCount: number;\n attachmentCount: number;\n graphEdgeCount: number;\n}\n\n/** Result of a cascade delete operation. */\nexport interface DeleteCascadeResult {\n deleted: boolean;\n counts: {\n prompts: number;\n spores: number;\n attachments: number;\n graphEdges: number;\n resolutionEvents: number;\n };\n /** Spore IDs that were deleted (needed for vault file + vector cleanup). */\n deletedSporeIds: string[];\n /** Attachment file paths that were deleted from DB (needed for disk cleanup). */\n deletedAttachmentPaths: string[];\n}\n\n/**\n * Get counts of all data related to a session, for pre-delete impact display.\n */\nexport function getSessionImpact(sessionId: string): SessionImpact {\n const db = getDatabase();\n\n const row = db.prepare(\n `SELECT\n (SELECT COUNT(*) FROM prompt_batches WHERE session_id = ?) AS promptCount,\n (SELECT COUNT(*) FROM spores WHERE session_id = ?) AS sporeCount,\n (SELECT COUNT(*) FROM attachments WHERE session_id = ?) AS attachmentCount,\n (SELECT COUNT(*) FROM graph_edges WHERE session_id = ?) AS graphEdgeCount`,\n ).get(sessionId, sessionId, sessionId, sessionId) as SessionImpact;\n\n return row;\n}\n\n/**\n * Delete a session and ALL related data in a single transaction.\n *\n * Returns counts of deleted rows and IDs needed for post-transaction\n * cleanup (vault files, embedding vectors).\n */\nexport function deleteSessionCascade(sessionId: string): DeleteCascadeResult {\n const db = getDatabase();\n\n const zeroCounts: DeleteCascadeResult = {\n deleted: false,\n counts: { prompts: 0, spores: 0, attachments: 0, graphEdges: 0, resolutionEvents: 0 },\n deletedSporeIds: [],\n deletedAttachmentPaths: [],\n };\n\n // Check session exists first\n const exists = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);\n if (!exists) return zeroCounts;\n\n // Collect IDs/paths needed for post-transaction cleanup before deleting\n const sporeIds = (db.prepare(\n `SELECT id FROM spores WHERE session_id = ?`,\n ).all(sessionId) as { id: string }[]).map((r) => r.id);\n\n const attachmentPaths = (db.prepare(\n `SELECT file_path FROM attachments WHERE session_id = ?`,\n ).all(sessionId) as { file_path: string }[]).map((r) => r.file_path);\n\n // Run all deletes in a single transaction.\n //\n // Order matters — foreign_keys = ON is set in client.ts, so every DELETE\n // is checked immediately. Child rows must be removed before their parents:\n // - spores.prompt_batch_id → prompt_batches(id) [spores BEFORE prompt_batches]\n // - plans.prompt_batch_id → prompt_batches(id) [plans BEFORE prompt_batches]\n // - resolution_events.spore_id → spores(id) [resolution_events BEFORE spores]\n // - skill_usage.session_id → sessions(id) NOT NULL\n // - plans.session_id → sessions(id)\n // resolution_events can reference spores across sessions (e.g. a later\n // session supersedes an earlier session's spore), so we match by either\n // session_id OR spore_id-in-this-session to catch cross-session references.\n const result = db.transaction(() => {\n db.prepare(`DELETE FROM activities WHERE session_id = ?`).run(sessionId);\n const attachments = db.prepare(`DELETE FROM attachments WHERE session_id = ?`).run(sessionId);\n db.prepare(`DELETE FROM plans WHERE session_id = ?`).run(sessionId);\n db.prepare(`DELETE FROM skill_usage WHERE session_id = ?`).run(sessionId);\n const resEvents = db.prepare(\n `DELETE FROM resolution_events\n WHERE session_id = ?\n OR spore_id IN (SELECT id FROM spores WHERE session_id = ?)`,\n ).run(sessionId, sessionId);\n const edges = db.prepare(`DELETE FROM graph_edges WHERE session_id = ?`).run(sessionId);\n const spores = db.prepare(`DELETE FROM spores WHERE session_id = ?`).run(sessionId);\n const prompts = db.prepare(`DELETE FROM prompt_batches WHERE session_id = ?`).run(sessionId);\n const session = db.prepare(`DELETE FROM sessions WHERE id = ?`).run(sessionId);\n\n return {\n deleted: session.changes > 0,\n counts: {\n prompts: prompts.changes,\n spores: spores.changes,\n attachments: attachments.changes,\n graphEdges: edges.changes,\n resolutionEvents: resEvents.changes,\n },\n };\n })();\n\n return {\n ...result,\n deletedSporeIds: sporeIds,\n deletedAttachmentPaths: attachmentPaths,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/read-stdin.ts","../src/hooks/normalize.ts"],"sourcesContent":["import { STDIN_TIMEOUT_MS } from '../constants.js';\n\nexport function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n process.stdin.on('data', (chunk: Buffer) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n setTimeout(() => resolve(data || '{}'), STDIN_TIMEOUT_MS);\n });\n}\n","/**\n * Hook payload normalization layer.\n *\n * Each agent sends different field names in hook stdin (e.g., Claude Code uses\n * `session_id`, VS Code uses `sessionId`, Windsurf uses `trajectory_id`).\n * This module detects the active agent, loads its manifest, and maps the\n * raw input to a canonical shape that all hooks can consume uniformly.\n */\n\nimport { loadManifests } from '../symbionts/detect.js';\nimport type { SymbiontManifest } from '../symbionts/manifest-schema.js';\n\n/** Default field mappings when no agent manifest is detected (Claude Code conventions). */\nconst DEFAULT_HOOK_FIELDS = {\n sessionId: 'session_id',\n transcriptPath: 'transcript_path',\n lastResponse: 'last_assistant_message',\n prompt: 'prompt',\n toolName: 'tool_name',\n toolInput: 'tool_input',\n toolOutput: 'tool_output',\n} as const;\n\n/** Canonical hook input with normalized field names. */\nexport interface NormalizedHookInput {\n /** Detected agent name from manifest (e.g., 'claude-code', 'codex', 'windsurf'). */\n agent: string;\n sessionId: string;\n transcriptPath?: string;\n lastResponse?: string;\n prompt?: string;\n toolName?: string;\n toolInput?: unknown;\n toolOutput?: unknown;\n /** The full raw input for any fields not covered by the mapping. */\n raw: Record<string, unknown>;\n}\n\n/** Default agent name when no manifest is detected. */\nconst DEFAULT_AGENT_NAME = 'claude-code';\n\n/** Cached manifest for the detected agent — resolved once per process. */\nlet cachedManifest: SymbiontManifest | null | undefined;\n\nfunction detectManifest(): SymbiontManifest | null {\n if (cachedManifest !== undefined) return cachedManifest;\n\n const manifests = loadManifests();\n\n // Try env-var detection: check pluginRootEnvVar for each manifest\n for (const m of manifests) {\n if (process.env[m.pluginRootEnvVar]) {\n cachedManifest = m;\n return m;\n }\n }\n\n // Fallback: check sessionIdEnv (e.g., GEMINI_SESSION_ID)\n for (const m of manifests) {\n if (m.hookFields.sessionIdEnv && process.env[m.hookFields.sessionIdEnv]) {\n cachedManifest = m;\n return m;\n }\n }\n\n cachedManifest = null;\n return null;\n}\n\n/**\n * Resolve a potentially nested field path from the input.\n * Supports dot notation for nested objects (e.g., \"tool_info.command_line\").\n */\nfunction resolveField(input: Record<string, unknown>, fieldPath: string): unknown {\n const parts = fieldPath.split('.');\n let current: unknown = input;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\n/**\n * Normalize a raw hook input using the active agent's manifest field mappings.\n * Falls back to Claude Code field names if no agent is detected.\n */\nexport function normalizeHookInput(input: Record<string, unknown>): NormalizedHookInput {\n const manifest = detectManifest();\n const fields = manifest?.hookFields ?? DEFAULT_HOOK_FIELDS;\n\n // Resolve session ID: try the mapped field, then env var fallback, then MYCO_SESSION_ID\n const sessionIdFromInput = resolveField(input, fields.sessionId) as string | undefined;\n const sessionIdFromEnv = 'sessionIdEnv' in fields && fields.sessionIdEnv\n ? process.env[fields.sessionIdEnv]\n : undefined;\n const sessionId = sessionIdFromInput\n ?? sessionIdFromEnv\n ?? process.env.MYCO_SESSION_ID\n ?? `s-${Date.now()}`;\n\n return {\n agent: manifest?.name ?? DEFAULT_AGENT_NAME,\n sessionId,\n transcriptPath: resolveField(input, fields.transcriptPath) as string | undefined,\n lastResponse: resolveField(input, fields.lastResponse) as string | undefined,\n prompt: resolveField(input, fields.prompt) as string | undefined,\n toolName: resolveField(input, fields.toolName) as string | undefined,\n toolInput: resolveField(input, fields.toolInput),\n toolOutput: resolveField(input, fields.toolOutput),\n raw: input,\n };\n}\n\n/** Reset cached manifest — exposed for testing only. */\nexport function _resetManifestCache(): void {\n cachedManifest = undefined;\n}\n"],"mappings":";;;;;;;;;AAEO,SAAS,YAA6B;AAC3C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AACX,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAkB;AAAE,cAAQ;AAAA,IAAO,CAAC;AAC9D,YAAQ,MAAM,GAAG,OAAO,MAAM,QAAQ,IAAI,CAAC;AAC3C,eAAW,MAAM,QAAQ,QAAQ,IAAI,GAAG,gBAAgB;AAAA,EAC1D,CAAC;AACH;;;ACIA,IAAM,sBAAsB;AAAA,EAC1B,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,YAAY;AACd;AAkBA,IAAM,qBAAqB;AAG3B,IAAI;AAEJ,SAAS,iBAA0C;AACjD,MAAI,mBAAmB,OAAW,QAAO;AAEzC,QAAM,YAAY,cAAc;AAGhC,aAAW,KAAK,WAAW;AACzB,QAAI,QAAQ,IAAI,EAAE,gBAAgB,GAAG;AACnC,uBAAiB;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AAGA,aAAW,KAAK,WAAW;AACzB,QAAI,EAAE,WAAW,gBAAgB,QAAQ,IAAI,EAAE,WAAW,YAAY,GAAG;AACvE,uBAAiB;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,mBAAiB;AACjB,SAAO;AACT;AAMA,SAAS,aAAa,OAAgC,WAA4B;AAChF,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,MAAI,UAAmB;AACvB,aAAW,QAAQ,OAAO;AACxB,QAAI,YAAY,QAAQ,YAAY,UAAa,OAAO,YAAY,SAAU,QAAO;AACrF,cAAW,QAAoC,IAAI;AAAA,EACrD;AACA,SAAO;AACT;AAMO,SAAS,mBAAmB,OAAqD;AACtF,QAAM,WAAW,eAAe;AAChC,QAAM,SAAS,UAAU,cAAc;AAGvC,QAAM,qBAAqB,aAAa,OAAO,OAAO,SAAS;AAC/D,QAAM,mBAAmB,kBAAkB,UAAU,OAAO,eACxD,QAAQ,IAAI,OAAO,YAAY,IAC/B;AACJ,QAAM,YAAY,sBACb,oBACA,QAAQ,IAAI,mBACZ,KAAK,KAAK,IAAI,CAAC;AAEpB,SAAO;AAAA,IACL,OAAO,UAAU,QAAQ;AAAA,IACzB;AAAA,IACA,gBAAgB,aAAa,OAAO,OAAO,cAAc;AAAA,IACzD,cAAc,aAAa,OAAO,OAAO,YAAY;AAAA,IACrD,QAAQ,aAAa,OAAO,OAAO,MAAM;AAAA,IACzC,UAAU,aAAa,OAAO,OAAO,QAAQ;AAAA,IAC7C,WAAW,aAAa,OAAO,OAAO,SAAS;AAAA,IAC/C,YAAY,aAAa,OAAO,OAAO,UAAU;AAAA,IACjD,KAAK;AAAA,EACP;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/constants/update.ts","../src/constants.ts"],"sourcesContent":["import path from 'node:path';\nimport os from 'node:os';\n\n/** npm registry URL for the Myco package. */\nexport const NPM_REGISTRY_URL = 'https://registry.npmjs.org/@goondocks/myco';\n\n/** Global Myco directory for machine-wide state. */\nexport const MYCO_GLOBAL_DIR = path.join(os.homedir(), '.myco');\n\n/** Path to the cached update check result. */\nexport const UPDATE_CHECK_CACHE_PATH = path.join(MYCO_GLOBAL_DIR, 'last-update-check.json');\n\n/** Path to the update configuration file (channel, interval). */\nexport const UPDATE_CONFIG_PATH = path.join(MYCO_GLOBAL_DIR, 'update.yaml');\n\n/** Path to the update error file (written by update script on failure). */\nexport const UPDATE_ERROR_PATH = path.join(MYCO_GLOBAL_DIR, 'update-error.json');\n\n/** Default check interval in hours. */\nexport const UPDATE_CHECK_INTERVAL_HOURS = 6;\n\n/** Milliseconds per hour. */\nexport const MS_PER_HOUR = 3_600_000;\n\n/** npm package name. */\nexport const NPM_PACKAGE_NAME = '@goondocks/myco';\n\n/** Delay in seconds before update script starts (allows daemon to exit). */\nexport const UPDATE_SCRIPT_DELAY_SECONDS = 2;\n\n/** Valid release channels. */\nexport const RELEASE_CHANNELS = ['stable', 'beta'] as const;\nexport type ReleaseChannel = (typeof RELEASE_CHANNELS)[number];\n\n/** Default release channel. */\nexport const DEFAULT_RELEASE_CHANNEL: ReleaseChannel = 'stable';\n","/**\n * Shared constants for the Myco codebase.\n * Per CLAUDE.md: \"No Magic Literals — Numeric and string constants\n * MUST NOT appear inline in logic.\"\n */\n\nexport { LOG_KINDS, type LogKind, kindToComponent } from './constants/log-kinds.js';\n\n// --- Agent phase prompt composition ---\n/**\n * Maximum chars per phase summary passed to subsequent phases.\n * Set to 4000 to ensure the digest-assess phase findings pass\n * untruncated to parallel tier phases.\n */\nexport const PHASE_SUMMARY_MAX_CHARS = 4000;\n\n// --- Token estimation ---\n/** Approximate characters per token for the chars/4 heuristic. */\nexport const CHARS_PER_TOKEN = 4;\n\n/** Estimate token count from character length using the CHARS_PER_TOKEN heuristic. */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\n// --- Time (primitives — must precede derived constants) ---\n/** Milliseconds per second. */\nexport const MS_PER_SECOND = 1000;\n\n// --- Embedding ---\n/** Max characters of text sent to the embedding model. */\nexport const EMBEDDING_INPUT_LIMIT = 8000;\n\n/** Max rows per embedding worker cycle. */\nexport const EMBEDDING_BATCH_SIZE = 10;\n\n/** Content hash algorithm for staleness detection. */\nexport const CONTENT_HASH_ALGORITHM = 'sha256';\n\n// --- Truncation limits (display/preview) ---\n/** Max chars for a user prompt preview in event summaries. */\nexport const PROMPT_PREVIEW_CHARS = 300;\n/** Max chars for an AI response preview in event summaries. */\nexport const AI_RESPONSE_PREVIEW_CHARS = 500;\n/** Max chars for a command string preview. */\nexport const COMMAND_PREVIEW_CHARS = 80;\n/** Max chars for a content snippet in search results. */\nexport const CONTENT_SNIPPET_CHARS = 120;\n/** Max chars for a tool output preview in hooks. */\nexport const TOOL_OUTPUT_PREVIEW_CHARS = 200;\n/** Max chars for a session summary preview in MCP tools. */\nexport const SESSION_SUMMARY_PREVIEW_CHARS = 300;\n/** Max chars for a recall summary preview. */\nexport const RECALL_SUMMARY_PREVIEW_CHARS = 200;\n/** Max chars for search result and hydrated context previews. */\nexport const SEARCH_PREVIEW_CHARS = 300;\n\n// --- Log preview limits (short previews for structured log fields) ---\n/** Max chars for a user prompt preview in log entries. */\nexport const LOG_PROMPT_PREVIEW_CHARS = 50;\n/** Max chars for an assistant message preview in log entries. */\nexport const LOG_MESSAGE_PREVIEW_CHARS = 80;\n\n// --- Context injection layer budgets (chars, not tokens — used with .slice()) ---\nexport const CONTEXT_SESSION_PREVIEW_CHARS = 80;\nexport const CONTEXT_SPORE_PREVIEW_CHARS = 80;\n\n// --- Processor maxTokens budgets ---\n/** Response token budget for observation extraction. */\nexport const EXTRACTION_MAX_TOKENS = 2048;\n/** Response token budget for session summary. */\nexport const SUMMARY_MAX_TOKENS = 512;\n/** Response token budget for session title generation. */\nexport const TITLE_MAX_TOKENS = 32;\n\n// --- Timeouts ---\n/** Daemon client HTTP request timeout (ms). */\nexport const DAEMON_CLIENT_TIMEOUT_MS = 2000;\n/** Health check timeout (ms) — fail fast if daemon isn't responding. */\nexport const DAEMON_HEALTH_CHECK_TIMEOUT_MS = 500;\n/** LLM request timeout (ms). All LLM calls are background daemon work — no need to be aggressive. */\nexport const LLM_REQUEST_TIMEOUT_MS = 180_000;\n/** Embedding request timeout (ms). Embeddings run in background batch processing — generous timeout. */\nexport const EMBEDDING_REQUEST_TIMEOUT_MS = 60_000;\n/** Digest LLM request timeout (ms). Digest cycles use large context windows and may need model loading time. */\nexport const DIGEST_LLM_REQUEST_TIMEOUT_MS = 600_000;\n/** Stdin read timeout for hooks (ms). */\nexport const STDIN_TIMEOUT_MS = 100;\n/** Provider detection timeout for detect-providers CLI command (ms). */\nexport const PROVIDER_DETECT_TIMEOUT_MS = 3000;\n\n// --- Time ---\n/** Milliseconds in one day. */\nexport const MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/** Current Unix epoch in seconds. */\nexport function epochSeconds(): number {\n return Math.floor(Date.now() / MS_PER_SECOND);\n}\n\n// --- Buffer cleanup ---\n/** Max age for stale buffer files before cleanup (ms). */\nexport const STALE_BUFFER_MAX_AGE_MS = 1 * MS_PER_DAY;\n\n// --- Retry backoff ---\n/** Retry delays for daemon health check (ms). */\nexport const DAEMON_HEALTH_RETRY_DELAYS = [100, 200, 400, 800, 1500];\n\n/** Grace period after daemon.json is written before stale checks can trigger a restart (ms).\n * Prevents rapid restart loops from concurrent hooks or session reloads. */\nexport const DAEMON_STALE_GRACE_PERIOD_MS = 60_000;\n\n/** Grace period for SIGTERM before escalating to SIGKILL (ms).\n * Gives the old daemon a chance to shut down cleanly, but force-kills\n * to guarantee the configured port is reclaimed. */\nexport const DAEMON_EVICT_TIMEOUT_MS = 3000;\n/** Poll interval when waiting for an evicted daemon to die (ms). */\nexport const DAEMON_EVICT_POLL_MS = 100;\n\n// --- Slug limits ---\n/** Max length for slugified artifact IDs. */\n\n// --- Turn rendering ---\n/** Max file paths displayed per turn in session notes. */\nexport const TURN_MAX_FILES_DISPLAYED = 10;\n\n// --- Transcript mining ---\n/** Minimum content length to consider a transcript entry meaningful. */\nexport const MIN_TRANSCRIPT_CONTENT_LENGTH = 10;\n\n// --- Graph edge types (lineage — auto-created by daemon) ---\n/** Spore was extracted during this session. */\nexport const EDGE_TYPE_FROM_SESSION = 'FROM_SESSION';\n/** Spore was extracted from this prompt batch. */\nexport const EDGE_TYPE_EXTRACTED_FROM = 'EXTRACTED_FROM';\n/** Wisdom spore was derived from (consolidated) this source spore. */\nexport const EDGE_TYPE_DERIVED_FROM = 'DERIVED_FROM';\n/** Session contains this prompt batch. */\nexport const EDGE_TYPE_HAS_BATCH = 'HAS_BATCH';\n// --- Query defaults ---\n/** Default row limit for query module list operations. */\nexport const QUERY_DEFAULT_LIST_LIMIT = 100;\n/** Default LIMIT for paginated list queries. */\nexport const DEFAULT_LIST_LIMIT = 50;\n/** Default confidence score for graph edges. */\nexport const GRAPH_EDGE_DEFAULT_CONFIDENCE = 1.0;\n\n// --- Query limits ---\n/** Max recent sessions to check for lineage heuristics. */\nexport const LINEAGE_RECENT_SESSIONS_LIMIT = 5;\n/** Max related spores to query for session notes. */\nexport const RELATED_SPORES_LIMIT = 50;\n\n// --- Context injection ---\n/** Max spores to inject per prompt. */\nexport const PROMPT_CONTEXT_MAX_SPORES = 3;\n/** Minimum similarity score for prompt context injection (0-1). */\nexport const PROMPT_CONTEXT_MIN_SIMILARITY = 0.3;\n/** Max token budget for session-start context injection. */\nexport const SESSION_CONTEXT_MAX_TOKENS = 500;\n/** Max token budget for per-prompt context injection. */\nexport const PROMPT_CONTEXT_MAX_TOKENS = 300;\n/** Minimum prompt length to trigger context search. */\nexport const PROMPT_CONTEXT_MIN_LENGTH = 10;\n\n/** Over-fetch multiplier for vector search to compensate for post-filtering. */\nexport const PROMPT_VECTOR_OVER_FETCH = 2;\n\n// --- Spore status filtering ---\n/** Spore statuses excluded from search results and context injection. */\nexport const EXCLUDED_SPORE_STATUSES = new Set(['superseded', 'archived']);\n\n// --- Agent identity ---\n/** Default agent ID for the built-in intelligence agent. */\nexport const DEFAULT_AGENT_ID = 'myco-agent';\n/** Agent ID for user-initiated MCP operations. */\nexport const USER_AGENT_ID = 'user';\n/** Agent name for user-initiated MCP operations. */\nexport const USER_AGENT_NAME = 'User (MCP)';\n\n// --- MCP tool defaults ---\n/** Default result limit for myco_search. */\nexport const MCP_SEARCH_DEFAULT_LIMIT = 10;\n/** Default result limit for myco_sessions. */\nexport const MCP_SESSIONS_DEFAULT_LIMIT = 20;\n/** Default result limit for myco_logs. */\nexport const MCP_LOGS_DEFAULT_LIMIT = 50;\n/** Default result limit for myco_skills and myco_skill_candidates. */\nexport const MCP_SKILLS_DEFAULT_LIMIT = 50;\n\n// --- Feed ---\n/** Default number of entries returned by the activity feed. */\nexport const FEED_DEFAULT_LIMIT = 50;\n\n// --- Digest — Tiers ---\n/** Available token-budget tiers for digest synthesis. */\nexport const DIGEST_TIERS = [1500, 5000, 10000] as const;\nexport type DigestTier = (typeof DIGEST_TIERS)[number];\n\n// --- Digest — Context window minimums per tier ---\n/** Minimum context window (tokens) required to run a digest at a given tier. */\nexport const DIGEST_TIER_MIN_CONTEXT: Record<number, number> = {\n 1500: 6500,\n 5000: 18500,\n 10000: 30500,\n};\n\n// --- Digest — Substrate ---\n/** Default minimum substrate notes required before a digest cycle runs. */\nexport const DIGEST_MIN_NOTES_FOR_CYCLE = 10;\n\n/** Scoring weights by note type when selecting substrate for synthesis. */\nexport const DIGEST_SUBSTRATE_TYPE_WEIGHTS: Record<string, number> = {\n session: 3,\n spore: 3,\n plan: 2,\n artifact: 1,\n team: 1,\n};\n\n// --- LLM reasoning control ---\n/** Reasoning mode for all Myco LLM calls. Suppresses chain-of-thought tokens from reasoning models. */\nexport const LLM_REASONING_MODE = 'off' as const;\n\n// --- Digest — System prompt overhead estimate ---\n\n// --- Vault intelligence ---\n/** Max candidate spores after post-filtering for supersession check. */\nexport const SUPERSESSION_CANDIDATE_LIMIT = 5;\n\n/** Over-fetch from vector index before post-filtering by status/type. */\nexport const SUPERSESSION_VECTOR_FETCH_LIMIT = 20;\n\n/** Max output tokens for supersession LLM evaluation. */\nexport const SUPERSESSION_MAX_TOKENS = 256;\n\n/** Similarity threshold for clustering related spores in batch agent processing. */\nexport const AGENT_CLUSTER_SIMILARITY = 0.75;\n\n// --- Search ---\n/** Default number of results returned by vector search and fullTextSearch. */\nexport const SEARCH_RESULTS_DEFAULT_LIMIT = 20;\n/** Minimum cosine similarity score for semantic search results (0-1). */\nexport const SEARCH_SIMILARITY_THRESHOLD = 0.3;\n\n// --- Pipeline processing ---\n/** Default page size for pipeline items API listing. */\nexport const PIPELINE_ITEMS_DEFAULT_LIMIT = 50;\n\n// --- Pipeline retry ---\n/** Max retries for parse (structural) pipeline failures — fail fast. */\nexport const PIPELINE_PARSE_MAX_RETRIES = 1;\n/** Exponential backoff multiplier for successive pipeline retries. */\nexport const PIPELINE_BACKOFF_MULTIPLIER = 4;\n\n// --- Pipeline stages (ordered) ---\nexport const PIPELINE_STAGES = ['capture', 'extraction', 'embedding', 'consolidation', 'digest'] as const;\nexport type PipelineStage = typeof PIPELINE_STAGES[number];\n\n// --- Pipeline statuses ---\nexport const PIPELINE_STATUSES = ['pending', 'processing', 'succeeded', 'failed', 'blocked', 'skipped', 'poisoned'] as const;\nexport type PipelineStatus = typeof PIPELINE_STATUSES[number];\n\n// --- Provider roles for circuit breakers ---\nexport const PIPELINE_PROVIDER_ROLES = ['llm', 'embedding', 'digest-llm'] as const;\nexport type PipelineProviderRole = typeof PIPELINE_PROVIDER_ROLES[number];\n\n// --- Stage to provider role mapping ---\nexport const STAGE_PROVIDER_MAP: Record<PipelineStage, PipelineProviderRole | null> = {\n capture: null,\n extraction: 'llm',\n embedding: 'embedding',\n consolidation: 'digest-llm',\n digest: 'digest-llm',\n};\n\n/**\n * Stages processed by the pipeline tick timer.\n * Capture is handled at registration time, digest is gated by the metabolism timer.\n */\nexport const PIPELINE_TICK_STAGES: PipelineStage[] = ['extraction', 'embedding', 'consolidation'];\n\n// --- Item type to applicable stages ---\n// Sessions skip consolidation — consolidation applies to the spores\n// extracted FROM sessions, not the session work item itself.\n// Lineage detection stays outside the pipeline (fire-and-forget, non-critical).\nexport const ITEM_STAGE_MAP: Record<string, PipelineStage[]> = {\n session: ['capture', 'extraction', 'embedding', 'digest'],\n spore: ['capture', 'embedding', 'consolidation', 'digest'],\n artifact: ['capture', 'embedding', 'digest'],\n};\n\n// --- User task registry ---\n/** Subdirectory within the vault for user-created task YAML files. */\nexport const USER_TASKS_DIR = 'tasks';\n\n/** Source label for user-created tasks. */\nexport const USER_TASK_SOURCE = 'user';\n\n/** Source label for built-in tasks shipped with the package. */\nexport const BUILT_IN_SOURCE = 'built-in';\n\n/** Task name validation pattern (lowercase, hyphens, digits). */\nexport const TASK_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;\n\n/** Maximum length for task names. */\nexport const MAX_TASK_NAME_LENGTH = 50;\n\n// --- Automatic consolidation ---\n/** Minimum cluster size required before asking LLM to consolidate. */\nexport const CONSOLIDATION_MIN_CLUSTER_SIZE = 3;\n\n/** Over-fetch from vector index before post-filtering by status/type. */\nexport const CONSOLIDATION_VECTOR_FETCH_LIMIT = 20;\n\n/** Max output tokens for consolidation LLM synthesis.\n * Must be large enough for the full JSON response including content field. */\nexport const CONSOLIDATION_MAX_TOKENS = 2048;\n\n// --- Power management ---\n/** PowerManager states valid for task scheduling (excludes deep_sleep which halts all ticks). */\nexport const SCHEDULABLE_POWER_STATES = ['active', 'idle', 'sleep'] as const;\nexport type SchedulablePowerState = typeof SCHEDULABLE_POWER_STATES[number];\n\n/** Time without activity before transitioning to idle (ms). */\nexport const POWER_IDLE_THRESHOLD_MS = 5 * 60 * MS_PER_SECOND;\n/** Time without activity before transitioning to sleep (ms). */\nexport const POWER_SLEEP_THRESHOLD_MS = 30 * 60 * MS_PER_SECOND;\n/** Time without activity before transitioning to deep sleep (ms). */\nexport const POWER_DEEP_SLEEP_THRESHOLD_MS = 90 * 60 * MS_PER_SECOND;\n/** Job cycle interval during active/idle states (ms). */\nexport const POWER_ACTIVE_INTERVAL_MS = 60 * MS_PER_SECOND;\n/** Job cycle interval during sleep state (ms). */\nexport const POWER_SLEEP_INTERVAL_MS = 5 * 60 * MS_PER_SECOND;\n\n// --- Session maintenance ---\n/** Time without new prompts before an active session is auto-completed (ms). */\nexport const STALE_SESSION_THRESHOLD_MS = 60 * 60 * MS_PER_SECOND;\n/**\n * Max prompt count for a session to be considered dead and auto-deleted.\n *\n * Set to 0: only sessions that were registered but never received a prompt\n * are eligible for dead-session cleanup. A session with even ONE real user\n * prompt has produced captured state worth preserving — the user did work,\n * the agent likely responded, tool calls may have happened, code may have\n * changed. Deleting such a session was a real data-loss failure mode seen\n * during opencode testing where a 1-prompt session that made an actual\n * committed code change was auto-deleted within a minute of TUI exit.\n */\nexport const DEAD_SESSION_MAX_PROMPTS = 0;\n\n// --- Init wizard ---\n/** Minimum Node.js major version required by Myco. */\nexport const MIN_NODE_MAJOR_VERSION = 22;\n\n/** Recommended context window for local intelligence models. */\nexport const RECOMMENDED_LOCAL_CONTEXT_WINDOW = 8192;\n\n/** Default Ollama embedding model recommended during init. */\nexport const DEFAULT_OLLAMA_EMBEDDING_MODEL = 'bge-m3';\n\n/** Default OpenAI embedding model recommended during init. */\nexport const DEFAULT_OPENAI_EMBEDDING_MODEL = 'text-embedding-3-small';\n\n// --- Sync protocol ---\n/** Protocol version for backup and team sync wire format. */\nexport const SYNC_PROTOCOL_VERSION = 1;\n\n// --- Team sync ---\n/** Default machine ID for rows created before multi-machine support. */\nexport const DEFAULT_MACHINE_ID = 'local';\n/** Prefix for team search result source attribution. */\nexport const TEAM_SOURCE_PREFIX = 'team:';\n/** Timeout for team search requests (ms). */\nexport const TEAM_SEARCH_TIMEOUT_MS = 3000;\n/** Timeout for team health check requests (ms). */\nexport const TEAM_HEALTH_TIMEOUT_MS = 5000;\n/** Secrets key for the team API key in secrets.env. */\nexport const TEAM_API_KEY_SECRET = 'MYCO_TEAM_API_KEY';\n/** Timeout for wrangler CLI commands (ms). */\nexport const WRANGLER_COMMAND_TIMEOUT_MS = 60_000;\n\n// --- HTTP response flush ---\n/** Delay before initiating shutdown — allows the HTTP response to flush. */\nexport const RESTART_RESPONSE_FLUSH_MS = 500;\n\n// --- Self-update ---\nexport {\n NPM_REGISTRY_URL,\n MYCO_GLOBAL_DIR,\n UPDATE_CHECK_CACHE_PATH,\n UPDATE_CONFIG_PATH,\n UPDATE_ERROR_PATH,\n UPDATE_CHECK_INTERVAL_HOURS,\n MS_PER_HOUR,\n NPM_PACKAGE_NAME,\n UPDATE_SCRIPT_DELAY_SECONDS,\n RELEASE_CHANNELS,\n DEFAULT_RELEASE_CHANNEL,\n type ReleaseChannel,\n} from './constants/update.js';\n"],"mappings":";;;AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AAGR,IAAM,mBAAmB;AAGzB,IAAM,kBAAkB,KAAK,KAAK,GAAG,QAAQ,GAAG,OAAO;AAGvD,IAAM,0BAA0B,KAAK,KAAK,iBAAiB,wBAAwB;AAGnF,IAAM,qBAAqB,KAAK,KAAK,iBAAiB,aAAa;AAGnE,IAAM,oBAAoB,KAAK,KAAK,iBAAiB,mBAAmB;AAGxE,IAAM,8BAA8B;AAGpC,IAAM,cAAc;AAGpB,IAAM,mBAAmB;AAGzB,IAAM,8BAA8B;AAGpC,IAAM,mBAAmB,CAAC,UAAU,MAAM;AAI1C,IAAM,0BAA0C;;;ACrBhD,IAAM,0BAA0B;AAIhC,IAAM,kBAAkB;AAGxB,SAAS,eAAe,MAAsB;AACnD,SAAO,KAAK,KAAK,KAAK,SAAS,eAAe;AAChD;AAIO,IAAM,gBAAgB;AAOtB,IAAM,uBAAuB;AAG7B,IAAM,yBAAyB;AAI/B,IAAM,uBAAuB;AAM7B,IAAM,wBAAwB;AAE9B,IAAM,4BAA4B;AAMlC,IAAM,uBAAuB;AAI7B,IAAM,2BAA2B;AAEjC,IAAM,4BAA4B;AAGlC,IAAM,gCAAgC;AACtC,IAAM,8BAA8B;AAYpC,IAAM,2BAA2B;AAEjC,IAAM,iCAAiC;AAEvC,IAAM,yBAAyB;AAE/B,IAAM,+BAA+B;AAIrC,IAAM,mBAAmB;AAEzB,IAAM,6BAA6B;AAInC,IAAM,aAAa,KAAK,KAAK,KAAK;AAGlC,SAAS,eAAuB;AACrC,SAAO,KAAK,MAAM,KAAK,IAAI,IAAI,aAAa;AAC9C;AAIO,IAAM,0BAA0B,IAAI;AAIpC,IAAM,6BAA6B,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI;AAI5D,IAAM,+BAA+B;AAKrC,IAAM,0BAA0B;AAEhC,IAAM,uBAAuB;AAe7B,IAAM,yBAAyB;AAE/B,IAAM,2BAA2B;AAEjC,IAAM,yBAAyB;AAE/B,IAAM,sBAAsB;AAG5B,IAAM,2BAA2B;AAEjC,IAAM,qBAAqB;AAE3B,IAAM,gCAAgC;AAYtC,IAAM,gCAAgC;AAItC,IAAM,4BAA4B;AAElC,IAAM,4BAA4B;AAGlC,IAAM,2BAA2B;AAIjC,IAAM,0BAA0B,oBAAI,IAAI,CAAC,cAAc,UAAU,CAAC;AAIlE,IAAM,mBAAmB;AAEzB,IAAM,gBAAgB;AAEtB,IAAM,kBAAkB;AAIxB,IAAM,2BAA2B;AAEjC,IAAM,6BAA6B;AAInC,IAAM,2BAA2B;AAIjC,IAAM,qBAAqB;AAI3B,IAAM,eAAe,CAAC,MAAM,KAAM,GAAK;AA6CvC,IAAM,+BAA+B;AAErC,IAAM,8BAA8B;AAmDpC,IAAM,iBAAiB;AAGvB,IAAM,mBAAmB;AAGzB,IAAM,kBAAkB;AAGxB,IAAM,oBAAoB;AAG1B,IAAM,uBAAuB;AAe7B,IAAM,2BAA2B,CAAC,UAAU,QAAQ,OAAO;AAI3D,IAAM,0BAA0B,IAAI,KAAK;AAEzC,IAAM,2BAA2B,KAAK,KAAK;AAE3C,IAAM,gCAAgC,KAAK,KAAK;AAEhD,IAAM,2BAA2B,KAAK;AAEtC,IAAM,0BAA0B,IAAI,KAAK;AAIzC,IAAM,6BAA6B,KAAK,KAAK;AAY7C,IAAM,2BAA2B;AAUjC,IAAM,iCAAiC;AAOvC,IAAM,wBAAwB;AAI9B,IAAM,qBAAqB;AAE3B,IAAM,qBAAqB;AAE3B,IAAM,yBAAyB;AAE/B,IAAM,yBAAyB;AAE/B,IAAM,sBAAsB;AAE5B,IAAM,8BAA8B;AAIpC,IAAM,4BAA4B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/db/queries/embeddings.ts","../src/services/stats.ts"],"sourcesContent":["/**\n * Embedded flag management — tracks which rows have been indexed in the external vector store.\n *\n * All vector storage and similarity search is handled by the external VectorStore.\n * This module only manages the `embedded` flag on relational tables.\n */\n\nimport { getDatabase } from '@myco/db/client.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Tables that participate in vector embedding. */\nexport const EMBEDDABLE_TABLES = ['sessions', 'spores', 'plans', 'artifacts'] as const;\n\n/** TypeScript type for valid embeddable table names. */\nexport type EmbeddableTable = (typeof EMBEDDABLE_TABLES)[number];\n\n/** Per-table column that holds the text content used for embedding. */\nexport const EMBEDDABLE_TEXT_COLUMNS: Record<EmbeddableTable, string> = {\n sessions: 'summary',\n spores: 'content',\n plans: 'content',\n artifacts: 'content',\n};\n\n/** Error message for invalid table names. */\nconst INVALID_TABLE_MSG = 'Invalid table name — must be one of: sessions, spores, plans, artifacts';\n\n/** Default number of rows returned by getUnembedded. */\nconst DEFAULT_UNEMBEDDED_LIMIT = 100;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Validate that a table name is in the allowlist.\n *\n * @throws if the table name is not one of the embeddable tables.\n */\nexport function assertValidTable(table: string): asserts table is EmbeddableTable {\n if (!(EMBEDDABLE_TABLES as readonly string[]).includes(table)) {\n throw new Error(INVALID_TABLE_MSG);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Mark a row as embedded in the external vector store. */\nexport function markEmbedded(table: string, id: string | number): void {\n assertValidTable(table);\n const db = getDatabase();\n db.prepare(`UPDATE ${table} SET embedded = 1 WHERE id = ?`).run(id);\n}\n\n/** Clear the embedded flag (e.g., when vector is removed or needs re-embedding). */\nexport function clearEmbedded(table: string, id: string | number): void {\n assertValidTable(table);\n const db = getDatabase();\n db.prepare(`UPDATE ${table} SET embedded = 0 WHERE id = ?`).run(id);\n}\n\n/** Find rows that have not yet been embedded, oldest first. */\nexport function getUnembedded(\n table: string,\n limit: number = DEFAULT_UNEMBEDDED_LIMIT,\n): Array<{ id: string | number; created_at: number; text: string }> {\n assertValidTable(table);\n const db = getDatabase();\n const textCol = EMBEDDABLE_TEXT_COLUMNS[table as EmbeddableTable];\n const contentFilter = table === 'sessions' ? ' AND summary IS NOT NULL' : '';\n const statusFilter = table === 'spores' ? \" AND status = 'active'\" : '';\n\n return db.prepare(\n `SELECT id, created_at, ${textCol} AS text\n FROM ${table}\n WHERE embedded = 0${contentFilter}${statusFilter}\n ORDER BY created_at ASC\n LIMIT ?`\n ).all(limit) as Array<{ id: string | number; created_at: number; text: string }>;\n}\n\n/** Get aggregated embedding queue depth across all embeddable tables. */\nexport function getEmbeddingQueueDepth(): {\n queue_depth: number;\n embedded_count: number;\n total: number;\n} {\n const db = getDatabase();\n\n const queueRow = db.prepare(`\n SELECT\n (SELECT COUNT(*) FROM sessions WHERE embedded = 0 AND summary IS NOT NULL) +\n (SELECT COUNT(*) FROM spores WHERE embedded = 0 AND status = 'active') +\n (SELECT COUNT(*) FROM plans WHERE embedded = 0 AND content IS NOT NULL) +\n (SELECT COUNT(*) FROM artifacts WHERE embedded = 0 AND content IS NOT NULL)\n AS cnt\n `).get() as { cnt: number };\n\n const embeddedRow = db.prepare(`\n SELECT\n (SELECT COUNT(*) FROM sessions WHERE embedded = 1) +\n (SELECT COUNT(*) FROM spores WHERE embedded = 1) +\n (SELECT COUNT(*) FROM plans WHERE embedded = 1) +\n (SELECT COUNT(*) FROM artifacts WHERE embedded = 1)\n AS cnt\n `).get() as { cnt: number };\n\n const queue_depth = Number(queueRow.cnt ?? 0);\n const embedded_count = Number(embeddedRow.cnt ?? 0);\n return { queue_depth, embedded_count, total: queue_depth + embedded_count };\n}\n","/**\n * Vault statistics — gathered from SQLite.\n */\n\nimport { getDatabase } from '@myco/db/client.js';\nimport { getEmbeddingQueueDepth } from '@myco/db/queries/embeddings.js';\nimport { loadConfig } from '@myco/config/loader.js';\nimport { isProcessAlive } from '@myco/cli/shared.js';\nimport { DIGEST_TIERS } from '@myco/constants.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Process uptime is available directly from the daemon process via process.uptime(). */\nconst DAEMON_JSON_FILENAME = 'daemon.json';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface V2Stats {\n daemon: {\n pid: number;\n port: number;\n version: string;\n uptime_seconds: number;\n active_sessions: string[];\n };\n vault: {\n path: string;\n name: string;\n session_count: number;\n batch_count: number;\n spore_count: number;\n plan_count: number;\n artifact_count: number;\n entity_count: number;\n edge_count: number;\n };\n embedding: {\n provider: string;\n model: string;\n queue_depth: number;\n embedded_count: number;\n total_embeddable: number;\n };\n agent: {\n last_run_at: number | null;\n last_run_status: string | null;\n total_runs: number;\n };\n digest: {\n freshest_tier: number | null;\n generated_at: number | null;\n tiers_available: number[];\n };\n unprocessed_batches: number;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Count rows in a table (sync). */\nfunction countTable(db: ReturnType<typeof getDatabase>, table: string): number {\n const row = db.prepare(`SELECT COUNT(*) AS cnt FROM ${table}`).get() as { cnt: number };\n return Number(row.cnt);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function gatherStats(vaultDir: string, options?: { active_sessions?: string[] }): V2Stats {\n const db = getDatabase();\n\n // Load config for embedding provider info (sync — already on disk)\n const config = loadConfig(vaultDir);\n\n // All queries are synchronous — no Promise.all needed\n const session_count = countTable(db, 'sessions');\n const batch_count = countTable(db, 'prompt_batches');\n const spore_count = countTable(db, 'spores');\n const plan_count = countTable(db, 'plans');\n const artifact_count = countTable(db, 'artifacts');\n const entity_count = countTable(db, 'entities');\n const edge_count = countTable(db, 'graph_edges');\n\n // Shared embedding queue depth helper (consistent filter logic)\n const embeddingStats = getEmbeddingQueueDepth();\n const { queue_depth, embedded_count, total: total_embeddable } = embeddingStats;\n\n // Unprocessed batches\n const unprocessedRow = db.prepare(\n 'SELECT COUNT(*) AS cnt FROM prompt_batches WHERE processed = 0',\n ).get() as { cnt: number };\n const unprocessed_batches = Number(unprocessedRow.cnt ?? 0);\n\n // Agent: most recent run\n const lastRun = db.prepare(\n 'SELECT started_at, status FROM agent_runs ORDER BY started_at DESC LIMIT 1',\n ).get() as { started_at: number; status: string } | undefined;\n const last_run_at = lastRun ? lastRun.started_at : null;\n const last_run_status = lastRun ? lastRun.status : null;\n\n // Total agent runs\n const agentTotalRow = db.prepare(\n 'SELECT COUNT(*) AS cnt FROM agent_runs',\n ).get() as { cnt: number };\n const total_runs = Number(agentTotalRow.cnt ?? 0);\n\n // Digest extracts: only report tiers that are currently configured\n const digestRows = db.prepare(\n 'SELECT tier, generated_at FROM digest_extracts ORDER BY tier ASC',\n ).all() as Array<{ tier: number; generated_at: number }>;\n const configuredTiers = new Set<number>(DIGEST_TIERS);\n const activeDigestRows = digestRows.filter((r) => configuredTiers.has(r.tier));\n const tiers_available = activeDigestRows.map((r) => r.tier);\n const freshest_tier = tiers_available.length > 0 ? Math.max(...tiers_available) : null;\n const freshestRow = activeDigestRows.find((r) => r.tier === freshest_tier);\n const generated_at = freshestRow ? freshestRow.generated_at : null;\n\n // Daemon info from daemon.json\n let daemonPid = 0;\n let daemonPort = 0;\n let daemonVersion = '';\n let daemonUptimeSeconds = 0;\n const daemonPath = path.join(vaultDir, DAEMON_JSON_FILENAME);\n if (fs.existsSync(daemonPath)) {\n try {\n const info = JSON.parse(fs.readFileSync(daemonPath, 'utf-8')) as Record<string, unknown>;\n daemonPid = (info.pid as number) ?? 0;\n daemonPort = (info.port as number) ?? 0;\n daemonVersion = (info.version as string) ?? '';\n // uptime: if daemon is alive, compute from started timestamp\n if (typeof info.started === 'string' && isProcessAlive(daemonPid)) {\n const startedMs = new Date(info.started as string).getTime();\n daemonUptimeSeconds = Math.floor((Date.now() - startedMs) / 1000);\n }\n } catch { /* ignore corrupt daemon.json */ }\n }\n\n return {\n daemon: {\n pid: daemonPid,\n port: daemonPort,\n version: daemonVersion,\n uptime_seconds: daemonUptimeSeconds,\n active_sessions: options?.active_sessions ?? [],\n },\n vault: {\n path: vaultDir,\n name: path.basename(path.dirname(vaultDir)),\n session_count,\n batch_count,\n spore_count,\n plan_count,\n artifact_count,\n entity_count,\n edge_count,\n },\n embedding: {\n provider: config.embedding.provider,\n model: config.embedding.model,\n queue_depth,\n embedded_count,\n total_embeddable,\n },\n agent: {\n last_run_at,\n last_run_status,\n total_runs,\n },\n digest: {\n freshest_tier,\n generated_at,\n tiers_available,\n },\n unprocessed_batches,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
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# Binary attachments — screenshots captured from transcripts\nattachments/\n\n# Team worker deployment — patched wrangler.toml + source copy\n.team-worker/\n`;\n\n/** Collapse an absolute home-dir path to its `~/` form for portable config storage. */\nexport function collapseHomePath(absPath: string): string {\n const home = os.homedir();\n if (absPath.startsWith(home + path.sep) || absPath === home) {\n return '~' + absPath.slice(home.length);\n }\n return absPath;\n}\n\n/**\n * Run the SymbiontInstaller for each symbiont manifest and log results.\n * Shared between myco init and myco update.\n */\nexport function registerSymbionts(\n manifests: SymbiontManifest[],\n projectRoot: string,\n packageRoot: string,\n verb: 'Registered' | 'Updated',\n): number {\n let count = 0;\n for (const manifest of manifests) {\n try {\n const installer = new SymbiontInstaller(manifest, projectRoot, packageRoot);\n const result = installer.install();\n\n const installed = [\n result.hooks && 'hooks',\n result.mcp && 'MCP server',\n result.skills && 'skills',\n result.settings && 'settings',\n result.instructions && 'instructions',\n 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;AAmCxB,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":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/symbionts/manifest-schema.ts","../src/symbionts/detect.ts"],"sourcesContent":["import { z } from 'zod';\n\nconst CaptureManifestSchema = z.object({\n planDirs: z.array(z.string()).default([]),\n});\n\nconst RegistrationSchema = z.object({\n hooksTarget: z.string().optional(),\n /**\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 * 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"]}