@iowarp/clio-coder 0.3.9 → 0.4.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 (416) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/NOTICE +33 -0
  3. package/README.md +7 -2
  4. package/dist/{acp-7LOELQFP.js → acp-G5WJBNCT.js} +13 -12
  5. package/dist/{agents-FIBG2SHA.js → agents-FMV2Q5G4.js} +39 -36
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-OI4LIH2I.js → auth-3IDSJEIK.js} +16 -15
  8. package/dist/{builtins-AD25UL3C.js → builtins-XCZWXSC7.js} +3 -3
  9. package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
  10. package/dist/{chunk-56KB5IJP.js → chunk-2OQE55CK.js} +3 -3
  11. package/dist/{chunk-N3PBVRTZ.js → chunk-32KWKNSF.js} +9 -7
  12. package/dist/{chunk-VKBMFOYV.js → chunk-36EJLSQQ.js} +23 -27
  13. package/dist/{chunk-465CC7FK.js → chunk-3BT2XMV4.js} +16 -13
  14. package/dist/{chunk-NQ6UCCOD.js → chunk-3URVFKWK.js} +7 -7
  15. package/dist/{chunk-WIE7ZOSW.js → chunk-3XML7CDN.js} +2 -2
  16. package/dist/chunk-42FMPA75.js +101 -0
  17. package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
  18. package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
  19. package/dist/{chunk-JEQQR47K.js → chunk-6DB53AJS.js} +168 -9
  20. package/dist/{chunk-KV2AOLDF.js → chunk-76ONBSIA.js} +5 -25
  21. package/dist/{chunk-FALJGAWU.js → chunk-7MCTRUCE.js} +2 -2
  22. package/dist/{chunk-5T7RBWN2.js → chunk-AB44T6BB.js} +5 -5
  23. package/dist/chunk-B7OBL7PK.js +1405 -0
  24. package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
  25. package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
  26. package/dist/{chunk-O6I4CIEU.js → chunk-BKFJHQCA.js} +6 -6
  27. package/dist/chunk-BKFM6EJV.js +462 -0
  28. package/dist/chunk-BMS5RKQY.js +27 -0
  29. package/dist/{chunk-MV2VUEJC.js → chunk-BPKCPIL7.js} +2 -2
  30. package/dist/{chunk-TEO2TLVN.js → chunk-BUMFYQFY.js} +964 -1120
  31. package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
  32. package/dist/chunk-C2LTL2W6.js +2447 -0
  33. package/dist/{chunk-EBOC7MT3.js → chunk-CODPRO7Q.js} +8 -8
  34. package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
  35. package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
  36. package/dist/{chunk-MIX5N5AC.js → chunk-DQITNCXG.js} +394 -154
  37. package/dist/{chunk-S4COXYBG.js → chunk-DYJP44XW.js} +129 -106
  38. package/dist/{chunk-N5XKWMDW.js → chunk-F4CKPOEQ.js} +6 -6
  39. package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
  40. package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
  41. package/dist/{chunk-7C6RYZGQ.js → chunk-GKF55TAZ.js} +3 -3
  42. package/dist/{chunk-B5XRQOLB.js → chunk-GR5G2PVF.js} +9 -8
  43. package/dist/{chunk-XDOQXGFO.js → chunk-GXNLGKAB.js} +64 -8
  44. package/dist/chunk-HHV2GANA.js +88 -0
  45. package/dist/{chunk-774ILSRL.js → chunk-HI63TFOG.js} +4 -3
  46. package/dist/{chunk-R7LNVMCS.js → chunk-HJJTYUHX.js} +64 -72
  47. package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
  48. package/dist/{chunk-CA42X6KT.js → chunk-HWHKMHUA.js} +6 -6
  49. package/dist/chunk-HZHHCK24.js +1631 -0
  50. package/dist/{chunk-HJB5IUKP.js → chunk-I5VEOC6I.js} +12 -12
  51. package/dist/chunk-IBEBSCYA.js +564 -0
  52. package/dist/chunk-IQ7KR472.js +362 -0
  53. package/dist/{chunk-4H6ULJ3H.js → chunk-J4W7KFM7.js} +921 -990
  54. package/dist/{chunk-4LJX2PUC.js → chunk-JDG2WCRO.js} +5 -5
  55. package/dist/{chunk-NZU6YDNV.js → chunk-K5C3NCBD.js} +4 -4
  56. package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
  57. package/dist/{chunk-NNNWO6F2.js → chunk-KFZI4NIL.js} +93 -3
  58. package/dist/chunk-KMVISBZR.js +132 -0
  59. package/dist/{chunk-BVDVID7E.js → chunk-LDQ2ZF2M.js} +2 -2
  60. package/dist/{chunk-OEDBCISO.js → chunk-LQ3DZAMX.js} +2 -2
  61. package/dist/{chunk-PZ4I4JE2.js → chunk-LY4S7GJC.js} +124 -116
  62. package/dist/{chunk-3DUR4WUA.js → chunk-MLKNTWH2.js} +19 -19
  63. package/dist/chunk-NEKRRTYW.js +56 -0
  64. package/dist/{chunk-5DQRIYDZ.js → chunk-NHCZP4K7.js} +2 -2
  65. package/dist/chunk-NHLBIGRH.js +1506 -0
  66. package/dist/chunk-NQQH3YT7.js +302 -0
  67. package/dist/chunk-NYS75XW5.js +15 -0
  68. package/dist/{chunk-TD7UE2L5.js → chunk-O4XIVISU.js} +7 -7
  69. package/dist/{chunk-WXCJ7VME.js → chunk-O6TL7WWY.js} +6 -6
  70. package/dist/chunk-OQBA45DZ.js +97 -0
  71. package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
  72. package/dist/chunk-PMZCIOCJ.js +25 -0
  73. package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
  74. package/dist/{chunk-HKO36JWF.js → chunk-QBJA7R7N.js} +31 -3
  75. package/dist/chunk-QDC3K2U3.js +262 -0
  76. package/dist/{chunk-5HFBWUMU.js → chunk-QLFS5GO2.js} +4 -4
  77. package/dist/{chunk-GAYUJ7LE.js → chunk-QLL7ILRG.js} +41 -32
  78. package/dist/{chunk-LXPJXFM5.js → chunk-QREDIESB.js} +7 -7
  79. package/dist/chunk-QSNYB6ZV.js +195 -0
  80. package/dist/chunk-R346GLFC.js +31 -0
  81. package/dist/{chunk-VPTUJU4P.js → chunk-SJ5ZKQ4S.js} +2 -2
  82. package/dist/{chunk-QQ7EKM72.js → chunk-SP2RXXYO.js} +6 -54
  83. package/dist/chunk-SUCTJL45.js +45 -0
  84. package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
  85. package/dist/chunk-T56WDKA5.js +183 -0
  86. package/dist/chunk-TVHHYFHE.js +255 -0
  87. package/dist/{chunk-IHKBWSXF.js → chunk-TZ3SGWZZ.js} +2 -2
  88. package/dist/{chunk-ECUO3KDP.js → chunk-U77AMWDL.js} +47 -7
  89. package/dist/{chunk-3UUY7R3Z.js → chunk-ULC6OTWO.js} +7 -7
  90. package/dist/{chunk-AEYBF3TB.js → chunk-UM7N4G5A.js} +2 -2
  91. package/dist/{chunk-3V5AYSEQ.js → chunk-UXMFQ54G.js} +43 -36
  92. package/dist/{chunk-YW7UVM5V.js → chunk-V5DHCITQ.js} +34 -1
  93. package/dist/{chunk-47CMYGET.js → chunk-VAZSBTKF.js} +2 -2
  94. package/dist/{chunk-3MRC2YSQ.js → chunk-VEO4AP2K.js} +2 -2
  95. package/dist/{chunk-PNY46YEY.js → chunk-VFA6GDY5.js} +47 -3
  96. package/dist/chunk-VO67MWHC.js +75 -0
  97. package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
  98. package/dist/{chunk-AD7Y7STJ.js → chunk-VYMXRQI6.js} +36 -22
  99. package/dist/{chunk-T3Z6VAAF.js → chunk-W5VSYASO.js} +19 -17
  100. package/dist/{chunk-5PVQ4SRS.js → chunk-WZR7K7ZX.js} +7 -123
  101. package/dist/{chunk-DG4M6ZUE.js → chunk-X3YGUTOB.js} +4 -4
  102. package/dist/chunk-X75E3D2N.js +686 -0
  103. package/dist/{chunk-P3JGPQFL.js → chunk-YDFRH54B.js} +4 -4
  104. package/dist/chunk-YJX4SHTD.js +40 -0
  105. package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
  106. package/dist/{chunk-YSEHGPCT.js → chunk-Z2RR6MAK.js} +3 -3
  107. package/dist/{chunk-HCBCAYZU.js → chunk-Z4TXYIEG.js} +5 -5
  108. package/dist/cli/index.js +47 -36
  109. package/dist/{clio-LT5V7SSZ.js → clio-2JXHBBY5.js} +7 -7
  110. package/dist/{code-nav-LMW275PA.js → code-nav-3YYRMYNF.js} +6 -6
  111. package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
  112. package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
  113. package/dist/{config-RXS5T3JT.js → config-QZPCMYSO.js} +58 -50
  114. package/dist/{configure-2WYWSCSD.js → configure-TEGEBYCA.js} +21 -19
  115. package/dist/{context-I3BTOTCS.js → context-AV7OEZ4D.js} +11 -11
  116. package/dist/{context-MVOORGMF.js → context-E6H5RNMC.js} +49 -41
  117. package/dist/{context-PALKKQYL.js → context-GSXUE4CT.js} +25 -23
  118. package/dist/{context-clear-N2WOYZ2K.js → context-clear-SHIBYK6T.js} +48 -40
  119. package/dist/{context-working-set-MIEVECVZ.js → context-working-set-5ZGKPGZQ.js} +11 -10
  120. package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-EFMJT4LD.js} +88 -60
  121. package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
  122. package/dist/doctor-QOA5FNY5.js +313 -0
  123. package/dist/{eval-IJ5VEZDJ.js → eval-TFBYQH4H.js} +66 -64
  124. package/dist/eval-inventory-SXH7PDKX.js +316 -0
  125. package/dist/{evidence-L5APPXNV.js → evidence-ERGESKGN.js} +198 -44
  126. package/dist/{evolve-RGNKFJ52.js → evolve-VDXTSYCJ.js} +46 -38
  127. package/dist/{extensions-7WYWUX5A.js → extensions-7BGBHN57.js} +6 -6
  128. package/dist/{fleet-6CNVBZZP.js → fleet-2RRVDF2V.js} +189 -101
  129. package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-VJ726XIA.js} +10 -10
  130. package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
  131. package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-JF5QOATM.js} +16 -15
  132. package/dist/fleet-inspect-VLY4S7QM.js +442 -0
  133. package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-AIZUEJOY.js} +6 -5
  134. package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-AJRPDMDV.js} +20 -18
  135. package/dist/fleet-verify-JFEL2L3H.js +175 -0
  136. package/dist/fleet-view-ZCON35AG.js +102 -0
  137. package/dist/{init-VBN2ACVA.js → init-DN2WWLFE.js} +64 -56
  138. package/dist/install-XGLBQY5E.js +13 -0
  139. package/dist/interop-OZBKXAYL.js +114 -0
  140. package/dist/{library-JHGUMLY2.js → library-YWZG7IMW.js} +19 -18
  141. package/dist/{memory-K4OQIYWG.js → memory-I4C4HMLW.js} +48 -40
  142. package/dist/{models-2NCZUWDD.js → models-CEYXJBO6.js} +30 -28
  143. package/dist/{monitor-MMVTJABD.js → monitor-NZ6GCI3P.js} +53 -47
  144. package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-GCGQ4N5I.js} +6311 -7145
  145. package/dist/panes-HMABYVO4.js +58 -0
  146. package/dist/panes-KY6W3V2E.js +103 -0
  147. package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
  148. package/dist/{reset-DD5JGOY3.js → reset-DQ6FGCSH.js} +13 -11
  149. package/dist/resources-BB3MVJMD.js +111 -0
  150. package/dist/{run-QEGNX7FL.js → run-H2GQDUER.js} +113 -82
  151. package/dist/{share-JKD3BQMW.js → share-GTJN6A5O.js} +18 -17
  152. package/dist/{skills-LMQIKDOZ.js → skills-L55TEW6R.js} +31 -24
  153. package/dist/{skills-eval-I7X2774U.js → skills-eval-XVXPH2JI.js} +61 -52
  154. package/dist/skills-inventory-S4MXPJFV.js +126 -0
  155. package/dist/slash-commands-ZSGASKJC.js +77 -0
  156. package/dist/{steer-CF5TDANS.js → steer-RZGSCY4R.js} +3 -3
  157. package/dist/{support-I7LOJLIF.js → support-PKEUNNQL.js} +4 -4
  158. package/dist/{targets-RUSR6B5Z.js → targets-NCPZ644J.js} +31 -29
  159. package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-44SV3YCN.js} +4 -4
  160. package/dist/tools-DAF3DI3C.js +27 -0
  161. package/dist/{trace-ODOQIVIW.js → trace-FYVW2MQA.js} +149 -7
  162. package/dist/tui-primitives-2AKXQNZK.js +13 -0
  163. package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
  164. package/dist/{upgrade-XANW3FXB.js → upgrade-3XPP6OQL.js} +26 -24
  165. package/dist/{usage-4H7ZRXQT.js → usage-3NLHGTU2.js} +57 -49
  166. package/dist/{verifiers-UZXNBZEB.js → verifiers-SSQONKRT.js} +171 -12
  167. package/dist/{verify-BVKWTNDL.js → verify-3U6J7FZI.js} +9 -9
  168. package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
  169. package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-CEHYGPGQ.js} +67 -59
  170. package/dist/with-panes-MKB46MPQ.js +782 -0
  171. package/dist/worker/entry.js +101 -66
  172. package/docs/README.md +3 -2
  173. package/docs/acp.md +24 -3
  174. package/docs/alcf-provider.md +1 -1
  175. package/docs/architecture.md +2 -2
  176. package/docs/artifact-versions.md +4 -1
  177. package/docs/built-in-agents.md +1 -1
  178. package/docs/capacity-and-scheduling.md +43 -5
  179. package/docs/commands-and-modes.md +31 -2
  180. package/docs/configuration-and-targets.md +40 -10
  181. package/docs/context-engine.md +1 -1
  182. package/docs/development-pipeline.md +19 -0
  183. package/docs/dispatch-typed-intent.md +385 -0
  184. package/docs/documentation-coverage.md +2 -2
  185. package/docs/documentation-guide.md +1 -1
  186. package/docs/environment-variables.md +1 -0
  187. package/docs/eval-runner.md +1 -1
  188. package/docs/evals-internal.md +1 -1
  189. package/docs/evidence-and-memory.md +2 -2
  190. package/docs/evolution.md +1 -1
  191. package/docs/exit-codes-and-output.md +1 -1
  192. package/docs/extensions-and-sharing.md +25 -1
  193. package/docs/fleet-dispatch.md +22 -1
  194. package/docs/installation-and-lifecycle.md +15 -2
  195. package/docs/middleware-and-components.md +1 -1
  196. package/docs/model-catalog.md +10 -1
  197. package/docs/observability.md +3 -3
  198. package/docs/proactive-memory.md +1 -1
  199. package/docs/prompt-envelope-and-tools.md +1 -1
  200. package/docs/provider-adapter-cookbook.md +1 -1
  201. package/docs/safety-model.md +2 -2
  202. package/docs/scientific-validation.md +3 -3
  203. package/docs/session-lifecycle.md +1 -1
  204. package/docs/skills-marketplace.md +1 -1
  205. package/docs/tool-usage.md +18 -8
  206. package/docs/trace-store.md +1 -1
  207. package/docs/troubleshooting.md +1 -1
  208. package/docs/tui-design.md +1 -1
  209. package/docs/worker-dispatch-mechanics.md +1 -1
  210. package/package.json +4 -2
  211. package/src/cli/acp.ts +6 -2
  212. package/src/cli/argv.ts +25 -0
  213. package/src/cli/configure.ts +23 -21
  214. package/src/cli/doctor-panes.ts +124 -0
  215. package/src/cli/doctor-toolchain.ts +57 -0
  216. package/src/cli/doctor.ts +20 -1
  217. package/src/cli/eval-inventory.ts +436 -0
  218. package/src/cli/eval.ts +13 -0
  219. package/src/cli/evidence-detail.ts +88 -0
  220. package/src/cli/evidence-inventory.ts +183 -0
  221. package/src/cli/evidence.ts +30 -5
  222. package/src/cli/fleet-decisions.ts +69 -0
  223. package/src/cli/fleet-inspect.ts +334 -0
  224. package/src/cli/fleet-verify.ts +133 -0
  225. package/src/cli/fleet-view.ts +810 -0
  226. package/src/cli/fleet.ts +148 -37
  227. package/src/cli/index.ts +14 -2
  228. package/src/cli/interop-inspect.ts +128 -0
  229. package/src/cli/interop.ts +34 -0
  230. package/src/cli/panes.ts +35 -0
  231. package/src/cli/reset.ts +5 -2
  232. package/src/cli/run.ts +58 -0
  233. package/src/cli/skills-inventory.ts +185 -0
  234. package/src/cli/skills.ts +16 -13
  235. package/src/cli/tools.ts +321 -0
  236. package/src/cli/trace-inspect.ts +252 -0
  237. package/src/cli/trace.ts +23 -2
  238. package/src/cli/verifiers-inspect.ts +347 -0
  239. package/src/cli/verifiers.ts +9 -0
  240. package/src/core/bus-events.ts +4 -0
  241. package/src/core/config.ts +49 -0
  242. package/src/core/defaults.ts +93 -7
  243. package/src/core/response-schema.ts +44 -4
  244. package/src/core/theme-token-hex.ts +43 -0
  245. package/src/core/tool-names.ts +2 -1
  246. package/src/core/xdg.ts +1 -1
  247. package/src/domains/agents/fleets/build-review.md +0 -3
  248. package/src/domains/agents/fleets/build-test.md +0 -3
  249. package/src/domains/agents/result-contract-filesystem.ts +32 -0
  250. package/src/domains/agents/result-contract.ts +164 -35
  251. package/src/domains/config/classify.ts +3 -0
  252. package/src/domains/dispatch/admission-error.ts +9 -0
  253. package/src/domains/dispatch/admission.ts +22 -21
  254. package/src/domains/dispatch/capacity-lease.ts +21 -1
  255. package/src/domains/dispatch/council-topology.ts +398 -0
  256. package/src/domains/dispatch/extension.ts +222 -50
  257. package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
  258. package/src/domains/dispatch/fleet-plan.ts +7 -2
  259. package/src/domains/dispatch/fleet-run.ts +64 -1
  260. package/src/domains/dispatch/gate-decisions.ts +11 -1
  261. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  262. package/src/domains/dispatch/gate-topology.ts +289 -0
  263. package/src/domains/dispatch/index.ts +19 -0
  264. package/src/domains/dispatch/intent-compatibility.ts +330 -0
  265. package/src/domains/dispatch/intent.ts +85 -1
  266. package/src/domains/dispatch/reservation-store.ts +24 -4
  267. package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
  268. package/src/domains/dispatch/run-event-journal.ts +598 -0
  269. package/src/domains/dispatch/state.ts +45 -1
  270. package/src/domains/dispatch/types.ts +13 -0
  271. package/src/domains/dispatch/validation.ts +33 -8
  272. package/src/domains/eval/compare/compare.ts +3 -16
  273. package/src/domains/eval/inventory.ts +113 -0
  274. package/src/domains/eval/schema/serving.ts +31 -0
  275. package/src/domains/evidence/store.ts +6 -0
  276. package/src/domains/memory/index.ts +0 -1
  277. package/src/domains/memory/task-memory-policy.ts +6 -10
  278. package/src/domains/memory/task-memory-telemetry.ts +1 -0
  279. package/src/domains/middleware/memory-intervention.ts +33 -21
  280. package/src/domains/mux/contract.ts +434 -0
  281. package/src/domains/mux/detect.ts +158 -0
  282. package/src/domains/mux/extension.ts +47 -0
  283. package/src/domains/mux/index.ts +96 -0
  284. package/src/domains/mux/manifest.ts +6 -0
  285. package/src/domains/mux/operations.ts +164 -0
  286. package/src/domains/mux/pane-registry.ts +90 -0
  287. package/src/domains/mux/protocol.ts +49 -0
  288. package/src/domains/mux/socket-client.ts +816 -0
  289. package/src/domains/mux/types.ts +222 -0
  290. package/src/domains/mux/viewer-command.ts +59 -0
  291. package/src/domains/mux/yazi/assets/init.lua +2 -0
  292. package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
  293. package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
  294. package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
  295. package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
  296. package/src/domains/mux/yazi/assets/yazi.toml +17 -0
  297. package/src/domains/mux/yazi/event-stream.ts +180 -0
  298. package/src/domains/mux/yazi/profile.ts +299 -0
  299. package/src/domains/mux/yazi/session.ts +228 -0
  300. package/src/domains/mux/yazi/theme.ts +30 -0
  301. package/src/domains/observability/cost.ts +21 -0
  302. package/src/domains/observability/index.ts +2 -0
  303. package/src/domains/observability/trace-store.ts +42 -0
  304. package/src/domains/providers/endpoint-capacity.ts +154 -22
  305. package/src/domains/providers/endpoint-slots-store.ts +189 -0
  306. package/src/domains/providers/extension.ts +20 -3
  307. package/src/domains/providers/index.ts +22 -0
  308. package/src/domains/providers/model-runtime-capabilities.ts +32 -0
  309. package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
  310. package/src/domains/providers/runtimes/builtins.ts +2 -0
  311. package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
  312. package/src/domains/providers/support.ts +1 -0
  313. package/src/domains/providers/target-model-cache.ts +124 -0
  314. package/src/domains/resources/index.ts +3 -0
  315. package/src/domains/resources/skills/loader.ts +33 -0
  316. package/src/domains/safety/action-classifier.ts +6 -0
  317. package/src/domains/toolchain/archive.ts +175 -0
  318. package/src/domains/toolchain/contract.ts +28 -0
  319. package/src/domains/toolchain/extension.ts +47 -0
  320. package/src/domains/toolchain/index.ts +39 -0
  321. package/src/domains/toolchain/install.ts +327 -0
  322. package/src/domains/toolchain/manifest.ts +8 -0
  323. package/src/domains/toolchain/paths.ts +34 -0
  324. package/src/domains/toolchain/registry.ts +265 -0
  325. package/src/domains/toolchain/remove.ts +218 -0
  326. package/src/domains/toolchain/resolve.ts +182 -0
  327. package/src/domains/toolchain/types.ts +113 -0
  328. package/src/domains/toolchain/version.ts +88 -0
  329. package/src/engine/acp/server.ts +413 -70
  330. package/src/engine/acp/types.ts +19 -1
  331. package/src/engine/claude/sdk-module.ts +98 -0
  332. package/src/engine/claude/sdk-runtime.ts +19 -11
  333. package/src/engine/tui-primitives.ts +21 -0
  334. package/src/engine/tui.ts +1 -0
  335. package/src/engine/worker-runtime.ts +2 -13
  336. package/src/entry/boot-options.ts +2 -0
  337. package/src/entry/orchestrator.ts +103 -5
  338. package/src/entry/panes-activation.ts +31 -0
  339. package/src/entry/with-panes.ts +20 -0
  340. package/src/interactive/context-overlay.ts +1 -0
  341. package/src/interactive/cost-overlay.ts +2 -0
  342. package/src/interactive/council-grid.ts +1 -3
  343. package/src/interactive/council.ts +11 -0
  344. package/src/interactive/dispatch-board.ts +26 -16
  345. package/src/interactive/interactive-application.ts +153 -6
  346. package/src/interactive/interactive-input-runtime.ts +7 -0
  347. package/src/interactive/interactive-slash-runtime.ts +36 -6
  348. package/src/interactive/memory-overlay.ts +1 -0
  349. package/src/interactive/modal-marker.ts +170 -0
  350. package/src/interactive/mux-bridge.ts +214 -0
  351. package/src/interactive/overlay-frame.ts +58 -2
  352. package/src/interactive/overlay-general-openers.ts +1 -0
  353. package/src/interactive/overlay-key-routing.ts +14 -3
  354. package/src/interactive/overlay-lifecycle.ts +19 -3
  355. package/src/interactive/overlay-model-selectors.ts +40 -3
  356. package/src/interactive/overlay-permission-lifecycle.ts +90 -22
  357. package/src/interactive/overlay-transitions.ts +18 -4
  358. package/src/interactive/overlays/agents.ts +1 -0
  359. package/src/interactive/overlays/ask-user.ts +136 -30
  360. package/src/interactive/overlays/auth-dialog.ts +1 -0
  361. package/src/interactive/overlays/context-reset.ts +1 -0
  362. package/src/interactive/overlays/cwd-fallback.ts +1 -0
  363. package/src/interactive/overlays/decisions.ts +11 -11
  364. package/src/interactive/overlays/extensions.ts +1 -0
  365. package/src/interactive/overlays/fleet-run-approval.ts +1 -0
  366. package/src/interactive/overlays/handoff-review.ts +1 -0
  367. package/src/interactive/overlays/help-reference.ts +2 -0
  368. package/src/interactive/overlays/interop.ts +1 -0
  369. package/src/interactive/overlays/library-install-confirm.ts +1 -0
  370. package/src/interactive/overlays/library-tabs.ts +28 -0
  371. package/src/interactive/overlays/list-overlay.ts +10 -1
  372. package/src/interactive/overlays/message-picker.ts +1 -0
  373. package/src/interactive/overlays/model-scope.ts +86 -0
  374. package/src/interactive/overlays/model-selector.ts +1 -0
  375. package/src/interactive/overlays/prompts.ts +1 -0
  376. package/src/interactive/overlays/session-selector.ts +1 -0
  377. package/src/interactive/overlays/settings-sections.ts +30 -0
  378. package/src/interactive/overlays/settings.ts +579 -44
  379. package/src/interactive/overlays/side-question.ts +1 -0
  380. package/src/interactive/overlays/skills-hub.ts +3 -11
  381. package/src/interactive/overlays/tree-selector.ts +1 -0
  382. package/src/interactive/pane-policy.ts +46 -0
  383. package/src/interactive/panes-runtime.ts +292 -0
  384. package/src/interactive/renderers/compaction-summary.ts +29 -0
  385. package/src/interactive/renderers/worker-entry.ts +122 -14
  386. package/src/interactive/slash-commands.ts +251 -15
  387. package/src/interactive/tasks-overlay.ts +1 -0
  388. package/src/interactive/theme/tokens.ts +3 -14
  389. package/src/interactive/turn-context.ts +47 -2
  390. package/src/interactive/view/artifacts.ts +109 -1
  391. package/src/interactive/view/view-overlay.ts +1 -0
  392. package/src/interactive/watch-pane.ts +152 -0
  393. package/src/interactive/worker-progress.ts +7 -1
  394. package/src/interactive/worker-receipts.ts +19 -1
  395. package/src/interactive/worker-stream.ts +5 -0
  396. package/src/interactive/yazi-bridge.ts +444 -0
  397. package/src/tools/bootstrap.ts +26 -2
  398. package/src/tools/builtin-tool-catalog.ts +15 -0
  399. package/src/tools/compete-worktrees.ts +83 -2
  400. package/src/tools/core-bootstrap.ts +2 -1
  401. package/src/tools/dispatch-admission.ts +14 -3
  402. package/src/tools/dispatch-arguments.ts +20 -20
  403. package/src/tools/dispatch-run-events.ts +134 -19
  404. package/src/tools/dispatch-runner.ts +29 -7
  405. package/src/tools/dispatch-types.ts +15 -3
  406. package/src/tools/dispatch.ts +1 -1
  407. package/src/tools/executables.ts +17 -14
  408. package/src/tools/observation.ts +54 -4
  409. package/src/tools/panes-surface.ts +38 -0
  410. package/src/tools/panes.ts +112 -0
  411. package/src/tools/policy.ts +10 -1
  412. package/src/tools/presentation.ts +1 -0
  413. package/dist/chunk-D73KXYPF.js +0 -37
  414. package/dist/chunk-MLOK6ZOS.js +0 -2888
  415. package/dist/chunk-YKOFT37S.js +0 -279
  416. package/dist/doctor-TWBWFK5V.js +0 -165
