@goondocks/myco 0.6.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/.claude-plugin/marketplace.json +2 -3
  2. package/.claude-plugin/plugin.json +3 -3
  3. package/CONTRIBUTING.md +37 -30
  4. package/README.md +64 -28
  5. package/bin/myco-run +2 -0
  6. package/dist/agent-run-EFICNTAU.js +34 -0
  7. package/dist/agent-run-EFICNTAU.js.map +1 -0
  8. package/dist/agent-tasks-RXJ7Z5NG.js +180 -0
  9. package/dist/agent-tasks-RXJ7Z5NG.js.map +1 -0
  10. package/dist/chunk-2T7RPVPP.js +116 -0
  11. package/dist/chunk-2T7RPVPP.js.map +1 -0
  12. package/dist/chunk-3K5WGSJ4.js +165 -0
  13. package/dist/chunk-3K5WGSJ4.js.map +1 -0
  14. package/dist/chunk-46PWOKSI.js +26 -0
  15. package/dist/chunk-46PWOKSI.js.map +1 -0
  16. package/dist/chunk-4LPQ26CK.js +277 -0
  17. package/dist/chunk-4LPQ26CK.js.map +1 -0
  18. package/dist/chunk-5PEUFJ6U.js +92 -0
  19. package/dist/chunk-5PEUFJ6U.js.map +1 -0
  20. package/dist/chunk-5VZ52A4T.js +136 -0
  21. package/dist/chunk-5VZ52A4T.js.map +1 -0
  22. package/dist/chunk-BUSP3OJB.js +103 -0
  23. package/dist/chunk-BUSP3OJB.js.map +1 -0
  24. package/dist/chunk-D7TYRPRM.js +7312 -0
  25. package/dist/chunk-D7TYRPRM.js.map +1 -0
  26. package/dist/chunk-DCXRSSBP.js +22 -0
  27. package/dist/chunk-DCXRSSBP.js.map +1 -0
  28. package/dist/chunk-E4VLWIJC.js +2 -0
  29. package/dist/chunk-FFAYUQ5N.js +39 -0
  30. package/dist/chunk-FFAYUQ5N.js.map +1 -0
  31. package/dist/chunk-IB76KGBY.js +2 -0
  32. package/dist/chunk-JMJJEQ3P.js +486 -0
  33. package/dist/chunk-JMJJEQ3P.js.map +1 -0
  34. package/dist/{chunk-N33KUCFP.js → chunk-JTYZRPX5.js} +1 -9
  35. package/dist/chunk-JTYZRPX5.js.map +1 -0
  36. package/dist/{chunk-NLUE6CYG.js → chunk-JYOOJCPQ.js} +33 -17
  37. package/dist/chunk-JYOOJCPQ.js.map +1 -0
  38. package/dist/{chunk-Z74SDEKE.js → chunk-KB4DGYIY.js} +91 -9
  39. package/dist/chunk-KB4DGYIY.js.map +1 -0
  40. package/dist/{chunk-ERG2IEWX.js → chunk-KH64DHOY.js} +3 -7413
  41. package/dist/chunk-KH64DHOY.js.map +1 -0
  42. package/dist/chunk-KV4OC4H3.js +498 -0
  43. package/dist/chunk-KV4OC4H3.js.map +1 -0
  44. package/dist/chunk-KYLDNM7H.js +66 -0
  45. package/dist/chunk-KYLDNM7H.js.map +1 -0
  46. package/dist/chunk-LPUQPDC2.js +19 -0
  47. package/dist/chunk-LPUQPDC2.js.map +1 -0
  48. package/dist/chunk-M5XWW7UI.js +97 -0
  49. package/dist/chunk-M5XWW7UI.js.map +1 -0
  50. package/dist/chunk-MHSCMET3.js +275 -0
  51. package/dist/chunk-MHSCMET3.js.map +1 -0
  52. package/dist/chunk-MYX5NCRH.js +45 -0
  53. package/dist/chunk-MYX5NCRH.js.map +1 -0
  54. package/dist/chunk-OXZSXYAT.js +877 -0
  55. package/dist/chunk-OXZSXYAT.js.map +1 -0
  56. package/dist/chunk-PB6TOLRQ.js +35 -0
  57. package/dist/chunk-PB6TOLRQ.js.map +1 -0
  58. package/dist/chunk-PT5IC642.js +162 -0
  59. package/dist/chunk-PT5IC642.js.map +1 -0
  60. package/dist/chunk-QIK2XSDQ.js +187 -0
  61. package/dist/chunk-QIK2XSDQ.js.map +1 -0
  62. package/dist/chunk-RJ6ZQKG5.js +26 -0
  63. package/dist/chunk-RJ6ZQKG5.js.map +1 -0
  64. package/dist/{chunk-YIQLYIHW.js → chunk-TRUJLI6K.js} +29 -43
  65. package/dist/chunk-TRUJLI6K.js.map +1 -0
  66. package/dist/chunk-U3IBO3O3.js +41 -0
  67. package/dist/chunk-U3IBO3O3.js.map +1 -0
  68. package/dist/{chunk-7WHF2OIZ.js → chunk-UBZPD4HN.js} +25 -7
  69. package/dist/chunk-UBZPD4HN.js.map +1 -0
  70. package/dist/{chunk-HIN3UVOG.js → chunk-V7XG6V6C.js} +20 -11
  71. package/dist/chunk-V7XG6V6C.js.map +1 -0
  72. package/dist/chunk-WGTCA2NU.js +84 -0
  73. package/dist/chunk-WGTCA2NU.js.map +1 -0
  74. package/dist/{chunk-O6PERU7U.js → chunk-XNOCTDHF.js} +2 -2
  75. package/dist/chunk-YDN4OM33.js +80 -0
  76. package/dist/chunk-YDN4OM33.js.map +1 -0
  77. package/dist/cli-ODLFRIYS.js +128 -0
  78. package/dist/cli-ODLFRIYS.js.map +1 -0
  79. package/dist/client-EYOTW3JU.js +19 -0
  80. package/dist/client-MXRNQ5FI.js +13 -0
  81. package/dist/{config-IBS6KOLQ.js → config-UR5BSGVX.js} +21 -34
  82. package/dist/config-UR5BSGVX.js.map +1 -0
  83. package/dist/detect-H5OPI7GD.js +17 -0
  84. package/dist/detect-H5OPI7GD.js.map +1 -0
  85. package/dist/detect-providers-Q42OD4OS.js +26 -0
  86. package/dist/detect-providers-Q42OD4OS.js.map +1 -0
  87. package/dist/doctor-JLKTXDEH.js +258 -0
  88. package/dist/doctor-JLKTXDEH.js.map +1 -0
  89. package/dist/executor-ONSDHPGX.js +1441 -0
  90. package/dist/executor-ONSDHPGX.js.map +1 -0
  91. package/dist/init-6GWY345B.js +198 -0
  92. package/dist/init-6GWY345B.js.map +1 -0
  93. package/dist/init-wizard-UONLDYLI.js +294 -0
  94. package/dist/init-wizard-UONLDYLI.js.map +1 -0
  95. package/dist/llm-BV3QNVRD.js +17 -0
  96. package/dist/llm-BV3QNVRD.js.map +1 -0
  97. package/dist/loader-SH67XD54.js +28 -0
  98. package/dist/loader-SH67XD54.js.map +1 -0
  99. package/dist/loader-XVXKZZDH.js +18 -0
  100. package/dist/loader-XVXKZZDH.js.map +1 -0
  101. package/dist/{chunk-H7PRCVGQ.js → logs-QZVYF6FP.js} +74 -5
  102. package/dist/logs-QZVYF6FP.js.map +1 -0
  103. package/dist/main-BMCL7CPO.js +4393 -0
  104. package/dist/main-BMCL7CPO.js.map +1 -0
  105. package/dist/openai-embeddings-C265WRNK.js +14 -0
  106. package/dist/openai-embeddings-C265WRNK.js.map +1 -0
  107. package/dist/openrouter-U6VFCRX2.js +14 -0
  108. package/dist/openrouter-U6VFCRX2.js.map +1 -0
  109. package/dist/post-compact-OWFSOITU.js +26 -0
  110. package/dist/post-compact-OWFSOITU.js.map +1 -0
  111. package/dist/post-tool-use-DOUM7CGQ.js +56 -0
  112. package/dist/post-tool-use-DOUM7CGQ.js.map +1 -0
  113. package/dist/post-tool-use-failure-SG3C7PE6.js +28 -0
  114. package/dist/post-tool-use-failure-SG3C7PE6.js.map +1 -0
  115. package/dist/pre-compact-3J33CHXQ.js +25 -0
  116. package/dist/pre-compact-3J33CHXQ.js.map +1 -0
  117. package/dist/provider-check-3WBPZADE.js +12 -0
  118. package/dist/provider-check-3WBPZADE.js.map +1 -0
  119. package/dist/registry-J4XTWARS.js +25 -0
  120. package/dist/registry-J4XTWARS.js.map +1 -0
  121. package/dist/resolution-events-TFEQPVKS.js +12 -0
  122. package/dist/resolution-events-TFEQPVKS.js.map +1 -0
  123. package/dist/resolve-3FEUV462.js +9 -0
  124. package/dist/resolve-3FEUV462.js.map +1 -0
  125. package/dist/{restart-XCMILOL5.js → restart-2VM33WOB.js} +10 -6
  126. package/dist/{restart-XCMILOL5.js.map → restart-2VM33WOB.js.map} +1 -1
  127. package/dist/search-ZGQR5MDE.js +91 -0
  128. package/dist/search-ZGQR5MDE.js.map +1 -0
  129. package/dist/{server-6UDN35QN.js → server-6KMBJCHZ.js} +308 -517
  130. package/dist/server-6KMBJCHZ.js.map +1 -0
  131. package/dist/session-Z2FXDDG6.js +68 -0
  132. package/dist/session-Z2FXDDG6.js.map +1 -0
  133. package/dist/session-end-FLVX32LE.js +38 -0
  134. package/dist/session-end-FLVX32LE.js.map +1 -0
  135. package/dist/session-start-UCLK7PXE.js +169 -0
  136. package/dist/session-start-UCLK7PXE.js.map +1 -0
  137. package/dist/setup-digest-4KDSXAIV.js +15 -0
  138. package/dist/setup-digest-4KDSXAIV.js.map +1 -0
  139. package/dist/setup-llm-GKMCHURK.js +81 -0
  140. package/dist/setup-llm-GKMCHURK.js.map +1 -0
  141. package/dist/src/agent/definitions/agent.yaml +35 -0
  142. package/dist/src/agent/definitions/tasks/digest-only.yaml +84 -0
  143. package/dist/src/agent/definitions/tasks/extract-only.yaml +87 -0
  144. package/dist/src/agent/definitions/tasks/full-intelligence.yaml +472 -0
  145. package/dist/src/agent/definitions/tasks/graph-maintenance.yaml +92 -0
  146. package/dist/src/agent/definitions/tasks/review-session.yaml +132 -0
  147. package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +86 -0
  148. package/dist/src/agent/definitions/tasks/title-summary.yaml +88 -0
  149. package/dist/src/agent/prompts/agent.md +121 -0
  150. package/dist/src/agent/prompts/orchestrator.md +91 -0
  151. package/dist/src/cli.js +1 -8
  152. package/dist/src/cli.js.map +1 -1
  153. package/dist/src/daemon/main.js +1 -8
  154. package/dist/src/daemon/main.js.map +1 -1
  155. package/dist/src/hooks/post-tool-use.js +3 -50
  156. package/dist/src/hooks/post-tool-use.js.map +1 -1
  157. package/dist/src/hooks/session-end.js +3 -32
  158. package/dist/src/hooks/session-end.js.map +1 -1
  159. package/dist/src/hooks/session-start.js +2 -8
  160. package/dist/src/hooks/session-start.js.map +1 -1
  161. package/dist/src/hooks/stop.js +3 -42
  162. package/dist/src/hooks/stop.js.map +1 -1
  163. package/dist/src/hooks/user-prompt-submit.js +3 -53
  164. package/dist/src/hooks/user-prompt-submit.js.map +1 -1
  165. package/dist/src/mcp/server.js +1 -8
  166. package/dist/src/mcp/server.js.map +1 -1
  167. package/dist/src/prompts/digest-system.md +1 -1
  168. package/dist/src/symbionts/manifests/claude-code.yaml +16 -0
  169. package/dist/src/symbionts/manifests/cursor.yaml +14 -0
  170. package/dist/stats-IUJPZSVZ.js +94 -0
  171. package/dist/stats-IUJPZSVZ.js.map +1 -0
  172. package/dist/stop-XRQLLXST.js +42 -0
  173. package/dist/stop-XRQLLXST.js.map +1 -0
  174. package/dist/stop-failure-2CAJJKRG.js +26 -0
  175. package/dist/stop-failure-2CAJJKRG.js.map +1 -0
  176. package/dist/subagent-start-MWWQTZMQ.js +26 -0
  177. package/dist/subagent-start-MWWQTZMQ.js.map +1 -0
  178. package/dist/subagent-stop-PJXYGRXB.js +28 -0
  179. package/dist/subagent-stop-PJXYGRXB.js.map +1 -0
  180. package/dist/task-completed-4LFRJVGI.js +27 -0
  181. package/dist/task-completed-4LFRJVGI.js.map +1 -0
  182. package/dist/ui/assets/index-DZrElonz.js +744 -0
  183. package/dist/ui/assets/index-TkeiYbZB.css +1 -0
  184. package/dist/ui/favicon.svg +7 -7
  185. package/dist/ui/fonts/Inter-Variable.woff2 +0 -0
  186. package/dist/ui/fonts/JetBrainsMono-Variable.woff2 +0 -0
  187. package/dist/ui/fonts/Newsreader-Italic-Variable.woff2 +0 -0
  188. package/dist/ui/fonts/Newsreader-Variable.woff2 +0 -0
  189. package/dist/ui/index.html +2 -2
  190. package/dist/user-prompt-submit-KSM3AR6P.js +59 -0
  191. package/dist/user-prompt-submit-KSM3AR6P.js.map +1 -0
  192. package/dist/{verify-TOWQHPBX.js → verify-UDAYVX37.js} +17 -22
  193. package/dist/verify-UDAYVX37.js.map +1 -0
  194. package/dist/{version-36RVCQA6.js → version-KLBN4HZT.js} +3 -4
  195. package/dist/version-KLBN4HZT.js.map +1 -0
  196. package/hooks/hooks.json +82 -5
  197. package/package.json +6 -3
  198. package/skills/myco/SKILL.md +10 -10
  199. package/skills/myco/references/cli-usage.md +15 -13
  200. package/skills/myco/references/vault-status.md +3 -3
  201. package/skills/myco/references/wisdom.md +4 -4
  202. package/skills/myco-curate/SKILL.md +86 -0
  203. package/dist/chunk-2ZIBCEYO.js +0 -113
  204. package/dist/chunk-2ZIBCEYO.js.map +0 -1
  205. package/dist/chunk-4RMSHZE4.js +0 -107
  206. package/dist/chunk-4RMSHZE4.js.map +0 -1
  207. package/dist/chunk-4XVKZ3WA.js +0 -1078
  208. package/dist/chunk-4XVKZ3WA.js.map +0 -1
  209. package/dist/chunk-6FQISQNA.js +0 -61
  210. package/dist/chunk-6FQISQNA.js.map +0 -1
  211. package/dist/chunk-7WHF2OIZ.js.map +0 -1
  212. package/dist/chunk-ERG2IEWX.js.map +0 -1
  213. package/dist/chunk-FPRXMJLT.js +0 -56
  214. package/dist/chunk-FPRXMJLT.js.map +0 -1
  215. package/dist/chunk-GENQ5QGP.js +0 -37
  216. package/dist/chunk-GENQ5QGP.js.map +0 -1
  217. package/dist/chunk-H7PRCVGQ.js.map +0 -1
  218. package/dist/chunk-HIN3UVOG.js.map +0 -1
  219. package/dist/chunk-HYVT345Y.js +0 -159
  220. package/dist/chunk-HYVT345Y.js.map +0 -1
  221. package/dist/chunk-J4D4CROB.js +0 -143
  222. package/dist/chunk-J4D4CROB.js.map +0 -1
  223. package/dist/chunk-MDLSAFPP.js +0 -99
  224. package/dist/chunk-MDLSAFPP.js.map +0 -1
  225. package/dist/chunk-N33KUCFP.js.map +0 -1
  226. package/dist/chunk-NL6WQO56.js +0 -65
  227. package/dist/chunk-NL6WQO56.js.map +0 -1
  228. package/dist/chunk-NLUE6CYG.js.map +0 -1
  229. package/dist/chunk-P723N2LP.js +0 -147
  230. package/dist/chunk-P723N2LP.js.map +0 -1
  231. package/dist/chunk-QLUE3BUL.js +0 -161
  232. package/dist/chunk-QLUE3BUL.js.map +0 -1
  233. package/dist/chunk-QN4W3JUA.js +0 -43
  234. package/dist/chunk-QN4W3JUA.js.map +0 -1
  235. package/dist/chunk-RGVBGTD6.js +0 -21
  236. package/dist/chunk-RGVBGTD6.js.map +0 -1
  237. package/dist/chunk-TWSTAVLO.js +0 -132
  238. package/dist/chunk-TWSTAVLO.js.map +0 -1
  239. package/dist/chunk-UP4P4OAA.js +0 -4423
  240. package/dist/chunk-UP4P4OAA.js.map +0 -1
  241. package/dist/chunk-YIQLYIHW.js.map +0 -1
  242. package/dist/chunk-YTFXA4RX.js +0 -86
  243. package/dist/chunk-YTFXA4RX.js.map +0 -1
  244. package/dist/chunk-Z74SDEKE.js.map +0 -1
  245. package/dist/cli-IHILSS6N.js +0 -97
  246. package/dist/cli-IHILSS6N.js.map +0 -1
  247. package/dist/client-AGFNR2S4.js +0 -12
  248. package/dist/config-IBS6KOLQ.js.map +0 -1
  249. package/dist/curate-3D4GHKJH.js +0 -78
  250. package/dist/curate-3D4GHKJH.js.map +0 -1
  251. package/dist/detect-providers-XEP4QA3R.js +0 -35
  252. package/dist/detect-providers-XEP4QA3R.js.map +0 -1
  253. package/dist/digest-7HLJXL77.js +0 -85
  254. package/dist/digest-7HLJXL77.js.map +0 -1
  255. package/dist/init-ARQ53JOR.js +0 -109
  256. package/dist/init-ARQ53JOR.js.map +0 -1
  257. package/dist/logs-IENORIYR.js +0 -84
  258. package/dist/logs-IENORIYR.js.map +0 -1
  259. package/dist/main-6AGPIMH2.js +0 -5715
  260. package/dist/main-6AGPIMH2.js.map +0 -1
  261. package/dist/rebuild-Q2ACEB6F.js +0 -64
  262. package/dist/rebuild-Q2ACEB6F.js.map +0 -1
  263. package/dist/reprocess-CDEFGQOV.js +0 -79
  264. package/dist/reprocess-CDEFGQOV.js.map +0 -1
  265. package/dist/search-7W25SKCB.js +0 -120
  266. package/dist/search-7W25SKCB.js.map +0 -1
  267. package/dist/server-6UDN35QN.js.map +0 -1
  268. package/dist/session-F326AWCH.js +0 -44
  269. package/dist/session-F326AWCH.js.map +0 -1
  270. package/dist/session-start-K6IGAC7H.js +0 -192
  271. package/dist/session-start-K6IGAC7H.js.map +0 -1
  272. package/dist/setup-digest-X5PN27F4.js +0 -15
  273. package/dist/setup-llm-S5OHQJXK.js +0 -15
  274. package/dist/src/prompts/classification.md +0 -43
  275. package/dist/stats-TTSDXGJV.js +0 -58
  276. package/dist/stats-TTSDXGJV.js.map +0 -1
  277. package/dist/templates-XPRBOWCE.js +0 -38
  278. package/dist/templates-XPRBOWCE.js.map +0 -1
  279. package/dist/ui/assets/index-08wKT7wS.css +0 -1
  280. package/dist/ui/assets/index-CMSMi4Jb.js +0 -369
  281. package/dist/verify-TOWQHPBX.js.map +0 -1
  282. package/skills/setup/SKILL.md +0 -174
  283. package/skills/setup/references/model-recommendations.md +0 -83
  284. /package/dist/{client-AGFNR2S4.js.map → chunk-E4VLWIJC.js.map} +0 -0
  285. /package/dist/{setup-digest-X5PN27F4.js.map → chunk-IB76KGBY.js.map} +0 -0
  286. /package/dist/{chunk-O6PERU7U.js.map → chunk-XNOCTDHF.js.map} +0 -0
  287. /package/dist/{setup-llm-S5OHQJXK.js.map → client-EYOTW3JU.js.map} +0 -0
  288. /package/dist/{version-36RVCQA6.js.map → client-MXRNQ5FI.js.map} +0 -0
