@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,26 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ CloudEmbeddingBase
4
+ } from "./chunk-KYLDNM7H.js";
5
+
6
+ // src/cli/providers/openai-embeddings.ts
7
+ var OPENAI_API_KEY_ENV = "MYCO_OPENAI_API_KEY";
8
+ var OpenAIEmbeddingProvider = class extends CloudEmbeddingBase {
9
+ constructor(opts) {
10
+ super({
11
+ apiBase: "https://api.openai.com/v1",
12
+ modelsEndpoint: "/models",
13
+ embeddingsEndpoint: "/embeddings",
14
+ apiKeyEnvVar: OPENAI_API_KEY_ENV,
15
+ defaultModel: "text-embedding-3-small",
16
+ providerName: "openai",
17
+ modelFilter: (id) => id.includes("embedding")
18
+ }, opts);
19
+ }
20
+ };
21
+
22
+ export {
23
+ OPENAI_API_KEY_ENV,
24
+ OpenAIEmbeddingProvider
25
+ };
26
+ //# sourceMappingURL=chunk-RJ6ZQKG5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/providers/openai-embeddings.ts"],"sourcesContent":["import { CloudEmbeddingBase } from './cloud-embedding-base.js';\n\n/** Environment variable for OpenAI API key (stored in secrets.env). */\nexport const OPENAI_API_KEY_ENV = 'MYCO_OPENAI_API_KEY';\n\nexport class OpenAIEmbeddingProvider extends CloudEmbeddingBase {\n constructor(opts?: { api_key?: string; model?: string }) {\n super({\n apiBase: 'https://api.openai.com/v1',\n modelsEndpoint: '/models',\n embeddingsEndpoint: '/embeddings',\n apiKeyEnvVar: OPENAI_API_KEY_ENV,\n defaultModel: 'text-embedding-3-small',\n providerName: 'openai',\n modelFilter: (id) => id.includes('embedding'),\n }, opts);\n }\n}\n"],"mappings":";;;;;;AAGO,IAAM,qBAAqB;AAE3B,IAAM,0BAAN,cAAsC,mBAAmB;AAAA,EAC9D,YAAY,MAA6C;AACvD,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,gBAAgB;AAAA,MAChB,oBAAoB;AAAA,MACpB,cAAc;AAAA,MACd,cAAc;AAAA,MACd,cAAc;AAAA,MACd,aAAa,CAAC,OAAO,GAAG,SAAS,WAAW;AAAA,IAC9C,GAAG,IAAI;AAAA,EACT;AACF;","names":[]}
@@ -1,16 +1,13 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
- import {
3
- getPluginVersion
4
- } from "./chunk-QN4W3JUA.js";
5
- import {
6
- AgentRegistry
7
- } from "./chunk-Z74SDEKE.js";
8
2
  import {
9
3
  DAEMON_CLIENT_TIMEOUT_MS,
10
4
  DAEMON_HEALTH_CHECK_TIMEOUT_MS,
11
5
  DAEMON_HEALTH_RETRY_DELAYS,
12
6
  DAEMON_STALE_GRACE_PERIOD_MS
13
- } from "./chunk-J4D4CROB.js";
7
+ } from "./chunk-5VZ52A4T.js";
8
+ import {
9
+ getPluginVersion
10
+ } from "./chunk-PB6TOLRQ.js";
14
11
 
15
12
  // src/hooks/client.ts
16
13
  import fs from "fs";
@@ -52,9 +49,24 @@ var DaemonClient = class {
52
49
  return { ok: false };
53
50
  }
54
51
  }