@@ -21,6 +21,8 @@ import type { FleetCommandRegistry } from "../agents/fleet-commands.js";
21
21
  import type { FleetContract } from "../agents/fleet-contract.js";
22
22
  import { resultContractAuthorship } from "../agents/result-contract.js";
23
23
  import type { AgentSpec } from "../agents/spec.js";
24
+ import { aggregateCostAmounts, type CostAggregate, renderCostAmount } from "../observability/cost.js";
25
+ import type { CostProvenance } from "../providers/index.js";
24
26
  import { claimAssignmentVerdict, recordAssignmentAttempt, settleStoredAssignment } from "./assignment-store.js";
25
27
  import { runCodeStep } from "./code-step.js";
26
28
  import { codeStepDir, writeCodeStepRecord } from "./code-step-store.js";
@@ -43,6 +45,7 @@ import {
43
45
  materializePendingGateDecision,
44
46
  stagePendingGateDecision,
45
47
  } from "./gate-decisions.js";
48
+ import { type DispatchIntent, declaredScopeIntent } from "./intent.js";
46
49
  import { verifyReceiptIntegrity } from "./receipt-integrity.js";
47
50
  import { type FleetRunRecord, writeFleetRun } from "./state.js";
48
51
  import type { RunReceipt } from "./types.js";