@@ -0,0 +1,1441 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ insertResolutionEvent
4
+ } from "./chunk-YDN4OM33.js";
5
+ import {
6
+ STATUS_COMPLETED,
7
+ STATUS_FAILED,
8
+ STATUS_RUNNING,
9
+ createSporeLineage,
10
+ errorMessage,
11
+ getRunningRun,
12
+ getUnprocessedBatches,
13
+ insertEntity,
14
+ insertGraphEdge,
15
+ insertReport,
16
+ insertRun,
17
+ insertTurn,
18
+ listDigestExtracts,
19
+ listEntities,
20
+ listGraphEdges,
21
+ markBatchProcessed,
22
+ updateRunStatus,
23
+ upsertDigestExtract
24
+ } from "./chunk-OXZSXYAT.js";
25
+ import {
26
+ fullTextSearch
27
+ } from "./chunk-PT5IC642.js";
28
+ import {
29
+ loadAllTasks
30
+ } from "./chunk-BUSP3OJB.js";
31
+ import {
32
+ getAgent,
33
+ getDefaultTask,
34
+ getTask,
35
+ loadAgentDefinition,
36
+ loadSystemPrompt,
37
+ resolveDefinitionsDir,
38
+ resolveEffectiveConfig
39
+ } from "./chunk-JMJJEQ3P.js";
40
+ import "./chunk-IB76KGBY.js";
41
+ import {
42
+ DEFAULT_IMPORTANCE,
43
+ insertSpore,
44
+ listSpores,
45
+ updateSporeStatus
46
+ } from "./chunk-3K5WGSJ4.js";
47
+ import {
48
+ listSessions,
49
+ updateSession
50
+ } from "./chunk-4LPQ26CK.js";
51
+ import {
52
+ createSchema
53
+ } from "./chunk-KV4OC4H3.js";
54
+ import {
55
+ loadConfig
56
+ } from "./chunk-MHSCMET3.js";
57
+ import "./chunk-D7TYRPRM.js";
58
+ import "./chunk-E4VLWIJC.js";
59
+ import {
60
+ external_exports
61
+ } from "./chunk-KH64DHOY.js";
62
+ import {
63
+ getDatabase,
64
+ initDatabase,
65
+ vaultDbPath
66
+ } from "./chunk-MYX5NCRH.js";
67
+ import {
68
+ DEFAULT_AGENT_ID,
69
+ MS_PER_SECOND,
70
+ PHASE_SUMMARY_MAX_CHARS,
71
+ SEARCH_SIMILARITY_THRESHOLD,
72
+ epochSeconds
73
+ } from "./chunk-5VZ52A4T.js";
74
+ import "./chunk-WGTCA2NU.js";
75
+ import {
76
+ getPluginVersion
77
+ } from "./chunk-PB6TOLRQ.js";
78
+ import {
79
+ findPackageRoot
80
+ } from "./chunk-LPUQPDC2.js";
81
+ import "./chunk-PZUWP5VK.js";
82
+
83
+ // src/agent/executor.ts
84
+ import crypto2 from "crypto";
85
+
86
+ // src/agent/tools.ts
87
+ import crypto from "crypto";
88
+ import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
89
+
90
+ // src/db/queries/agent-state.ts
91
+ var STATE_COLUMNS = [
92
+ "agent_id",
93
+ "key",
94
+ "value",
95
+ "updated_at"
96
+ ];
97
+ var SELECT_COLUMNS = STATE_COLUMNS.join(", ");
98
+ function toAgentStateRow(row) {
99
+ return {
100
+ agent_id: row.agent_id,
101
+ key: row.key,
102
+ value: row.value,
103
+ updated_at: row.updated_at
104
+ };
105
+ }
106
+ function setState(agentId, key, value, updatedAt) {
107
+ const db = getDatabase();
108
+ db.prepare(
109
+ `INSERT INTO agent_state (agent_id, key, value, updated_at)
110
+ VALUES (?, ?, ?, ?)
111
+ ON CONFLICT (agent_id, key) DO UPDATE SET
112
+ value = EXCLUDED.value,
113
+ updated_at = EXCLUDED.updated_at`
114
+ ).run(agentId, key, value, updatedAt);
115
+ return toAgentStateRow(
116
+ db.prepare(`SELECT ${SELECT_COLUMNS} FROM agent_state WHERE agent_id = ? AND key = ?`).get(agentId, key)
117
+ );
118
+ }
119
+ function getStatesForAgent(agentId) {
120
+ const db = getDatabase();
121
+ const rows = db.prepare(
122
+ `SELECT ${SELECT_COLUMNS}
123
+ FROM agent_state
124
+ WHERE agent_id = ?
125
+ ORDER BY key ASC`
126
+ ).all(agentId);
127
+ return rows.map(toAgentStateRow);
128
+ }
129
+
130
+ // src/agent/tools.ts
131
+ var DEFAULT_UNPROCESSED_LIMIT = 50;
132
+ var DEFAULT_SPORES_LIMIT = 50;
133
+ var DEFAULT_SESSIONS_LIMIT = 20;
134
+ var DEFAULT_SEARCH_LIMIT = 10;
135
+ var DEFAULT_ENTITIES_LIMIT = 50;
136
+ var DEFAULT_EDGES_LIMIT = 50;
137
+ function textResult(data) {
138
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
139
+ }
140
+ function createVaultTools(agentId, runId, turnOffset = 0, embeddingManager) {
141
+ let turnCounter = turnOffset;
142
+ function recordTurn(toolName, toolInput) {
143
+ turnCounter++;
144
+ try {
145
+ insertTurn({
146
+ run_id: runId,
147
+ agent_id: agentId,
148
+ turn_number: turnCounter,
149
+ tool_name: toolName,
150
+ tool_input: JSON.stringify(toolInput),
151
+ started_at: epochSeconds()
152
+ });
153
+ } catch {
154
+ }
155
+ }
156
+ const vaultUnprocessed = tool(
157
+ "vault_unprocessed",
158
+ "Get unprocessed prompt batches, ordered by id ASC. Supports cursor-based pagination.",
159
+ {
160
+ after_id: external_exports.number().optional().describe("Return batches with id greater than this"),
161
+ limit: external_exports.number().optional().describe("Maximum number of batches to return")
162
+ },
163
+ async (args) => {
164
+ recordTurn("vault_unprocessed", args);
165
+ const batches = getUnprocessedBatches({
166
+ after_id: args.after_id,
167
+ limit: args.limit ?? DEFAULT_UNPROCESSED_LIMIT
168
+ });
169
+ return textResult(batches);
170
+ },
171
+ { annotations: { readOnlyHint: true } }
172
+ );
173
+ const vaultSpores = tool(
174
+ "vault_spores",
175
+ "List spores with optional filters (agent, observation type, status, session).",
176
+ {
177
+ agent_id: external_exports.string().optional().describe("Filter by agent ID"),
178
+ observation_type: external_exports.string().optional().describe("Filter by observation type (e.g., gotcha, decision)"),
179
+ status: external_exports.enum(["active", "superseded", "archived"]).optional().describe("Filter by status"),
180
+ session_id: external_exports.string().optional().describe("Filter by session ID"),
181
+ limit: external_exports.number().optional().describe("Maximum number of spores to return")
182
+ },
183
+ async (args) => {
184
+ recordTurn("vault_spores", args);
185
+ const spores = listSpores({
186
+ agent_id: args.agent_id,
187
+ observation_type: args.observation_type,
188
+ status: args.status,
189
+ session_id: args.session_id,
190
+ limit: args.limit ?? DEFAULT_SPORES_LIMIT
191
+ });
192
+ return textResult(spores);
193
+ },
194
+ { annotations: { readOnlyHint: true } }
195
+ );
196
+ const vaultSessions = tool(
197
+ "vault_sessions",
198
+ "List sessions with optional status filter, ordered by created_at DESC.",
199
+ {
200
+ limit: external_exports.number().optional().describe("Maximum number of sessions to return"),
201
+ status: external_exports.string().optional().describe("Filter by status (active, completed)")
202
+ },
203
+ async (args) => {
204
+ recordTurn("vault_sessions", args);
205
+ const sessions = listSessions({
206
+ limit: args.limit ?? DEFAULT_SESSIONS_LIMIT,
207
+ status: args.status
208
+ });
209
+ return textResult(sessions);
210
+ },
211
+ { annotations: { readOnlyHint: true } }
212
+ );
213
+ const vaultSearchFts = tool(
214
+ "vault_search_fts",
215
+ "Full-text search across prompt batches and activities using FTS5. Best for finding specific text, keywords, or session content. Does NOT search spores or entities.",
216
+ {
217
+ query: external_exports.string().describe("Search query text"),
218
+ type: external_exports.string().optional().describe("Restrict to a result type (prompt_batch, activity)"),
219
+ limit: external_exports.number().optional().describe("Maximum number of results to return")
220
+ },
221
+ async (args) => {
222
+ recordTurn("vault_search_fts", args);
223
+ try {
224
+ const results = fullTextSearch(args.query, {
225
+ type: args.type,
226
+ limit: args.limit ?? DEFAULT_SEARCH_LIMIT
227
+ });
228
+ return textResult({ results });
229
+ } catch {
230
+ return textResult({ results: [], message: "Search unavailable" });
231
+ }
232
+ },
233
+ { annotations: { readOnlyHint: true } }
234
+ );
235
+ const vaultSearchSemantic = tool(
236
+ "vault_search_semantic",
237
+ "Semantic similarity search across embedded vault content (spores, sessions). Best for finding conceptually related content. Returns results ranked by similarity score.",
238
+ {
239
+ query: external_exports.string().describe("Search query text"),
240
+ namespace: external_exports.string().optional().describe("Restrict to a content type: spores, sessions"),
241
+ limit: external_exports.number().optional().describe("Maximum results to return")
242
+ },
243
+ async (args) => {
244
+ recordTurn("vault_search_semantic", args);
245
+ if (!embeddingManager) {
246
+ return textResult({ results: [], message: "Embedding provider unavailable" });
247
+ }
248
+ try {
249
+ const queryVector = await embeddingManager.embedQuery(args.query);
250
+ if (!queryVector) {
251
+ return textResult({ results: [], message: "Embedding provider unavailable" });
252
+ }
253
+ const results = embeddingManager.searchVectors(queryVector, {
254
+ namespace: args.namespace,
255
+ limit: args.limit ?? DEFAULT_SEARCH_LIMIT,
256
+ threshold: SEARCH_SIMILARITY_THRESHOLD
257
+ });
258
+ return textResult({ results });
259
+ } catch {
260
+ return textResult({ results: [], message: "Semantic search unavailable" });
261
+ }
262
+ },
263
+ { annotations: { readOnlyHint: true } }
264
+ );
265
+ const vaultState = tool(
266
+ "vault_state",
267
+ "Get all state key-value pairs for the current agent.",
268
+ {},
269
+ async () => {
270
+ recordTurn("vault_state", {});
271
+ const states = getStatesForAgent(agentId);
272
+ return textResult(states);
273
+ },
274
+ { annotations: { readOnlyHint: true } }
275
+ );
276
+ const vaultEntities = tool(
277
+ "vault_entities",
278
+ "List knowledge graph entities with optional filters.",
279
+ {
280
+ type: external_exports.enum(["component", "concept", "person"]).optional().describe("Filter by entity type"),
281
+ name: external_exports.string().optional().describe("Filter by entity name (exact match)"),
282
+ limit: external_exports.number().optional().describe("Maximum entities to return")
283
+ },
284
+ async (args) => {
285
+ recordTurn("vault_entities", args);
286
+ const entities = listEntities({
287
+ agent_id: agentId,
288
+ type: args.type,
289
+ name: args.name,
290
+ limit: args.limit ?? DEFAULT_ENTITIES_LIMIT
291
+ });
292
+ return textResult(entities);
293
+ },
294
+ { annotations: { readOnlyHint: true } }
295
+ );
296
+ const vaultEdges = tool(
297
+ "vault_edges",
298
+ "List knowledge graph edges with optional filters. Use to check existing relationships before creating new ones.",
299
+ {
300
+ source_id: external_exports.string().optional().describe("Filter by source node ID"),
301
+ target_id: external_exports.string().optional().describe("Filter by target node ID"),
302
+ type: external_exports.string().optional().describe("Filter by edge type (REFERENCES, DEPENDS_ON, AFFECTS, etc.)"),
303
+ limit: external_exports.number().optional().describe("Maximum edges to return")
304
+ },
305
+ async (args) => {
306
+ recordTurn("vault_edges", args);
307
+ const edges = listGraphEdges({
308
+ sourceId: args.source_id,
309
+ targetId: args.target_id,
310
+ type: args.type,
311
+ agentId,
312
+ limit: args.limit ?? DEFAULT_EDGES_LIMIT
313
+ });
314
+ return textResult(edges);
315
+ },
316
+ { annotations: { readOnlyHint: true } }
317
+ );
318
+ const vaultCreateSpore = tool(
319
+ "vault_create_spore",
320
+ "Create a new spore (observation) in the vault. The agent_id is set automatically.",
321
+ {
322
+ observation_type: external_exports.string().describe("Type of observation (gotcha, decision, discovery, trade-off, bug_fix, etc.)"),
323
+ content: external_exports.string().describe("The observation content in markdown"),
324
+ session_id: external_exports.string().optional().describe("Associated session ID"),
325
+ prompt_batch_id: external_exports.number().optional().describe("Associated prompt batch ID"),
326
+ importance: external_exports.number().optional().describe("Importance score 1-10 (default 5)"),
327
+ tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
328
+ context: external_exports.string().optional().describe("Additional context about the observation"),
329
+ file_path: external_exports.string().optional().describe("Related file path"),
330
+ properties: external_exports.string().optional().describe('JSON metadata (e.g., {"consolidated_from": [...]} for wisdom spores)')
331
+ },
332
+ async (args) => {
333
+ const id = crypto.randomUUID();
334
+ const now = epochSeconds();
335
+ const spore = insertSpore({
336
+ id,
337
+ agent_id: agentId,
338
+ observation_type: args.observation_type,
339
+ content: args.content,
340
+ session_id: args.session_id ?? null,
341
+ prompt_batch_id: args.prompt_batch_id ?? null,
342
+ importance: args.importance ?? DEFAULT_IMPORTANCE,
343
+ tags: args.tags ? JSON.stringify(args.tags) : null,
344
+ context: args.context ?? null,
345
+ file_path: args.file_path ?? null,
346
+ properties: args.properties ?? null,
347
+ created_at: now
348
+ });
349
+ try {
350
+ createSporeLineage(spore);
351
+ } catch {
352
+ }
353
+ embeddingManager?.onContentWritten("spores", spore.id, args.content, {
354
+ status: "active",
355
+ observation_type: args.observation_type,
356
+ session_id: args.session_id
357
+ }).catch(() => {
358
+ });
359
+ recordTurn("vault_create_spore", args);
360
+ return textResult(spore);
361
+ }
362
+ );
363
+ const vaultCreateEntity = tool(
364
+ "vault_create_entity",
365
+ "Create or update an entity in the knowledge graph. Uses UPSERT on (agent_id, type, name).",
366
+ {
367
+ type: external_exports.enum(["component", "concept", "person"]).describe("Entity type"),
368
+ name: external_exports.string().describe("Entity name (unique within agent + type)"),
369
+ properties: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Additional properties as key-value pairs")
370
+ },
371
+ async (args) => {
372
+ const id = crypto.randomUUID();
373
+ const now = epochSeconds();
374
+ const props = args.properties ? JSON.stringify(args.properties) : null;
375
+ const entity = insertEntity({
376
+ id,
377
+ agent_id: agentId,
378
+ type: args.type,
379
+ name: args.name,
380
+ properties: props,
381
+ first_seen: now,
382
+ last_seen: now
383
+ });
384
+ recordTurn("vault_create_entity", args);
385
+ return textResult(entity);
386
+ }
387
+ );
388
+ const vaultCreateEdge = tool(
389
+ "vault_create_edge",
390
+ "Create a semantic edge in the knowledge graph. Lineage edges (FROM_SESSION, EXTRACTED_FROM, HAS_BATCH, DERIVED_FROM) are created automatically \u2014 do NOT create those.",
391
+ {
392
+ source_id: external_exports.string().describe("Source node ID"),
393
+ source_type: external_exports.enum(["session", "batch", "spore", "entity"]).describe("Source node type"),
394
+ target_id: external_exports.string().describe("Target node ID"),
395
+ target_type: external_exports.enum(["session", "batch", "spore", "entity"]).describe("Target node type"),
396
+ type: external_exports.enum(["RELATES_TO", "SUPERSEDED_BY", "REFERENCES", "DEPENDS_ON", "AFFECTS"]).describe("Semantic edge type"),
397
+ session_id: external_exports.string().optional().describe("Session where this relationship was observed"),
398
+ confidence: external_exports.number().optional().describe("Confidence score 0-1 (default 1.0)"),
399
+ properties: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Additional properties as key-value pairs")
400
+ },
401
+ async (args) => {
402
+ const now = epochSeconds();
403
+ const props = args.properties ? JSON.stringify(args.properties) : void 0;
404
+ const edge = insertGraphEdge({
405
+ agent_id: agentId,
406
+ source_id: args.source_id,
407
+ source_type: args.source_type,
408
+ target_id: args.target_id,
409
+ target_type: args.target_type,
410
+ type: args.type,
411
+ session_id: args.session_id,
412
+ confidence: args.confidence,
413
+ properties: props,
414
+ created_at: now
415
+ });
416
+ recordTurn("vault_create_edge", args);
417
+ return textResult(edge);
418
+ }
419
+ );
420
+ const vaultResolveSpore = tool(
421
+ "vault_resolve_spore",
422
+ "Resolve a spore by updating its status and recording a resolution event.",
423
+ {
424
+ spore_id: external_exports.string().describe("ID of the spore to resolve"),
425
+ action: external_exports.enum(["supersede", "archive", "merge", "split", "consolidate"]).describe("Resolution action"),
426
+ new_spore_id: external_exports.string().optional().describe("ID of the replacement spore (for supersede/merge)"),
427
+ reason: external_exports.string().optional().describe("Explanation for the resolution"),
428
+ session_id: external_exports.string().optional().describe("Session where this resolution occurred")
429
+ },
430
+ async (args) => {
431
+ const now = epochSeconds();
432
+ const statusMap = {
433
+ supersede: "superseded",
434
+ archive: "archived",
435
+ merge: "merged",
436
+ split: "split",
437
+ consolidate: "consolidated"
438
+ };
439
+ const newStatus = statusMap[args.action] ?? args.action;
440
+ const updatedSpore = updateSporeStatus(args.spore_id, newStatus, now);
441
+ const eventId = crypto.randomUUID();
442
+ insertResolutionEvent({
443
+ id: eventId,
444
+ agent_id: agentId,
445
+ spore_id: args.spore_id,
446
+ action: args.action,
447
+ new_spore_id: args.new_spore_id ?? null,
448
+ reason: args.reason ?? null,
449
+ session_id: args.session_id ?? null,
450
+ created_at: now
451
+ });
452
+ if (newStatus !== "active") {
453
+ try {
454
+ embeddingManager?.onStatusChanged("spores", args.spore_id, newStatus);
455
+ } catch {
456
+ }
457
+ }
458
+ recordTurn("vault_resolve_spore", args);
459
+ return textResult({ spore: updatedSpore, resolution_event_id: eventId });
460
+ }
461
+ );
462
+ const vaultUpdateSession = tool(
463
+ "vault_update_session",
464
+ "Update a session title and/or summary. When generating for the first time, provide BOTH title and summary. Title should be under 80 characters and reflect the full session scope.",
465
+ {
466
+ session_id: external_exports.string().describe("Session ID to update"),
467
+ title: external_exports.string().optional().describe("New session title"),
468
+ summary: external_exports.string().optional().describe("New session summary")
469
+ },
470
+ async (args) => {
471
+ const updates = {};
472
+ if (args.title !== void 0) updates.title = args.title;
473
+ if (args.summary !== void 0) updates.summary = args.summary;
474
+ const session = updateSession(args.session_id, updates);
475
+ if (args.summary) {
476
+ embeddingManager?.onContentWritten("sessions", args.session_id, args.summary, {}).catch(() => {
477
+ });
478
+ }
479
+ recordTurn("vault_update_session", args);
480
+ return textResult(session);
481
+ }
482
+ );
483
+ const vaultSetState = tool(
484
+ "vault_set_state",
485
+ "Set a key-value state pair for the current agent. Used for bookmarks, cursors, and preferences.",
486
+ {
487
+ key: external_exports.string().describe("State key (e.g., last_processed_batch_id, cursor)"),
488
+ value: external_exports.string().describe("State value (stored as text)")
489
+ },
490
+ async (args) => {
491
+ const now = epochSeconds();
492
+ const state = setState(agentId, args.key, args.value, now);
493
+ recordTurn("vault_set_state", args);
494
+ return textResult(state);
495
+ }
496
+ );
497
+ const vaultReadDigest = tool(
498
+ "vault_read_digest",
499
+ "Read current digest extracts. Without a tier parameter, returns a summary of all tiers (content length, generation time). With a tier parameter, returns the full content for that specific tier.",
500
+ {
501
+ tier: external_exports.number().optional().describe("Specific tier to read in full (e.g., 1500, 5000, 10000). Omit to get summary of all tiers.")
502
+ },
503
+ async (args) => {
504
+ recordTurn("vault_read_digest", args);
505
+ const extracts = listDigestExtracts(agentId);
506
+ if (args.tier !== void 0) {
507
+ const extract = extracts.find((e) => e.tier === args.tier);
508
+ if (!extract) return textResult({ tier: args.tier, content: null, message: "No digest at this tier" });
509
+ return textResult({ tier: extract.tier, content: extract.content, generated_at: extract.generated_at });
510
+ }
511
+ return textResult(extracts.map((e) => ({
512
+ tier: e.tier,
513
+ content_length: e.content.length,
514
+ generated_at: e.generated_at
515
+ })));
516
+ },
517
+ { annotations: { readOnlyHint: true } }
518
+ );
519
+ const vaultWriteDigest = tool(
520
+ "vault_write_digest",
521
+ "Write or update a digest extract at a specific token tier. Uses UPSERT on (agent_id, tier).",
522
+ {
523
+ tier: external_exports.number().describe("Token budget tier (e.g., 1500, 5000, 10000)"),
524
+ content: external_exports.string().describe("The digest extract content in markdown")
525
+ },
526
+ async (args) => {
527
+ const now = epochSeconds();
528
+ const extract = upsertDigestExtract({
529
+ agent_id: agentId,
530
+ tier: args.tier,
531
+ content: args.content,
532
+ generated_at: now
533
+ });
534
+ recordTurn("vault_write_digest", args);
535
+ return textResult(extract);
536
+ }
537
+ );
538
+ const vaultMarkProcessed = tool(
539
+ "vault_mark_processed",
540
+ "Mark a prompt batch as processed so it is not returned by vault_unprocessed.",
541
+ {
542
+ batch_id: external_exports.number().describe("ID of the prompt batch to mark as processed")
543
+ },
544
+ async (args) => {
545
+ const batch = markBatchProcessed(args.batch_id);
546
+ recordTurn("vault_mark_processed", args);
547
+ return textResult(batch);
548
+ }
549
+ );
550
+ const vaultReport = tool(
551
+ "vault_report",
552
+ 'Record an observability report for the current run. Use action "skip" when skipping expected operations (e.g., not updating a session summary) with reasoning in the summary field.',
553
+ {
554
+ action: external_exports.string().describe("Action name (e.g., extract, consolidate, digest, skip)"),
555
+ summary: external_exports.string().describe("Human-readable summary of what was done"),
556
+ details: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Structured details as key-value pairs")
557
+ },
558
+ async (args) => {
559
+ recordTurn("vault_report", args);
560
+ const now = epochSeconds();
561
+ const report = insertReport({
562
+ run_id: runId,
563
+ agent_id: agentId,
564
+ action: args.action,
565
+ summary: args.summary,
566
+ details: args.details ? JSON.stringify(args.details) : null,
567
+ created_at: now
568
+ });
569
+ return textResult(report);
570
+ }
571
+ );
572
+ return [
573
+ vaultUnprocessed,
574
+ vaultSpores,
575
+ vaultSessions,
576
+ vaultSearchFts,
577
+ vaultSearchSemantic,
578
+ vaultState,
579
+ vaultEntities,
580
+ vaultEdges,
581
+ vaultCreateSpore,
582
+ vaultCreateEntity,
583
+ vaultCreateEdge,
584
+ vaultResolveSpore,
585
+ vaultUpdateSession,
586
+ vaultSetState,
587
+ vaultReadDigest,
588
+ vaultWriteDigest,
589
+ vaultMarkProcessed,
590
+ vaultReport
591
+ ];
592
+ }
593
+ function createVaultToolServer(agentId, runId, embeddingManager) {
594
+ const tools = createVaultTools(agentId, runId, 0, embeddingManager);
595
+ return createSdkMcpServer({
596
+ name: "myco-vault",
597
+ version: getPluginVersion(),
598
+ tools
599
+ });
600
+ }
601
+ function createScopedVaultToolServer(agentId, runId, toolNames, turnOffset = 0, embeddingManager) {
602
+ const allTools = createVaultTools(agentId, runId, turnOffset, embeddingManager);
603
+ const nameSet = new Set(toolNames);
604
+ const scopedTools = allTools.filter((t) => nameSet.has(t.name));
605
+ return createSdkMcpServer({
606
+ name: "myco-vault",
607
+ version: getPluginVersion(),
608
+ tools: scopedTools
609
+ });
610
+ }
611
+
612
+ // src/agent/context.ts
613
+ var STATE_UNSET = "(unset)";
614
+ var STATE_KEY_LAST_PROCESSED_BATCH = "last_processed_batch_id";
615
+ var SPORE_STATUS_ACTIVE = "active";
616
+ function countRows(table, conditions = []) {
617
+ const db = getDatabase();
618
+ const whereParts = [];
619
+ const params = [];
620
+ for (const { clause, value } of conditions) {
621
+ whereParts.push(clause);
622
+ params.push(value);
623
+ }
624
+ const whereClause = whereParts.length > 0 ? `WHERE ${whereParts.join(" AND ")}` : "";
625
+ const row = db.prepare(
626
+ `SELECT count(*) AS count FROM ${table} ${whereClause}`
627
+ ).get(...params);
628
+ return Number(row.count);
629
+ }
630
+ function buildVaultContext(agentId) {
631
+ const states = getStatesForAgent(agentId);
632
+ const totalSessions = countRows("sessions");
633
+ const totalActiveSpores = countRows("spores", [{ clause: "status = ?", value: SPORE_STATUS_ACTIVE }]);
634
+ const totalEntities = countRows("entities");
635
+ const totalEdges = countRows("graph_edges");
636
+ const unprocessedBatches = countRows("prompt_batches", [{ clause: "processed = ?", value: 0 }]);
637
+ const lastDigestAt = getLastDigestTimestamp(agentId);
638
+ const stateMap = new Map(states.map((s) => [s.key, s.value]));
639
+ const lastProcessedBatchId = stateMap.get(STATE_KEY_LAST_PROCESSED_BATCH) ?? STATE_UNSET;
640
+ const lines = [
641
+ "## Current Vault State",
642
+ `agent_id: ${agentId}`,
643
+ `last_processed_batch_id: ${lastProcessedBatchId}`,
644
+ `unprocessed_batches: ${unprocessedBatches}`,
645
+ `total_sessions: ${totalSessions}`,
646
+ `total_active_spores: ${totalActiveSpores}`,
647
+ `total_entities: ${totalEntities}`,
648
+ `total_edges: ${totalEdges}`,
649
+ `last_digest_at: ${lastDigestAt}`
650
+ ];
651
+ return lines.join("\n");
652
+ }
653
+ function getLastDigestTimestamp(agentId) {
654
+ const db = getDatabase();
655
+ const row = db.prepare(
656
+ `SELECT MAX(generated_at) AS max_at
657
+ FROM digest_extracts
658
+ WHERE agent_id = ?`
659
+ ).get(agentId);
660
+ return row?.max_at ?? 0;
661
+ }
662
+
663
+ // src/agent/orchestrator.ts
664
+ import fs from "fs";
665
+ import path from "path";
666
+ import { fileURLToPath } from "url";
667
+
668
+ // src/intelligence/response.ts
669
+ var REASONING_PATTERNS = [
670
+ // <think>...</think>answer (DeepSeek, Qwen, GLM, many others)
671
+ /<think>[\s\S]*?<\/think>\s*/gi,
672
+ // Implicit opening: reasoning...</think>answer (GLM-4.7 observed)
673
+ /^[\s\S]*?<\/think>\s*/i,
674
+ // <reasoning>...</reasoning>answer
675
+ /<reasoning>[\s\S]*?<\/reasoning>\s*/gi,
676
+ // <|thinking|>...<|/thinking|>answer
677
+ /<\|thinking\|>[\s\S]*?<\|\/thinking\|>\s*/gi,
678
+ // Plain-text "Thinking Process:" block followed by actual content
679
+ // (Qwen 3.5 via LM Studio without native thinking mode)
680
+ // Matches from "Thinking Process:" up to the last numbered step, then the synthesis follows
681
+ /^Thinking Process:[\s\S]*?(?=\n(?:## |# |\*\*[A-Z]))/i
682
+ ];
683
+ function stripReasoningTokens(text) {
684
+ if (!text) return text;
685
+ for (const pattern of REASONING_PATTERNS) {
686
+ const stripped = text.replace(pattern, "").trim();
687
+ if (stripped && stripped !== text.trim()) {
688
+ return stripped;
689
+ }
690
+ }
691
+ return text;
692
+ }
693
+ function extractJson(text) {
694
+ const cleaned = stripReasoningTokens(text);
695
+ const fenceMatch = cleaned.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
696
+ if (fenceMatch) {
697
+ return JSON.parse(fenceMatch[1].trim());
698
+ }
699
+ const objectMatch = cleaned.match(/\{[\s\S]*\}/);
700
+ if (objectMatch) {
701
+ return JSON.parse(objectMatch[0]);
702
+ }
703
+ return JSON.parse(cleaned);
704
+ }
705
+
706
+ // src/agent/orchestrator.ts
707
+ var DEFAULT_ORCHESTRATOR_MAX_TURNS = 3;
708
+ var ORCHESTRATOR_PROMPT_FILE = "orchestrator.md";
709
+ var PHASE_PROMPT_PREVIEW_CHARS = 100;
710
+ var ORCHESTRATOR_GUIDANCE_HEADER = "## Orchestrator Guidance";
711
+ var NO_CONTEXT_QUERIES_TEXT = "No context queries configured.";
712
+ var FALLBACK_REASONING_PARSE_ERROR = "Orchestrator response could not be parsed \u2014 running all phases with defaults.";
713
+ var FALLBACK_REASONING_MISSING_PHASES = "Orchestrator plan missing phases array \u2014 running all phases with defaults.";
714
+ var PLACEHOLDER_VAULT_STATE = "{{vault_state}}";
715
+ var PLACEHOLDER_PHASE_DEFINITIONS = "{{phase_definitions}}";
716
+ var PLACEHOLDER_CONTEXT_RESULTS = "{{context_results}}";
717
+ var cachedPromptTemplate;
718
+ function loadPromptTemplate() {
719
+ if (!cachedPromptTemplate) {
720
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
721
+ const adjacentPath = path.join(scriptDir, "prompts", ORCHESTRATOR_PROMPT_FILE);
722
+ if (fs.existsSync(adjacentPath)) {
723
+ cachedPromptTemplate = fs.readFileSync(adjacentPath, "utf-8");
724
+ return cachedPromptTemplate;
725
+ }
726
+ const root = findPackageRoot(scriptDir);
727
+ if (root) {
728
+ const distPath = path.join(root, "dist", "src", "agent", "prompts", ORCHESTRATOR_PROMPT_FILE);
729
+ if (fs.existsSync(distPath)) {
730
+ cachedPromptTemplate = fs.readFileSync(distPath, "utf-8");
731
+ return cachedPromptTemplate;
732
+ }
733
+ const srcPath = path.join(root, "src", "agent", "prompts", ORCHESTRATOR_PROMPT_FILE);
734
+ cachedPromptTemplate = fs.readFileSync(srcPath, "utf-8");
735
+ return cachedPromptTemplate;
736
+ }
737
+ cachedPromptTemplate = fs.readFileSync(adjacentPath, "utf-8");
738
+ }
739
+ return cachedPromptTemplate;
740
+ }
741
+ function composeOrchestratorPrompt(vaultState, phases, contextResults) {
742
+ const template = loadPromptTemplate();
743
+ const phaseList = formatPhaseList(phases);
744
+ const contextSection = formatContextResults(contextResults);
745
+ return template.replace(PLACEHOLDER_VAULT_STATE, vaultState).replace(PLACEHOLDER_PHASE_DEFINITIONS, phaseList).replace(PLACEHOLDER_CONTEXT_RESULTS, contextSection);
746
+ }
747
+ function parseOrchestratorPlan(response, phases) {
748
+ const trimmed = response.trim();
749
+ if (!trimmed) {
750
+ return buildRunAllPlan(phases, FALLBACK_REASONING_PARSE_ERROR);
751
+ }
752
+ try {
753
+ const parsed = extractJson(trimmed);
754
+ if (!isOrchestratorPlanShape(parsed)) {
755
+ return buildRunAllPlan(phases, FALLBACK_REASONING_MISSING_PHASES);
756
+ }
757
+ return parsed;
758
+ } catch {
759
+ return buildRunAllPlan(phases, FALLBACK_REASONING_PARSE_ERROR);
760
+ }
761
+ }
762
+ function applyDirectives(phases, directives) {
763
+ const directiveMap = new Map(
764
+ directives.map((d) => [d.name, d])
765
+ );
766
+ const result = [];
767
+ for (const phase of phases) {
768
+ const directive = directiveMap.get(phase.name);
769
+ if (!directive) {
770
+ result.push(phase);
771
+ continue;
772
+ }
773
+ if (directive.skip) {
774
+ if (phase.required) {
775
+ console.warn(
776
+ `[orchestrator] Cannot skip required phase "${phase.name}" \u2014 keeping it. Reason: ${directive.skipReason ?? "none given"}`
777
+ );
778
+ result.push(applyNonSkipDirective(phase, directive));
779
+ }
780
+ continue;
781
+ }
782
+ result.push(applyNonSkipDirective(phase, directive));
783
+ }
784
+ return result;
785
+ }
786
+ function applyNonSkipDirective(phase, directive) {
787
+ let updated = { ...phase };
788
+ if (directive.maxTurns !== void 0) {
789
+ updated = { ...updated, maxTurns: directive.maxTurns };
790
+ }
791
+ if (directive.contextNotes) {
792
+ updated = {
793
+ ...updated,
794
+ prompt: `${updated.prompt}
795
+
796
+ ${ORCHESTRATOR_GUIDANCE_HEADER}
797
+
798
+ ${directive.contextNotes}`
799
+ };
800
+ }
801
+ return updated;
802
+ }
803
+ function formatPhaseList(phases) {
804
+ if (phases.length === 0) {
805
+ return "(no phases defined)";
806
+ }
807
+ return phases.map((p) => {
808
+ const preview = p.prompt.slice(0, PHASE_PROMPT_PREVIEW_CHARS);
809
+ const ellipsis = p.prompt.length > PHASE_PROMPT_PREVIEW_CHARS ? "..." : "";
810
+ return `- **${p.name}** (maxTurns: ${p.maxTurns}, required: ${p.required}): ${preview}${ellipsis}`;
811
+ }).join("\n");
812
+ }
813
+ function formatContextResults(results) {
814
+ if (results.length === 0) {
815
+ return NO_CONTEXT_QUERIES_TEXT;
816
+ }
817
+ return results.map((r) => {
818
+ const dataSection = r.error ? `Error: ${r.error}` : JSON.stringify(r.data, null, 2);
819
+ return `### ${r.tool}
820
+ Purpose: ${r.purpose}
821
+
822
+ ${dataSection}`;
823
+ }).join("\n\n");
824
+ }
825
+ function isOrchestratorPlanShape(value) {
826
+ if (typeof value !== "object" || value === null) return false;
827
+ const obj = value;
828
+ return Array.isArray(obj["phases"]);
829
+ }
830
+ function buildRunAllPlan(phases, reasoning) {
831
+ return {
832
+ phases: phases.map((p) => ({ name: p.name, skip: false })),
833
+ reasoning
834
+ };
835
+ }
836
+
837
+ // src/agent/context-queries.ts
838
+ var DEFAULT_CONTEXT_QUERY_LIMIT = 10;
839
+ async function executeContextQueries(agentId, queries) {
840
+ for (const query of queries) {
841
+ validateTool(query.tool);
842
+ }
843
+ const settled = await Promise.allSettled(
844
+ queries.map(async (query) => {
845
+ const limit = query.limit ?? DEFAULT_CONTEXT_QUERY_LIMIT;
846
+ const data = await executeQuery(agentId, query.tool, limit);
847
+ return { tool: query.tool, purpose: query.purpose, data };
848
+ })
849
+ );
850
+ const results = [];
851
+ for (let i = 0; i < settled.length; i++) {
852
+ const outcome = settled[i];
853
+ const query = queries[i];
854
+ if (outcome.status === "fulfilled") {
855
+ results.push(outcome.value);
856
+ } else {
857
+ const message = errorMessage(outcome.reason);
858
+ if (query.required) {
859
+ throw new Error(
860
+ `Required context query "${query.tool}" failed: ${message}`
861
+ );
862
+ }
863
+ results.push({
864
+ tool: query.tool,
865
+ purpose: query.purpose,
866
+ data: null,
867
+ error: message
868
+ });
869
+ }
870
+ }
871
+ return results;
872
+ }
873
+ var KNOWN_CONTEXT_QUERY_TOOLS = /* @__PURE__ */ new Set([
874
+ "vault_unprocessed",
875
+ "vault_spores",
876
+ "vault_sessions",
877
+ "vault_state"
878
+ ]);
879
+ function validateTool(tool2) {
880
+ if (!KNOWN_CONTEXT_QUERY_TOOLS.has(tool2)) {
881
+ throw new Error(`Unknown context query tool: "${tool2}"`);
882
+ }
883
+ }
884
+ async function executeQuery(agentId, tool2, limit) {
885
+ switch (tool2) {
886
+ case "vault_unprocessed":
887
+ return getUnprocessedBatches({ limit });
888
+ case "vault_spores":
889
+ return listSpores({ agent_id: agentId, limit });
890
+ case "vault_sessions":
891
+ return listSessions({ limit });
892
+ case "vault_state":
893
+ return getStatesForAgent(agentId);
894
+ default:
895
+ throw new Error(`Unknown context query tool: "${tool2}"`);
896
+ }
897
+ }
898
+
899
+ // src/agent/provider.ts
900
+ var ENV_ANTHROPIC_BASE_URL = "ANTHROPIC_BASE_URL";
901
+ var ENV_ANTHROPIC_AUTH_TOKEN = "ANTHROPIC_AUTH_TOKEN";
902
+ var ENV_ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY";
903
+ var ENV_OLLAMA_NUM_CTX = "OLLAMA_NUM_CTX";
904
+ var DEFAULT_OLLAMA_URL = "http://localhost:11434";
905
+ var DEFAULT_LMSTUDIO_URL = "http://localhost:1234";
906
+ var OLLAMA_AUTH_TOKEN = "ollama";
907
+ var LMSTUDIO_AUTH_TOKEN = "lmstudio";
908
+ function buildPhaseEnv(provider) {
909
+ if (!provider || provider.type === "cloud") return void 0;
910
+ return { ...process.env, ...getProviderEnvVars(provider) };
911
+ }
912
+ function getProviderEnvVars(provider) {
913
+ switch (provider.type) {
914
+ case "cloud":
915
+ return {};
916
+ case "ollama":
917
+ return {
918
+ [ENV_ANTHROPIC_BASE_URL]: provider.baseUrl ?? DEFAULT_OLLAMA_URL,
919
+ [ENV_ANTHROPIC_AUTH_TOKEN]: OLLAMA_AUTH_TOKEN,
920
+ [ENV_ANTHROPIC_API_KEY]: "",
921
+ ...provider.contextLength ? { [ENV_OLLAMA_NUM_CTX]: String(provider.contextLength) } : {}
922
+ };
923
+ case "lmstudio":
924
+ return {
925
+ [ENV_ANTHROPIC_BASE_URL]: provider.baseUrl ?? DEFAULT_LMSTUDIO_URL,
926
+ [ENV_ANTHROPIC_AUTH_TOKEN]: provider.apiKey ?? LMSTUDIO_AUTH_TOKEN,
927
+ [ENV_ANTHROPIC_API_KEY]: ""
928
+ };
929
+ default:
930
+ return {};
931
+ }
932
+ }
933
+
934
+ // src/agent/executor.ts
935
+ var STATUS_SKIPPED = "skipped";
936
+ var SKIP_REASON_ALREADY_RUNNING = "already_running";
937
+ var PROMPT_SECTION_TASK = "## Task: ";
938
+ var PROMPT_SECTION_INSTRUCTION = "## User Instruction";
939
+ var PROMPT_SECTION_SEPARATOR = "\n\n";
940
+ var MCP_SERVER_NAME = "myco-vault";
941
+ var PERSIST_SESSION = true;
942
+ var PROMPT_SECTION_PRIOR_PHASES = "## Prior Phase Results";
943
+ var PROMPT_SECTION_CURRENT_PHASE = "## Current Phase: ";
944
+ function composeTaskPrompt(vaultContext, taskDisplayName, taskPrompt, instruction) {
945
+ const sessionIdMatch = instruction?.match(/\b([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b/i);
946
+ const sessionId = sessionIdMatch?.[1] ?? "";
947
+ let resolvedPrompt = taskPrompt;
948
+ resolvedPrompt = resolvedPrompt.replace(/\{\{session_id\}\}/g, sessionId);
949
+ resolvedPrompt = resolvedPrompt.replace(/\{\{instruction\}\}/g, instruction ?? "");
950
+ const parts = [
951
+ vaultContext,
952
+ `${PROMPT_SECTION_TASK}${taskDisplayName}
953
+ ${resolvedPrompt}`
954
+ ];
955
+ if (instruction) {
956
+ parts.push(`${PROMPT_SECTION_INSTRUCTION}
957
+ ${instruction}`);
958
+ }
959
+ return parts.join(PROMPT_SECTION_SEPARATOR);
960
+ }
961
+ function composePhasePrompt(vaultContext, taskDisplayName, taskOverview, phase, priorPhaseResults, instruction) {
962
+ const parts = [
963
+ vaultContext,
964
+ `${PROMPT_SECTION_TASK}${taskDisplayName}
965
+ ${taskOverview}`
966
+ ];
967
+ if (instruction) {
968
+ parts.push(`${PROMPT_SECTION_INSTRUCTION}
969
+ ${instruction}`);
970
+ }
971
+ if (priorPhaseResults.length > 0 && !phase.skipPriorContext) {
972
+ const summaries = priorPhaseResults.map((pr) => {
973
+ const truncated = pr.summary.length > PHASE_SUMMARY_MAX_CHARS ? pr.summary.slice(0, PHASE_SUMMARY_MAX_CHARS) + "..." : pr.summary;
974
+ return `### ${pr.name} (${pr.status})
975
+ ${truncated}`;
976
+ });
977
+ parts.push(`${PROMPT_SECTION_PRIOR_PHASES}
978
+ ${summaries.join("\n\n")}`);
979
+ }
980
+ parts.push(`${PROMPT_SECTION_CURRENT_PHASE}${phase.name}
981
+ ${phase.prompt}`);
982
+ return parts.join(PROMPT_SECTION_SEPARATOR);
983
+ }
984
+ var OLLAMA_PRELOAD_TIMEOUT_MS = 3e4;
985
+ async function ensureOllamaContextVariant(model, contextLength) {
986
+ const { execFileSync } = await import("child_process");
987
+ const { writeFileSync, unlinkSync } = await import("fs");
988
+ const { tmpdir } = await import("os");
989
+ const { join } = await import("path");
990
+ const baseName = model.replace(/:latest$/, "");
991
+ const variantName = `${baseName}-ctx${contextLength}`;
992
+ try {
993
+ execFileSync("ollama", ["show", variantName], { stdio: "ignore" });
994
+ return variantName;
995
+ } catch {
996
+ }
997
+ try {
998
+ const modelfilePath = join(tmpdir(), `myco-modelfile-${Date.now()}`);
999
+ writeFileSync(modelfilePath, `FROM ${model}
1000
+ PARAMETER num_ctx ${contextLength}
1001
+ `);
1002
+ execFileSync("ollama", ["create", variantName, "-f", modelfilePath], {
1003
+ stdio: "ignore",
1004
+ timeout: OLLAMA_PRELOAD_TIMEOUT_MS
1005
+ });
1006
+ try {
1007
+ unlinkSync(modelfilePath);
1008
+ } catch {
1009
+ }
1010
+ return variantName;
1011
+ } catch {
1012
+ return model;
1013
+ }
1014
+ }
1015
+ function computeWaves(phases) {
1016
+ const nameToPhase = new Map(phases.map((p) => [p.name, p]));
1017
+ const inDegree = /* @__PURE__ */ new Map();
1018
+ const dependents = /* @__PURE__ */ new Map();
1019
+ for (const phase of phases) {
1020
+ inDegree.set(phase.name, 0);
1021
+ dependents.set(phase.name, []);
1022
+ }
1023
+ for (const phase of phases) {
1024
+ const deps = phase.dependsOn ?? [];
1025
+ for (const dep of deps) {
1026
+ if (!nameToPhase.has(dep)) continue;
1027
+ inDegree.set(phase.name, (inDegree.get(phase.name) ?? 0) + 1);
1028
+ dependents.get(dep).push(phase.name);
1029
+ }
1030
+ }
1031
+ const waves = [];
1032
+ const completed = /* @__PURE__ */ new Set();
1033
+ while (completed.size < phases.length) {
1034
+ const wave = [];
1035
+ for (const phase of phases) {
1036
+ if (completed.has(phase.name)) continue;
1037
+ if ((inDegree.get(phase.name) ?? 0) === 0) {
1038
+ wave.push(phase);
1039
+ }
1040
+ }
1041
+ if (wave.length === 0) {
1042
+ const remaining = phases.filter((p) => !completed.has(p.name)).map((p) => p.name);
1043
+ throw new Error(`Circular dependency detected among phases: ${remaining.join(", ")}`);
1044
+ }
1045
+ waves.push(wave);
1046
+ for (const phase of wave) {
1047
+ completed.add(phase.name);
1048
+ for (const dependent of dependents.get(phase.name) ?? []) {
1049
+ inDegree.set(dependent, (inDegree.get(dependent) ?? 0) - 1);
1050
+ }
1051
+ }
1052
+ }
1053
+ return waves;
1054
+ }
1055
+ function phaseSessionId(runId, phaseName) {
1056
+ const hash = crypto2.createHash("sha256").update(`${runId}-${phaseName}`).digest("hex");
1057
+ return [
1058
+ hash.slice(0, 8),
1059
+ hash.slice(8, 12),
1060
+ hash.slice(12, 16),
1061
+ hash.slice(16, 20),
1062
+ hash.slice(20, 32)
1063
+ ].join("-");
1064
+ }
1065
+ async function executePhase(query, phasePrompt, phaseModel, systemPrompt, toolServer, phase, env, sessionId, abortController) {
1066
+ let phaseCost = 0;
1067
+ let phaseTokens = 0;
1068
+ let phaseTurns = 0;
1069
+ let phaseSummary = "";
1070
+ try {
1071
+ for await (const message of query({
1072
+ prompt: phasePrompt,
1073
+ options: {
1074
+ model: phaseModel,
1075
+ systemPrompt,
1076
+ mcpServers: { [MCP_SERVER_NAME]: toolServer },
1077
+ maxTurns: phase.maxTurns,
1078
+ permissionMode: "bypassPermissions",
1079
+ allowDangerouslySkipPermissions: true,
1080
+ persistSession: PERSIST_SESSION,
1081
+ env,
1082
+ tools: [],
1083
+ ...sessionId ? { sessionId } : {},
1084
+ ...abortController ? { abortController } : {}
1085
+ }
1086
+ })) {
1087
+ if (message.type === "result") {
1088
+ phaseCost = message.total_cost_usd ?? 0;
1089
+ phaseTokens = (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0);
1090
+ phaseTurns = message.num_turns ?? 0;
1091
+ if ("result" in message && typeof message.result === "string") {
1092
+ phaseSummary = message.result;
1093
+ }
1094
+ }
1095
+ }
1096
+ if (phase.required && phaseTurns === 0) {
1097
+ console.warn(`[agent] Required phase "${phase.name}" produced 0 turns`);
1098
+ }
1099
+ return {
1100
+ name: phase.name,
1101
+ status: "completed",
1102
+ turnsUsed: phaseTurns,
1103
+ tokensUsed: phaseTokens,
1104
+ costUsd: phaseCost,
1105
+ summary: phaseSummary
1106
+ };
1107
+ } catch (err) {
1108
+ return {
1109
+ name: phase.name,
1110
+ status: "failed",
1111
+ turnsUsed: phaseTurns,
1112
+ tokensUsed: phaseTokens,
1113
+ costUsd: phaseCost,
1114
+ summary: `Error: ${errorMessage(err)}`
1115
+ };
1116
+ }
1117
+ }
1118
+ async function executeSingleQuery(config, systemPrompt, taskPrompt, agentId, runId, provider, embeddingManager, abortController) {
1119
+ const { query } = await import("@anthropic-ai/claude-agent-sdk");
1120
+ const toolServer = createVaultToolServer(agentId, runId, embeddingManager);
1121
+ const env = buildPhaseEnv(provider);
1122
+ const effectiveModel = provider?.model ?? config.model;
1123
+ let resultCostUsd = 0;
1124
+ let resultTokens = 0;
1125
+ for await (const message of query({
1126
+ prompt: taskPrompt,
1127
+ options: {
1128
+ model: effectiveModel,
1129
+ systemPrompt,
1130
+ mcpServers: { [MCP_SERVER_NAME]: toolServer },
1131
+ maxTurns: config.maxTurns,
1132
+ permissionMode: "bypassPermissions",
1133
+ allowDangerouslySkipPermissions: true,
1134
+ persistSession: PERSIST_SESSION,
1135
+ env,
1136
+ tools: [],
1137
+ ...abortController ? { abortController } : {}
1138
+ }
1139
+ })) {
1140
+ if (message.type === "result") {
1141
+ resultCostUsd = message.total_cost_usd ?? 0;
1142
+ resultTokens = (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0);
1143
+ }
1144
+ }
1145
+ return { tokensUsed: resultTokens, costUsd: resultCostUsd };
1146
+ }
1147
+ async function executePhasedQuery(config, systemPrompt, vaultContext, agentId, runId, taskProviderOverride, phaseProviderOverrides, instruction, embeddingManager, abortController) {
1148
+ const { query } = await import("@anthropic-ai/claude-agent-sdk");
1149
+ const phases = config.phases;
1150
+ const phaseResults = [];
1151
+ let totalTokens = 0;
1152
+ let totalCost = 0;
1153
+ let runningTurnCount = 0;
1154
+ let effectivePhases = [...phases];
1155
+ if (config.orchestrator?.enabled) {
1156
+ const contextQueries = config.contextQueries ? Object.values(config.contextQueries).flat() : [];
1157
+ const contextResults = contextQueries.length > 0 ? await executeContextQueries(agentId, contextQueries) : [];
1158
+ const orchestratorPrompt = composeOrchestratorPrompt(vaultContext, phases, contextResults);
1159
+ const orchestratorModel = config.orchestrator.model ?? config.model;
1160
+ const orchestratorMaxTurns = config.orchestrator.maxTurns ?? DEFAULT_ORCHESTRATOR_MAX_TURNS;
1161
+ let planResponse = "";
1162
+ for await (const message of query({
1163
+ prompt: orchestratorPrompt,
1164
+ options: {
1165
+ model: orchestratorModel,
1166
+ maxTurns: orchestratorMaxTurns,
1167
+ permissionMode: "bypassPermissions",
1168
+ allowDangerouslySkipPermissions: true,
1169
+ persistSession: PERSIST_SESSION,
1170
+ tools: []
1171
+ }
1172
+ })) {
1173
+ if (message.type === "result" && "result" in message && typeof message.result === "string") {
1174
+ planResponse = message.result;
1175
+ }
1176
+ }
1177
+ const plan = parseOrchestratorPlan(planResponse, phases);
1178
+ effectivePhases = applyDirectives(phases, plan.phases);
1179
+ }
1180
+ const declarationOrder = new Map(phases.map((p, i) => [p.name, i]));
1181
+ const waves = computeWaves(effectivePhases);
1182
+ for (const wave of waves) {
1183
+ const executions = wave.map((phase, indexInWave) => {
1184
+ const phasePrompt = composePhasePrompt(
1185
+ vaultContext,
1186
+ config.taskDisplayName,
1187
+ config.taskPrompt,
1188
+ phase,
1189
+ phaseResults,
1190
+ instruction
1191
+ );
1192
+ const phaseOverride = phaseProviderOverrides?.[phase.name];
1193
+ const effectiveMaxTurns = phaseOverride?.maxTurns ?? phase.maxTurns;
1194
+ const phaseModel = phase.model ?? phaseOverride?.provider?.model ?? taskProviderOverride?.model ?? config.model;
1195
+ const toolServer = createScopedVaultToolServer(
1196
+ agentId,
1197
+ runId,
1198
+ phase.tools,
1199
+ runningTurnCount + indexInWave * effectiveMaxTurns,
1200
+ embeddingManager
1201
+ );
1202
+ const phaseProvider = phase.provider ?? phaseOverride?.provider ?? taskProviderOverride ?? config.execution?.provider;
1203
+ const env = buildPhaseEnv(phaseProvider);
1204
+ const sessionId = phaseSessionId(runId, phase.name);
1205
+ const effectivePhase = effectiveMaxTurns !== phase.maxTurns ? { ...phase, maxTurns: effectiveMaxTurns } : phase;
1206
+ return executePhase(query, phasePrompt, phaseModel, systemPrompt, toolServer, effectivePhase, env, sessionId, abortController);
1207
+ });
1208
+ const settled = await Promise.allSettled(executions);
1209
+ const waveResults = settled.map((outcome, i) => {
1210
+ if (outcome.status === "fulfilled") {
1211
+ return outcome.value;
1212
+ }
1213
+ return {
1214
+ name: wave[i].name,
1215
+ status: "failed",
1216
+ turnsUsed: 0,
1217
+ tokensUsed: 0,
1218
+ costUsd: 0,
1219
+ summary: `Error: ${errorMessage(outcome.reason)}`
1220
+ };
1221
+ });
1222
+ waveResults.sort(
1223
+ (a, b) => (declarationOrder.get(a.name) ?? 0) - (declarationOrder.get(b.name) ?? 0)
1224
+ );
1225
+ for (const result of waveResults) {
1226
+ phaseResults.push(result);
1227
+ totalTokens += result.tokensUsed;
1228
+ totalCost += result.costUsd;
1229
+ runningTurnCount += result.turnsUsed;
1230
+ }
1231
+ const shouldStop = wave.some((phase, i) => {
1232
+ if (!phase.required) return false;
1233
+ const outcome = settled[i];
1234
+ if (outcome.status === "rejected") return true;
1235
+ return outcome.value.status === "failed";
1236
+ });
1237
+ if (shouldStop) {
1238
+ break;
1239
+ }
1240
+ }
1241
+ return { tokensUsed: totalTokens, costUsd: totalCost, phases: phaseResults };
1242
+ }
1243
+ async function runAgent(vaultDir, options) {
1244
+ const db = initDatabase(vaultDbPath(vaultDir));
1245
+ createSchema(db);
1246
+ const agentId = options?.agentId ?? DEFAULT_AGENT_ID;
1247
+ const running = getRunningRun(agentId);
1248
+ if (running) {
1249
+ return {
1250
+ runId: running.id,
1251
+ status: STATUS_SKIPPED,
1252
+ reason: SKIP_REASON_ALREADY_RUNNING
1253
+ };
1254
+ }
1255
+ const definitionsDir = resolveDefinitionsDir();
1256
+ const definition = loadAgentDefinition(definitionsDir);
1257
+ const agentRow = getAgent(agentId);
1258
+ const taskRow = options?.task ? getTask(options.task) : getDefaultTask(agentId);
1259
+ const allTasks = loadAllTasks(definitionsDir, vaultDir);
1260
+ const taskName = taskRow?.id ?? options?.task;
1261
+ const yamlTask = taskName ? allTasks.get(taskName) : void 0;
1262
+ const taskOverrides = taskRow ? {
1263
+ name: taskRow.id,
1264
+ displayName: taskRow.display_name ?? taskRow.id,
1265
+ description: taskRow.description ?? "",
1266
+ agent: taskRow.agent_id,
1267
+ prompt: taskRow.prompt,
1268
+ isDefault: taskRow.is_default === 1,
1269
+ ...taskRow.tool_overrides ? { toolOverrides: JSON.parse(taskRow.tool_overrides) } : {},
1270
+ // Scalar config from YAML (model, turns, timeout) — DB doesn't store these
1271
+ ...yamlTask?.model ? { model: yamlTask.model } : {},
1272
+ ...yamlTask?.maxTurns ? { maxTurns: yamlTask.maxTurns } : {},
1273
+ ...yamlTask?.timeoutSeconds ? { timeoutSeconds: yamlTask.timeoutSeconds } : {},
1274
+ // Structural config from YAML
1275
+ ...yamlTask?.phases ? { phases: yamlTask.phases } : {},
1276
+ ...yamlTask?.execution ? { execution: yamlTask.execution } : {},
1277
+ ...yamlTask?.contextQueries ? { contextQueries: yamlTask.contextQueries } : {},
1278
+ ...yamlTask?.orchestrator ? { orchestrator: yamlTask.orchestrator } : {}
1279
+ } : void 0;
1280
+ const config = resolveEffectiveConfig(definition, agentRow, taskOverrides);
1281
+ let taskProviderOverride;
1282
+ let phaseProviderOverrides = {};
1283
+ try {
1284
+ const mycoConfig = loadConfig(vaultDir);
1285
+ const toProviderConfig = (p) => ({
1286
+ type: p.type,
1287
+ baseUrl: p.base_url,
1288
+ model: p.model,
1289
+ contextLength: p.context_length
1290
+ });
1291
+ const taskConfig = taskName ? mycoConfig.agent.tasks?.[taskName] : void 0;
1292
+ const globalProvider = mycoConfig.agent.provider;
1293
+ if (taskConfig?.provider) {
1294
+ taskProviderOverride = toProviderConfig(taskConfig.provider);
1295
+ } else if (globalProvider) {
1296
+ taskProviderOverride = toProviderConfig(globalProvider);
1297
+ }
1298
+ if (taskConfig?.phases) {
1299
+ for (const [phaseName, phaseConfig] of Object.entries(taskConfig.phases)) {
1300
+ phaseProviderOverrides[phaseName] = {
1301
+ ...phaseConfig.provider ? { provider: toProviderConfig(phaseConfig.provider) } : {},
1302
+ ...phaseConfig.maxTurns != null ? { maxTurns: phaseConfig.maxTurns } : {}
1303
+ };
1304
+ }
1305
+ }
1306
+ } catch {
1307
+ }
1308
+ const runId = options?.resumeRunId ?? crypto2.randomUUID();
1309
+ const now = epochSeconds();
1310
+ if (!options?.resumeRunId) {
1311
+ insertRun({
1312
+ id: runId,
1313
+ agent_id: agentId,
1314
+ task: config.taskName,
1315
+ instruction: options?.instruction ?? null,
1316
+ status: STATUS_RUNNING,
1317
+ started_at: now
1318
+ });
1319
+ }
1320
+ const systemPrompt = loadSystemPrompt(definitionsDir, config.systemPromptPath);
1321
+ const vaultContext = buildVaultContext(agentId);
1322
+ const effectiveProvider = taskProviderOverride ?? config.execution?.provider;
1323
+ const effectiveModel = effectiveProvider?.model ?? config.model;
1324
+ const runMeta = {
1325
+ model: effectiveModel,
1326
+ provider: effectiveProvider?.type ?? "cloud",
1327
+ ...effectiveProvider?.baseUrl ? { baseUrl: effectiveProvider.baseUrl } : {}
1328
+ };
1329
+ if (effectiveProvider?.type === "ollama" && effectiveProvider.contextLength && effectiveProvider.model) {
1330
+ const variantModel = await ensureOllamaContextVariant(
1331
+ effectiveProvider.model,
1332
+ effectiveProvider.contextLength
1333
+ );
1334
+ taskProviderOverride = { ...taskProviderOverride, model: variantModel };
1335
+ }
1336
+ const taskAbortController = new AbortController();
1337
+ const timeoutMs = config.timeoutSeconds * MS_PER_SECOND;
1338
+ const timeoutId = setTimeout(() => {
1339
+ console.warn(`[agent] Run ${runId} exceeded timeout (${config.timeoutSeconds}s), aborting`);
1340
+ taskAbortController.abort();
1341
+ }, timeoutMs);
1342
+ timeoutId.unref?.();
1343
+ let phaseResults;
1344
+ try {
1345
+ let tokensUsed;
1346
+ let costUsd;
1347
+ if (config.phases && config.phases.length > 0) {
1348
+ const result = await executePhasedQuery(
1349
+ config,
1350
+ systemPrompt,
1351
+ vaultContext,
1352
+ agentId,
1353
+ runId,
1354
+ taskProviderOverride,
1355
+ phaseProviderOverrides,
1356
+ options?.instruction,
1357
+ options?.embeddingManager,
1358
+ taskAbortController
1359
+ );
1360
+ tokensUsed = result.tokensUsed;
1361
+ costUsd = result.costUsd;
1362
+ phaseResults = result.phases;
1363
+ } else {
1364
+ const taskPrompt = composeTaskPrompt(
1365
+ vaultContext,
1366
+ config.taskDisplayName,
1367
+ config.taskPrompt,
1368
+ options?.instruction
1369
+ );
1370
+ const singleProvider = taskProviderOverride ?? config.execution?.provider;
1371
+ const result = await executeSingleQuery(
1372
+ config,
1373
+ systemPrompt,
1374
+ taskPrompt,
1375
+ agentId,
1376
+ runId,
1377
+ singleProvider,
1378
+ options?.embeddingManager,
1379
+ taskAbortController
1380
+ );
1381
+ tokensUsed = result.tokensUsed;
1382
+ costUsd = result.costUsd;
1383
+ }
1384
+ clearTimeout(timeoutId);
1385
+ const completedAt = epochSeconds();
1386
+ updateRunStatus(runId, STATUS_COMPLETED, {
1387
+ completed_at: completedAt,
1388
+ tokens_used: tokensUsed,
1389
+ cost_usd: costUsd,
1390
+ actions_taken: JSON.stringify({ ...runMeta, ...phaseResults ? { phases: phaseResults } : {} })
1391
+ });
1392
+ return {
1393
+ runId,
1394
+ status: STATUS_COMPLETED,
1395
+ tokensUsed,
1396
+ costUsd,
1397
+ ...phaseResults ? { phases: phaseResults } : {}
1398
+ };
1399
+ } catch (err) {
1400
+ clearTimeout(timeoutId);
1401
+ let errorMessage2;
1402
+ if (err instanceof Error) {
1403
+ errorMessage2 = err.message || err.constructor.name || "Error (no message)";
1404
+ if (err.stack) errorMessage2 += `
1405
+ ${err.stack.split("\n").slice(0, 3).join("\n")}`;
1406
+ } else if (typeof err === "string") {
1407
+ errorMessage2 = err || "Empty string error";
1408
+ } else {
1409
+ try {
1410
+ errorMessage2 = JSON.stringify(err);
1411
+ } catch {
1412
+ errorMessage2 = "Unserializable error";
1413
+ }
1414
+ }
1415
+ const failedAt = epochSeconds();
1416
+ console.error(`[agent] Run ${runId} failed: ${errorMessage2}`);
1417
+ try {
1418
+ updateRunStatus(runId, STATUS_FAILED, {
1419
+ completed_at: failedAt,
1420
+ error: errorMessage2,
1421
+ // Preserve phase results collected before the failure
1422
+ actions_taken: JSON.stringify({ ...runMeta, ...phaseResults ? { phases: phaseResults } : {} })
1423
+ });
1424
+ } catch (dbErr) {
1425
+ console.error(`[agent] Failed to save error to DB:`, dbErr);
1426
+ }
1427
+ return {
1428
+ runId,
1429
+ status: STATUS_FAILED,
1430
+ error: errorMessage2,
1431
+ ...phaseResults ? { phases: phaseResults } : {}
1432
+ };
1433
+ }
1434
+ }
1435
+ export {
1436
+ composePhasePrompt,
1437
+ composeTaskPrompt,
1438
+ computeWaves,
1439
+ runAgent
1440
+ };
1441
+ //# sourceMappingURL=executor-ONSDHPGX.js.map