55
- async isHealthy() {
52
+ async delete(endpoint) {
56
53
  try {
57
54
  const info = this.readDaemonJson();
55
+ if (!info) return { ok: false };
56
+ const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {
57
+ method: "DELETE",
58
+ signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS)
59
+ });
60
+ if (!res.ok) return { ok: false };
61
+ const data = await res.json();
62
+ return { ok: true, data };
63
+ } catch {
64
+ return { ok: false };
65
+ }
66
+ }
67
+ async isHealthy(cachedInfo) {
68
+ try {
69
+ const info = cachedInfo ?? this.readDaemonJson();
58
70
  if (!info) return false;
59
71
  const res = await fetch(`http://127.0.0.1:${info.port}/health`, {
60
72
  signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS)
@@ -72,15 +84,13 @@ var DaemonClient = class {
72
84
  * Skips the check if daemon.json was written recently (grace period) to prevent
73
85
  * rapid restart loops from concurrent hooks or session reloads.
74
86
  */
75
- async isStale() {
87
+ async isStale(info) {
76
88
  try {
77
89
  const jsonPath = path.join(this.vaultDir, "daemon.json");
78
90
  const stat = fs.statSync(jsonPath);
79
91
  if (Date.now() - stat.mtimeMs < DAEMON_STALE_GRACE_PERIOD_MS) {
80
92
  return false;
81
93
  }
82
- const info = this.readDaemonJson();
83
- if (!info) return false;
84
94
  const res = await fetch(`http://127.0.0.1:${info.port}/health`, {
85
95
  signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS)
86
96
  });
@@ -96,9 +106,8 @@ var DaemonClient = class {
96
106
  /**
97
107
  * Kill the running daemon process.
98
108
  */
99
- killDaemon() {
109
+ killDaemon(info) {
100
110
  try {
101
- const info = this.readDaemonJson();
102
111
  if (!info) return;
103
112
  process.kill(info.pid, "SIGTERM");
104
113
  } catch {
@@ -117,10 +126,11 @@ var DaemonClient = class {
117
126
  */
118
127
  async ensureRunning(opts) {
119
128
  const checkStale = opts?.checkStale ?? true;
120
- if (checkStale && await this.isStale()) {
121
- this.killDaemon();
129
+ const info = this.readDaemonJson();
130
+ if (checkStale && info && await this.isStale(info)) {
131
+ this.killDaemon(info);
122
132
  await new Promise((r) => setTimeout(r, 200));
123
- } else if (await this.isHealthy()) {
133
+ } else if (await this.isHealthy(info)) {
124
134
  return true;
125
135
  }
126
136
  this.spawnDaemon();
@@ -131,37 +141,13 @@ var DaemonClient = class {
131
141
  return false;
132
142
  }
133
143
  spawnDaemon() {
134
- const daemonScript = this.resolveDaemonScript();
135
- if (!daemonScript || !fs.existsSync(daemonScript)) return;
136
- const child = spawn("node", [daemonScript, "--vault", this.vaultDir], {
144
+ const mycoCmd = process.env.MYCO_CMD || "myco";
145
+ const child = spawn(mycoCmd, ["daemon", "--vault", this.vaultDir], {
137
146
  detached: true,
138
147
  stdio: "ignore"
139
148
  });
140
149
  child.unref();
141
150
  }
142
- /**
143
- * Resolve the daemon entry script path.
144
- * Priority:
145
- * 1. Plugin root env var (set by the agent host) → dist/src/daemon/main.js
146
- * 2. Walk up from the current file to find the dist/ directory containing
147
- * the daemon entry. This handles both chunk files (dist/chunk-*.js) and
148
- * thin entry points (dist/src/hooks/*.js) after bundling.
149
- */
150
- resolveDaemonScript() {
151
- const pluginRoot = new AgentRegistry().resolvePluginRoot();
152
- if (pluginRoot) {
153
- return path.join(pluginRoot, "dist", "src", "daemon", "main.js");
154
- }
155
- let dir = import.meta.dirname;
156
- for (let i = 0; i < 5; i++) {
157
- const candidate = path.join(dir, "dist", "src", "daemon", "main.js");
158
- if (fs.existsSync(candidate)) return candidate;
159
- const inDist = path.join(dir, "src", "daemon", "main.js");
160
- if (fs.existsSync(inDist)) return inDist;
161
- dir = path.dirname(dir);
162
- }
163
- return void 0;
164
- }
165
151
  readDaemonJson() {
166
152
  try {
167
153
  const jsonPath = path.join(this.vaultDir, "daemon.json");
@@ -178,4 +164,4 @@ var DaemonClient = class {
178
164
  export {
179
165
  DaemonClient
180
166
  };
181
- //# sourceMappingURL=chunk-YIQLYIHW.js.map
167
+ //# sourceMappingURL=chunk-TRUJLI6K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/client.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { DAEMON_CLIENT_TIMEOUT_MS, DAEMON_HEALTH_CHECK_TIMEOUT_MS, DAEMON_HEALTH_RETRY_DELAYS, DAEMON_STALE_GRACE_PERIOD_MS } from '../constants.js';\nimport { getPluginVersion } from '../version.js';\n\ninterface DaemonInfo {\n pid: number;\n port: number;\n}\n\ninterface HealthResponse {\n myco: boolean;\n version?: string;\n}\n\ninterface ClientResult {\n ok: boolean;\n data?: any;\n}\n\nexport class DaemonClient {\n private vaultDir: string;\n\n constructor(vaultDir: string) {\n this.vaultDir = vaultDir;\n }\n\n async post(endpoint: string, body: unknown): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async get(endpoint: string): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async delete(endpoint: string): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n method: 'DELETE',\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async isHealthy(cachedInfo?: DaemonInfo | null): Promise<boolean> {\n try {\n const info = cachedInfo ?? this.readDaemonJson();\n if (!info) return false;\n\n const res = await fetch(`http://127.0.0.1:${info.port}/health`, {\n signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS),\n });\n if (!res.ok) return false;\n const data = await res.json() as HealthResponse;\n return data.myco === true;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if the daemon is running a stale version.\n * Returns true if the daemon's version doesn't match the current plugin version.\n * Skips the check if daemon.json was written recently (grace period) to prevent\n * rapid restart loops from concurrent hooks or session reloads.\n */\n private async isStale(info: DaemonInfo): Promise<boolean> {\n try {\n const jsonPath = path.join(this.vaultDir, 'daemon.json');\n const stat = fs.statSync(jsonPath);\n if (Date.now() - stat.mtimeMs < DAEMON_STALE_GRACE_PERIOD_MS) {\n return false;\n }\n\n const res = await fetch(`http://127.0.0.1:${info.port}/health`, {\n signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS),\n });\n if (!res.ok) return false;\n const data = await res.json() as HealthResponse;\n if (!data.myco) return false;\n\n // No version in response = old daemon that predates this check\n if (!data.version) return true;\n\n return data.version !== getPluginVersion();\n } catch {\n return false;\n }\n }\n\n /**\n * Kill the running daemon process.\n */\n private killDaemon(info: DaemonInfo | null): void {\n try {\n if (!info) return;\n process.kill(info.pid, 'SIGTERM');\n } catch { /* already dead */ }\n try {\n fs.unlinkSync(path.join(this.vaultDir, 'daemon.json'));\n } catch { /* already gone */ }\n }\n\n /**\n * Ensure the daemon is running. Spawns it if unhealthy.\n * When checkStale is true (default), also restarts a healthy daemon if its\n * version doesn't match the current plugin version. Use checkStale: false\n * for hooks that just need the daemon alive (e.g., stop) without triggering\n * version-driven restarts.\n */\n async ensureRunning(opts?: { checkStale?: boolean }): Promise<boolean> {\n const checkStale = opts?.checkStale ?? true;\n const info = this.readDaemonJson();\n\n if (checkStale && info && await this.isStale(info)) {\n this.killDaemon(info);\n // Brief pause for port release\n await new Promise((r) => setTimeout(r, 200));\n } else if (await this.isHealthy(info)) {\n return true;\n }\n\n this.spawnDaemon();\n\n for (const delay of DAEMON_HEALTH_RETRY_DELAYS) {\n await new Promise((r) => setTimeout(r, delay));\n if (await this.isHealthy()) return true;\n }\n return false;\n }\n\n spawnDaemon(): void {\n const mycoCmd = process.env.MYCO_CMD || 'myco';\n const child = spawn(mycoCmd, ['daemon', '--vault', this.vaultDir], {\n detached: true,\n stdio: 'ignore',\n });\n child.unref();\n }\n\n private readDaemonJson(): DaemonInfo | null {\n try {\n const jsonPath = path.join(this.vaultDir, 'daemon.json');\n const content = fs.readFileSync(jsonPath, 'utf-8');\n const info = JSON.parse(content);\n if (typeof info.port !== 'number') return null;\n return info as DaemonInfo;\n } catch {\n return null;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,41 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ EventBuffer
4
+ } from "./chunk-V7XG6V6C.js";
5
+ import {
6
+ readStdin
7
+ } from "./chunk-XNOCTDHF.js";
8
+ import {
9
+ DaemonClient
10
+ } from "./chunk-TRUJLI6K.js";
11
+ import {
12
+ resolveVaultDir
13
+ } from "./chunk-JTYZRPX5.js";
14
+
15
+ // src/hooks/send-event.ts
16
+ import fs from "fs";
17
+ import path from "path";
18
+ async function sendEvent(hookName, buildEvent) {
19
+ const VAULT_DIR = resolveVaultDir();
20
+ if (!fs.existsSync(path.join(VAULT_DIR, "myco.yaml"))) return;
21
+ try {
22
+ const input = JSON.parse(await readStdin());
23
+ const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID ?? `s-${Date.now()}`;
24
+ const event = buildEvent(input, sessionId);
25
+ const client = new DaemonClient(VAULT_DIR);
26
+ const result = await client.post("/events", { ...event, session_id: sessionId });
27
+ if (!result.ok) {
28
+ const buffer = new EventBuffer(path.join(VAULT_DIR, "buffer"), sessionId);
29
+ const { session_id: _, ...bufferPayload } = event;
30
+ buffer.append(bufferPayload);
31
+ }
32
+ } catch (error) {
33
+ process.stderr.write(`[myco] ${hookName} error: ${error.message}
34
+ `);
35
+ }
36
+ }
37
+
38
+ export {
39
+ sendEvent
40
+ };
41
+ //# sourceMappingURL=chunk-U3IBO3O3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/send-event.ts"],"sourcesContent":["/**\n * Shared hook helper — sends an event to the daemon, buffers on failure.\n *\n * Every hook follows the same pattern: read stdin, POST to daemon /events,\n * buffer to disk if the daemon is unreachable. This helper extracts that\n * skeleton so each hook is a one-liner mapping input fields to event fields.\n */\n\nimport { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { EventBuffer } from '../capture/buffer.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/**\n * Read hook stdin, POST event to daemon, buffer on failure.\n *\n * @param hookName — used for error logging (e.g., 'subagent-start')\n * @param buildEvent — maps the raw hook input to the event payload.\n * Receives the parsed stdin JSON and the resolved session ID.\n * Return the full event object (must include `type`).\n */\nexport async function sendEvent(\n hookName: string,\n buildEvent: (input: Record<string, unknown>, sessionId: string) => Record<string, unknown>,\n): Promise<void> {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin()) as Record<string, unknown>;\n const sessionId = (input.session_id as string) ?? process.env.MYCO_SESSION_ID ?? `s-${Date.now()}`;\n\n const event = buildEvent(input, sessionId);\n\n const client = new DaemonClient(VAULT_DIR);\n const result = await client.post('/events', { ...event, session_id: sessionId });\n\n if (!result.ok) {\n const buffer = new EventBuffer(path.join(VAULT_DIR, 'buffer'), sessionId);\n // Strip session_id from buffer entry — it's in the filename\n const { session_id: _, ...bufferPayload } = event;\n buffer.append(bufferPayload);\n }\n } catch (error) {\n process.stderr.write(`[myco] ${hookName} error: ${(error as Error).message}\\n`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAYA,OAAO,QAAQ;AACf,OAAO,UAAU;AAUjB,eAAsB,UACpB,UACA,YACe;AACf,QAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,WAAW,WAAW,CAAC,EAAG;AAEvD,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,CAAC;AAC1C,UAAM,YAAa,MAAM,cAAyB,QAAQ,IAAI,mBAAmB,KAAK,KAAK,IAAI,CAAC;AAEhG,UAAM,QAAQ,WAAW,OAAO,SAAS;AAEzC,UAAM,SAAS,IAAI,aAAa,SAAS;AACzC,UAAM,SAAS,MAAM,OAAO,KAAK,WAAW,EAAE,GAAG,OAAO,YAAY,UAAU,CAAC;AAE/E,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,SAAS,IAAI,YAAY,KAAK,KAAK,WAAW,QAAQ,GAAG,SAAS;AAExE,YAAM,EAAE,YAAY,GAAG,GAAG,cAAc,IAAI;AAC5C,aAAO,OAAO,aAAa;AAAA,IAC7B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,UAAU,QAAQ,WAAY,MAAgB,OAAO;AAAA,CAAI;AAAA,EAChF;AACF;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  DAEMON_CLIENT_TIMEOUT_MS,
4
4
  EMBEDDING_REQUEST_TIMEOUT_MS,
5
5
  LLM_REQUEST_TIMEOUT_MS
6
- } from "./chunk-J4D4CROB.js";
6
+ } from "./chunk-5VZ52A4T.js";
7
7
 
8
8
  // src/intelligence/ollama.ts
9
9
  var ENDPOINT_GENERATE = "/api/generate";
@@ -144,6 +144,8 @@ var LmStudioBackend = class _LmStudioBackend {
144
144
  instanceId = null;
145
145
  contextWindow;
146
146
  defaultMaxTokens;
147
+ /** Set after a model rejects the `reasoning` param — skip it on future calls. */
148
+ reasoningUnsupported = false;
147
149
  constructor(config) {
148
150
  this.baseUrl = config?.base_url ?? _LmStudioBackend.DEFAULT_BASE_URL;
149
151
  this.model = config?.model ?? config?.summary_model ?? "llama3.2";
@@ -172,10 +174,11 @@ var LmStudioBackend = class _LmStudioBackend {
172
174
  if (opts?.systemPrompt) {
173
175
  body.system_prompt = opts.systemPrompt;
174
176
  }
175
- if (opts?.reasoning) {
177
+ const sendReasoning = opts?.reasoning && !this.reasoningUnsupported;
178
+ if (sendReasoning) {
176
179
  body.reasoning = opts.reasoning;
177
180
  }
178
- const response = await fetch(`${this.baseUrl}${ENDPOINT_CHAT}`, {
181
+ let response = await fetch(`${this.baseUrl}${ENDPOINT_CHAT}`, {
179
182
  method: "POST",
180
183
  headers: { "Content-Type": "application/json" },
181
184
  body: JSON.stringify(body),
@@ -183,10 +186,25 @@ var LmStudioBackend = class _LmStudioBackend {
183
186
  });
184
187
  if (!response.ok) {
185
188
  const errorBody = await response.text().catch(() => "");
186
- if (response.status === 404 && this.instanceId) {
187
- this.instanceId = null;
189
+ if (sendReasoning && /does not support reasoning|"param"\s*:\s*"reasoning"/.test(errorBody)) {
190
+ this.reasoningUnsupported = true;
191
+ delete body.reasoning;
192
+ response = await fetch(`${this.baseUrl}${ENDPOINT_CHAT}`, {
193
+ method: "POST",
194
+ headers: { "Content-Type": "application/json" },
195
+ body: JSON.stringify(body),
196
+ signal: AbortSignal.timeout(opts?.timeoutMs ?? LLM_REQUEST_TIMEOUT_MS)
197
+ });
198
+ if (!response.ok) {
199
+ const retryError = await response.text().catch(() => "");
200
+ throw new Error(`LM Studio summarize failed: ${response.status} ${retryError.slice(0, 500)}`);
201
+ }
202
+ } else {
203
+ if (response.status === 404 && this.instanceId) {
204
+ this.instanceId = null;
205
+ }
206
+ throw new Error(`LM Studio summarize failed: ${response.status} ${errorBody.slice(0, 500)}`);
188
207
  }
189
- throw new Error(`LM Studio summarize failed: ${response.status} ${errorBody.slice(0, 500)}`);
190
208
  }
191
209
  const data = await response.json();
192
210
  const messageOutput = data.output.find((o) => o.type === "message");
@@ -307,4 +325,4 @@ export {
307
325
  OllamaBackend,
308
326
  LmStudioBackend
309
327
  };
310
- //# sourceMappingURL=chunk-7WHF2OIZ.js.map
328
+ //# sourceMappingURL=chunk-UBZPD4HN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/intelligence/ollama.ts","../src/intelligence/lm-studio.ts"],"sourcesContent":["import type { LlmProvider, EmbeddingProvider, LlmResponse, EmbeddingResponse, LlmRequestOptions } from './llm.js';\nimport { LLM_REQUEST_TIMEOUT_MS, EMBEDDING_REQUEST_TIMEOUT_MS, DAEMON_CLIENT_TIMEOUT_MS } from '../constants.js';\n\ninterface OllamaConfig {\n model?: string;\n base_url?: string;\n context_window?: number;\n max_tokens?: number;\n // Legacy fields (ignored, kept for backward compat during migration)\n embedding_model?: string;\n summary_model?: string;\n}\n\n// Ollama API endpoints\nconst ENDPOINT_GENERATE = '/api/generate';\nconst ENDPOINT_EMBED = '/api/embed';\nconst ENDPOINT_TAGS = '/api/tags';\n\nexport class OllamaBackend implements LlmProvider, EmbeddingProvider {\n static readonly DEFAULT_BASE_URL = 'http://localhost:11434';\n readonly name = 'ollama';\n private baseUrl: string;\n private model: string;\n private defaultMaxTokens: number;\n private contextWindow: number | undefined;\n\n constructor(config?: OllamaConfig) {\n this.baseUrl = config?.base_url ?? OllamaBackend.DEFAULT_BASE_URL;\n this.model = config?.model ?? config?.summary_model ?? 'llama3.2';\n this.defaultMaxTokens = config?.max_tokens ?? 1024;\n this.contextWindow = config?.context_window;\n }\n\n async summarize(prompt: string, opts?: LlmRequestOptions): Promise<LlmResponse> {\n const maxTokens = opts?.maxTokens ?? this.defaultMaxTokens;\n\n // Send num_ctx from config or per-call override. Ollama reloads the model\n // on num_ctx changes, but consistent values (same num_ctx every call)\n // only cause one reload on first use. Without this, Ollama falls back to\n // its model default (often 2048), ignoring the user's configured context.\n const contextLength = opts?.contextLength ?? this.contextWindow;\n const options: Record<string, unknown> = { num_predict: maxTokens };\n if (contextLength) {\n options.num_ctx = contextLength;\n }\n\n const body: Record<string, unknown> = {\n model: this.model,\n prompt,\n stream: true,\n options,\n };\n\n // System prompt — sent as a separate field instead of concatenated into prompt\n if (opts?.systemPrompt) {\n body.system = opts.systemPrompt;\n }\n\n // Thinking control — false suppresses chain-of-thought for reasoning models\n if (opts?.reasoning) {\n body.think = opts.reasoning === 'off' ? false : opts.reasoning;\n }\n\n // Keep model loaded between requests (useful for digest cycles)\n if (opts?.keepAlive) {\n body.keep_alive = opts.keepAlive;\n }\n\n const response = await fetch(`${this.baseUrl}${ENDPOINT_GENERATE}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(opts?.timeoutMs ?? LLM_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => '');\n throw new Error(`Ollama summarize failed: ${response.status} ${errorBody.slice(0, 500)}`);\n }\n\n return this.readStream(response);\n }\n\n /** Read an Ollama streaming response (newline-delimited JSON) and accumulate the result. */\n private async readStream(response: Response): Promise<LlmResponse> {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let text = '';\n let model = this.model;\n let buffer = '';\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n const chunk = JSON.parse(line) as { response?: string; model?: string; error?: string };\n if (chunk.error) throw new Error(`Ollama stream error: ${chunk.error}`);\n text += chunk.response ?? '';\n if (chunk.model) model = chunk.model;\n }\n }\n\n // Process remaining buffer\n if (buffer.trim()) {\n const chunk = JSON.parse(buffer) as { response?: string; model?: string; error?: string };\n if (chunk.error) throw new Error(`Ollama stream error: ${chunk.error}`);\n text += chunk.response ?? '';\n if (chunk.model) model = chunk.model;\n }\n } finally {\n reader.releaseLock();\n }\n\n return { text, model };\n }\n\n async embed(text: string): Promise<EmbeddingResponse> {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_EMBED}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n input: text,\n }),\n signal: AbortSignal.timeout(EMBEDDING_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(`Ollama embed failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json() as { embeddings: number[][]; model: string };\n const embedding = data.embeddings[0];\n return { embedding, model: data.model, dimensions: embedding.length };\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_TAGS}`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /** List available models on this Ollama instance. */\n async listModels(timeoutMs?: number): Promise<string[]> {\n try {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_TAGS}`, {\n signal: AbortSignal.timeout(timeoutMs ?? DAEMON_CLIENT_TIMEOUT_MS),\n });\n const data = await response.json() as { models: Array<{ name: string }> };\n return data.models.map((m) => m.name);\n } catch {\n return [];\n }\n }\n}\n","import type { LlmProvider, EmbeddingProvider, LlmResponse, EmbeddingResponse, LlmRequestOptions } from './llm.js';\nimport { LLM_REQUEST_TIMEOUT_MS, EMBEDDING_REQUEST_TIMEOUT_MS, DAEMON_CLIENT_TIMEOUT_MS } from '../constants.js';\n\ninterface LmStudioConfig {\n model?: string;\n base_url?: string;\n context_window?: number;\n max_tokens?: number;\n // Legacy fields\n embedding_model?: string;\n summary_model?: string;\n}\n\n// LM Studio API endpoints\nconst ENDPOINT_CHAT = '/api/v1/chat';\nconst ENDPOINT_MODELS_LOAD = '/api/v1/models/load';\nconst ENDPOINT_MODELS_LIST = '/v1/models';\nconst ENDPOINT_MODELS_NATIVE = '/api/v1/models';\nconst ENDPOINT_EMBEDDINGS = '/v1/embeddings';\n\n/** Shape of a loaded instance from the LM Studio native models API.\n * Config fields vary by engine — llama.cpp models include flash_attention\n * and offload_kv_cache_to_gpu, but other engines (MLX, etc.) may omit them. */\ninterface NativeLoadedInstance {\n id: string;\n config: {\n context_length: number;\n flash_attention?: boolean;\n offload_kv_cache_to_gpu?: boolean;\n };\n}\n\n/** Shape of a model entry from the LM Studio native models API. */\ninterface NativeModelEntry {\n type: string;\n key: string;\n loaded_instances: NativeLoadedInstance[];\n}\n\nexport class LmStudioBackend implements LlmProvider, EmbeddingProvider {\n static readonly DEFAULT_BASE_URL = 'http://localhost:1234';\n readonly name = 'lm-studio';\n private baseUrl: string;\n private model: string;\n private instanceId: string | null = null;\n private contextWindow: number | undefined;\n private defaultMaxTokens: number;\n /** Set after a model rejects the `reasoning` param — skip it on future calls. */\n private reasoningUnsupported = false;\n\n constructor(config?: LmStudioConfig) {\n this.baseUrl = config?.base_url ?? LmStudioBackend.DEFAULT_BASE_URL;\n this.model = config?.model ?? config?.summary_model ?? 'llama3.2';\n this.contextWindow = config?.context_window;\n this.defaultMaxTokens = config?.max_tokens ?? 1024;\n }\n\n /**\n * Generate text using LM Studio's native REST API (/api/v1/chat).\n * Routes to our specific instance by ID when available, with model name +\n * context_length as fallback. This ensures correct routing when multiple\n * daemons share the same LM Studio, and graceful degradation when our\n * instance is evicted by idle TTL.\n */\n async summarize(prompt: string, opts?: LlmRequestOptions): Promise<LlmResponse> {\n const maxTokens = opts?.maxTokens ?? this.defaultMaxTokens;\n const contextLength = opts?.contextLength ?? this.contextWindow;\n\n const body: Record<string, unknown> = {\n model: this.instanceId ?? this.model,\n input: prompt,\n max_output_tokens: maxTokens,\n store: false,\n };\n\n // Always send context_length — even when routing by instance ID.\n // If our instance was evicted and LM Studio auto-loads, this ensures\n // the replacement gets the correct context window.\n if (contextLength) {\n body.context_length = contextLength;\n }\n\n // System prompt — sent separately from user content\n if (opts?.systemPrompt) {\n body.system_prompt = opts.systemPrompt;\n }\n\n // Reasoning control — 'off' suppresses chain-of-thought for reasoning models.\n // Non-reasoning models reject this param, so we retry without it on failure.\n const sendReasoning = opts?.reasoning && !this.reasoningUnsupported;\n if (sendReasoning) {\n body.reasoning = opts!.reasoning;\n }\n\n let response = await fetch(`${this.baseUrl}${ENDPOINT_CHAT}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(opts?.timeoutMs ?? LLM_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => '');\n\n // Model doesn't support reasoning — retry without it and remember\n // so subsequent calls skip the param entirely.\n if (sendReasoning && /does not support reasoning|\"param\"\\s*:\\s*\"reasoning\"/.test(errorBody)) {\n this.reasoningUnsupported = true;\n delete body.reasoning;\n response = await fetch(`${this.baseUrl}${ENDPOINT_CHAT}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(opts?.timeoutMs ?? LLM_REQUEST_TIMEOUT_MS),\n });\n if (!response.ok) {\n const retryError = await response.text().catch(() => '');\n throw new Error(`LM Studio summarize failed: ${response.status} ${retryError.slice(0, 500)}`);\n }\n } else {\n // If our instance was evicted, clear the ID so ensureLoaded\n // reloads on the next cycle instead of hitting a stale ID repeatedly\n if (response.status === 404 && this.instanceId) {\n this.instanceId = null;\n }\n throw new Error(`LM Studio summarize failed: ${response.status} ${errorBody.slice(0, 500)}`);\n }\n }\n\n const data = await response.json() as {\n model_instance_id: string;\n output: Array<{ type: string; content: string }>;\n };\n const messageOutput = data.output.find((o) => o.type === 'message');\n const text = messageOutput?.content ?? '';\n return { text, model: data.model_instance_id };\n }\n\n /**\n * Generate embeddings using LM Studio's OpenAI-compatible endpoint.\n * (The native API doesn't have an embedding endpoint — OpenAI-compat is fine here.)\n */\n async embed(text: string): Promise<EmbeddingResponse> {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_EMBEDDINGS}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n input: text,\n }),\n signal: AbortSignal.timeout(EMBEDDING_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(`LM Studio embed failed: ${response.status}`);\n }\n\n const data = await response.json() as {\n data: Array<{ embedding: number[] }>;\n model: string;\n };\n const embedding = data.data[0].embedding;\n return { embedding, model: data.model, dimensions: embedding.length };\n }\n\n /**\n * Ensure a model instance is loaded and capture its ID for routing.\n * Called every digest cycle so it recovers from idle TTL eviction.\n *\n * Strategy: reuse ANY loaded instance of this model. Only load a new one\n * when zero instances exist. This avoids the previous bug where strict\n * config matching (context_length, offload_kv_cache_to_gpu) caused new\n * instances to spawn every cycle — exhausting system resources.\n *\n * context_length is set per-request on /api/v1/chat, so we don't need\n * to match it at load time. Load-time-only params like\n * offload_kv_cache_to_gpu are llama.cpp-specific and may not apply to\n * all models (e.g., glm-4.7-flash has no KV cache setting).\n */\n async ensureLoaded(contextLength?: number, gpuKvCache?: boolean): Promise<void> {\n // Query native API for existing loaded instances of this model\n const instances = await this.getLoadedInstances();\n\n if (instances.length > 0) {\n // Reuse the first available instance — don't reject over config differences.\n // context_length is set per-request; load-time params like kv_cache are\n // model-dependent and may not even appear in the instance config.\n this.instanceId = instances[0].id;\n return;\n }\n\n // No instances loaded — load one with our preferred settings.\n // These are hints; LM Studio silently ignores params that don't apply to the model's engine.\n const ctx = contextLength ?? this.contextWindow;\n const body: Record<string, unknown> = {\n model: this.model,\n // llama.cpp-specific — ignored by other engines (MLX, etc.)\n flash_attention: true,\n };\n if (ctx) {\n body.context_length = ctx;\n }\n if (gpuKvCache) {\n body.offload_kv_cache_to_gpu = true;\n }\n\n const response = await fetch(`${this.baseUrl}${ENDPOINT_MODELS_LOAD}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(LLM_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => '');\n throw new Error(`LM Studio model load failed: ${response.status} ${errorBody.slice(0, 200)}`);\n }\n\n const loadResult = await response.json() as Record<string, unknown>;\n const id = (loadResult.instance_id ?? loadResult.id ?? loadResult.model_instance_id) as string | undefined;\n if (id) {\n this.instanceId = id;\n }\n }\n\n /**\n * Query the LM Studio native API for loaded instances of this model.\n * Returns an empty array if the API is unavailable or the model has no loaded instances.\n */\n private async getLoadedInstances(): Promise<NativeLoadedInstance[]> {\n try {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_MODELS_NATIVE}`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n if (!response.ok) return [];\n\n const data = await response.json() as { models: NativeModelEntry[] };\n const entry = data.models.find((m) => m.key === this.model);\n return entry?.loaded_instances ?? [];\n } catch {\n return [];\n }\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_MODELS_LIST}`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /** List available models on this LM Studio instance. */\n async listModels(timeoutMs?: number): Promise<string[]> {\n try {\n const response = await fetch(`${this.baseUrl}${ENDPOINT_MODELS_LIST}`, {\n signal: AbortSignal.timeout(timeoutMs ?? DAEMON_CLIENT_TIMEOUT_MS),\n });\n const data = await response.json() as { data: Array<{ id: string }> };\n return data.data.map((m) => m.id);\n } catch {\n return [];\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -51,26 +51,35 @@ var EventBuffer = class {
51
51
  return this.filePath;
52
52
  }
53
53
  };
54
- function resolveSessionFromBuffer(bufferDir) {
54
+ function listBufferSessionIds(bufferDir) {
55
55
  try {
56
- let bestSession;
57
- let bestMtime = 0;
56
+ return fs.readdirSync(bufferDir).filter((f) => f.endsWith(".jsonl")).map((f) => f.replace(".jsonl", ""));
57
+ } catch {
58
+ return [];
59
+ }
60
+ }
61
+ function cleanStaleBuffers(bufferDir, maxAgeMs, excludeSessionId) {
62
+ let removed = 0;
63
+ try {
64
+ const cutoff = Date.now() - maxAgeMs;
58
65
  for (const file of fs.readdirSync(bufferDir)) {
59
66
  if (!file.endsWith(".jsonl")) continue;
60
- const mtime = fs.statSync(path.join(bufferDir, file)).mtimeMs;
61
- if (mtime > bestMtime) {
62
- bestMtime = mtime;
63
- bestSession = file.replace(".jsonl", "");
67
+ if (excludeSessionId && file === `${excludeSessionId}.jsonl`) continue;
68
+ const filePath = path.join(bufferDir, file);
69
+ const stat = fs.statSync(filePath);
70
+ if (stat.mtimeMs < cutoff) {
71
+ fs.unlinkSync(filePath);
72
+ removed++;
64
73
  }
65
74
  }
66
- return bestSession;
67
75
  } catch {
68
- return void 0;
69
76
  }
77
+ return removed;
70
78
  }
71
79
 
72
80
  export {
73
81
  EventBuffer,
74
- resolveSessionFromBuffer
82
+ listBufferSessionIds,
83
+ cleanStaleBuffers
75
84
  };
76
- //# sourceMappingURL=chunk-HIN3UVOG.js.map
85
+ //# sourceMappingURL=chunk-V7XG6V6C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capture/buffer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\ninterface BufferOptions {\n maxEvents?: number;\n}\n\nexport class EventBuffer {\n private filePath: string;\n private maxEvents: number;\n private eventCount = 0;\n\n constructor(\n private bufferDir: string,\n private sessionId: string,\n options: BufferOptions = {},\n ) {\n this.filePath = path.join(bufferDir, `${sessionId}.jsonl`);\n this.maxEvents = options.maxEvents ?? 500;\n\n if (fs.existsSync(this.filePath)) {\n const content = fs.readFileSync(this.filePath, 'utf-8').trim();\n this.eventCount = content ? content.split('\\n').length : 0;\n }\n }\n\n append(event: Record<string, unknown>): void {\n fs.mkdirSync(this.bufferDir, { recursive: true });\n\n const line = JSON.stringify({\n ...event,\n timestamp: event.timestamp ?? new Date().toISOString(),\n });\n\n fs.appendFileSync(this.filePath, line + '\\n');\n this.eventCount++;\n }\n\n readAll(): Array<Record<string, unknown>> {\n if (!fs.existsSync(this.filePath)) return [];\n const content = fs.readFileSync(this.filePath, 'utf-8').trim();\n if (!content) return [];\n return content.split('\\n').map((line) => JSON.parse(line));\n }\n\n count(): number {\n return this.eventCount;\n }\n\n exists(): boolean {\n return fs.existsSync(this.filePath);\n }\n\n delete(): void {\n if (fs.existsSync(this.filePath)) {\n fs.unlinkSync(this.filePath);\n }\n this.eventCount = 0;\n }\n\n isOverflow(): boolean {\n return this.eventCount > this.maxEvents;\n }\n\n getFilePath(): string {\n return this.filePath;\n }\n}\n\n/**\n * List all session IDs that have buffer files in the given directory.\n * Returns an empty array if the directory doesn't exist.\n */\nexport function listBufferSessionIds(bufferDir: string): string[] {\n try {\n return fs.readdirSync(bufferDir)\n .filter((f) => f.endsWith('.jsonl'))\n .map((f) => f.replace('.jsonl', ''));\n } catch {\n return [];\n }\n}\n\n/**\n * Remove buffer files older than `maxAgeMs`.\n *\n * @param excludeSessionId - skip this session (e.g., the currently active one)\n * @returns count of files removed\n */\nexport function cleanStaleBuffers(\n bufferDir: string,\n maxAgeMs: number,\n excludeSessionId?: string,\n): number {\n let removed = 0;\n try {\n const cutoff = Date.now() - maxAgeMs;\n for (const file of fs.readdirSync(bufferDir)) {\n if (!file.endsWith('.jsonl')) continue;\n if (excludeSessionId && file === `${excludeSessionId}.jsonl`) continue;\n const filePath = path.join(bufferDir, file);\n const stat = fs.statSync(filePath);\n if (stat.mtimeMs < cutoff) {\n fs.unlinkSync(filePath);\n removed++;\n }\n }\n } catch { /* buffer dir may not exist */ }\n return removed;\n}\n\n/**\n * Find the most recently active session by buffer file mtime.\n * The UserPromptSubmit hook appends to the session's buffer on every prompt,\n * so the most recently modified buffer is the calling session.\n */\nexport function resolveSessionFromBuffer(bufferDir: string): string | undefined {\n try {\n let bestSession: string | undefined;\n let bestMtime = 0;\n for (const file of fs.readdirSync(bufferDir)) {\n if (!file.endsWith('.jsonl')) continue;\n const mtime = fs.statSync(path.join(bufferDir, file)).mtimeMs;\n if (mtime > bestMtime) {\n bestMtime = mtime;\n bestSession = file.replace('.jsonl', '');\n }\n }\n return bestSession;\n } catch {\n return undefined;\n }\n}\n"],"mappings":";;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAMV,IAAM,cAAN,MAAkB;AAAA,EAKvB,YACU,WACA,WACR,UAAyB,CAAC,GAC1B;AAHQ;AACA;AAGR,SAAK,WAAW,KAAK,KAAK,WAAW,GAAG,SAAS,QAAQ;AACzD,SAAK,YAAY,QAAQ,aAAa;AAEtC,QAAI,GAAG,WAAW,KAAK,QAAQ,GAAG;AAChC,YAAM,UAAU,GAAG,aAAa,KAAK,UAAU,OAAO,EAAE,KAAK;AAC7D,WAAK,aAAa,UAAU,QAAQ,MAAM,IAAI,EAAE,SAAS;AAAA,IAC3D;AAAA,EACF;AAAA,EAhBQ;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EAgBrB,OAAO,OAAsC;AAC3C,OAAG,UAAU,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAEhD,UAAM,OAAO,KAAK,UAAU;AAAA,MAC1B,GAAG;AAAA,MACH,WAAW,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvD,CAAC;AAED,OAAG,eAAe,KAAK,UAAU,OAAO,IAAI;AAC5C,SAAK;AAAA,EACP;AAAA,EAEA,UAA0C;AACxC,QAAI,CAAC,GAAG,WAAW,KAAK,QAAQ,EAAG,QAAO,CAAC;AAC3C,UAAM,UAAU,GAAG,aAAa,KAAK,UAAU,OAAO,EAAE,KAAK;AAC7D,QAAI,CAAC,QAAS,QAAO,CAAC;AACtB,WAAO,QAAQ,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,KAAK,MAAM,IAAI,CAAC;AAAA,EAC3D;AAAA,EAEA,QAAgB;AACd,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAAkB;AAChB,WAAO,GAAG,WAAW,KAAK,QAAQ;AAAA,EACpC;AAAA,EAEA,SAAe;AACb,QAAI,GAAG,WAAW,KAAK,QAAQ,GAAG;AAChC,SAAG,WAAW,KAAK,QAAQ;AAAA,IAC7B;AACA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,aAAsB;AACpB,WAAO,KAAK,aAAa,KAAK;AAAA,EAChC;AAAA,EAEA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AACF;AAMO,SAAS,qBAAqB,WAA6B;AAChE,MAAI;AACF,WAAO,GAAG,YAAY,SAAS,EAC5B,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC,EAClC,IAAI,CAAC,MAAM,EAAE,QAAQ,UAAU,EAAE,CAAC;AAAA,EACvC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAQO,SAAS,kBACd,WACA,UACA,kBACQ;AACR,MAAI,UAAU;AACd,MAAI;AACF,UAAM,SAAS,KAAK,IAAI,IAAI;AAC5B,eAAW,QAAQ,GAAG,YAAY,SAAS,GAAG;AAC5C,UAAI,CAAC,KAAK,SAAS,QAAQ,EAAG;AAC9B,UAAI,oBAAoB,SAAS,GAAG,gBAAgB,SAAU;AAC9D,YAAM,WAAW,KAAK,KAAK,WAAW,IAAI;AAC1C,YAAM,OAAO,GAAG,SAAS,QAAQ;AACjC,UAAI,KAAK,UAAU,QAAQ;AACzB,WAAG,WAAW,QAAQ;AACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAAiC;AACzC,SAAO;AACT;","names":[]}
@@ -0,0 +1,84 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+
3
+ // src/constants/log-kinds.ts
4
+ var LOG_KINDS = {
5
+ // Context injection
6
+ CONTEXT_QUERY: "context.query",
7
+ CONTEXT_SESSION: "context.session",
8
+ CONTEXT_PROMPT: "context.prompt",
9
+ CONTEXT_DIGEST: "context.digest",
10
+ CONTEXT_SEARCH: "context.search",
11
+ CONTEXT_EMBED: "context.embed",
12
+ CONTEXT_FILTER: "context.filter",
13
+ // Session lifecycle
14
+ LIFECYCLE_REGISTER: "lifecycle.register",
15
+ LIFECYCLE_RECONCILE: "lifecycle.reconcile",
16
+ LIFECYCLE_UNREGISTER: "lifecycle.unregister",
17
+ LIFECYCLE_CLEANUP: "lifecycle.cleanup",
18
+ LIFECYCLE_AUTO_REGISTER: "lifecycle.auto-register",
19
+ // Hooks (event ingestion)
20
+ HOOKS_EVENT: "hooks.event",
21
+ HOOKS_PROMPT: "hooks.prompt",
22
+ HOOKS_STOP: "hooks.stop",
23
+ HOOKS_TOOL: "hooks.tool",
24
+ HOOKS_SUBAGENT: "hooks.subagent",
25
+ // Capture (batch/activity recording)
26
+ CAPTURE_BATCH: "capture.batch",
27
+ CAPTURE_ACTIVITY: "capture.activity",
28
+ CAPTURE_PLAN: "capture.plan",
29
+ CAPTURE_ATTACHMENT: "capture.attachment",
30
+ CAPTURE_BUFFER: "capture.buffer",
31
+ // Processor (stop-event session processing)
32
+ PROCESSOR_SESSION: "processor.session",
33
+ PROCESSOR_TRANSCRIPT: "processor.transcript",
34
+ PROCESSOR_BATCH: "processor.batch",
35
+ PROCESSOR_TITLE: "processor.title",
36
+ // Agent
37
+ AGENT_RUN: "agent.run",
38
+ AGENT_PHASE: "agent.phase",
39
+ AGENT_TASK: "agent.task",
40
+ AGENT_AUTO_RUN: "agent.auto-run",
41
+ AGENT_ERROR: "agent.error",
42
+ // Embedding
43
+ EMBEDDING_EMBED: "embedding.embed",
44
+ EMBEDDING_RECONCILE: "embedding.reconcile",
45
+ EMBEDDING_SEARCH: "embedding.search",
46
+ EMBEDDING_REBUILD: "embedding.rebuild",
47
+ EMBEDDING_CLEANUP: "embedding.cleanup",
48
+ EMBEDDING_PROVIDER: "embedding.provider",
49
+ // Power management
50
+ POWER_TICK: "power.tick",
51
+ POWER_STATE: "power.state",
52
+ POWER_JOB: "power.job",
53
+ POWER_JOB_ERROR: "power.job-error",
54
+ // Daemon core
55
+ DAEMON_START: "daemon.start",
56
+ DAEMON_CONFIG: "daemon.config",
57
+ DAEMON_READY: "daemon.ready",
58
+ DAEMON_MIGRATION: "daemon.migration",
59
+ DAEMON_PORT: "daemon.port",
60
+ DAEMON_RECONCILE: "daemon.reconcile",
61
+ // Server (HTTP)
62
+ SERVER_REQUEST: "server.request",
63
+ SERVER_STATIC: "server.static",
64
+ SERVER_ERROR: "server.error",
65
+ // Session maintenance job
66
+ MAINTENANCE_SESSION: "maintenance.session",
67
+ MAINTENANCE_EMBEDDING: "maintenance.embedding",
68
+ // API operations
69
+ API_SESSION_DELETE: "api.session-delete",
70
+ // MCP
71
+ MCP_EVENT: "mcp.event",
72
+ // Log retention
73
+ LOG_RETENTION: "log.retention"
74
+ };
75
+ function kindToComponent(kind) {
76
+ const dot = kind.indexOf(".");
77
+ return dot > 0 ? kind.slice(0, dot) : kind;
78
+ }
79
+
80
+ export {
81
+ LOG_KINDS,
82
+ kindToComponent
83
+ };
84
+ //# sourceMappingURL=chunk-WGTCA2NU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants/log-kinds.ts"],"sourcesContent":["/**\n * Structured log entry kinds — every logger call uses one of these.\n *\n * Convention: `{component}.{action}` — the component is derived from the\n * first segment (before the dot) for fast column filtering.\n */\nexport const LOG_KINDS = {\n // Context injection\n CONTEXT_QUERY: 'context.query',\n CONTEXT_SESSION: 'context.session',\n CONTEXT_PROMPT: 'context.prompt',\n CONTEXT_DIGEST: 'context.digest',\n CONTEXT_SEARCH: 'context.search',\n CONTEXT_EMBED: 'context.embed',\n CONTEXT_FILTER: 'context.filter',\n\n // Session lifecycle\n LIFECYCLE_REGISTER: 'lifecycle.register',\n LIFECYCLE_RECONCILE: 'lifecycle.reconcile',\n LIFECYCLE_UNREGISTER: 'lifecycle.unregister',\n LIFECYCLE_CLEANUP: 'lifecycle.cleanup',\n LIFECYCLE_AUTO_REGISTER: 'lifecycle.auto-register',\n\n // Hooks (event ingestion)\n HOOKS_EVENT: 'hooks.event',\n HOOKS_PROMPT: 'hooks.prompt',\n HOOKS_STOP: 'hooks.stop',\n HOOKS_TOOL: 'hooks.tool',\n HOOKS_SUBAGENT: 'hooks.subagent',\n\n // Capture (batch/activity recording)\n CAPTURE_BATCH: 'capture.batch',\n CAPTURE_ACTIVITY: 'capture.activity',\n CAPTURE_PLAN: 'capture.plan',\n CAPTURE_ATTACHMENT: 'capture.attachment',\n CAPTURE_BUFFER: 'capture.buffer',\n\n // Processor (stop-event session processing)\n PROCESSOR_SESSION: 'processor.session',\n PROCESSOR_TRANSCRIPT: 'processor.transcript',\n PROCESSOR_BATCH: 'processor.batch',\n PROCESSOR_TITLE: 'processor.title',\n\n // Agent\n AGENT_RUN: 'agent.run',\n AGENT_PHASE: 'agent.phase',\n AGENT_TASK: 'agent.task',\n AGENT_AUTO_RUN: 'agent.auto-run',\n AGENT_ERROR: 'agent.error',\n\n // Embedding\n EMBEDDING_EMBED: 'embedding.embed',\n EMBEDDING_RECONCILE: 'embedding.reconcile',\n EMBEDDING_SEARCH: 'embedding.search',\n EMBEDDING_REBUILD: 'embedding.rebuild',\n EMBEDDING_CLEANUP: 'embedding.cleanup',\n EMBEDDING_PROVIDER: 'embedding.provider',\n\n // Power management\n POWER_TICK: 'power.tick',\n POWER_STATE: 'power.state',\n POWER_JOB: 'power.job',\n POWER_JOB_ERROR: 'power.job-error',\n\n // Daemon core\n DAEMON_START: 'daemon.start',\n DAEMON_CONFIG: 'daemon.config',\n DAEMON_READY: 'daemon.ready',\n DAEMON_MIGRATION: 'daemon.migration',\n DAEMON_PORT: 'daemon.port',\n DAEMON_RECONCILE: 'daemon.reconcile',\n\n // Server (HTTP)\n SERVER_REQUEST: 'server.request',\n SERVER_STATIC: 'server.static',\n SERVER_ERROR: 'server.error',\n\n // Session maintenance job\n MAINTENANCE_SESSION: 'maintenance.session',\n MAINTENANCE_EMBEDDING: 'maintenance.embedding',\n\n // API operations\n API_SESSION_DELETE: 'api.session-delete',\n\n // MCP\n MCP_EVENT: 'mcp.event',\n\n // Log retention\n LOG_RETENTION: 'log.retention',\n} as const;\n\nexport type LogKind = (typeof LOG_KINDS)[keyof typeof LOG_KINDS];\n\n/**\n * Extract the component (first segment) from a kind string.\n * e.g., 'context.session' -> 'context'\n */\nexport function kindToComponent(kind: string): string {\n const dot = kind.indexOf('.');\n return dot > 0 ? kind.slice(0, dot) : kind;\n}\n"],"mappings":";;;AAMO,IAAM,YAAY;AAAA;AAAA,EAEvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,gBAAgB;AAAA;AAAA,EAGhB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,yBAAyB;AAAA;AAAA,EAGzB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,gBAAgB;AAAA;AAAA,EAGhB,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,aAAa;AAAA;AAAA,EAGb,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA;AAAA,EAGpB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA,EAGjB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,kBAAkB;AAAA;AAAA,EAGlB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,cAAc;AAAA;AAAA,EAGd,qBAAqB;AAAA,EACrB,uBAAuB;AAAA;AAAA,EAGvB,oBAAoB;AAAA;AAAA,EAGpB,WAAW;AAAA;AAAA,EAGX,eAAe;AACjB;AAQO,SAAS,gBAAgB,MAAsB;AACpD,QAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,SAAO,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI;AACxC;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
3
  STDIN_TIMEOUT_MS
4
- } from "./chunk-J4D4CROB.js";
4
+ } from "./chunk-5VZ52A4T.js";
5
5
 
6
6
  // src/hooks/read-stdin.ts
7
7
  function readStdin() {
@@ -18,4 +18,4 @@ function readStdin() {
18
18
  export {
19
19
  readStdin
20
20
  };
21
- //# sourceMappingURL=chunk-O6PERU7U.js.map
21
+ //# sourceMappingURL=chunk-XNOCTDHF.js.map
@@ -0,0 +1,80 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ getDatabase
4
+ } from "./chunk-MYX5NCRH.js";
5
+
6
+ // src/db/queries/resolution-events.ts
7
+ var DEFAULT_LIST_LIMIT = 100;
8
+ var EVENT_COLUMNS = [
9
+ "id",
10
+ "agent_id",
11
+ "spore_id",
12
+ "action",
13
+ "new_spore_id",
14
+ "reason",
15
+ "session_id",
16
+ "created_at"
17
+ ];
18
+ var SELECT_COLUMNS = EVENT_COLUMNS.join(", ");
19
+ function toResolutionEventRow(row) {
20
+ return {
21
+ id: row.id,
22
+ agent_id: row.agent_id,
23
+ spore_id: row.spore_id,
24
+ action: row.action,
25
+ new_spore_id: row.new_spore_id ?? null,
26
+ reason: row.reason ?? null,
27
+ session_id: row.session_id ?? null,
28
+ created_at: row.created_at
29
+ };
30
+ }
31
+ function insertResolutionEvent(data) {
32
+ const db = getDatabase();
33
+ db.prepare(
34
+ `INSERT INTO resolution_events (
35
+ id, agent_id, spore_id, action, new_spore_id, reason, session_id, created_at
36
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
37
+ ).run(
38
+ data.id,
39
+ data.agent_id,
40
+ data.spore_id,
41
+ data.action,
42
+ data.new_spore_id ?? null,
43
+ data.reason ?? null,
44
+ data.session_id ?? null,
45
+ data.created_at
46
+ );
47
+ return toResolutionEventRow(
48
+ db.prepare(`SELECT ${SELECT_COLUMNS} FROM resolution_events WHERE id = ?`).get(data.id)
49
+ );
50
+ }
51
+ function listResolutionEvents(options = {}) {
52
+ const db = getDatabase();
53
+ const conditions = [];
54
+ const params = [];
55
+ if (options.agent_id !== void 0) {
56
+ conditions.push(`agent_id = ?`);
57
+ params.push(options.agent_id);
58
+ }
59
+ if (options.spore_id !== void 0) {
60
+ conditions.push(`spore_id = ?`);
61
+ params.push(options.spore_id);
62
+ }
63
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
64
+ const limit = options.limit ?? DEFAULT_LIST_LIMIT;
65
+ params.push(limit);
66
+ const rows = db.prepare(
67
+ `SELECT ${SELECT_COLUMNS}
68
+ FROM resolution_events
69
+ ${where}
70
+ ORDER BY created_at DESC
71
+ LIMIT ?`
72
+ ).all(...params);
73
+ return rows.map(toResolutionEventRow);
74
+ }
75
+
76
+ export {
77
+ insertResolutionEvent,
78
+ listResolutionEvents
79
+ };
80
+ //# sourceMappingURL=chunk-YDN4OM33.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db/queries/resolution-events.ts"],"sourcesContent":["/**\n * Resolution event 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';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Default number of events returned by listResolutionEvents when no limit given. */\nconst DEFAULT_LIST_LIMIT = 100;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Fields required (or optional) when inserting a resolution event. */\nexport interface ResolutionEventInsert {\n id: string;\n agent_id: string;\n spore_id: string;\n action: string;\n created_at: number;\n new_spore_id?: string | null;\n reason?: string | null;\n session_id?: string | null;\n}\n\n/** Row shape returned from resolution_events queries (all columns). */\nexport interface ResolutionEventRow {\n id: string;\n agent_id: string;\n spore_id: string;\n action: string;\n new_spore_id: string | null;\n reason: string | null;\n session_id: string | null;\n created_at: number;\n}\n\n/** Filter options for `listResolutionEvents`. */\nexport interface ListResolutionEventsOptions {\n agent_id?: string;\n spore_id?: string;\n limit?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Column list\n// ---------------------------------------------------------------------------\n\nconst EVENT_COLUMNS = [\n 'id',\n 'agent_id',\n 'spore_id',\n 'action',\n 'new_spore_id',\n 'reason',\n 'session_id',\n 'created_at',\n] as const;\n\nconst SELECT_COLUMNS = EVENT_COLUMNS.join(', ');\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Normalize a SQLite result row into a typed ResolutionEventRow. */\nfunction toResolutionEventRow(row: Record<string, unknown>): ResolutionEventRow {\n return {\n id: row.id as string,\n agent_id: row.agent_id as string,\n spore_id: row.spore_id as string,\n action: row.action as string,\n new_spore_id: (row.new_spore_id as string) ?? null,\n reason: (row.reason as string) ?? null,\n session_id: (row.session_id as string) ?? null,\n created_at: row.created_at as number,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Insert a new resolution event.\n */\nexport function insertResolutionEvent(\n data: ResolutionEventInsert,\n): ResolutionEventRow {\n const db = getDatabase();\n\n db.prepare(\n `INSERT INTO resolution_events (\n id, agent_id, spore_id, action, new_spore_id, reason, session_id, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n data.id,\n data.agent_id,\n data.spore_id,\n data.action,\n data.new_spore_id ?? null,\n data.reason ?? null,\n data.session_id ?? null,\n data.created_at,\n );\n\n return toResolutionEventRow(\n db.prepare(`SELECT ${SELECT_COLUMNS} FROM resolution_events WHERE id = ?`).get(data.id) as Record<string, unknown>,\n );\n}\n\n/**\n * List resolution events with optional filters, ordered by created_at DESC.\n */\nexport function listResolutionEvents(\n options: ListResolutionEventsOptions = {},\n): ResolutionEventRow[] {\n const db = getDatabase();\n\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent_id !== undefined) {\n conditions.push(`agent_id = ?`);\n params.push(options.agent_id);\n }\n\n if (options.spore_id !== undefined) {\n conditions.push(`spore_id = ?`);\n params.push(options.spore_id);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = options.limit ?? DEFAULT_LIST_LIMIT;\n\n params.push(limit);\n\n const rows = db.prepare(\n `SELECT ${SELECT_COLUMNS}\n FROM resolution_events\n ${where}\n ORDER BY created_at DESC\n LIMIT ?`,\n ).all(...params) as Record<string, unknown>[];\n\n return rows.map(toResolutionEventRow);\n}\n"],"mappings":";;;;;;AAcA,IAAM,qBAAqB;AAyC3B,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,iBAAiB,cAAc,KAAK,IAAI;AAO9C,SAAS,qBAAqB,KAAkD;AAC9E,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,UAAU,IAAI;AAAA,IACd,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI;AAAA,IACZ,cAAe,IAAI,gBAA2B;AAAA,IAC9C,QAAS,IAAI,UAAqB;AAAA,IAClC,YAAa,IAAI,cAAyB;AAAA,IAC1C,YAAY,IAAI;AAAA,EAClB;AACF;AASO,SAAS,sBACd,MACoB;AACpB,QAAM,KAAK,YAAY;AAEvB,KAAG;AAAA,IACD;AAAA;AAAA;AAAA,EAGF,EAAE;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,gBAAgB;AAAA,IACrB,KAAK,UAAU;AAAA,IACf,KAAK,cAAc;AAAA,IACnB,KAAK;AAAA,EACP;AAEA,SAAO;AAAA,IACL,GAAG,QAAQ,UAAU,cAAc,sCAAsC,EAAE,IAAI,KAAK,EAAE;AAAA,EACxF;AACF;AAKO,SAAS,qBACd,UAAuC,CAAC,GAClB;AACtB,QAAM,KAAK,YAAY;AAEvB,QAAM,aAAuB,CAAC;AAC9B,QAAM,SAAoB,CAAC;AAE3B,MAAI,QAAQ,aAAa,QAAW;AAClC,eAAW,KAAK,cAAc;AAC9B,WAAO,KAAK,QAAQ,QAAQ;AAAA,EAC9B;AAEA,MAAI,QAAQ,aAAa,QAAW;AAClC,eAAW,KAAK,cAAc;AAC9B,WAAO,KAAK,QAAQ,QAAQ;AAAA,EAC9B;AAEA,QAAM,QAAQ,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,OAAO,CAAC,KAAK;AAC5E,QAAM,QAAQ,QAAQ,SAAS;AAE/B,SAAO,KAAK,KAAK;AAEjB,QAAM,OAAO,GAAG;AAAA,IACd,UAAU,cAAc;AAAA;AAAA,OAErB,KAAK;AAAA;AAAA;AAAA,EAGV,EAAE,IAAI,GAAG,MAAM;AAEf,SAAO,KAAK,IAAI,oBAAoB;AACtC;","names":[]}