@@ -83,6 +86,15 @@ export interface FleetRunStepOutcome extends FleetRunStepEvent {
83
86
  /** Terminal run id, which is the receipt id for an agent step. */
84
87
  terminalRunId: string;
85
88
  costUsd: number;
89
+ /**
90
+ * Where the number in `costUsd` came from, carried beside it because the two
91
+ * are one fact. A gateway-routed run seals `costUsd: 0` with `unknown`: its
92
+ * tokens were measured and nobody priced them. A renderer that reads the
93
+ * amount without this prints `$0.0000` and turns unpriced work into a
94
+ * measured zero. `known_free` on a deterministic step is the honest reading:
95
+ * no model ran, so the zero is something code observed rather than missed.
96
+ */
97
+ costProvenance: CostProvenance;
86
98
  /** The sealed agent receipt when this was an agent step. */
87
99
  receipt?: RunReceipt;
88
100
  /** The durable code-step record when this was a deterministic step. */
@@ -192,7 +204,18 @@ export interface FleetRunOutcome {
192
204
  planHash: string;
193
205
  result: ExecutionPlanResult;
194
206
  receipts: ReadonlyArray<RunReceipt>;
207
+ /**
208
+ * The bare sum of every receipt's `costUsd`, which adds unpriced zeros to
209
+ * priced dollars and so cannot be rendered on its own. Retained for the
210
+ * interactive fleet overlay, which still reads it. Render `totalCost`.
211
+ */
195
212
  totalCostUsd: number;
213
+ /**
214
+ * The fold that keeps unpriced calls distinguishable from priced ones, so a
215
+ * run whose every receipt came back `unknown` renders as not measured rather
216
+ * than as a total of zero dollars.
217
+ */
218
+ totalCost: CostAggregate;
196
219
  /** Steps that ran unconditionally, excluding nodes a resolved loop skipped. */
197
220
  requiredStepCount: number;
198
221
  succeededStepCount: number;
@@ -217,6 +240,24 @@ function fleetGateCorrelation(subject: RunReceipt, decider: RunReceipt): GateDec
217
240
  return { agent, target, modelFamily, runtime, node, independent };
218
241
  }
219
242
 
243
+ /**
244
+ * Typed scope for one fleet step, drawn from the boundary its contract already
245
+ * declared. Returns null when the contract declared nothing for this position,
246
+ * which is every step of a pre-v4 contract and every readonly step: those keep
247
+ * the legacy inference path rather than being handed an empty declaration that
248
+ * would silently switch off path-scoped rule selection for them.
249
+ *
250
+ * A contract whose declared paths do not survive the boundary grammar is a
251
+ * compile-time authoring bug, not a dispatch-time one, so a malformed entry
252
+ * falls back to inference here rather than aborting a run mid-wave; the
253
+ * contract loader is the surface that refuses it.
254
+ */
255
+ function fleetStepIntent(writes: ReadonlyArray<string> | undefined): DispatchIntent | null {
256
+ if (writes === undefined || writes.length === 0) return null;
257
+ const built = declaredScopeIntent({ relevantPaths: writes });
258
+ return built.ok ? built.intent : null;
259
+ }
260
+
220
261
  export function fleetPlanWaveIndex(plan: ExecutionPlan, stepId: string): number {
221
262
  return plan.waves.findIndex((wave) => wave.includes(stepId));
222
263
  }
@@ -338,6 +379,9 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
338
379
  succeeded: true,
339
380
  terminalRunId: replayedResult.terminalRunId,
340
381
  costUsd: receiptsByStep.get(stepId)?.costUsd ?? 0,
382
+ // A replay whose receipt no longer exists on disk has no cost claim at
383
+ // all, which is `unknown` rather than a zero the projection invented.
384
+ costProvenance: receiptsByStep.get(stepId)?.costProvenance ?? "unknown",
341
385
  result: replayedResult,
342
386
  });
