agentix-cli 0.26.0 → 0.27.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 (268) hide show
  1. package/dist/{App-BPNHIGUX.js → App-U52IPUK2.js} +2 -2
  2. package/dist/{ChatApp-6XSSZB4U.js → ChatApp-XP4OMHPL.js} +2 -2
  3. package/dist/agent-V2CA4TXD.js +2 -0
  4. package/dist/article-fields-L4D2BOGY.js +2 -0
  5. package/dist/article-quality-44ONVGLN.js +3 -0
  6. package/dist/article-quality-44ONVGLN.js.map +1 -0
  7. package/dist/{audit-JU3HWISB.js → audit-4245CX6P.js} +2 -2
  8. package/dist/backfill-MTD2B62I.js +6 -0
  9. package/dist/backfill-MTD2B62I.js.map +1 -0
  10. package/dist/{board-dashboard-M3372FLO.js → board-dashboard-TTMAYRLG.js} +1407 -447
  11. package/dist/board-dashboard-TTMAYRLG.js.map +1 -0
  12. package/dist/{builtin-FRKAQMFS.js → builtin-B67DMJ3M.js} +2 -2
  13. package/dist/calibration-ILS5OI44.js +2 -0
  14. package/dist/chunk-2T5W3ETS.js +5 -0
  15. package/dist/{chunk-K2CAPYES.js.map → chunk-2T5W3ETS.js.map} +1 -1
  16. package/dist/chunk-3SCPRYJB.js +5 -0
  17. package/dist/chunk-3SCPRYJB.js.map +1 -0
  18. package/dist/chunk-4BR7D2OU.js +36 -0
  19. package/dist/chunk-4BR7D2OU.js.map +1 -0
  20. package/dist/{chunk-P4VWIVKN.js → chunk-52ZPELD2.js} +403 -29
  21. package/dist/chunk-52ZPELD2.js.map +1 -0
  22. package/dist/{chunk-5U35WAZF.js → chunk-77OV7346.js} +6 -6
  23. package/dist/chunk-77OV7346.js.map +1 -0
  24. package/dist/chunk-AJ5RMU7X.js +2 -0
  25. package/dist/chunk-AJ5RMU7X.js.map +1 -0
  26. package/dist/chunk-AJONZWLT.js +2 -0
  27. package/dist/chunk-AJONZWLT.js.map +1 -0
  28. package/dist/chunk-AX2PWSRT.js +114 -0
  29. package/dist/chunk-AX2PWSRT.js.map +1 -0
  30. package/dist/chunk-BH3GTCZ6.js +2 -0
  31. package/dist/chunk-BH3GTCZ6.js.map +1 -0
  32. package/dist/chunk-BPIRO4YD.js +126 -0
  33. package/dist/chunk-BPIRO4YD.js.map +1 -0
  34. package/dist/chunk-CJQQIRPD.js +13 -0
  35. package/dist/chunk-CJQQIRPD.js.map +1 -0
  36. package/dist/chunk-DCDQZR7I.js +24 -0
  37. package/dist/chunk-DCDQZR7I.js.map +1 -0
  38. package/dist/chunk-EVWEG3VD.js +3 -0
  39. package/dist/chunk-EVWEG3VD.js.map +1 -0
  40. package/dist/chunk-F4HZTZHW.js +2 -0
  41. package/dist/chunk-F4HZTZHW.js.map +1 -0
  42. package/dist/chunk-F6CNF7V3.js +25 -0
  43. package/dist/chunk-F6CNF7V3.js.map +1 -0
  44. package/dist/chunk-FIEJDZVC.js +121 -0
  45. package/dist/chunk-FIEJDZVC.js.map +1 -0
  46. package/dist/chunk-FIOB3MEX.js +2 -0
  47. package/dist/{chunk-H5D7ATXS.js → chunk-FKBGJYWQ.js} +5 -5
  48. package/dist/chunk-FKBGJYWQ.js.map +1 -0
  49. package/dist/chunk-GDWJUGB5.js +9 -0
  50. package/dist/chunk-GDWJUGB5.js.map +1 -0
  51. package/dist/{chunk-BVGJSPW4.js → chunk-IB3F7VBE.js} +7 -7
  52. package/dist/{chunk-BVGJSPW4.js.map → chunk-IB3F7VBE.js.map} +1 -1
  53. package/dist/chunk-IBUSGCLQ.js +109 -0
  54. package/dist/chunk-IBUSGCLQ.js.map +1 -0
  55. package/dist/{chunk-LDHPMJ7M.js → chunk-IWMW5432.js} +3 -3
  56. package/dist/chunk-IWMW5432.js.map +1 -0
  57. package/dist/chunk-K33GIBSE.js +2 -0
  58. package/dist/chunk-K33GIBSE.js.map +1 -0
  59. package/dist/chunk-L2IZPR6P.js +45 -0
  60. package/dist/chunk-L2IZPR6P.js.map +1 -0
  61. package/dist/chunk-L2WSPY6S.js +2 -0
  62. package/dist/chunk-L2WSPY6S.js.map +1 -0
  63. package/dist/chunk-LCIREYTD.js +54 -0
  64. package/dist/chunk-LCIREYTD.js.map +1 -0
  65. package/dist/chunk-LNRB5MCU.js +530 -0
  66. package/dist/chunk-LNRB5MCU.js.map +1 -0
  67. package/dist/chunk-OPHIXXGI.js +157 -0
  68. package/dist/chunk-OPHIXXGI.js.map +1 -0
  69. package/dist/{chunk-JTJIPNXY.js → chunk-PNWNVOEZ.js} +1 -1
  70. package/dist/chunk-PNWNVOEZ.js.map +1 -0
  71. package/dist/{chunk-V3U4OF7L.js → chunk-UFAGYX73.js} +45 -47
  72. package/dist/chunk-UFAGYX73.js.map +1 -0
  73. package/dist/{chunk-DJEZ2HVU.js → chunk-VDMYBPYB.js} +1 -1
  74. package/dist/chunk-VDMYBPYB.js.map +1 -0
  75. package/dist/chunk-VTE7L6LO.js +5 -0
  76. package/dist/{chunk-O6YPEOQF.js.map → chunk-VTE7L6LO.js.map} +1 -1
  77. package/dist/chunk-W5C2GDNC.js +32 -0
  78. package/dist/{chunk-JP5IEXR7.js.map → chunk-W5C2GDNC.js.map} +1 -1
  79. package/dist/chunk-WPMX3VGI.js +3 -0
  80. package/dist/chunk-WPMX3VGI.js.map +1 -0
  81. package/dist/chunk-WZ72HX5C.js +1182 -0
  82. package/dist/chunk-WZ72HX5C.js.map +1 -0
  83. package/dist/chunk-ZTEU5JVQ.js +2 -0
  84. package/dist/chunk-ZTEU5JVQ.js.map +1 -0
  85. package/dist/{chunk-2WVX3LEC.js → chunk-ZVP6GB4G.js} +1 -1
  86. package/dist/chunk-ZVP6GB4G.js.map +1 -0
  87. package/dist/cli.js +1 -1
  88. package/dist/cli.js.map +1 -1
  89. package/dist/client-PX25MD47.js +2 -0
  90. package/dist/{compaction-NWEMOSHA.js → compaction-FD4R23HZ.js} +4 -4
  91. package/dist/config-HL5F36V4.js +2 -0
  92. package/dist/config-mutator-HBX53OMJ.js +2 -0
  93. package/dist/{conflict-detector-D7VIYPDI.js → conflict-detector-ZPOT3M2C.js} +2 -2
  94. package/dist/conflict-detector-ZPOT3M2C.js.map +1 -0
  95. package/dist/context-planner-AQHJMVY2.js +17 -0
  96. package/dist/context-planner-AQHJMVY2.js.map +1 -0
  97. package/dist/debug-3MEUO2P2.js +2 -0
  98. package/dist/{discover-XJXQXXIO.js → discover-D4VVRNAI.js} +2 -2
  99. package/dist/discover-D4VVRNAI.js.map +1 -0
  100. package/dist/doctor-PBAH6XL3.js +2 -0
  101. package/dist/editor-chat-OB7IQOB5.js +137 -0
  102. package/dist/editor-chat-OB7IQOB5.js.map +1 -0
  103. package/dist/entry-triage-LK34TSQD.js +2 -0
  104. package/dist/entry-triage-LK34TSQD.js.map +1 -0
  105. package/dist/facts-YVEJOM7O.js +22 -0
  106. package/dist/facts-YVEJOM7O.js.map +1 -0
  107. package/dist/heal-FVLBHYP7.js +2 -0
  108. package/dist/index.d.ts +1016 -65
  109. package/dist/index.js +13 -13
  110. package/dist/index.js.map +1 -1
  111. package/dist/{ingest-whatsapp-LZE62INA.js → ingest-whatsapp-NS4OWDOU.js} +2 -2
  112. package/dist/loader-4ZGTK7LD.js +2 -0
  113. package/dist/loader-BOKE5M5S.js +2 -0
  114. package/dist/memory-extract-F5ZHWY5E.js +2 -0
  115. package/dist/{migrate-v2-QO7SLKIM.js → migrate-v2-V4WN2VVM.js} +2 -2
  116. package/dist/ntfy-X7EPB3TG.js +4 -0
  117. package/dist/ntfy-X7EPB3TG.js.map +1 -0
  118. package/dist/processes-WU23U2OJ.js +2 -0
  119. package/dist/program-YGXVCV2Y.js +2 -0
  120. package/dist/{projects-api-KRME2YKZ.js → projects-api-QE6L65SK.js} +2 -2
  121. package/dist/{projects-mutate-3NHVG437.js → projects-mutate-MY7JTLSZ.js} +2 -2
  122. package/dist/providers-KO2DODIO.js +2 -0
  123. package/dist/query-ZKTFJMNE.js +2 -0
  124. package/dist/questions-4B4KSPXG.js +3 -0
  125. package/dist/questions-4B4KSPXG.js.map +1 -0
  126. package/dist/recipes-7S4MC5OJ.js +2 -0
  127. package/dist/registry-PSZDPFZK.js +2 -0
  128. package/dist/review-candidates-AEUXRQQC.js +4 -0
  129. package/dist/review-candidates-AEUXRQQC.js.map +1 -0
  130. package/dist/review-store-B4YE3EFK.js +4 -0
  131. package/dist/review-store-B4YE3EFK.js.map +1 -0
  132. package/dist/{rotation-memo-B3EXXSEH.js → rotation-memo-7T75BLEX.js} +2 -2
  133. package/dist/routing-4PV66BK6.js +2 -0
  134. package/dist/routing-4PV66BK6.js.map +1 -0
  135. package/dist/runner-YRBVNYTY.js +2 -0
  136. package/dist/scheduler-GZZAN6ZG.js +2 -0
  137. package/dist/seat-VZ7AVO27.js +2 -0
  138. package/dist/select-F5I5PO2O.js +2 -0
  139. package/dist/select-F5I5PO2O.js.map +1 -0
  140. package/dist/store-MCOA6N4F.js +2 -0
  141. package/dist/{subagent-WV7QKQ3L.js → subagent-2SJHSSJS.js} +2 -2
  142. package/dist/{surface-usage-PRL6Z4U3.js → surface-usage-NS74AXSE.js} +2 -2
  143. package/dist/timers-PCB4ZIBD.js +2 -0
  144. package/dist/triage-backtest-JNO7RKX7.js +2 -0
  145. package/dist/triage-backtest-JNO7RKX7.js.map +1 -0
  146. package/dist/types-H5ENIUIT.js +2 -0
  147. package/dist/types-OIFU3KSQ.js +2 -0
  148. package/dist/web/workflow-editor.global.js +1542 -0
  149. package/dist/web/workflow-editor.global.js.map +1 -0
  150. package/dist/{whatsapp-state-XMTCSRXU.js → whatsapp-state-6D6FHHD2.js} +2 -2
  151. package/dist/wiki-N5SMP3DT.js +2 -0
  152. package/dist/wiki-N5SMP3DT.js.map +1 -0
  153. package/dist/workflows/templates/branching.yaml +1 -1
  154. package/dist/{workspace-setup-TBQAHYHJ.js → workspace-setup-B3F3TUDE.js} +2 -2
  155. package/dist/workspace-setup-B3F3TUDE.js.map +1 -0
  156. package/package.json +1 -1
  157. package/dist/agent-5QMITZT6.js +0 -2
  158. package/dist/architect-SEPWMWS4.js +0 -2
  159. package/dist/board-dashboard-M3372FLO.js.map +0 -1
  160. package/dist/chunk-2WVX3LEC.js.map +0 -1
  161. package/dist/chunk-3WQFCIB6.js +0 -24
  162. package/dist/chunk-3WQFCIB6.js.map +0 -1
  163. package/dist/chunk-4YCH6IZV.js +0 -2
  164. package/dist/chunk-53NRX2NA.js +0 -2
  165. package/dist/chunk-53NRX2NA.js.map +0 -1
  166. package/dist/chunk-5U35WAZF.js.map +0 -1
  167. package/dist/chunk-BFXONUUN.js +0 -108
  168. package/dist/chunk-BFXONUUN.js.map +0 -1
  169. package/dist/chunk-BFZUG66X.js +0 -45
  170. package/dist/chunk-BFZUG66X.js.map +0 -1
  171. package/dist/chunk-BTHHSY7D.js +0 -13
  172. package/dist/chunk-BTHHSY7D.js.map +0 -1
  173. package/dist/chunk-D46VZ7K7.js +0 -116
  174. package/dist/chunk-D46VZ7K7.js.map +0 -1
  175. package/dist/chunk-DJEZ2HVU.js.map +0 -1
  176. package/dist/chunk-E5CXCI33.js +0 -155
  177. package/dist/chunk-E5CXCI33.js.map +0 -1
  178. package/dist/chunk-FDWOECJY.js +0 -54
  179. package/dist/chunk-FDWOECJY.js.map +0 -1
  180. package/dist/chunk-H5D7ATXS.js.map +0 -1
  181. package/dist/chunk-HR4JSRZS.js +0 -3
  182. package/dist/chunk-HR4JSRZS.js.map +0 -1
  183. package/dist/chunk-ISEBLHWX.js +0 -118
  184. package/dist/chunk-ISEBLHWX.js.map +0 -1
  185. package/dist/chunk-JP5IEXR7.js +0 -32
  186. package/dist/chunk-JTJIPNXY.js.map +0 -1
  187. package/dist/chunk-K2CAPYES.js +0 -5
  188. package/dist/chunk-LDHPMJ7M.js.map +0 -1
  189. package/dist/chunk-METYYZKQ.js +0 -1115
  190. package/dist/chunk-METYYZKQ.js.map +0 -1
  191. package/dist/chunk-MTAPOCGA.js +0 -47
  192. package/dist/chunk-MTAPOCGA.js.map +0 -1
  193. package/dist/chunk-O6YPEOQF.js +0 -5
  194. package/dist/chunk-P4VWIVKN.js.map +0 -1
  195. package/dist/chunk-SR3X25TN.js +0 -3
  196. package/dist/chunk-SR3X25TN.js.map +0 -1
  197. package/dist/chunk-UHE5FCPB.js +0 -431
  198. package/dist/chunk-UHE5FCPB.js.map +0 -1
  199. package/dist/chunk-V3U4OF7L.js.map +0 -1
  200. package/dist/chunk-VJUTQAPJ.js +0 -2
  201. package/dist/chunk-VJUTQAPJ.js.map +0 -1
  202. package/dist/chunk-VT5XYFDD.js +0 -126
  203. package/dist/chunk-VT5XYFDD.js.map +0 -1
  204. package/dist/client-HGKAC6VP.js +0 -2
  205. package/dist/config-A4RWEJHV.js +0 -2
  206. package/dist/config-mutator-MNSFUN7D.js +0 -2
  207. package/dist/conflict-detector-D7VIYPDI.js.map +0 -1
  208. package/dist/context-planner-45GEWKGL.js +0 -17
  209. package/dist/context-planner-45GEWKGL.js.map +0 -1
  210. package/dist/debug-N3B5NVJU.js +0 -2
  211. package/dist/discover-XJXQXXIO.js.map +0 -1
  212. package/dist/doctor-3Q36ZFE6.js +0 -2
  213. package/dist/heal-HZ3EQD52.js +0 -2
  214. package/dist/loader-5CA3O5GM.js +0 -2
  215. package/dist/loader-6IHUCPVO.js +0 -2
  216. package/dist/memory-extract-AENFVVO5.js +0 -2
  217. package/dist/processes-UIC4XXA6.js +0 -2
  218. package/dist/program-SAUNRCCD.js +0 -2
  219. package/dist/providers-L27BJ5A6.js +0 -2
  220. package/dist/query-HZYYRCLU.js +0 -2
  221. package/dist/recipes-EPLE2SNT.js +0 -2
  222. package/dist/registry-HK3WQ7BS.js +0 -2
  223. package/dist/runner-BFYDWPUO.js +0 -2
  224. package/dist/scheduler-6T2SU5ST.js +0 -2
  225. package/dist/store-I3HEWVLQ.js +0 -2
  226. package/dist/timers-5LPZN55J.js +0 -2
  227. package/dist/types-VECTMYTO.js +0 -2
  228. package/dist/types-Y6ZCZ52Z.js +0 -2
  229. package/dist/wiki-M6YNRFC4.js +0 -2
  230. /package/dist/{App-BPNHIGUX.js.map → App-U52IPUK2.js.map} +0 -0
  231. /package/dist/{ChatApp-6XSSZB4U.js.map → ChatApp-XP4OMHPL.js.map} +0 -0
  232. /package/dist/{agent-5QMITZT6.js.map → agent-V2CA4TXD.js.map} +0 -0
  233. /package/dist/{architect-SEPWMWS4.js.map → article-fields-L4D2BOGY.js.map} +0 -0
  234. /package/dist/{audit-JU3HWISB.js.map → audit-4245CX6P.js.map} +0 -0
  235. /package/dist/{builtin-FRKAQMFS.js.map → builtin-B67DMJ3M.js.map} +0 -0
  236. /package/dist/{chunk-4YCH6IZV.js.map → calibration-ILS5OI44.js.map} +0 -0
  237. /package/dist/{client-HGKAC6VP.js.map → chunk-FIOB3MEX.js.map} +0 -0
  238. /package/dist/{config-A4RWEJHV.js.map → client-PX25MD47.js.map} +0 -0
  239. /package/dist/{compaction-NWEMOSHA.js.map → compaction-FD4R23HZ.js.map} +0 -0
  240. /package/dist/{config-mutator-MNSFUN7D.js.map → config-HL5F36V4.js.map} +0 -0
  241. /package/dist/{debug-N3B5NVJU.js.map → config-mutator-HBX53OMJ.js.map} +0 -0
  242. /package/dist/{doctor-3Q36ZFE6.js.map → debug-3MEUO2P2.js.map} +0 -0
  243. /package/dist/{heal-HZ3EQD52.js.map → doctor-PBAH6XL3.js.map} +0 -0
  244. /package/dist/{loader-5CA3O5GM.js.map → heal-FVLBHYP7.js.map} +0 -0
  245. /package/dist/{ingest-whatsapp-LZE62INA.js.map → ingest-whatsapp-NS4OWDOU.js.map} +0 -0
  246. /package/dist/{loader-6IHUCPVO.js.map → loader-4ZGTK7LD.js.map} +0 -0
  247. /package/dist/{memory-extract-AENFVVO5.js.map → loader-BOKE5M5S.js.map} +0 -0
  248. /package/dist/{processes-UIC4XXA6.js.map → memory-extract-F5ZHWY5E.js.map} +0 -0
  249. /package/dist/{migrate-v2-QO7SLKIM.js.map → migrate-v2-V4WN2VVM.js.map} +0 -0
  250. /package/dist/{program-SAUNRCCD.js.map → processes-WU23U2OJ.js.map} +0 -0
  251. /package/dist/{providers-L27BJ5A6.js.map → program-YGXVCV2Y.js.map} +0 -0
  252. /package/dist/{projects-api-KRME2YKZ.js.map → projects-api-QE6L65SK.js.map} +0 -0
  253. /package/dist/{projects-mutate-3NHVG437.js.map → projects-mutate-MY7JTLSZ.js.map} +0 -0
  254. /package/dist/{query-HZYYRCLU.js.map → providers-KO2DODIO.js.map} +0 -0
  255. /package/dist/{recipes-EPLE2SNT.js.map → query-ZKTFJMNE.js.map} +0 -0
  256. /package/dist/{registry-HK3WQ7BS.js.map → recipes-7S4MC5OJ.js.map} +0 -0
  257. /package/dist/{runner-BFYDWPUO.js.map → registry-PSZDPFZK.js.map} +0 -0
  258. /package/dist/{rotation-memo-B3EXXSEH.js.map → rotation-memo-7T75BLEX.js.map} +0 -0
  259. /package/dist/{scheduler-6T2SU5ST.js.map → runner-YRBVNYTY.js.map} +0 -0
  260. /package/dist/{store-I3HEWVLQ.js.map → scheduler-GZZAN6ZG.js.map} +0 -0
  261. /package/dist/{surface-usage-PRL6Z4U3.js.map → seat-VZ7AVO27.js.map} +0 -0
  262. /package/dist/{timers-5LPZN55J.js.map → store-MCOA6N4F.js.map} +0 -0
  263. /package/dist/{subagent-WV7QKQ3L.js.map → subagent-2SJHSSJS.js.map} +0 -0
  264. /package/dist/{types-VECTMYTO.js.map → surface-usage-NS74AXSE.js.map} +0 -0
  265. /package/dist/{types-Y6ZCZ52Z.js.map → timers-PCB4ZIBD.js.map} +0 -0
  266. /package/dist/{wiki-M6YNRFC4.js.map → types-H5ENIUIT.js.map} +0 -0
  267. /package/dist/{workspace-setup-TBQAHYHJ.js.map → types-OIFU3KSQ.js.map} +0 -0
  268. /package/dist/{whatsapp-state-XMTCSRXU.js.map → whatsapp-state-6D6FHHD2.js.map} +0 -0