343
387
  await fileStepAttempt(replayedResult.terminalRunId);
@@ -434,11 +478,24 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
434
478
  // The fleet write boundary is deliberately enforced after the step. The enforcer in
435
479
  // write-boundary-enforcer.ts snapshots and verifies the step window. Pre-emptive
436
480
  // confinement for declared commands would require a command sandbox, which does not exist.
481
+ //
482
+ // That enforcement split is exactly why a step's declared `writes:` reaches
483
+ // typed intent as `relevant_paths` rather than as `write_roots`. The
484
+ // contract already said what this position may change and the enforcer
485
+ // already holds it; restating it as intent write roots would mint a second
486
+ // grant enforced at the per-tool worker seam, which refuses outright on the
487
+ // subprocess and ACP runtimes a fleet may legitimately route a step to.
488
+ // Carrying it as declared scope changes no authority and gets the
489
+ // contract's own paths into project-rule selection and worker context,
490
+ // where prose tokens scraped from the rendered prompt were standing in for
491
+ // a declaration the contract had already made.
492
+ const stepIntent = fleetStepIntent(step.writes);
437
493
  const request: DispatchRequest = {
438
494
  agentId: step.agentId,
439
495
  executionRole: step.executionRole,
440
496
  task: step.task,
441
497
  cwd: workspaceRoot,
498
+ ...(stepIntent === null ? {} : { intent: stepIntent }),
442
499
  predecessorHandoffs: handoffs,
443
500
  requestOrigin: "user",
444
501
  lineage: {
@@ -591,11 +648,12 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
591
648
  succeeded: stepSucceeded,
592
649
  terminalRunId: receipt.runId,
593
650
  costUsd: receipt.costUsd,
651
+ costProvenance: receipt.costProvenance,
594
652
  receipt,
595
653
  ...(failureReason !== undefined ? { failureReason } : {}),
596
654
  });
597
655
  notice(
598
- `step ${step.id} ${step.agentId}: ${stepSucceeded ? "succeeded" : "failed"}${failureReason !== undefined ? ` reason=${failureReason}` : ""} assignment=${handle.runId} terminal-run=${receipt.runId} cost=$${receipt.costUsd.toFixed(4)}`,
656
+ `step ${step.id} ${step.agentId}: ${stepSucceeded ? "succeeded" : "failed"}${failureReason !== undefined ? ` reason=${failureReason}` : ""} assignment=${handle.runId} terminal-run=${receipt.runId} cost=${renderCostAmount(receipt.costUsd, receipt.costProvenance)}`,
599
657
  );
600
658
  return {
601
659
  stepId: step.id,
@@ -658,6 +716,8 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
658
716
  succeeded: outcome.report.passed,
659
717
  terminalRunId: outcome.record.runId,
660
718
  costUsd: 0,
719
+ // No model ran, so nothing needed pricing. This zero was observed.
720
+ costProvenance: "known_free",
661
721
  codeStep: outcome.record,
662
722
  recordPath,
663
723
  });
@@ -803,6 +863,9 @@ export async function executeFleetRun(input: ExecuteFleetRunInput): Promise<Flee
803
863
  result,
804
864
  receipts,
805
865
  totalCostUsd: receipts.reduce((sum, receipt) => sum + receipt.costUsd, 0),