@@ -1,2 +1,2 @@
1
- import{a,b,c,i as d,j as e}from"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-4YCH6IZV.js";export{e as _resetBuiltinsForTesting,a as getBuiltin,b as listBuiltins,d as registerAllBuiltins,c as runBuiltin};
2
- //# sourceMappingURL=builtin-FRKAQMFS.js.map
1
+ import{a,b,c,i as d,j as e}from"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-FIOB3MEX.js";export{e as _resetBuiltinsForTesting,a as getBuiltin,b as listBuiltins,d as registerAllBuiltins,c as runBuiltin};
2
+ //# sourceMappingURL=builtin-B67DMJ3M.js.map
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e,f,g,h,i,j,k,l}from"./chunk-BH3GTCZ6.js";import"./chunk-FIOB3MEX.js";l();export{a as agreement,h as applyTemperature,j as bootstrapInterval,e as brier,k as calibrationReport,g as coverageCurve,c as ece,i as fitTemperature,f as logLoss,d as mce,b as reliabilityBins};
2
+ //# sourceMappingURL=calibration-ILS5OI44.js.map
@@ -0,0 +1,5 @@
1
+ import{e as m,f as $,j as S}from"./chunk-CJQQIRPD.js";S();import{readFileSync as x,writeFileSync as P,existsSync as b}from"fs";import{resolve as f}from"path";function w(r){if(r)return f(r);let e=[f(process.cwd(),"agentx.json"),f(process.cwd(),".agentx/config.json")];for(let n of e)if(b(n))return n;return e[0]}function v(r){return JSON.parse(JSON.stringify(r))}async function O(r){try{let e=await fetch(`${r.replace(/\/$/,"")}/reload`,{method:"POST",signal:AbortSignal.timeout(3e3)});return e.ok?{ok:!0}:{ok:!1,reason:`HTTP ${e.status}`}}catch(e){return{ok:!1,reason:e?.cause?.code||e?.message||"unreachable"}}}async function J(r,e={}){let{validate:n=!0,dryRun:t=!1,reload:s=!0,configPath:u,daemonUrl:c}=e,o=w(u);if(!b(o))return{success:!1,path:o,error:`Config not found at ${o}. Run \`agentx init\` first.`};let d;try{d=x(o,"utf-8")}catch(a){return{success:!1,path:o,error:`Cannot read ${o}: ${a.message}`}}let g;try{g=JSON.parse(d)}catch(a){return{success:!1,path:o,error:`Invalid JSON in ${o}: ${a.message}`}}let i=v(g);try{await r(i)}catch(a){return{success:!1,path:o,error:`Mutator threw: ${a.message}`}}if(n){let a=$(i),l=m.safeParse(a);if(!l.success){let k=l.error.issues.map(y=>` ${y.path.join(".")||"<root>"}: ${y.message}`).join(`
2
+ `);return{success:!1,path:o,error:`Validation failed:
3
+ ${k}`,after:i}}}if(t)return{success:!0,path:o,after:i,dryRun:!0};try{P(o,JSON.stringify(i,null,2)+`
4
+ `)}catch(a){return{success:!1,path:o,error:`Write failed: ${a.message}`,after:i}}let p=!1,h;if(s){let a=c||R(i),l=await O(a);l.ok?p=!0:h=l.reason}return{success:!0,path:o,after:i,reloaded:p,reloadSkipped:h}}function R(r){let e=r?.node?.bind;if(!e)return"http://127.0.0.1:18800";let[n,t]=e.split(":");return`http://${n==="0.0.0.0"||n==="::"?"127.0.0.1":n}:${t}`}function N(r,e,n){let t=e.split("."),s=r;for(let u=0;u<t.length-1;u++){let c=t[u];(s[c]===void 0||s[c]===null)&&(s[c]={}),s=s[c]}s[t[t.length-1]]=n}function j(r,e){let n=e.split("."),t=r;for(let s of n){if(t==null)return;t=t[s]}return t}function A(r,e){let n=e.split("."),t=r;for(let s=0;s<n.length-1;s++){if(t==null)return;t=t[n[s]]}t!=null&&delete t[n[n.length-1]]}export{J as a,N as b,j as c,A as d};
5
+ //# sourceMappingURL=chunk-2T5W3ETS.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/daemon/config-mutator.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { daemonConfigSchema, expandEnvVars } from \"./config\"\n\n// --- Config mutator ---\n//\n// Single helper for every \"edit agentx.json\" code path. Handles:\n// 1. Read raw JSON (preserves ${VAR} tokens)\n// 2. Call user-supplied mutator on a deep clone\n// 3. Validate the env-expanded clone through the Zod schema\n// 4. Pretty-print and write back (raw, unexpanded form)\n// 5. Signal the running daemon via POST /reload if reachable\n//\n// Commands that previously called saveConfig() now go through this,\n// so every add-wizard gets pre-save validation and auto-reload for free.\n\nexport interface MutationOptions {\n /** Run the Zod schema against the env-expanded mutated config. Default: true. */\n validate?: boolean\n /** Compute + print the diff but do NOT write. Default: false. */\n dryRun?: boolean\n /** POST /reload to the running daemon if reachable. Default: true. */\n reload?: boolean\n /** Override the config file path. Default: ./agentx.json then .agentx/config.json. */\n configPath?: string\n /** Override daemon URL for the reload signal. Default: inferred from config. */\n daemonUrl?: string\n}\n\nexport interface MutationResult {\n success: boolean\n /** Path that was (or would have been) written. */\n path?: string\n /** The mutated raw config (before write, after mutator fn). */\n after?: unknown\n /** Validation error if the Zod parse failed. */\n error?: string\n /** True if the daemon acknowledged the reload. */\n reloaded?: boolean\n /** Reload failure reason — daemon unreachable, 5xx, etc. Not a hard error. */\n reloadSkipped?: string\n /** True when opts.dryRun was set. */\n dryRun?: boolean\n}\n\nfunction findConfigPath(override?: string): string {\n if (override) return resolve(override)\n const candidates = [\n resolve(process.cwd(), \"agentx.json\"),\n resolve(process.cwd(), \".agentx/config.json\"),\n ]\n for (const c of candidates) if (existsSync(c)) return c\n return candidates[0]\n}\n\nfunction deepClone<T>(v: T): T {\n return JSON.parse(JSON.stringify(v))\n}\n\nasync function signalReload(daemonUrl: string): Promise<{ ok: boolean; reason?: string }> {\n try {\n const res = await fetch(`${daemonUrl.replace(/\\/$/, \"\")}/reload`, {\n method: \"POST\",\n signal: AbortSignal.timeout(3000),\n })\n if (!res.ok) return { ok: false, reason: `HTTP ${res.status}` }\n return { ok: true }\n } catch (e: any) {\n // Daemon not running is fine — user is editing config before start.\n return { ok: false, reason: e?.cause?.code || e?.message || \"unreachable\" }\n }\n}\n\n/**\n * Read current config, apply `mutator(cfg)` in place, validate, write, reload.\n *\n * The mutator receives the raw parsed JSON (with `${VAR}` tokens intact). Mutate\n * the object directly — no need to return anything. Validation runs against an\n * env-expanded clone so schema errors are caught before we overwrite the file.\n */\nexport async function applyConfigMutation(\n mutator: (cfg: any) => void | Promise<void>,\n opts: MutationOptions = {},\n): Promise<MutationResult> {\n const {\n validate = true,\n dryRun = false,\n reload = true,\n configPath,\n daemonUrl,\n } = opts\n\n const path = findConfigPath(configPath)\n\n if (!existsSync(path)) {\n return { success: false, path, error: `Config not found at ${path}. Run \\`agentx init\\` first.` }\n }\n\n let raw: string\n try {\n raw = readFileSync(path, \"utf-8\")\n } catch (e: any) {\n return { success: false, path, error: `Cannot read ${path}: ${e.message}` }\n }\n\n let current: any\n try {\n current = JSON.parse(raw)\n } catch (e: any) {\n return { success: false, path, error: `Invalid JSON in ${path}: ${e.message}` }\n }\n\n const mutated = deepClone(current)\n try {\n await mutator(mutated)\n } catch (e: any) {\n return { success: false, path, error: `Mutator threw: ${e.message}` }\n }\n\n if (validate) {\n const expanded = expandEnvVars(mutated)\n const parsed = daemonConfigSchema.safeParse(expanded)\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => ` ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\n .join(\"\\n\")\n return { success: false, path, error: `Validation failed:\\n${issues}`, after: mutated }\n }\n }\n\n if (dryRun) {\n return { success: true, path, after: mutated, dryRun: true }\n }\n\n try {\n writeFileSync(path, JSON.stringify(mutated, null, 2) + \"\\n\")\n } catch (e: any) {\n return { success: false, path, error: `Write failed: ${e.message}`, after: mutated }\n }\n\n let reloaded = false\n let reloadSkipped: string | undefined\n\n if (reload) {\n const url = daemonUrl || inferDaemonUrl(mutated)\n const res = await signalReload(url)\n if (res.ok) reloaded = true\n else reloadSkipped = res.reason\n }\n\n return { success: true, path, after: mutated, reloaded, reloadSkipped }\n}\n\nfunction inferDaemonUrl(cfg: any): string {\n const bind: string | undefined = cfg?.node?.bind\n if (!bind) return \"http://127.0.0.1:18800\"\n // bind is \"host:port\" (host may be 0.0.0.0)\n const [host, port] = bind.split(\":\")\n const reachable = host === \"0.0.0.0\" || host === \"::\" ? \"127.0.0.1\" : host\n return `http://${reachable}:${port}`\n}\n\n/**\n * Convenience wrapper for dot-path set: `agents.devops.model` = value.\n * Creates intermediate objects as needed. Array indices (`crons.foo.onError.0`)\n * supported.\n */\nexport function setAtPath(obj: any, path: string, value: unknown): void {\n const parts = path.split(\".\")\n let cur = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i]\n if (cur[k] === undefined || cur[k] === null) cur[k] = {}\n cur = cur[k]\n }\n cur[parts[parts.length - 1]] = value\n}\n\nexport function getAtPath(obj: any, path: string): unknown {\n const parts = path.split(\".\")\n let cur = obj\n for (const k of parts) {\n if (cur == null) return undefined\n cur = cur[k]\n }\n return cur\n}\n\nexport function unsetAtPath(obj: any, path: string): void {\n const parts = path.split(\".\")\n let cur = obj\n for (let i = 0; i < parts.length - 1; i++) {\n if (cur == null) return\n cur = cur[parts[i]]\n }\n if (cur != null) delete cur[parts[parts.length - 1]]\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","existsSync","resolve","findConfigPath","override","resolve","candidates","c","existsSync","deepClone","v","signalReload","daemonUrl","res","applyConfigMutation","mutator","opts","validate","dryRun","reload","configPath","path","raw","readFileSync","e","current","mutated","expanded","expandEnvVars","parsed","daemonConfigSchema","issues","i","writeFileSync","reloaded","reloadSkipped","url","inferDaemonUrl","cfg","bind","host","port","setAtPath","obj","value","parts","cur","k","getAtPath","unsetAtPath"]}
1
+ {"version":3,"sources":["../src/daemon/config-mutator.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { daemonConfigSchema, expandEnvVars } from \"./config\"\n\n// --- Config mutator ---\n//\n// Single helper for every \"edit agentx.json\" code path. Handles:\n// 1. Read raw JSON (preserves ${VAR} tokens)\n// 2. Call user-supplied mutator on a deep clone\n// 3. Validate the env-expanded clone through the Zod schema\n// 4. Pretty-print and write back (raw, unexpanded form)\n// 5. Signal the running daemon via POST /reload if reachable\n//\n// Commands that previously called saveConfig() now go through this,\n// so every add-wizard gets pre-save validation and auto-reload for free.\n\nexport interface MutationOptions {\n /** Run the Zod schema against the env-expanded mutated config. Default: true. */\n validate?: boolean\n /** Compute + print the diff but do NOT write. Default: false. */\n dryRun?: boolean\n /** POST /reload to the running daemon if reachable. Default: true. */\n reload?: boolean\n /** Override the config file path. Default: ./agentx.json then .agentx/config.json. */\n configPath?: string\n /** Override daemon URL for the reload signal. Default: inferred from config. */\n daemonUrl?: string\n}\n\nexport interface MutationResult {\n success: boolean\n /** Path that was (or would have been) written. */\n path?: string\n /** The mutated raw config (before write, after mutator fn). */\n after?: unknown\n /** Validation error if the Zod parse failed. */\n error?: string\n /** True if the daemon acknowledged the reload. */\n reloaded?: boolean\n /** Reload failure reason — daemon unreachable, 5xx, etc. Not a hard error. */\n reloadSkipped?: string\n /** True when opts.dryRun was set. */\n dryRun?: boolean\n}\n\nfunction findConfigPath(override?: string): string {\n if (override) return resolve(override)\n const candidates = [\n resolve(process.cwd(), \"agentx.json\"),\n resolve(process.cwd(), \".agentx/config.json\"),\n ]\n for (const c of candidates) if (existsSync(c)) return c\n return candidates[0]\n}\n\nfunction deepClone<T>(v: T): T {\n return JSON.parse(JSON.stringify(v))\n}\n\nasync function signalReload(daemonUrl: string): Promise<{ ok: boolean; reason?: string }> {\n try {\n const res = await fetch(`${daemonUrl.replace(/\\/$/, \"\")}/reload`, {\n method: \"POST\",\n signal: AbortSignal.timeout(3000),\n })\n if (!res.ok) return { ok: false, reason: `HTTP ${res.status}` }\n return { ok: true }\n } catch (e: any) {\n // Daemon not running is fine — user is editing config before start.\n return { ok: false, reason: e?.cause?.code || e?.message || \"unreachable\" }\n }\n}\n\n/**\n * Read current config, apply `mutator(cfg)` in place, validate, write, reload.\n *\n * The mutator receives the raw parsed JSON (with `${VAR}` tokens intact). Mutate\n * the object directly — no need to return anything. Validation runs against an\n * env-expanded clone so schema errors are caught before we overwrite the file.\n */\nexport async function applyConfigMutation(\n mutator: (cfg: any) => void | Promise<void>,\n opts: MutationOptions = {},\n): Promise<MutationResult> {\n const {\n validate = true,\n dryRun = false,\n reload = true,\n configPath,\n daemonUrl,\n } = opts\n\n const path = findConfigPath(configPath)\n\n if (!existsSync(path)) {\n return { success: false, path, error: `Config not found at ${path}. Run \\`agentx init\\` first.` }\n }\n\n let raw: string\n try {\n raw = readFileSync(path, \"utf-8\")\n } catch (e: any) {\n return { success: false, path, error: `Cannot read ${path}: ${e.message}` }\n }\n\n let current: any\n try {\n current = JSON.parse(raw)\n } catch (e: any) {\n return { success: false, path, error: `Invalid JSON in ${path}: ${e.message}` }\n }\n\n const mutated = deepClone(current)\n try {\n await mutator(mutated)\n } catch (e: any) {\n return { success: false, path, error: `Mutator threw: ${e.message}` }\n }\n\n if (validate) {\n const expanded = expandEnvVars(mutated)\n const parsed = daemonConfigSchema.safeParse(expanded)\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => ` ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\n .join(\"\\n\")\n return { success: false, path, error: `Validation failed:\\n${issues}`, after: mutated }\n }\n }\n\n if (dryRun) {\n return { success: true, path, after: mutated, dryRun: true }\n }\n\n try {\n writeFileSync(path, JSON.stringify(mutated, null, 2) + \"\\n\")\n } catch (e: any) {\n return { success: false, path, error: `Write failed: ${e.message}`, after: mutated }\n }\n\n let reloaded = false\n let reloadSkipped: string | undefined\n\n if (reload) {\n const url = daemonUrl || inferDaemonUrl(mutated)\n const res = await signalReload(url)\n if (res.ok) reloaded = true\n else reloadSkipped = res.reason\n }\n\n return { success: true, path, after: mutated, reloaded, reloadSkipped }\n}\n\nfunction inferDaemonUrl(cfg: any): string {\n const bind: string | undefined = cfg?.node?.bind\n if (!bind) return \"http://127.0.0.1:18800\"\n // bind is \"host:port\" (host may be 0.0.0.0)\n const [host, port] = bind.split(\":\")\n const reachable = host === \"0.0.0.0\" || host === \"::\" ? \"127.0.0.1\" : host\n return `http://${reachable}:${port}`\n}\n\n/**\n * Convenience wrapper for dot-path set: `agents.devops.model` = value.\n * Creates intermediate objects as needed. Array indices (`crons.foo.onError.0`)\n * supported.\n */\nexport function setAtPath(obj: any, path: string, value: unknown): void {\n const parts = path.split(\".\")\n let cur = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i]\n if (cur[k] === undefined || cur[k] === null) cur[k] = {}\n cur = cur[k]\n }\n cur[parts[parts.length - 1]] = value\n}\n\nexport function getAtPath(obj: any, path: string): unknown {\n const parts = path.split(\".\")\n let cur = obj\n for (const k of parts) {\n if (cur == null) return undefined\n cur = cur[k]\n }\n return cur\n}\n\nexport function unsetAtPath(obj: any, path: string): void {\n const parts = path.split(\".\")\n let cur = obj\n for (let i = 0; i < parts.length - 1; i++) {\n if (cur == null) return\n cur = cur[parts[i]]\n }\n if (cur != null) delete cur[parts[parts.length - 1]]\n}\n"],"mappings":"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","names":["init_config","readFileSync","writeFileSync","existsSync","resolve","findConfigPath","override","candidates","c","deepClone","v","signalReload","daemonUrl","res","applyConfigMutation","mutator","opts","validate","dryRun","reload","configPath","path","raw","e","current","mutated","expanded","expandEnvVars","parsed","daemonConfigSchema","issues","i","reloaded","reloadSkipped","url","inferDaemonUrl","cfg","bind","host","port","setAtPath","obj","value","parts","cur","k","getAtPath","unsetAtPath"]}
@@ -0,0 +1,5 @@
1
+ import{a as y,f as k}from"./chunk-F4HZTZHW.js";k();var v="article-fields",w=["foundation","pillar","walls","openings","furniture"],c={foundation:0,pillar:1,walls:2,openings:3,furniture:4},R={foundation:"what the thing is \u2014 without it the article is about nothing",pillar:"the facts the article exists to carry \u2014 without them it cannot be acted on",walls:"what it connects to \u2014 people, projects, systems, status",openings:"how to work with it \u2014 access conventions, language, ownership",furniture:"history and colour \u2014 useful, replaceable, last"};function f(e){return e.tier==="foundation"||e.tier==="pillar"}var l=[{key:"whatItIs",tier:"foundation",label:"what it is, in its own terms",question:"Does the article say what the subject is, in its own terms?"},{key:"whyItMatters",tier:"walls",label:"why it matters to our work",question:"Does the article say why the subject matters to our work?"},{key:"relationships",tier:"walls",label:"which named people, projects or systems it connects to",question:"Does the article connect the subject to specific named people, projects or systems?"}],q={person:[...l,{key:"role",tier:"pillar",label:"role or job title",question:"Does the article state this person's role or job title?"},{key:"organisation",tier:"pillar",label:"organisation or team, and their position in it",question:"Does the article name the organisation or team this person belongs to?"},{key:"contactValue",tier:"pillar",label:'contact identifiers VERBATIM \u2014 the actual values, not "reaches us on WhatsApp"',question:"Does the article give an actual contact value \u2014 a number, handle, email or address \u2014 rather than only naming a channel?"},{key:"language",tier:"openings",label:"preferred language",question:"Does the article say what language to use with this person?"},{key:"ourOwner",tier:"openings",label:"who on our side owns the relationship",question:"Does the article say who on our side owns this relationship?"}],place:[...l,{key:"address",tier:"pillar",label:"hostname, IP, URL or path",question:"Does the article give a hostname, IP, URL or filesystem path for this system?"},{key:"access",tier:"pillar",label:"how access is obtained",question:"Does the article say how access is obtained?"},{key:"runsWhat",tier:"walls",label:"what runs on or is stored in it",question:"Does the article say what runs on or is stored in this system?"},{key:"administrator",tier:"walls",label:"who administers it",question:"Does the article say who administers it?"}],project:[...l,{key:"oneLine",tier:"foundation",label:"what it is, in one line",question:"Does the article describe in one line what the project delivers?"},{key:"ownerClient",tier:"pillar",label:"client or internal owner",question:"Does the article name the client or internal owner?"},{key:"locations",tier:"pillar",label:"repository, environment and URLs",question:"Does the article give a repository, environment or URL for it?"},{key:"status",tier:"walls",label:"current status",question:"Does the article state the project's current status?"},{key:"people",tier:"walls",label:"who works on it",question:"Does the article name who works on it?"}],concept:[...l,{key:"definition",tier:"foundation",label:"a one-line definition, first",question:"Does the article open with a one-line definition of the concept?"},{key:"whenApplies",tier:"walls",label:"when it applies",question:"Does the article say when this concept applies?"}],pattern:[...l,{key:"definition",tier:"foundation",label:"a one-line statement of the pattern, first",question:"Does the article open with a one-line statement of the pattern?"},{key:"whenApplies",tier:"pillar",label:"when to apply it",question:"Does the article say when to apply it?"},{key:"whatToDo",tier:"pillar",label:"what to actually do",question:"Does the article say what to actually do?"}],event:[...l,{key:"when",tier:"foundation",label:"the date it happened",question:"Does the article give the date the event happened?"},{key:"outcome",tier:"pillar",label:"what changed as a result",question:"Does the article say what changed as a result?"},{key:"who",tier:"walls",label:"who was involved",question:"Does the article name who was involved?"}],decision:[...l,{key:"what",tier:"foundation",label:"what was decided",question:"Does the article state plainly what was decided?"},{key:"why",tier:"pillar",label:"the reasoning behind it",question:"Does the article give the reasoning behind the decision?"},{key:"when",tier:"walls",label:"when it was decided",question:"Does the article say when it was decided?"},{key:"consequence",tier:"walls",label:"what it changed",question:"Does the article say what the decision changed?"}]},E={contactValue:{heading:"Contact identifiers",match:/contact|reach|phone|whatsapp|e-?mail/i},organisation:{heading:"Organisation and position",match:/organis|organiz|company|employer|team and/i},role:{heading:"Role or job title",match:/role|job title/i},language:{heading:"Preferred language",match:/language/i},ourOwner:{heading:"Relationship owner",match:/relationship owner|owns the relationship|our owner/i},address:{heading:"Address",match:/hostname|address|url|path/i},access:{heading:"Access",match:/access|credential|how to get in/i},administrator:{heading:"Administrator",match:/administrat|maintained by|who runs/i},ownerClient:{heading:"Client or owner",match:/client|owner/i},status:{heading:"Status",match:/status/i},locations:{heading:"Repository and environments",match:/repositor|environment|url/i}},j={contactValue:{heading:"Contact identifiers",match:/contact|reach|phone|whatsapp|e-?mail/i,from:["phone","whatsapp","email","gitlab"]},organisation:{heading:"Organisation and position",match:/organis|organiz|company|employer|team and/i,from:["organisation"]},role:{heading:"Role or job title",match:/role|job title/i,from:["role"]}},A=["contactValue","organisation","role"],D={contactValue:["wacli","gog","gitlab"],organisation:["gog","gitlab","erp"],role:["gog","gitlab"],locations:["gitlab"],address:["gitlab"],ownerClient:["erp"]};function d(e){return q[e??""]??l}function T(e){return[...d(e)].sort((n,o)=>c[n.tier]-c[o.tier])}function I(e){let n={};for(let o of d(e))n[o.key]=y(o.question);return n}function F(e,n=12e3){let o=String(e.body??"").trim();return{title:e.title,type:e.type??null,body:o.length>n?`${o.slice(0,n)}
2
+ \u2026[truncated]`:o}}function C(e,n,o={}){let a=o.low??.3,u=o.high??.7,s=d(e),t=[],r=[],h=[];for(let i of s){let g=n[i.key]?.noul;if(g===void 0){h.push(i.key);continue}g>u?t.push(i.key):g<=a?r.push(i.key):h.push(i.key)}let p=Object.fromEntries(w.map(i=>[i,[]]));for(let i of s)r.includes(i.key)&&p[i.tier].push(i.key);let m=s.filter(i=>f(i)&&r.includes(i.key)).map(i=>i.key),b=w.find(i=>p[i].length>0)??null;return{type:e??"?",present:t,missing:r,unclear:h,missingCritical:m,missingByTier:p,worstTier:b,coverage:s.length?t.length/s.length:0,fit:m.length===0}}function L(e,n={}){let o=new Map(d(e.type==="?"?void 0:e.type).map(t=>[t.key,t])),a=n.maxTier?c[n.maxTier]:c.furniture,u=[...e.missing,...n.includeUnclear?e.unclear:[]],s=[];for(let t of u){let r=o.get(t);if(!r||c[r.tier]>a)continue;let h=D[t]??[];s.push({field:t,label:r.label,tier:r.tier,sources:h,needsHuman:h.length===0,uncertain:e.unclear.includes(t)})}return s.sort((t,r)=>c[t.tier]-c[r.tier]||Number(t.needsHuman)-Number(r.needsHuman)||t.field.localeCompare(r.field))}function S(){let e=["person","project","place","concept","pattern","event","decision"],n=new Set(l.map(a=>a.key)),o=a=>{if(a.includes("**"))throw new Error(`field label must not carry its own emphasis: ${a}`);return`**${a}**`};return e.map(a=>{let s=T(a).filter(t=>!n.has(t.key)).map(t=>f(t)?o(t.label):t.label);return`- **${a}** \u2014 ${s.join("; ")}.`}).join(`
3
+ `)}function O(){return w.map((e,n)=>`${n+1}. **${e}** \u2014 ${R[e]}`).join(`
4
+ `)}export{v as a,w as b,c,R as d,f as e,q as f,E as g,j as h,A as i,D as j,d as k,T as l,I as m,F as n,C as o,L as p,S as q,O as r};
5
+ //# sourceMappingURL=chunk-3SCPRYJB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/decisions/seats/article-fields.ts"],"sourcesContent":["import { noul } from \"../questions\"\nimport type { NoulAnswer, Questions, StateValue } from \"../types\"\n\n// Required fields per article type, checked one Noul at a time, and\n// ordered by how much of the article rests on them.\n//\n// Grading an article on a 0-3 completeness scale tells you it scored\n// 2.17. It does not tell you what to do. Asking instead \"does this state\n// a contact value for this person?\" returns 0.05, and that is a work\n// item.\n//\n// This is the fan-out Jev is built for: one article as shared state, one\n// yes/no per required field, every answer in a single call. Thirteen\n// fields cost the same round trip as one.\n//\n// The field lists mirror the Identity section the absorb prompt now\n// demands, so the same contract is stated once to the writer and once to\n// the checker. When they drift, the checker is right — it is the one\n// measured against real articles.\n\nexport const ARTICLE_FIELDS_SEAT = \"article-fields\"\n\n/**\n * Facts are not equally load-bearing, and absorb treats them as if they\n * were.\n *\n * A building is not finished by adding furniture to a slab, but that is\n * what a single absorb pass does: it reads a batch of conversation and\n * writes down what the conversation emphasised. Conversations are about\n * events, so absorb produces history — two dated invoice exchanges on a\n * page that never states the person's number. The furniture arrived\n * before the pillars, and nothing in the pipeline noticed, because\n * nothing in the pipeline had a notion of order.\n *\n * Naming the order makes the gap reportable, prioritisable, and\n * resolvable in passes. A missing foundation is a broken article; a\n * missing piece of furniture is a Tuesday.\n */\nexport const TIERS = [\"foundation\", \"pillar\", \"walls\", \"openings\", \"furniture\"] as const\nexport type Tier = (typeof TIERS)[number]\n\nexport const TIER_RANK: Record<Tier, number> = {\n foundation: 0, pillar: 1, walls: 2, openings: 3, furniture: 4,\n}\n\nexport const TIER_MEANING: Record<Tier, string> = {\n foundation: \"what the thing is — without it the article is about nothing\",\n pillar: \"the facts the article exists to carry — without them it cannot be acted on\",\n walls: \"what it connects to — people, projects, systems, status\",\n openings: \"how to work with it — access conventions, language, ownership\",\n furniture: \"history and colour — useful, replaceable, last\",\n}\n\nexport interface RequiredField {\n key: string\n /** Imperative form, rendered into the absorb prompt for the writer. */\n label: string\n /** Phrased as a yes/no about the article, never about the subject. */\n question: string\n tier: Tier\n}\n\n/**\n * Foundation and pillar are what \"critical\" used to mean, field for\n * field. Deriving it removes the second concept rather than adding one —\n * there is no way now to mark a field critical and file it under\n * furniture.\n */\nexport function isCritical(f: RequiredField): boolean {\n return f.tier === \"foundation\" || f.tier === \"pillar\"\n}\n\nconst COMMON: RequiredField[] = [\n { key: \"whatItIs\", tier: \"foundation\", label: \"what it is, in its own terms\", question: \"Does the article say what the subject is, in its own terms?\" },\n { key: \"whyItMatters\", tier: \"walls\", label: \"why it matters to our work\", question: \"Does the article say why the subject matters to our work?\" },\n { key: \"relationships\", tier: \"walls\", label: \"which named people, projects or systems it connects to\", question: \"Does the article connect the subject to specific named people, projects or systems?\" },\n]\n\nexport const REQUIRED_FIELDS: Record<string, RequiredField[]> = {\n person: [\n ...COMMON,\n { key: \"role\", tier: \"pillar\", label: \"role or job title\", question: \"Does the article state this person's role or job title?\" },\n { key: \"organisation\", tier: \"pillar\", label: \"organisation or team, and their position in it\", question: \"Does the article name the organisation or team this person belongs to?\" },\n { key: \"contactValue\", tier: \"pillar\", label: \"contact identifiers VERBATIM — the actual values, not \\\"reaches us on WhatsApp\\\"\", question: \"Does the article give an actual contact value — a number, handle, email or address — rather than only naming a channel?\" },\n { key: \"language\", tier: \"openings\", label: \"preferred language\", question: \"Does the article say what language to use with this person?\" },\n { key: \"ourOwner\", tier: \"openings\", label: \"who on our side owns the relationship\", question: \"Does the article say who on our side owns this relationship?\" },\n ],\n place: [\n ...COMMON,\n { key: \"address\", tier: \"pillar\", label: \"hostname, IP, URL or path\", question: \"Does the article give a hostname, IP, URL or filesystem path for this system?\" },\n { key: \"access\", tier: \"pillar\", label: \"how access is obtained\", question: \"Does the article say how access is obtained?\" },\n { key: \"runsWhat\", tier: \"walls\", label: \"what runs on or is stored in it\", question: \"Does the article say what runs on or is stored in this system?\" },\n { key: \"administrator\", tier: \"walls\", label: \"who administers it\", question: \"Does the article say who administers it?\" },\n ],\n project: [\n ...COMMON,\n { key: \"oneLine\", tier: \"foundation\", label: \"what it is, in one line\", question: \"Does the article describe in one line what the project delivers?\" },\n { key: \"ownerClient\", tier: \"pillar\", label: \"client or internal owner\", question: \"Does the article name the client or internal owner?\" },\n { key: \"locations\", tier: \"pillar\", label: \"repository, environment and URLs\", question: \"Does the article give a repository, environment or URL for it?\" },\n { key: \"status\", tier: \"walls\", label: \"current status\", question: \"Does the article state the project's current status?\" },\n { key: \"people\", tier: \"walls\", label: \"who works on it\", question: \"Does the article name who works on it?\" },\n ],\n concept: [\n ...COMMON,\n { key: \"definition\", tier: \"foundation\", label: \"a one-line definition, first\", question: \"Does the article open with a one-line definition of the concept?\" },\n { key: \"whenApplies\", tier: \"walls\", label: \"when it applies\", question: \"Does the article say when this concept applies?\" },\n ],\n pattern: [\n ...COMMON,\n { key: \"definition\", tier: \"foundation\", label: \"a one-line statement of the pattern, first\", question: \"Does the article open with a one-line statement of the pattern?\" },\n { key: \"whenApplies\", tier: \"pillar\", label: \"when to apply it\", question: \"Does the article say when to apply it?\" },\n { key: \"whatToDo\", tier: \"pillar\", label: \"what to actually do\", question: \"Does the article say what to actually do?\" },\n ],\n event: [\n ...COMMON,\n { key: \"when\", tier: \"foundation\", label: \"the date it happened\", question: \"Does the article give the date the event happened?\" },\n { key: \"outcome\", tier: \"pillar\", label: \"what changed as a result\", question: \"Does the article say what changed as a result?\" },\n { key: \"who\", tier: \"walls\", label: \"who was involved\", question: \"Does the article name who was involved?\" },\n ],\n decision: [\n ...COMMON,\n { key: \"what\", tier: \"foundation\", label: \"what was decided\", question: \"Does the article state plainly what was decided?\" },\n { key: \"why\", tier: \"pillar\", label: \"the reasoning behind it\", question: \"Does the article give the reasoning behind the decision?\" },\n { key: \"when\", tier: \"walls\", label: \"when it was decided\", question: \"Does the article say when it was decided?\" },\n { key: \"consequence\", tier: \"walls\", label: \"what it changed\", question: \"Does the article say what the decision changed?\" },\n ],\n}\n\n/**\n * Which fact source can supply a field without asking a person.\n *\n * This is what splits the action list in two. A missing contact value is\n * a lookup — `wacli contacts search` answers it in 300ms and nobody is\n * interrupted. A missing role is a question, because no system of record\n * on this fleet holds job titles. Ranking gaps by tier says what matters\n * most; this says which of them we can close by ourselves.\n */\n/**\n * Fields a backfill may write on its own, and the resolved fact keys\n * that feed each one.\n *\n * Deliberately a short list, and deliberately not the same list as\n * FIELD_SOURCES. That one says which system *might* know something;\n * this one says what we can copy verbatim from a system of record with\n * no judgement involved. A contact value is a string we were handed. A\n * project's status is a reading of the world, and no lookup returns it.\n *\n * `role` and `organisation` are here because GitLab and Google return\n * them as literal profile fields — where those are blank, which is the\n * common case, nothing is written and the gap stays open for a human.\n */\n/**\n * Where a field lives in an article's Identity section.\n *\n * Separate from BACKFILLABLE, which is the narrower question of what a\n * machine may write on its own. A person answering \"what language does\n * she prefer\" has produced a fact that belongs in the article just as\n * much as a number does — it simply had to come from a person. Without\n * a slot for it the answer would be recorded on the queue and never\n * reach the wiki, which is the same dead end the queue exists to fix.\n *\n * A field absent from this map has no defined place, so an answer to it\n * is recorded and left for a person to file. Guessing a location in the\n * source of truth is worse than leaving the answer where it can be seen.\n */\nexport const IDENTITY_SLOTS: Record<string, { heading: string; match: RegExp }> = {\n // Order matters: `organisation` is matched before `role`, because\n // articles write \"Organisation and position\" and a /position/ test\n // for role would claim it.\n contactValue: { heading: \"Contact identifiers\", match: /contact|reach|phone|whatsapp|e-?mail/i },\n organisation: { heading: \"Organisation and position\", match: /organis|organiz|company|employer|team and/i },\n role: { heading: \"Role or job title\", match: /role|job title/i },\n language: { heading: \"Preferred language\", match: /language/i },\n ourOwner: { heading: \"Relationship owner\", match: /relationship owner|owns the relationship|our owner/i },\n address: { heading: \"Address\", match: /hostname|address|url|path/i },\n access: { heading: \"Access\", match: /access|credential|how to get in/i },\n administrator: { heading: \"Administrator\", match: /administrat|maintained by|who runs/i },\n ownerClient: { heading: \"Client or owner\", match: /client|owner/i },\n status: { heading: \"Status\", match: /status/i },\n locations: { heading: \"Repository and environments\", match: /repositor|environment|url/i },\n}\n\nexport const BACKFILLABLE: Record<string, { heading: string; match: RegExp; from: string[] }> = {\n // Ordered by how specific the heading match is: `organisation` is\n // tried before `role` because articles write \"Organisation and\n // position\", and a naive /position/ test for role would claim it.\n contactValue: {\n heading: \"Contact identifiers\",\n match: /contact|reach|phone|whatsapp|e-?mail/i,\n from: [\"phone\", \"whatsapp\", \"email\", \"gitlab\"],\n },\n organisation: {\n heading: \"Organisation and position\",\n match: /organis|organiz|company|employer|team and/i,\n from: [\"organisation\"],\n },\n role: {\n heading: \"Role or job title\",\n match: /role|job title/i,\n from: [\"role\"],\n },\n}\n\nexport const BACKFILL_ORDER = [\"contactValue\", \"organisation\", \"role\"] as const\n\nexport const FIELD_SOURCES: Record<string, string[]> = {\n contactValue: [\"wacli\", \"gog\", \"gitlab\"],\n organisation: [\"gog\", \"gitlab\", \"erp\"],\n role: [\"gog\", \"gitlab\"],\n locations: [\"gitlab\"],\n address: [\"gitlab\"],\n ownerClient: [\"erp\"],\n}\n\nexport function fieldsFor(type?: string): RequiredField[] {\n return REQUIRED_FIELDS[type ?? \"\"] ?? COMMON\n}\n\n/** Required fields in build order — foundation first, furniture last. */\nexport function fieldsByTier(type?: string): RequiredField[] {\n return [...fieldsFor(type)].sort((a, b) => TIER_RANK[a.tier] - TIER_RANK[b.tier])\n}\n\n/** One Noul per required field — all answered in a single call. */\nexport function fieldQuestions(type?: string): Questions {\n const q: Record<string, ReturnType<typeof noul>> = {}\n for (const f of fieldsFor(type)) q[f.key] = noul(f.question)\n return q as Questions\n}\n\nexport function articleFieldsState(a: { title: string; type?: string; body: string }, max = 12_000): StateValue {\n const body = String(a.body ?? \"\").trim()\n return {\n title: a.title,\n type: a.type ?? null,\n body: body.length > max ? `${body.slice(0, max)}\\n…[truncated]` : body,\n }\n}\n\nexport interface FieldReport {\n type: string\n present: string[]\n missing: string[]\n /** Between the thresholds — the model is not sure the field is there,\n * which usually means it is mentioned vaguely. Worth a human glance\n * rather than an automatic rewrite. */\n unclear: string[]\n missingCritical: string[]\n /** Missing field keys grouped by tier, so a gap can be ranked. */\n missingByTier: Record<Tier, string[]>\n /** The most load-bearing tier with a gap — what to fix first. */\n worstTier: Tier | null\n /** Share of required fields present. */\n coverage: number\n fit: boolean\n}\n\n/**\n * TypeSafe's own review band: act below 0.30 or above 0.70, escalate\n * between. classifier.dev — which runs on Jev — re-asks anything under\n * 0.70 for the same reason, and gains 2.5 points of accuracy on AG News\n * doing it. Treating the middle as an answer is where that gain is lost.\n */\nexport function reportFields(\n type: string | undefined,\n answers: Record<string, unknown>,\n opts: { low?: number; high?: number } = {},\n): FieldReport {\n const low = opts.low ?? 0.3\n const high = opts.high ?? 0.7\n const fields = fieldsFor(type)\n const present: string[] = [], missing: string[] = [], unclear: string[] = []\n\n for (const f of fields) {\n const p = (answers[f.key] as NoulAnswer | undefined)?.noul\n if (p === undefined) { unclear.push(f.key); continue }\n if (p > high) present.push(f.key)\n else if (p <= low) missing.push(f.key)\n else unclear.push(f.key)\n }\n\n const missingByTier = Object.fromEntries(TIERS.map((t) => [t, [] as string[]])) as Record<Tier, string[]>\n for (const f of fields) if (missing.includes(f.key)) missingByTier[f.tier].push(f.key)\n\n const missingCritical = fields.filter((f) => isCritical(f) && missing.includes(f.key)).map((f) => f.key)\n const worstTier = TIERS.find((t) => missingByTier[t].length > 0) ?? null\n\n return {\n type: type ?? \"?\",\n present, missing, unclear, missingCritical, missingByTier, worstTier,\n coverage: fields.length ? present.length / fields.length : 0,\n fit: missingCritical.length === 0,\n }\n}\n\nexport interface GapAction {\n field: string\n label: string\n tier: Tier\n /** Fact sources that could answer this without asking anyone. */\n sources: string[]\n /** True when no source holds it — this one needs a person. */\n needsHuman: boolean\n /** The grader was unsure rather than negative; verify before rewriting. */\n uncertain: boolean\n}\n\n/**\n * The post-absorb work list: what to go and find, most load-bearing\n * first.\n *\n * Absorbing an entry once and never revisiting it assumes one pass can\n * see everything worth keeping. It cannot — half of what an article\n * needs was never in the conversation at all. This turns the grader's\n * output into the next pass's input, so the corpus is built up in\n * layers instead of being declared finished at the first draft.\n */\nexport function nextActions(\n report: FieldReport,\n opts: { includeUnclear?: boolean; maxTier?: Tier } = {},\n): GapAction[] {\n const byKey = new Map(fieldsFor(report.type === \"?\" ? undefined : report.type).map((f) => [f.key, f]))\n const limit = opts.maxTier ? TIER_RANK[opts.maxTier] : TIER_RANK.furniture\n\n const keys = [...report.missing, ...(opts.includeUnclear ? report.unclear : [])]\n const actions: GapAction[] = []\n for (const key of keys) {\n const f = byKey.get(key)\n if (!f || TIER_RANK[f.tier] > limit) continue\n const sources = FIELD_SOURCES[key] ?? []\n actions.push({\n field: key,\n label: f.label,\n tier: f.tier,\n sources,\n needsHuman: sources.length === 0,\n uncertain: report.unclear.includes(key),\n })\n }\n\n // Tier first, then resolvable-by-lookup ahead of needs-a-human: within\n // one tier the automatable work should be drained before anyone is\n // interrupted.\n return actions.sort((a, b) =>\n TIER_RANK[a.tier] - TIER_RANK[b.tier] ||\n Number(a.needsHuman) - Number(b.needsHuman) ||\n a.field.localeCompare(b.field))\n}\n\n/**\n * The same field list, rendered for the absorb prompt.\n *\n * The writer and the checker read one definition. When these were two\n * hand-written lists they drifted within a day: the prompt asked for a\n * relationship owner, the rubric never looked for one, and nobody could\n * tell whether a missing owner was the writer's fault or the checker's\n * blind spot. Generating the prompt from the checked fields makes that\n * class of disagreement unrepresentable.\n *\n * Rendered in tier order, so the instruction reads in the order the\n * article should be built rather than the order the record happens to\n * list.\n */\nexport function fieldChecklistMarkdown(): string {\n const order = [\"person\", \"project\", \"place\", \"concept\", \"pattern\", \"event\", \"decision\"]\n const commonKeys = new Set(COMMON.map((f) => f.key))\n const bold = (t: string) => {\n if (t.includes(\"**\")) throw new Error(`field label must not carry its own emphasis: ${t}`)\n return `**${t}**`\n }\n return order\n .map((type) => {\n const own = fieldsByTier(type).filter((f) => !commonKeys.has(f.key))\n const parts = own.map((f) => (isCritical(f) ? bold(f.label) : f.label))\n return `- **${type}** — ${parts.join(\"; \")}.`\n })\n .join(\"\\n\")\n}\n\n/** The tier ladder, for the absorb prompt. */\nexport function tierLadderMarkdown(): string {\n return TIERS.map((t, i) => `${i + 1}. **${t}** — ${TIER_MEANING[t]}`).join(\"\\n\")\n}\n"],"mappings":"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","names":["init_questions","ARTICLE_FIELDS_SEAT","TIERS","TIER_RANK","TIER_MEANING","isCritical","f","COMMON","REQUIRED_FIELDS","IDENTITY_SLOTS","BACKFILLABLE","BACKFILL_ORDER","FIELD_SOURCES","fieldsFor","type","fieldsByTier","a","b","fieldQuestions","q","noul","articleFieldsState","max","body","reportFields","answers","opts","low","high","fields","present","missing","unclear","p","missingByTier","t","missingCritical","worstTier","nextActions","report","byKey","limit","keys","actions","key","sources","fieldChecklistMarkdown","order","commonKeys","bold","parts","tierLadderMarkdown","i"]}
@@ -0,0 +1,36 @@
1
+ import{a as u,b as o}from"./chunk-ZTEU5JVQ.js";o();function g(n,e,t=u()){return n.prepare(`
2
+ INSERT INTO task_traces (
3
+ task_id, agent_id, channel, chat_id, workflow_run_id, workflow_id,
4
+ workflow_node_id, intent_event_id, intent_decided_by, resume_session_id,
5
+ model, status, started_at, message_preview, original_message
6
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'in-flight', ?, ?, ?)
7
+ `).run(t,e.agentId,e.channel??null,e.chatId??null,e.workflowRunId??null,e.workflowId??null,e.workflowNodeId??null,e.intentEventId??null,e.intentDecidedBy??null,e.resumeSessionId??null,e.model??null,Date.now(),e.messagePreview??null,e.originalMessage??null),t}function m(n,e,t){let s=Date.now();n.prepare(`
8
+ UPDATE task_traces SET
9
+ status = ?,
10
+ final_session_id = ?,
11
+ input_tokens = ?,
12
+ output_tokens = ?,
13
+ cache_read_tokens = ?,
14
+ cache_create_tokens = ?,
15
+ error = ?,
16
+ final_response = COALESCE(?, final_response),
17
+ finished_at = ?,
18
+ duration_ms = ? - started_at
19
+ WHERE task_id = ?
20
+ `).run(t.status,t.finalSessionId??null,t.inputTokens??null,t.outputTokens??null,t.cacheReadTokens??null,t.cacheCreateTokens??null,t.error??null,t.finalResponse??null,s,s,e)}function _(n,e,t){let s=Date.now();return n.transaction(()=>{let l=(n.prepare("SELECT MAX(seq) AS max_seq FROM task_trace_steps WHERE task_id = ?").get(e)?.max_seq??-1)+1;return n.prepare(`
21
+ INSERT INTO task_trace_steps (
22
+ task_id, seq, name, action, status, input_summary, output_summary, error, ms, started_at
23
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
24
+ `).run(e,l,t.name,t.action??null,t.status??null,t.inputSummary??null,t.outputSummary??null,t.error??null,t.ms??null,s),l})()}function i(n){return{taskId:n.task_id,agentId:n.agent_id,channel:n.channel??null,chatId:n.chat_id??null,workflowRunId:n.workflow_run_id??null,workflowId:n.workflow_id??null,workflowNodeId:n.workflow_node_id??null,intentEventId:n.intent_event_id??null,intentDecidedBy:n.intent_decided_by??null,resumeSessionId:n.resume_session_id??null,finalSessionId:n.final_session_id??null,model:n.model??null,status:n.status,startedAt:n.started_at,finishedAt:n.finished_at??null,durationMs:n.duration_ms??null,inputTokens:n.input_tokens??null,outputTokens:n.output_tokens??null,cacheReadTokens:n.cache_read_tokens??null,cacheCreateTokens:n.cache_create_tokens??null,error:n.error??null,messagePreview:n.message_preview??null,originalMessage:n.original_message??null,finalResponse:n.final_response??null}}function d(n){return{taskId:n.task_id,seq:n.seq,name:n.name,action:n.action??null,status:n.status??null,inputSummary:n.input_summary??null,outputSummary:n.output_summary??null,error:n.error??null,ms:n.ms??null,startedAt:n.started_at}}function p(n,e){let t=n.prepare("SELECT * FROM task_traces WHERE task_id = ?").get(e);if(!t)return null;let s=n.prepare("SELECT * FROM task_trace_steps WHERE task_id = ? ORDER BY seq").all(e);return{task:i(t),steps:s.map(d)}}function k(n){let e=Date.now();return n.prepare(`
25
+ UPDATE task_traces
26
+ SET status = 'canceled',
27
+ error = 'daemon-restart (orphaned in-flight)',
28
+ finished_at = ?
29
+ WHERE status = 'in-flight'
30
+ `).run(e).changes??0}function h(n,e={}){let t=[],s=[];e.agentId&&(t.push("agent_id = ?"),s.push(e.agentId)),e.channel&&(t.push("channel = ?"),s.push(e.channel)),e.chatId&&(t.push("chat_id = ?"),s.push(e.chatId)),e.workflowRunId&&(t.push("workflow_run_id = ?"),s.push(e.workflowRunId)),e.status&&(t.push("status = ?"),s.push(e.status)),e.since!==void 0&&(t.push("started_at >= ?"),s.push(e.since)),e.until!==void 0&&(t.push("started_at <= ?"),s.push(e.until));let a=Math.max(1,Math.min(e.limit??100,1e3)),r=`
31
+ SELECT * FROM task_traces
32
+ ${t.length>0?"WHERE "+t.join(" AND "):""}
33
+ ORDER BY started_at DESC
34
+ LIMIT ?
35
+ `;return s.push(a),n.prepare(r).all(...s).map(i)}export{g as a,m as b,_ as c,p as d,k as e,h as f};
36
+ //# sourceMappingURL=chunk-4BR7D2OU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/traces.ts"],"sourcesContent":["import type Database from \"better-sqlite3\"\nimport { newEventId } from \"@/intent/ulid\"\n\n// --- Task trace store ---\n//\n// Improvement plan #2 — per-task observability backed by SQLite. One\n// task_traces row per executeTask invocation, an append-only stream of\n// task_trace_steps inside it. The store is intentionally dumb: it stores\n// what callers give it. Callers (capture sites in src/agents/runtime.ts)\n// are responsible for byte-capping large step payloads so the daemon\n// memory stays bounded under tool-heavy turns.\n//\n// Why a separate store layer (vs writing inline in runtime.ts)?\n// - Tests can exercise the trace lifecycle against a temp SQLite without\n// spinning up the agent runtime.\n// - The HTTP endpoints (GET /task/:id/trace) read through the same\n// functions producers write through, so there's a single source of\n// truth on field names + semantics.\n// - Future capture sites (sdk tier, orchestrator tier) reuse this API\n// without copying SQL.\n//\n// Why ULID for task_id?\n// - URL-safe in HTTP routes (GET /task/:id/trace).\n// - Time-sortable, so listTraces ORDER BY started_at and ORDER BY\n// task_id agree without an explicit timestamp column index.\n// - Already in-tree (src/intent/ulid.ts); no new dep.\n//\n// Cross-DB FK note:\n// intent_event_id and intent_decided_by are logical foreign keys into\n// the intent ledger at .agentx/intent/ledger.sqlite. better-sqlite3\n// doesn't enforce cross-database FKs and we don't ATTACH the ledger\n// here on purpose — the rescue plan's append-only contract on the\n// ledger is honoured by routing all writes through src/intent/ledger.ts.\n// Joins happen at the HTTP / CLI layer when needed.\n\nexport interface TraceStartInput {\n agentId: string\n channel?: string | null\n chatId?: string | null\n messagePreview?: string | null\n /** Full untruncated user message — used by `agentx trace replay <taskId>`\n * to re-fire a recorded task against the current agent config. NULL on\n * rows from before migration v8, in which case replay falls back to\n * messagePreview (which is capped at 200 chars). */\n originalMessage?: string | null\n workflowRunId?: string | null\n workflowId?: string | null\n workflowNodeId?: string | null\n intentEventId?: string | null\n intentDecidedBy?: string | null\n resumeSessionId?: string | null\n model?: string | null\n}\n\nexport interface TraceEndInput {\n status: \"ok\" | \"error\" | \"timeout\"\n finalSessionId?: string | null\n inputTokens?: number | null\n outputTokens?: number | null\n cacheReadTokens?: number | null\n cacheCreateTokens?: number | null\n error?: string | null\n /** The agent's final reply text. Stored verbatim so `replay --diff`\n * can compare original output vs the new run's output without\n * reconstructing it from the step ledger. NULL when the response\n * wasn't captured (older rows or non-text outputs). */\n finalResponse?: string | null\n}\n\nexport interface TraceStepInput {\n /** Coarse step kind. Conventional values: \"tool_use\" | \"tool_result\" |\n * \"llm_message\" | \"session_rotation\" | \"error\" | \"preflight\". Free-form\n * strings allowed so future capture sites don't need a schema bump. */\n name: string\n /** Fine-grained name within the kind. For \"tool_use\", this is the tool\n * name (e.g. \"Bash\", \"Edit\"). Optional. */\n action?: string | null\n status?: \"ok\" | \"error\" | \"in-flight\" | null\n /** JSON-stringified input or human-readable summary. Caller-byte-capped. */\n inputSummary?: string | null\n outputSummary?: string | null\n error?: string | null\n /** Step duration when known. Optional — many step kinds are point-in-time. */\n ms?: number | null\n}\n\nexport interface TraceRecord {\n taskId: string\n agentId: string\n channel: string | null\n chatId: string | null\n workflowRunId: string | null\n workflowId: string | null\n workflowNodeId: string | null\n intentEventId: string | null\n intentDecidedBy: string | null\n resumeSessionId: string | null\n finalSessionId: string | null\n model: string | null\n status: string\n startedAt: number\n finishedAt: number | null\n durationMs: number | null\n inputTokens: number | null\n outputTokens: number | null\n cacheReadTokens: number | null\n cacheCreateTokens: number | null\n error: string | null\n messagePreview: string | null\n /** Full untruncated user message — populated for traces from migration v8\n * onward. NULL on older rows; consumers should fall back to messagePreview. */\n originalMessage: string | null\n /** Agent's final reply text — populated for traces from migration v8\n * onward when the executor records it on end. */\n finalResponse: string | null\n}\n\nexport interface TraceStepRecord {\n taskId: string\n seq: number\n name: string\n action: string | null\n status: string | null\n inputSummary: string | null\n outputSummary: string | null\n error: string | null\n ms: number | null\n startedAt: number\n}\n\nexport interface ListTracesFilters {\n agentId?: string\n channel?: string\n chatId?: string\n workflowRunId?: string\n status?: string\n /** ms epoch */\n since?: number\n /** ms epoch */\n until?: number\n /** Default 100, capped at 1000. */\n limit?: number\n}\n\n/**\n * Insert an in-flight trace row and return its ULID. Callers thread the\n * returned id through the executor and call recordTraceEnd at finish time.\n *\n * `taskId` is optional — when supplied, the caller has already allocated\n * a ULID upstream (e.g. registry.execute generating it before the bus\n * event so the runtime can capture per-step rows under the same id).\n * When omitted, a fresh ULID is allocated here.\n */\nexport function recordTraceStart(\n db: Database.Database,\n input: TraceStartInput,\n taskId: string = newEventId(),\n): string {\n db.prepare(`\n INSERT INTO task_traces (\n task_id, agent_id, channel, chat_id, workflow_run_id, workflow_id,\n workflow_node_id, intent_event_id, intent_decided_by, resume_session_id,\n model, status, started_at, message_preview, original_message\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'in-flight', ?, ?, ?)\n `).run(\n taskId,\n input.agentId,\n input.channel ?? null,\n input.chatId ?? null,\n input.workflowRunId ?? null,\n input.workflowId ?? null,\n input.workflowNodeId ?? null,\n input.intentEventId ?? null,\n input.intentDecidedBy ?? null,\n input.resumeSessionId ?? null,\n input.model ?? null,\n Date.now(),\n input.messagePreview ?? null,\n input.originalMessage ?? null,\n )\n return taskId\n}\n\n/**\n * Finalize a trace. duration_ms is computed from finished_at - started_at\n * inside the UPDATE so the two columns can never disagree. Idempotent —\n * calling twice on the same task_id overwrites the prior end values; the\n * second call's status wins. (Soft-overwrite is intentional: timeout\n * handlers may write before a late stream-completion arrives.)\n */\nexport function recordTraceEnd(db: Database.Database, taskId: string, input: TraceEndInput): void {\n const finishedAt = Date.now()\n db.prepare(`\n UPDATE task_traces SET\n status = ?,\n final_session_id = ?,\n input_tokens = ?,\n output_tokens = ?,\n cache_read_tokens = ?,\n cache_create_tokens = ?,\n error = ?,\n final_response = COALESCE(?, final_response),\n finished_at = ?,\n duration_ms = ? - started_at\n WHERE task_id = ?\n `).run(\n input.status,\n input.finalSessionId ?? null,\n input.inputTokens ?? null,\n input.outputTokens ?? null,\n input.cacheReadTokens ?? null,\n input.cacheCreateTokens ?? null,\n input.error ?? null,\n input.finalResponse ?? null,\n finishedAt,\n finishedAt,\n taskId,\n )\n}\n\n/**\n * Append a step. seq is auto-allocated as MAX(seq)+1 within a transaction\n * so concurrent step writes for the same task_id can't collide. Returns\n * the assigned seq, useful for downstream correlation.\n */\nexport function recordTraceStep(db: Database.Database, taskId: string, input: TraceStepInput): number {\n const startedAt = Date.now()\n const allocateAndInsert = db.transaction((): number => {\n const row = db\n .prepare(\"SELECT MAX(seq) AS max_seq FROM task_trace_steps WHERE task_id = ?\")\n .get(taskId) as { max_seq: number | null } | undefined\n const seq = ((row?.max_seq ?? -1) as number) + 1\n db.prepare(`\n INSERT INTO task_trace_steps (\n task_id, seq, name, action, status, input_summary, output_summary, error, ms, started_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n taskId,\n seq,\n input.name,\n input.action ?? null,\n input.status ?? null,\n input.inputSummary ?? null,\n input.outputSummary ?? null,\n input.error ?? null,\n input.ms ?? null,\n startedAt,\n )\n return seq\n })\n return allocateAndInsert()\n}\n\nfunction rowToTrace(row: Record<string, unknown>): TraceRecord {\n return {\n taskId: row.task_id as string,\n agentId: row.agent_id as string,\n channel: (row.channel as string) ?? null,\n chatId: (row.chat_id as string) ?? null,\n workflowRunId: (row.workflow_run_id as string) ?? null,\n workflowId: (row.workflow_id as string) ?? null,\n workflowNodeId: (row.workflow_node_id as string) ?? null,\n intentEventId: (row.intent_event_id as string) ?? null,\n intentDecidedBy: (row.intent_decided_by as string) ?? null,\n resumeSessionId: (row.resume_session_id as string) ?? null,\n finalSessionId: (row.final_session_id as string) ?? null,\n model: (row.model as string) ?? null,\n status: row.status as string,\n startedAt: row.started_at as number,\n finishedAt: (row.finished_at as number) ?? null,\n durationMs: (row.duration_ms as number) ?? null,\n inputTokens: (row.input_tokens as number) ?? null,\n outputTokens: (row.output_tokens as number) ?? null,\n cacheReadTokens: (row.cache_read_tokens as number) ?? null,\n cacheCreateTokens: (row.cache_create_tokens as number) ?? null,\n error: (row.error as string) ?? null,\n messagePreview: (row.message_preview as string) ?? null,\n originalMessage: (row.original_message as string) ?? null,\n finalResponse: (row.final_response as string) ?? null,\n }\n}\n\nfunction rowToStep(row: Record<string, unknown>): TraceStepRecord {\n return {\n taskId: row.task_id as string,\n seq: row.seq as number,\n name: row.name as string,\n action: (row.action as string) ?? null,\n status: (row.status as string) ?? null,\n inputSummary: (row.input_summary as string) ?? null,\n outputSummary: (row.output_summary as string) ?? null,\n error: (row.error as string) ?? null,\n ms: (row.ms as number) ?? null,\n startedAt: row.started_at as number,\n }\n}\n\n/** Fetch a trace + its ordered steps. Returns null if no such task_id. */\nexport function getTrace(\n db: Database.Database,\n taskId: string,\n): { task: TraceRecord; steps: TraceStepRecord[] } | null {\n const row = db.prepare(\"SELECT * FROM task_traces WHERE task_id = ?\").get(taskId) as\n | Record<string, unknown>\n | undefined\n if (!row) return null\n const stepRows = db\n .prepare(\"SELECT * FROM task_trace_steps WHERE task_id = ? ORDER BY seq\")\n .all(taskId) as Record<string, unknown>[]\n return { task: rowToTrace(row), steps: stepRows.map(rowToStep) }\n}\n\n/**\n * Cancel any in-flight trace rows left over from a previous daemon\n * lifetime. Mirrors the intent ledger's startup cleanup (rescue plan\n * Phase 1 commit a8514d9): a hard-killed daemon never gets to fire\n * task:completed, so the row sits \"in-flight\" forever and contaminates\n * triage queries (`agentx trace list --status in-flight`) with stale\n * orphans. Run once at daemon boot before subscribers attach.\n *\n * Returns the number of rows updated. duration_ms is intentionally NOT\n * computed — we don't know when the task actually ended; preserving\n * NULL there is more honest than backdating to \"now\".\n */\nexport function cleanupOrphanedTraces(db: Database.Database): number {\n const now = Date.now()\n const r = db.prepare(`\n UPDATE task_traces\n SET status = 'canceled',\n error = 'daemon-restart (orphaned in-flight)',\n finished_at = ?\n WHERE status = 'in-flight'\n `).run(now)\n return (r.changes ?? 0) as number\n}\n\n/** Triage / dashboard surface — list traces newest-first, filtered. */\nexport function listTraces(db: Database.Database, filters: ListTracesFilters = {}): TraceRecord[] {\n const where: string[] = []\n const params: unknown[] = []\n if (filters.agentId) { where.push(\"agent_id = ?\"); params.push(filters.agentId) }\n if (filters.channel) { where.push(\"channel = ?\"); params.push(filters.channel) }\n if (filters.chatId) { where.push(\"chat_id = ?\"); params.push(filters.chatId) }\n if (filters.workflowRunId) { where.push(\"workflow_run_id = ?\"); params.push(filters.workflowRunId) }\n if (filters.status) { where.push(\"status = ?\"); params.push(filters.status) }\n if (filters.since !== undefined) { where.push(\"started_at >= ?\"); params.push(filters.since) }\n if (filters.until !== undefined) { where.push(\"started_at <= ?\"); params.push(filters.until) }\n\n const limit = Math.max(1, Math.min(filters.limit ?? 100, 1000))\n const sql = `\n SELECT * FROM task_traces\n ${where.length > 0 ? \"WHERE \" + where.join(\" AND \") : \"\"}\n ORDER BY started_at DESC\n LIMIT ?\n `\n params.push(limit)\n return (db.prepare(sql).all(...params) as Record<string, unknown>[]).map(rowToTrace)\n}\n"],"mappings":"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","names":["init_ulid","recordTraceStart","db","input","taskId","newEventId","recordTraceEnd","finishedAt","recordTraceStep","startedAt","seq","rowToTrace","row","rowToStep","getTrace","stepRows","cleanupOrphanedTraces","now","listTraces","filters","where","params","limit","sql"]}