866
+ totalCost: aggregateCostAmounts(
867
+ receipts.map((receipt) => ({ usd: receipt.costUsd, provenance: receipt.costProvenance })),
868
+ ),
806
869
  requiredStepCount: required.length,
807
870
  succeededStepCount,
808
871
  resolvedLoopCount: result.loops.length - failedLoops.length,
@@ -298,10 +298,20 @@ export interface StagePendingGateDecisionOptions {
298
298
  stateDir?: string;
299
299
  }
300
300
 
301
- function decisionsDirectory(stateDir = clioStateDir()): string {
301
+ /**
302
+ * Where the durable decision artifacts live.
303
+ *
304
+ * Exported so a read-only projection can bound its own scan without duplicating
305
+ * the layout. Nothing outside this module may compose an artifact path from it.
306
+ */
307
+ export function gateDecisionsDirectory(stateDir = clioStateDir()): string {
302
308
  return join(stateDir, "gate-decisions");
303
309
  }
304
310
 
311
+ function decisionsDirectory(stateDir = clioStateDir()): string {
312
+ return gateDecisionsDirectory(stateDir);
313
+ }
314
+
305
315
  function pendingDecisionsDirectory(stateDir = clioStateDir()): string {
306
316
  return join(decisionsDirectory(stateDir), "pending");
307
317
  }
@@ -2,6 +2,15 @@
2
2
 
3
3
  import { COUNCIL_BALLOT_SHAPE, COUNCIL_BALLOT_VERDICT_MAX_BYTES } from "../agents/result-contract.js";
4
4
 
5
+ /**
6
+ * Roster bounds for a council. Two is the point of the topology: one seated
7
+ * agent is a plain dispatch, and there is nothing to compare. Capacity denials
8
+ * quote the floor because it is the reason a council cannot answer saturation
9
+ * by dispatching fewer members.
10
+ */
11
+ export const COUNCIL_MIN_MEMBERS = 2;
12
+ export const COUNCIL_MAX_MEMBERS = 5;
13
+
5
14
  export const REVIEWER_GATE_PROMPT = [
6
15
  "You are a strict, read-only reviewer of one implementation run.",
7
16
  "Inspect the supplied result and repository state with read-only tools.",
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Read-only projection of the durable coordinator gate decisions.
3
+ *
4
+ * Unlike a council, a gate has a record of its own. A reviewer verdict and a
5
+ * judge's winner cannot be written back into the subject receipts without
6
+ * invalidating them, so the coordinator seals a separate integrity-covered
7
+ * artifact per decision that links the decider receipt to every subject
8
+ * receipt. {@link gate-decisions.ts} owns writing and verifying those; this
9
+ * module reads a bounded newest-first window of them and projects the shape.
10
+ *
11
+ * Two things stay behind. The decision `detail` is free prose that interpolates
12
+ * a thrown message, a pipeline failure reason, a protected artifact list, or a
13
+ * plan hash, so it is classified against a closed set and never quoted. And the
14
+ * receipt digests are omitted outright: a verified artifact carries one per
15
+ * subject by construction, so repeating them would be a fingerprint that tells
16
+ * a reader nothing the run id does not.
17
+ */
18
+
19
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { clioStateDir } from "../../core/xdg.js";
22
+ import type { GateRouteCorrelation } from "./execution-role.js";
23
+ import {
24
+ type GateDecisionArtifact,
25
+ type GateDecisionOutcome,
26
+ gateDecisionsDirectory,
27
+ verifyGateDecisionArtifact,
28
+ } from "./gate-decisions.js";
29
+
30
+ /** How many decisions one projection reports, newest first. */
31
+ export const GATE_TOPOLOGY_MAX_DECISIONS = 8;
32
+
33
+ /** Subject receipts named per decision. A compete gate judges at most four. */
34
+ export const GATE_TOPOLOGY_MAX_SUBJECTS = 6;
35
+
36
+ /**
37
+ * How many artifact files one listing will open.
38
+ *
39
+ * The directory is unbounded and a decision id sorts by its group before its
40
+ * timestamp, so the newest decision is only discoverable by reading each file's
41
+ * `createdAt`. The cap keeps the scan proportional on an installation that has
42
+ * accumulated gates for months, at the cost of missing a decision older than
43
+ * the cap. That is the right trade here, the same one {@link listFleetRuns}
44
+ * takes, because this window only ever wants the recent end.
45
+ */
46
+ export const GATE_TOPOLOGY_MAX_SCAN = 128;
47
+
48
+ /**
49
+ * Why a gate ended the way it did, as a closed set.
50
+ *
51
+ * Every member is the coordinator's own classification of its own branch. The
52
+ * durable `detail` string those branches write is not repeated: several
53
+ * interpolate a receipt's failure reason, the names of protected artifacts a
54
+ * candidate touched, or an approval request id, and any of the three would
55
+ * carry prose across a boundary that exists to stop exactly that. Anything this
56
+ * classifier does not recognise becomes `unclassified` rather than crossing.
57
+ */
58
+ export type GateDecisionReason =
59
+ | "all-candidates-failed"
60
+ | "builder-run-failed"
61
+ | "reviewer-run-failed"
62
+ | "reviewer-checks-failed"
63
+ | "reviewer-report-invalid"
64
+ | "judge-run-failed"
65
+ | "judge-result-invalid"
66
+ | "judge-winner-out-of-range"
67
+ | "judge-picked-failed-candidate"
68
+ | "winner-touches-protected-artifact"
69
+ | "operator-confirmed-winner"
70
+ | "full-auto-applied-winner"
71
+ | "unclassified";
72
+
73
+ export const GATE_DECISION_REASONS: ReadonlyArray<GateDecisionReason> = [
74
+ "all-candidates-failed",
75
+ "builder-run-failed",
76
+ "reviewer-run-failed",
77
+ "reviewer-checks-failed",
78
+ "reviewer-report-invalid",
79
+ "judge-run-failed",
80
+ "judge-result-invalid",
81
+ "judge-winner-out-of-range",
82
+ "judge-picked-failed-candidate",
83
+ "winner-touches-protected-artifact",
84
+ "operator-confirmed-winner",
85
+ "full-auto-applied-winner",
86
+ "unclassified",
87
+ ];
88
+
89
+ /**
90
+ * Prefix rules, first match wins, ordered so no rule shadows another.
91
+ *
92
+ * These are matched against the exact strings the coordinator writes. A rule
93
+ * failing to match costs its decision the specific reason and nothing else,
94
+ * because `unclassified` is a real answer here: the operator still learns that
95
+ * the gate ended and how, just not which branch produced the text.
96
+ */
97
+ const REASON_RULES: ReadonlyArray<readonly [string, GateDecisionReason]> = [
98
+ ["every candidate builder failed", "all-candidates-failed"],
99
+ ["builder ended ", "builder-run-failed"],
100
+ ["reviewer ended ", "reviewer-run-failed"],
101
+ ["reviewer reported ", "reviewer-checks-failed"],
102
+ ["reviewer did not return a valid verifier report", "reviewer-report-invalid"],
103
+ ["judge ended ", "judge-run-failed"],
104
+ ["judge result must", "judge-result-invalid"],
105
+ ["judge result has unknown fields", "judge-result-invalid"],
106
+ ["judge winner must be an integer", "judge-winner-out-of-range"],
107
+ ["judge picked failed or missing candidate", "judge-picked-failed-candidate"],
108
+ ["judge-selected candidate ", "winner-touches-protected-artifact"],
109
+ ["operator confirmation ", "operator-confirmed-winner"],
110
+ ["full-auto applied ", "full-auto-applied-winner"],
111
+ ];
112
+
113
+ /**
114
+ * The identifier shape the decision store already guarantees for both its ids
115
+ * and, transitively, its groups.
116
+ *
117
+ * A decision id is minted from a sanitized group plus a timestamp and random
118
+ * suffix, and a group is a coordinator-minted gate id. Re-enforcing the shape
119
+ * here means whatever wrote the file, the identifiers this projection reports
120
+ * can carry no separator, space, quote, or control byte.
121
+ */
122
+ const SAFE_GATE_IDENTIFIER = /^[A-Za-z0-9._:-]{1,128}$/u;
123
+
124
+ /** The independence facts sealed on the decision, exactly as the artifact holds them. */
125
+ export type GateDecisionCorrelationFacts = Pick<
126
+ GateRouteCorrelation,
127
+ "agent" | "target" | "modelFamily" | "runtime" | "node" | "independent"
128
+ >;
129
+
130
+ export interface GateTopologyWinner {
131
+ /** 1-based candidate ordinal the judge picked. */
132
+ readonly index: number;
133
+ readonly runId: string;
134
+ }
135
+
136
+ export interface GateTopologyDecision {
137
+ readonly id: string;
138
+ readonly group: string;
139
+ readonly topology: "review" | "compete";
140
+ readonly cycle: number;
141
+ readonly outcome: GateDecisionOutcome;
142
+ readonly decidedAt: string;
143
+ /** Runs this decision graded, in the order the coordinator sealed them. */
144
+ readonly subjects: readonly string[];
145
+ readonly subjectsTruncated: boolean;
146
+ /** The run that produced the verdict, or null when none ran. */
147
+ readonly decider: string | null;
148
+ /** Present exactly when a decider ran; the store requires the pair. */
149
+ readonly correlation: GateDecisionCorrelationFacts | null;
150
+ readonly winner: GateTopologyWinner | null;
151
+ /** A prior judge decision this one confirmed, by id. */
152
+ readonly confirms: string | null;
153
+ readonly reason: GateDecisionReason | null;
154
+ }
155
+
156
+ export interface GateTopologyResult {
157
+ /**
158
+ * Whether this installation has a decision store at all.
159
+ *
160
+ * An installation that has never run a gate and one whose gates all aged out
161
+ * both report no decisions, and they are different operator states, so the
162
+ * fact is read rather than inferred from an empty list.
163
+ */
164
+ readonly present: boolean;
165
+ readonly decisions: readonly GateTopologyDecision[];
166
+ /** True when the scanned window held decisions older than the reported ones. */
167
+ readonly truncated: boolean;
168
+ /**
169
+ * Files in the scanned window whose integrity did not verify.
170
+ *
171
+ * The store's own read API drops these silently, which is right for a
172
+ * consumer that must not act on untrusted evidence and wrong for an operator
173
+ * surface: a gate artifact that no longer authenticates is exactly the thing
174
+ * worth knowing about. Counted, never opened for content.
175
+ */
176
+ readonly unverifiable: number;
177
+ }
178
+
179
+ function classifyReason(detail: unknown): GateDecisionReason | null {
180
+ if (typeof detail !== "string" || detail.length === 0) return null;
181
+ return REASON_RULES.find(([prefix]) => detail.startsWith(prefix))?.[1] ?? "unclassified";
182
+ }
183
+
184
+ function safeIdentifier(value: unknown): string | null {
185
+ return typeof value === "string" && SAFE_GATE_IDENTIFIER.test(value) ? value : null;
186
+ }
187
+
188
+ /** Newest decision first. An unparseable stamp sorts oldest rather than throwing. */
189
+ function byNewest(a: GateDecisionArtifact, b: GateDecisionArtifact): number {
190
+ return (Date.parse(b.createdAt) || 0) - (Date.parse(a.createdAt) || 0);
191
+ }
192
+
193
+ /**
194
+ * Read a bounded window of verified decision artifacts, counting the rest.
195
+ *
196
+ * Reads defensively per file for the same reason the ledger scan does: one
197
+ * artifact written by another build, half-written, or removed between the
198
+ * listing and the open must cost that decision its row, never the whole
199
+ * listing. A file that parses but fails its own integrity check is a different
200
+ * state and is counted rather than dropped.
201
+ */
202
+ function readDecisionWindow(stateDir: string): {
203
+ present: boolean;
204
+ artifacts: GateDecisionArtifact[];
205
+ unverifiable: number;
206
+ } {
207
+ const directory = gateDecisionsDirectory(stateDir);
208
+ if (!existsSync(directory)) return { present: false, artifacts: [], unverifiable: 0 };
209
+ let entries: string[];
210
+ try {
211
+ entries = readdirSync(directory).filter((name) => name.endsWith(".json"));
212
+ } catch {
213
+ // The directory is there and unreadable, which is not the same as absent.
214
+ return { present: true, artifacts: [], unverifiable: 0 };
215
+ }
216
+ const artifacts: GateDecisionArtifact[] = [];
217
+ let unverifiable = 0;
218
+ for (const name of entries.slice(0, GATE_TOPOLOGY_MAX_SCAN)) {
219
+ let artifact: GateDecisionArtifact;
220
+ try {
221
+ artifact = JSON.parse(readFileSync(join(directory, name), "utf8")) as GateDecisionArtifact;
222
+ } catch {
223
+ unverifiable += 1;
224
+ continue;
225
+ }
226
+ if (verifyGateDecisionArtifact(artifact).ok) artifacts.push(artifact);
227
+ else unverifiable += 1;
228
+ }
229
+ artifacts.sort(byNewest);
230
+ return { present: true, artifacts, unverifiable };
231
+ }
232
+
233
+ function projectDecision(artifact: GateDecisionArtifact): GateTopologyDecision | null {
234
+ const id = safeIdentifier(artifact.id);
235
+ const group = safeIdentifier(artifact.group);
236
+ // The store mints both and already refuses either outside this shape, so a
237
+ // stored value failing it means something else wrote the file. A decision
238
+ // this projection cannot name is one it will not report.
239
+ if (id === null || group === null) return null;
240
+ const allSubjects = artifact.subjects.map((subject) => safeIdentifier(subject.runId));
241
+ if (allSubjects.some((runId) => runId === null)) return null;
242
+ const subjects = (allSubjects as string[]).slice(0, GATE_TOPOLOGY_MAX_SUBJECTS);
243
+ const decider = artifact.decider === undefined ? null : safeIdentifier(artifact.decider.runId);
244
+ if (artifact.decider !== undefined && decider === null) return null;
245
+ let winner: GateTopologyWinner | null = null;
246
+ if (artifact.winner !== undefined) {
247
+ const runId = safeIdentifier(artifact.winner.subject.runId);
248
+ if (runId === null) return null;
249
+ winner = { index: artifact.winner.index, runId };
250
+ }
251
+ return {
252
+ id,
253
+ group,
254
+ topology: artifact.topology,
255
+ cycle: artifact.cycle,
256
+ outcome: artifact.outcome,
257
+ decidedAt: new Date(artifact.createdAt).toISOString(),
258
+ subjects,
259
+ subjectsTruncated: allSubjects.length > subjects.length,
260
+ decider,
261
+ correlation: artifact.correlation === undefined ? null : { ...artifact.correlation },
262
+ winner,
263
+ confirms: artifact.confirmation === undefined ? null : safeIdentifier(artifact.confirmation.id),
264
+ reason: classifyReason(artifact.detail),
265
+ };
266
+ }
267
+
268
+ /**
269
+ * Bounded newest-first coordinator gate decisions.
270
+ *
271
+ * Selected by this function, never by a caller's argument, so a host that
272
+ * invokes the command behind it knows the process cannot be steered into a
273
+ * different window.
274
+ */
275
+ export function gateTopology(stateDir: string = clioStateDir()): GateTopologyResult {
276
+ const { present, artifacts, unverifiable } = readDecisionWindow(stateDir);
277
+ const window = artifacts.slice(0, GATE_TOPOLOGY_MAX_DECISIONS);
278
+ const decisions: GateTopologyDecision[] = [];
279
+ for (const artifact of window) {
280
+ const decision = projectDecision(artifact);
281
+ if (decision !== null) decisions.push(decision);
282
+ }
283
+ return {
284
+ present,
285
+ decisions,
286
+ truncated: artifacts.length > window.length || decisions.length !== window.length,
287
+ unverifiable,
288
+ };
289
+ }
@@ -124,9 +124,28 @@ export {
124
124
  DISPATCH_INTENT_PATH_LIST_CAP,
125
125
  DISPATCH_INTENT_TIMEOUT_MIN_MS,
126
126
  DISPATCH_INTENT_VERIFICATION_CAP,
127
+ declaredScopeIntent,
127
128
  isDispatchIntent,
129
+ narrowDispatchIntentToReadOnly,
128
130
  normalizeDispatchIntent,
129
131
  } from "./intent.js";
132
+ export type {
133
+ DispatchIntentAdoption,
134
+ DispatchIntentCompatibilityCode,
135
+ DispatchIntentCompatibilityDecision,
136
+ DispatchIntentCompatibilityFinding,
137
+ } from "./intent-compatibility.js";
138
+ export {
139
+ classifyDispatchIntentCompatibility,
140
+ DISPATCH_INTENT_RETIREMENT_MAX_LEGACY_SHARE,
141
+ DISPATCH_INTENT_RETIREMENT_MIN_SAMPLE,
142
+ DISPATCH_INTENT_SUPPORTED_VERSIONS,
143
+ DISPATCH_INTENT_VERSION,
144
+ dispatchIntentAdoption,
145
+ dispatchIntentRefusals,
146
+ dispatchIntentScopeWidening,
147
+ isSupportedDispatchIntentVersion,
148
+ } from "./intent-compatibility.js";
130
149
  export { DispatchManifest } from "./manifest.js";
131
150
  export { verifyReceiptIntegrity } from "./receipt-integrity.js";
132
151
  export { createRouteHistoryStore } from "./route-history.js";