@iowarp/clio-coder 0.3.8 → 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 (552) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/NOTICE +33 -0
  3. package/README.md +12 -3
  4. package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
  5. package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
  8. package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
  9. package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
  10. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  11. package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
  12. package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
  13. package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
  14. package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
  15. package/dist/chunk-3DPEIQKN.js +113 -0
  16. package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
  17. package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
  18. package/dist/chunk-42FMPA75.js +101 -0
  19. package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
  20. package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
  21. package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
  22. package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
  23. package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
  24. package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
  25. package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
  26. package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
  27. package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
  28. package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
  29. package/dist/chunk-BKFM6EJV.js +462 -0
  30. package/dist/chunk-BMS5RKQY.js +27 -0
  31. package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
  32. package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
  33. package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
  34. package/dist/chunk-C2LTL2W6.js +2447 -0
  35. package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
  36. package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
  37. package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
  38. package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
  39. package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
  40. package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
  41. package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
  42. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  43. package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
  44. package/dist/chunk-GKF55TAZ.js +391 -0
  45. package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
  46. package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
  47. package/dist/chunk-HHV2GANA.js +88 -0
  48. package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
  49. package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
  50. package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
  51. package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
  52. package/dist/chunk-HZHHCK24.js +1631 -0
  53. package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
  54. package/dist/chunk-IBEBSCYA.js +564 -0
  55. package/dist/chunk-IQ7KR472.js +362 -0
  56. package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
  57. package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
  58. package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
  59. package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
  60. package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
  61. package/dist/chunk-KMVISBZR.js +132 -0
  62. package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
  63. package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
  64. package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
  65. package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
  66. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  67. package/dist/chunk-NEKRRTYW.js +56 -0
  68. package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
  69. package/dist/chunk-NHLBIGRH.js +1506 -0
  70. package/dist/chunk-NQQH3YT7.js +302 -0
  71. package/dist/chunk-NYS75XW5.js +15 -0
  72. package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
  73. package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
  74. package/dist/chunk-OQBA45DZ.js +97 -0
  75. package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
  76. package/dist/chunk-PMZCIOCJ.js +25 -0
  77. package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
  78. package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
  79. package/dist/chunk-QDC3K2U3.js +262 -0
  80. package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
  81. package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
  82. package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
  83. package/dist/chunk-QSNYB6ZV.js +195 -0
  84. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  85. package/dist/chunk-RKKLTLYB.js +45 -0
  86. package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
  87. package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
  88. package/dist/chunk-SUCTJL45.js +45 -0
  89. package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
  90. package/dist/chunk-T56WDKA5.js +183 -0
  91. package/dist/chunk-TVHHYFHE.js +255 -0
  92. package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
  93. package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
  94. package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
  95. package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
  96. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  97. package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
  98. package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
  99. package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
  100. package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
  101. package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
  102. package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
  103. package/dist/chunk-VO67MWHC.js +75 -0
  104. package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
  105. package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
  106. package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
  107. package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
  108. package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
  109. package/dist/chunk-X75E3D2N.js +686 -0
  110. package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
  111. package/dist/chunk-YJX4SHTD.js +40 -0
  112. package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
  113. package/dist/chunk-Z2RR6MAK.js +127 -0
  114. package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
  115. package/dist/cli/index.js +47 -36
  116. package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
  117. package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
  118. package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
  119. package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
  120. package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
  121. package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
  122. package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
  123. package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
  124. package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
  125. package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
  126. package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
  127. package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
  128. package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
  129. package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
  130. package/dist/doctor-QOA5FNY5.js +313 -0
  131. package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
  132. package/dist/eval-inventory-SXH7PDKX.js +316 -0
  133. package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
  134. package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
  135. package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
  136. package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
  137. package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
  138. package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
  139. package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
  140. package/dist/fleet-inspect-VLY4S7QM.js +442 -0
  141. package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
  142. package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
  143. package/dist/fleet-verify-JFEL2L3H.js +175 -0
  144. package/dist/fleet-view-ZCON35AG.js +102 -0
  145. package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
  146. package/dist/install-XGLBQY5E.js +13 -0
  147. package/dist/interop-OZBKXAYL.js +114 -0
  148. package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
  149. package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
  150. package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
  151. package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
  152. package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
  153. package/dist/panes-HMABYVO4.js +58 -0
  154. package/dist/panes-KY6W3V2E.js +103 -0
  155. package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
  156. package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
  157. package/dist/resources-BB3MVJMD.js +111 -0
  158. package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
  159. package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
  160. package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
  161. package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
  162. package/dist/skills-inventory-S4MXPJFV.js +126 -0
  163. package/dist/slash-commands-ZSGASKJC.js +77 -0
  164. package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
  165. package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
  166. package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
  167. package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
  168. package/dist/tools-DAF3DI3C.js +27 -0
  169. package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
  170. package/dist/tui-primitives-2AKXQNZK.js +13 -0
  171. package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
  172. package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
  173. package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
  174. package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
  175. package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
  176. package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
  177. package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
  178. package/dist/with-panes-MKB46MPQ.js +782 -0
  179. package/dist/worker/entry.js +106 -75
  180. package/docs/README.md +3 -2
  181. package/docs/acp.md +24 -3
  182. package/docs/alcf-provider.md +1 -1
  183. package/docs/architecture.md +2 -2
  184. package/docs/artifact-versions.md +9 -1
  185. package/docs/built-in-agents.md +1 -1
  186. package/docs/capacity-and-scheduling.md +62 -3
  187. package/docs/commands-and-modes.md +31 -2
  188. package/docs/configuration-and-targets.md +69 -12
  189. package/docs/context-engine.md +63 -4
  190. package/docs/development-pipeline.md +19 -0
  191. package/docs/dispatch-typed-intent.md +385 -0
  192. package/docs/documentation-coverage.md +5 -5
  193. package/docs/documentation-guide.md +1 -1
  194. package/docs/environment-variables.md +3 -0
  195. package/docs/eval-runner.md +262 -11
  196. package/docs/evals-internal.md +72 -2
  197. package/docs/evidence-and-memory.md +12 -11
  198. package/docs/evolution.md +1 -1
  199. package/docs/exit-codes-and-output.md +1 -1
  200. package/docs/extensions-and-sharing.md +27 -1
  201. package/docs/fleet-dispatch.md +25 -4
  202. package/docs/installation-and-lifecycle.md +15 -2
  203. package/docs/middleware-and-components.md +1 -1
  204. package/docs/model-catalog.md +10 -1
  205. package/docs/observability.md +55 -4
  206. package/docs/proactive-memory.md +127 -14
  207. package/docs/prompt-envelope-and-tools.md +19 -1
  208. package/docs/provider-adapter-cookbook.md +1 -1
  209. package/docs/release-cut-checklist.md +19 -3
  210. package/docs/safety-model.md +2 -2
  211. package/docs/scientific-validation.md +3 -3
  212. package/docs/session-lifecycle.md +1 -1
  213. package/docs/skills-marketplace.md +1 -1
  214. package/docs/tool-usage.md +18 -8
  215. package/docs/trace-store.md +1 -1
  216. package/docs/troubleshooting.md +88 -1
  217. package/docs/tui-design.md +1 -1
  218. package/docs/worker-dispatch-mechanics.md +1 -1
  219. package/package.json +5 -2
  220. package/src/cli/acp.ts +6 -2
  221. package/src/cli/agents.ts +1 -1
  222. package/src/cli/argv.ts +25 -0
  223. package/src/cli/config-inspect.ts +33 -6
  224. package/src/cli/config.ts +1 -1
  225. package/src/cli/configure.ts +23 -21
  226. package/src/cli/doctor-panes.ts +124 -0
  227. package/src/cli/doctor-state-size.ts +82 -0
  228. package/src/cli/doctor-toolchain.ts +57 -0
  229. package/src/cli/doctor.ts +22 -1
  230. package/src/cli/eval-inventory.ts +436 -0
  231. package/src/cli/eval.ts +93 -16
  232. package/src/cli/evidence-detail.ts +88 -0
  233. package/src/cli/evidence-inventory.ts +183 -0
  234. package/src/cli/evidence.ts +30 -5
  235. package/src/cli/extensions.ts +5 -1
  236. package/src/cli/fleet-decisions.ts +69 -0
  237. package/src/cli/fleet-inspect.ts +334 -0
  238. package/src/cli/fleet-verify.ts +133 -0
  239. package/src/cli/fleet-view.ts +810 -0
  240. package/src/cli/fleet.ts +179 -39
  241. package/src/cli/index.ts +14 -2
  242. package/src/cli/interop-inspect.ts +128 -0
  243. package/src/cli/interop.ts +34 -0
  244. package/src/cli/panes.ts +35 -0
  245. package/src/cli/reset.ts +5 -2
  246. package/src/cli/run.ts +58 -0
  247. package/src/cli/skills-inventory.ts +185 -0
  248. package/src/cli/skills.ts +16 -13
  249. package/src/cli/targets.ts +44 -13
  250. package/src/cli/tools.ts +321 -0
  251. package/src/cli/trace-inspect.ts +252 -0
  252. package/src/cli/trace.ts +85 -5
  253. package/src/cli/usage.ts +63 -14
  254. package/src/cli/verifiers-inspect.ts +347 -0
  255. package/src/cli/verifiers.ts +9 -0
  256. package/src/core/bus-events.ts +33 -1
  257. package/src/core/cache-telemetry.ts +42 -0
  258. package/src/core/config.ts +67 -0
  259. package/src/core/defaults.ts +124 -8
  260. package/src/core/endpoint-key.ts +27 -0
  261. package/src/core/residency-target-key.ts +25 -0
  262. package/src/core/response-schema.ts +80 -6
  263. package/src/core/theme-token-hex.ts +43 -0
  264. package/src/core/tool-names.ts +2 -1
  265. package/src/core/xdg.ts +1 -1
  266. package/src/domains/agents/fleets/build-review.md +0 -3
  267. package/src/domains/agents/fleets/build-test.md +0 -3
  268. package/src/domains/agents/result-contract-filesystem.ts +32 -0
  269. package/src/domains/agents/result-contract.ts +164 -35
  270. package/src/domains/config/classify.ts +6 -0
  271. package/src/domains/context/codewiki/coordinator.ts +12 -4
  272. package/src/domains/dispatch/admission-error.ts +9 -0
  273. package/src/domains/dispatch/admission.ts +52 -14
  274. package/src/domains/dispatch/capacity-lease.ts +118 -9
  275. package/src/domains/dispatch/contract.ts +11 -0
  276. package/src/domains/dispatch/council-topology.ts +398 -0
  277. package/src/domains/dispatch/execution-plan.ts +44 -4
  278. package/src/domains/dispatch/extension.ts +378 -82
  279. package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
  280. package/src/domains/dispatch/fleet-plan.ts +7 -2
  281. package/src/domains/dispatch/fleet-run.ts +87 -4
  282. package/src/domains/dispatch/gate-decisions.ts +11 -1
  283. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  284. package/src/domains/dispatch/gate-topology.ts +289 -0
  285. package/src/domains/dispatch/heartbeat.ts +32 -8
  286. package/src/domains/dispatch/index.ts +22 -0
  287. package/src/domains/dispatch/intent-compatibility.ts +330 -0
  288. package/src/domains/dispatch/intent.ts +85 -1
  289. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  290. package/src/domains/dispatch/reservation-store.ts +139 -11
  291. package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
  292. package/src/domains/dispatch/run-event-journal.ts +598 -0
  293. package/src/domains/dispatch/state.ts +49 -1
  294. package/src/domains/dispatch/types.ts +13 -0
  295. package/src/domains/dispatch/validation.ts +33 -8
  296. package/src/domains/dispatch/worker-spawn.ts +25 -11
  297. package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
  298. package/src/domains/dispatch/write-boundary.ts +62 -1
  299. package/src/domains/eval/artifacts/store.ts +62 -0
  300. package/src/domains/eval/compare/behavioral.ts +224 -0
  301. package/src/domains/eval/compare/compare.ts +342 -2
  302. package/src/domains/eval/compare/envelope.ts +128 -0
  303. package/src/domains/eval/compare/gates.ts +24 -6
  304. package/src/domains/eval/compare/thresholds.ts +30 -3
  305. package/src/domains/eval/execution-provenance.ts +240 -0
  306. package/src/domains/eval/inventory.ts +113 -0
  307. package/src/domains/eval/metrics/aggregate.ts +136 -0
  308. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  309. package/src/domains/eval/metrics/tracked.ts +413 -0
  310. package/src/domains/eval/provenance.ts +117 -0
  311. package/src/domains/eval/reports/comparison.ts +128 -0
  312. package/src/domains/eval/reports/junit.ts +17 -3
  313. package/src/domains/eval/reports/markdown.ts +3 -3
  314. package/src/domains/eval/reports/text.ts +14 -0
  315. package/src/domains/eval/run-compare.ts +20 -0
  316. package/src/domains/eval/runners/clio-run.ts +127 -0
  317. package/src/domains/eval/runners/external-command.ts +28 -3
  318. package/src/domains/eval/schema/adapter.ts +111 -0
  319. package/src/domains/eval/schema/artifact.ts +20 -0
  320. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  321. package/src/domains/eval/schema/behavioral.ts +520 -0
  322. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  323. package/src/domains/eval/schema/serving.ts +105 -0
  324. package/src/domains/eval/schema/suite.ts +38 -8
  325. package/src/domains/eval/schema/validate.ts +58 -3
  326. package/src/domains/eval/schema/verdict.ts +237 -0
  327. package/src/domains/eval/suites/resolve.ts +2 -0
  328. package/src/domains/eval/suites/run.ts +264 -33
  329. package/src/domains/eval/verifiers/command.ts +2 -1
  330. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  331. package/src/domains/evidence/build.ts +2 -13
  332. package/src/domains/evidence/eval.ts +2 -12
  333. package/src/domains/evidence/findings-markdown.ts +33 -0
  334. package/src/domains/evidence/run-trust.ts +7 -113
  335. package/src/domains/evidence/store.ts +6 -0
  336. package/src/domains/evidence/trust-projection.ts +2 -2
  337. package/src/domains/extensions/compatibility.ts +285 -0
  338. package/src/domains/extensions/discovery.ts +38 -3
  339. package/src/domains/extensions/resources.ts +1 -1
  340. package/src/domains/extensions/state.ts +12 -3
  341. package/src/domains/extensions/types.ts +2 -0
  342. package/src/domains/lifecycle/doctor.ts +69 -1
  343. package/src/domains/memory/index.ts +14 -1
  344. package/src/domains/memory/task-bank-promotion.ts +64 -0
  345. package/src/domains/memory/task-memory-policy.ts +82 -17
  346. package/src/domains/memory/task-memory-spend.ts +131 -0
  347. package/src/domains/memory/task-memory-status.ts +7 -0
  348. package/src/domains/memory/task-memory-telemetry.ts +3 -0
  349. package/src/domains/middleware/index.ts +1 -0
  350. package/src/domains/middleware/memory-intervention.ts +97 -21
  351. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  352. package/src/domains/mux/contract.ts +434 -0
  353. package/src/domains/mux/detect.ts +158 -0
  354. package/src/domains/mux/extension.ts +47 -0
  355. package/src/domains/mux/index.ts +96 -0
  356. package/src/domains/mux/manifest.ts +6 -0
  357. package/src/domains/mux/operations.ts +164 -0
  358. package/src/domains/mux/pane-registry.ts +90 -0
  359. package/src/domains/mux/protocol.ts +49 -0
  360. package/src/domains/mux/socket-client.ts +816 -0
  361. package/src/domains/mux/types.ts +222 -0
  362. package/src/domains/mux/viewer-command.ts +59 -0
  363. package/src/domains/mux/yazi/assets/init.lua +2 -0
  364. package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
  365. package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
  366. package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
  367. package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
  368. package/src/domains/mux/yazi/assets/yazi.toml +17 -0
  369. package/src/domains/mux/yazi/event-stream.ts +180 -0
  370. package/src/domains/mux/yazi/profile.ts +299 -0
  371. package/src/domains/mux/yazi/session.ts +228 -0
  372. package/src/domains/mux/yazi/theme.ts +30 -0
  373. package/src/domains/observability/background-memory-usage.ts +140 -0
  374. package/src/domains/observability/cost.ts +22 -1
  375. package/src/domains/observability/index.ts +9 -0
  376. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  377. package/src/domains/observability/trace-store.ts +234 -2
  378. package/src/domains/prompts/compiler.ts +100 -13
  379. package/src/domains/providers/endpoint-capacity.ts +228 -0
  380. package/src/domains/providers/endpoint-slots-store.ts +189 -0
  381. package/src/domains/providers/extension.ts +20 -3
  382. package/src/domains/providers/index.ts +32 -0
  383. package/src/domains/providers/model-runtime-capabilities.ts +32 -0
  384. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  385. package/src/domains/providers/runtime-resolution.ts +8 -1
  386. package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
  387. package/src/domains/providers/runtimes/builtins.ts +2 -0
  388. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  389. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  390. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  391. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  392. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  393. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  394. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  395. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  396. package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
  397. package/src/domains/providers/support.ts +1 -0
  398. package/src/domains/providers/target-model-cache.ts +124 -0
  399. package/src/domains/providers/types/capability-flags.ts +2 -0
  400. package/src/domains/providers/types/target-descriptor.ts +2 -0
  401. package/src/domains/resources/index.ts +3 -0
  402. package/src/domains/resources/prompts/loader.ts +95 -33
  403. package/src/domains/resources/skills/loader.ts +33 -0
  404. package/src/domains/safety/action-classifier.ts +6 -0
  405. package/src/domains/safety/call-target.ts +52 -0
  406. package/src/domains/safety/run-effects.ts +35 -4
  407. package/src/domains/session/context-accounting.ts +52 -1
  408. package/src/domains/session/context-ledger.ts +37 -13
  409. package/src/domains/session/index.ts +6 -0
  410. package/src/domains/session/prompt-cache.ts +140 -0
  411. package/src/domains/session/prompt-manifest.ts +42 -0
  412. package/src/domains/toolchain/archive.ts +175 -0
  413. package/src/domains/toolchain/contract.ts +28 -0
  414. package/src/domains/toolchain/extension.ts +47 -0
  415. package/src/domains/toolchain/index.ts +39 -0
  416. package/src/domains/toolchain/install.ts +327 -0
  417. package/src/domains/toolchain/manifest.ts +8 -0
  418. package/src/domains/toolchain/paths.ts +34 -0
  419. package/src/domains/toolchain/registry.ts +265 -0
  420. package/src/domains/toolchain/remove.ts +218 -0
  421. package/src/domains/toolchain/resolve.ts +182 -0
  422. package/src/domains/toolchain/types.ts +113 -0
  423. package/src/domains/toolchain/version.ts +88 -0
  424. package/src/engine/acp/adapter.ts +18 -3
  425. package/src/engine/acp/server.ts +413 -70
  426. package/src/engine/acp/types.ts +19 -1
  427. package/src/engine/ai.ts +35 -0
  428. package/src/engine/apis/llamacpp-residency.ts +55 -3
  429. package/src/engine/apis/lmstudio.ts +25 -5
  430. package/src/engine/apis/ollama-native.ts +2 -1
  431. package/src/engine/apis/openai-completions.ts +80 -17
  432. package/src/engine/apis/residency-lock.ts +3 -1
  433. package/src/engine/apis/residency.ts +34 -1
  434. package/src/engine/claude/sdk-module.ts +98 -0
  435. package/src/engine/claude/sdk-runtime.ts +19 -11
  436. package/src/engine/provider-payload.ts +29 -1
  437. package/src/engine/tui-primitives.ts +21 -0
  438. package/src/engine/tui.ts +1 -0
  439. package/src/engine/worker-runtime.ts +2 -13
  440. package/src/entry/boot-options.ts +2 -0
  441. package/src/entry/orchestrator.ts +279 -35
  442. package/src/entry/panes-activation.ts +31 -0
  443. package/src/entry/with-panes.ts +20 -0
  444. package/src/interactive/chat-loop-messages.ts +26 -7
  445. package/src/interactive/chat-loop.ts +318 -41
  446. package/src/interactive/chat-panel.ts +62 -8
  447. package/src/interactive/clio-editor.ts +45 -8
  448. package/src/interactive/context-activity.ts +5 -1
  449. package/src/interactive/context-meter.ts +1 -1
  450. package/src/interactive/context-overlay.ts +41 -10
  451. package/src/interactive/cost-overlay.ts +66 -6
  452. package/src/interactive/council-grid.ts +1 -3
  453. package/src/interactive/council.ts +11 -0
  454. package/src/interactive/dispatch-board.ts +102 -20
  455. package/src/interactive/fleet-run-preview.ts +41 -15
  456. package/src/interactive/handoff-round.ts +41 -2
  457. package/src/interactive/interactive-application.ts +177 -7
  458. package/src/interactive/interactive-input-runtime.ts +15 -0
  459. package/src/interactive/interactive-presentation.ts +4 -0
  460. package/src/interactive/interactive-shell.ts +20 -17
  461. package/src/interactive/interactive-slash-runtime.ts +63 -10
  462. package/src/interactive/memory-overlay.ts +9 -0
  463. package/src/interactive/modal-marker.ts +170 -0
  464. package/src/interactive/mutation-preview.ts +295 -0
  465. package/src/interactive/mux-bridge.ts +214 -0
  466. package/src/interactive/overlay-frame.ts +58 -2
  467. package/src/interactive/overlay-general-openers.ts +17 -0
  468. package/src/interactive/overlay-key-routing.ts +52 -3
  469. package/src/interactive/overlay-lifecycle.ts +56 -7
  470. package/src/interactive/overlay-model-selectors.ts +40 -3
  471. package/src/interactive/overlay-permission-lifecycle.ts +112 -24
  472. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  473. package/src/interactive/overlay-transitions.ts +18 -4
  474. package/src/interactive/overlays/agents.ts +1 -0
  475. package/src/interactive/overlays/ask-user.ts +227 -49
  476. package/src/interactive/overlays/auth-dialog.ts +1 -0
  477. package/src/interactive/overlays/context-reset.ts +1 -0
  478. package/src/interactive/overlays/cwd-fallback.ts +1 -0
  479. package/src/interactive/overlays/decisions.ts +11 -11
  480. package/src/interactive/overlays/extensions.ts +1 -0
  481. package/src/interactive/overlays/fleet-run-approval.ts +1 -0
  482. package/src/interactive/overlays/handoff-review.ts +1 -0
  483. package/src/interactive/overlays/help-reference.ts +6 -0
  484. package/src/interactive/overlays/interop.ts +1 -0
  485. package/src/interactive/overlays/library-install-confirm.ts +1 -0
  486. package/src/interactive/overlays/library-tabs.ts +28 -0
  487. package/src/interactive/overlays/list-overlay.ts +10 -1
  488. package/src/interactive/overlays/message-picker.ts +1 -0
  489. package/src/interactive/overlays/model-scope.ts +86 -0
  490. package/src/interactive/overlays/model-selector.ts +1 -0
  491. package/src/interactive/overlays/prompts.ts +12 -1
  492. package/src/interactive/overlays/session-selector.ts +1 -0
  493. package/src/interactive/overlays/settings-sections.ts +30 -0
  494. package/src/interactive/overlays/settings.ts +614 -45
  495. package/src/interactive/overlays/side-question.ts +1 -0
  496. package/src/interactive/overlays/skills-hub.ts +3 -11
  497. package/src/interactive/overlays/tree-selector.ts +1 -0
  498. package/src/interactive/pane-policy.ts +46 -0
  499. package/src/interactive/panes-runtime.ts +292 -0
  500. package/src/interactive/permission-hint.ts +34 -2
  501. package/src/interactive/permission-overlay.ts +159 -9
  502. package/src/interactive/prewarm.ts +197 -0
  503. package/src/interactive/render-trace.ts +162 -15
  504. package/src/interactive/renderers/compaction-summary.ts +29 -0
  505. package/src/interactive/renderers/tool-execution.ts +4 -0
  506. package/src/interactive/renderers/worker-entry.ts +122 -14
  507. package/src/interactive/side-question.ts +58 -1
  508. package/src/interactive/slash-commands.ts +251 -15
  509. package/src/interactive/status/controller.ts +11 -0
  510. package/src/interactive/status/state-machine.ts +54 -2
  511. package/src/interactive/status/types.ts +7 -0
  512. package/src/interactive/tasks-overlay.ts +1 -0
  513. package/src/interactive/terminal-lease.ts +2 -0
  514. package/src/interactive/theme/tokens.ts +3 -14
  515. package/src/interactive/turn-context.ts +346 -33
  516. package/src/interactive/turn-persistence.ts +14 -4
  517. package/src/interactive/turn-prewarm.ts +364 -0
  518. package/src/interactive/turn-queues.ts +7 -4
  519. package/src/interactive/turn-runtime.ts +8 -1
  520. package/src/interactive/turn-state.ts +23 -0
  521. package/src/interactive/view/artifacts.ts +109 -1
  522. package/src/interactive/view/view-overlay.ts +29 -3
  523. package/src/interactive/watch-pane.ts +152 -0
  524. package/src/interactive/worker-progress.ts +7 -1
  525. package/src/interactive/worker-receipts.ts +19 -1
  526. package/src/interactive/worker-stream.ts +5 -0
  527. package/src/interactive/yazi-bridge.ts +444 -0
  528. package/src/tools/ask-user.ts +43 -2
  529. package/src/tools/bootstrap.ts +26 -2
  530. package/src/tools/builtin-tool-catalog.ts +15 -0
  531. package/src/tools/compete-worktrees.ts +83 -2
  532. package/src/tools/core-bootstrap.ts +2 -1
  533. package/src/tools/dispatch-admission.ts +14 -3
  534. package/src/tools/dispatch-arguments.ts +20 -20
  535. package/src/tools/dispatch-plan.ts +17 -9
  536. package/src/tools/dispatch-run-events.ts +134 -19
  537. package/src/tools/dispatch-runner.ts +29 -7
  538. package/src/tools/dispatch-scout.ts +1 -1
  539. package/src/tools/dispatch-types.ts +15 -3
  540. package/src/tools/dispatch.ts +1 -1
  541. package/src/tools/executables.ts +17 -14
  542. package/src/tools/observation.ts +54 -4
  543. package/src/tools/panes-surface.ts +38 -0
  544. package/src/tools/panes.ts +112 -0
  545. package/src/tools/policy.ts +10 -1
  546. package/src/tools/presentation.ts +1 -0
  547. package/src/tools/registry.ts +16 -0
  548. package/dist/chunk-AOCYTWAV.js +0 -449
  549. package/dist/chunk-HLE42MG7.js +0 -37
  550. package/dist/chunk-HWUFFB6L.js +0 -83
  551. package/dist/chunk-JOZYP4GM.js +0 -279
  552. package/dist/doctor-M7YEDGAE.js +0 -91
@@ -34,7 +34,7 @@ import {
34
34
  } from "node:fs";
35
35
  import { hostname } from "node:os";
36
36
  import { join, relative, resolve } from "node:path";
37
- import type { RunKind } from "../domains/dispatch/types.js";
37
+ import type { RunGateWorktreeProvenance, RunKind } from "../domains/dispatch/types.js";
38
38
  import {
39
39
  commitWorktreePath,
40
40
  isCanonicalWorktreePathInside,
@@ -47,6 +47,24 @@ export interface CandidateWorktree {
47
47
  index: number;
48
48
  branch: string;
49
49
  path: string;
50
+ provenance?: RunGateWorktreeProvenance;
51
+ }
52
+
53
+ /** Narrow mux surface used by compete; the native functions remain usable alone. */
54
+ export interface CompeteMuxWorktrees {
55
+ available(): boolean;
56
+ worktreeCreate(request: {
57
+ cwd: string;
58
+ branch: string;
59
+ base: string;
60
+ path: string;
61
+ label: string;
62
+ focus: boolean;
63
+ }): Promise<{
64
+ workspaceId: string;
65
+ worktree: { path: string; branch: string | null };
66
+ } | null>;
67
+ worktreeRemove(workspaceId: string, options?: { force?: boolean }): Promise<boolean>;
50
68
  }
51
69
 
52
70
  export type CompeteGroupState = "active" | "cleanup-ready" | "winner-preserved";
@@ -546,6 +564,52 @@ export function createCandidateWorktree(
546
564
  return { index, branch, path };
547
565
  }
548
566
 
567
+ /**
568
+ * Prefer herdr's worktree lifecycle while preserving Git as the recovery
569
+ * authority. A failed or vanished mux is deliberately indistinguishable from
570
+ * no mux to the caller except for the receipt provenance returned here.
571
+ */
572
+ export async function createCandidateWorktreeMapped(
573
+ ownership: CompeteGroupOwnership,
574
+ index: number,
575
+ baseline: string,
576
+ mux?: CompeteMuxWorktrees,
577
+ ): Promise<CandidateWorktree> {
578
+ assertOwnership(ownership);
579
+ const branch = competeBranch(ownership.group, index);
580
+ const path = join(ownership.directory, `candidate-${index}`);
581
+ if (!isCanonicalPathInside(ownership.directory, path)) {
582
+ throw new Error(`candidate ${index} path escapes compete group ${ownership.group}`);
583
+ }
584
+ let fallback: RunGateWorktreeProvenance["fallback"] = "mux-unavailable";
585
+ if (mux?.available()) {
586
+ const created = await mux
587
+ .worktreeCreate({
588
+ cwd: ownership.root,
589
+ branch,
590
+ base: baseline,
591
+ path,
592
+ label: `clio compete ${ownership.group} candidate ${index}`,
593
+ focus: false,
594
+ })
595
+ .catch(() => null);
596
+ if (created !== null) {
597
+ if (resolve(created.worktree.path) !== resolve(path) || created.worktree.branch !== branch) {
598
+ throw new Error(`herdr created candidate ${index} at an unexpected path or branch`);
599
+ }
600
+ return {
601
+ index,
602
+ branch,
603
+ path,
604
+ provenance: { backend: "herdr", path, branch, workspaceId: created.workspaceId },
605
+ };
606
+ }
607
+ fallback = "mux-operation-failed";
608
+ }
609
+ const native = createCandidateWorktree(ownership, index, baseline);
610
+ return { ...native, provenance: { backend: "native", path, branch, fallback } };
611
+ }
612
+
549
613
  /**
550
614
  * Seal a candidate's work as one commit on its branch. Returns false when the
551
615
  * builder changed nothing (an empty candidate is a legitimate ranking fact).
@@ -605,7 +669,7 @@ function removeRegisteredWorktree(root: string, path: string): void {
605
669
  }
606
670
  }
607
671
 
608
- export function removeCandidateWorktree(
672
+ function removeCandidateWorktree(
609
673
  ownership: CompeteGroupOwnership,
610
674
  worktree: CandidateWorktree,
611
675
  deleteBranch: boolean,
@@ -633,6 +697,23 @@ export function removeCandidateWorktree(
633
697
  }
634
698
  }
635
699
 
700
+ /** Remove through herdr when it owns the workspace, then verify with Git. */
701
+ export async function removeCandidateWorktreeMapped(
702
+ ownership: CompeteGroupOwnership,
703
+ worktree: CandidateWorktree,
704
+ deleteBranch: boolean,
705
+ mux?: CompeteMuxWorktrees,
706
+ ): Promise<void> {
707
+ const workspaceId = worktree.provenance?.backend === "herdr" ? worktree.provenance.workspaceId : undefined;
708
+ if (workspaceId && mux?.available()) {
709
+ await mux.worktreeRemove(workspaceId, { force: true }).catch(() => false);
710
+ }
711
+ // This is both the native fallback after mux loss and the postcondition check
712
+ // after a successful RPC. It prunes an already-removed path harmlessly and
713
+ // removes the candidate branch, which worktree.remove does not promise to do.
714
+ removeCandidateWorktree(ownership, worktree, deleteBranch);
715
+ }
716
+
636
717
  /**
637
718
  * Merge the winning candidate branch into the current branch. Fast-forward
638
719
  * is impossible by construction (the candidate branched from HEAD and HEAD
@@ -184,6 +184,7 @@ export function assertRegisteredBuiltinTools(
184
184
  registry: ToolRegistry,
185
185
  registration: CoreToolRegistration,
186
186
  includeDispatchTools: boolean,
187
+ includePanesTools = false,
187
188
  ): void {
188
- assertBuiltinToolPolicy(registry.listAll(), { ...registration, includeDispatchTools });
189
+ assertBuiltinToolPolicy(registry.listAll(), { ...registration, includeDispatchTools, includePanesTools });
189
190
  }
@@ -4,11 +4,13 @@ import type { ExecutionPlan } from "../domains/dispatch/execution-plan.js";
4
4
  import { gateDeciderAgentId } from "../domains/dispatch/execution-role.js";
5
5
  import {
6
6
  COUNCIL_JUDGE_PROMPT,
7
+ COUNCIL_MAX_MEMBERS,
8
+ COUNCIL_MIN_MEMBERS,
7
9
  JUDGE_GATE_PROMPT,
8
10
  REVIEWER_GATE_PROMPT,
9
11
  renderCouncilVoteMemberTask,
10
12
  } from "../domains/dispatch/gate-role-prompts.js";
11
- import { normalizeDispatchIntent } from "../domains/dispatch/intent.js";
13
+ import { narrowDispatchIntentToReadOnly, normalizeDispatchIntent } from "../domains/dispatch/intent.js";
12
14
  import { renderDispatchReviewerTask } from "../domains/dispatch/intent-requirements.js";
13
15
  import { approvedRouteCandidates } from "../domains/dispatch/route-approval.js";
14
16
  import { defaultRoutingIntent } from "../domains/dispatch/routing-intent.js";
@@ -109,7 +111,9 @@ function councilSettingsFromArgs(
109
111
  members.push({ label, target, ...(model ? { model } : {}), ...(thinking ? { thinking } : {}) });
110
112
  }
111
113
  }
112
- if (members.length < 2 || members.length > 5) return { ok: false, message: "council_members_out_of_range" };
114
+ if (members.length < COUNCIL_MIN_MEMBERS || members.length > COUNCIL_MAX_MEMBERS) {
115
+ return { ok: false, message: "council_members_out_of_range" };
116
+ }
113
117
  const labels = new Set<string>();
114
118
  for (const member of members) {
115
119
  if (labels.has(member.label)) return { ok: false, message: `council_member_label_duplicate: ${member.label}` };
@@ -389,7 +393,9 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
389
393
  };
390
394
  });
391
395
  const reservation = deps.dispatch.reservations.prepare({
392
- topology: artifact.topology === "fleet" || artifact.topology === "council" ? "parallel" : artifact.topology,
396
+ // A council keeps its own name so a capacity denial can say that its
397
+ // width has a floor. A fleet's waves are already parallel by shape.
398
+ topology: artifact.topology === "fleet" ? "parallel" : artifact.topology,
393
399
  tasks,
394
400
  });
395
401
  try {
@@ -638,6 +644,11 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
638
644
  executionRole: "researcher",
639
645
  autonomy: "read-only",
640
646
  toolProfile: "council-read-only",
647
+ // A member inherits the caller's declared scope but never its
648
+ // write authority: the same trees arrive as read roots, so the
649
+ // declaration stays enforceable against a read-only run instead of
650
+ // claiming a write scope nothing can grant.
651
+ ...(base.intent === undefined ? {} : { intent: narrowDispatchIntentToReadOnly(base.intent) }),
641
652
  // The runner reuses this composed task from the resolved plan, so
642
653
  // the approval artifact the plan hash binds shows the operator the
643
654
  // exact ballot the member is asked to cast.
@@ -1,12 +1,16 @@
1
1
  /** Pure model-argument parsing; every returned DispatchRequest has a concrete agent id. */
2
2
 
3
- import { pathBoundaryCovers } from "../core/path-boundary.js";
4
3
  import type { AgentAutomationAuthority } from "../domains/agents/spec.js";
5
4
  import { type AgentTaskType, classifyAgentTask } from "../domains/dispatch/agent-candidates.js";
6
5
  import { cloneDispatchBudgetRequest } from "../domains/dispatch/budget-envelope.js";
7
6
  import type { DispatchRequest } from "../domains/dispatch/contract.js";
8
7
  import { type AgentRoleFactsResolver, requestExecutionRole } from "../domains/dispatch/execution-role.js";
9
8
  import type { DispatchIntent } from "../domains/dispatch/intent.js";
9
+ import {
10
+ classifyDispatchIntentCompatibility,
11
+ dispatchIntentRefusals,
12
+ dispatchIntentScopeWidening,
13
+ } from "../domains/dispatch/intent-compatibility.js";
10
14
  import { parseRoutingIntent } from "../domains/dispatch/routing-intent.js";
11
15
  import { DISPATCH_BRIEFING_MAX_BYTES, type JobThinkingLevel } from "../domains/dispatch/validation.js";
12
16
  import { isToolProfileName, TOOL_PROFILE_NAMES } from "./profiles.js";
@@ -197,10 +201,17 @@ function dispatchRequestFromArgs(
197
201
  ? args.writeRoots.filter((entry): entry is string => typeof entry === "string")
198
202
  : undefined;
199
203
  if (legacy !== undefined) {
200
- const left = [...new Set(legacy)].sort();
201
- if (JSON.stringify(left) !== JSON.stringify(resolved.intent.writeRoots)) {
202
- return { ok: false, message: "intent_write_roots_contradiction" };
203
- }
204
+ // Asked through the same rule the job-spec validator asks, so the two
205
+ // cannot disagree about the same pair. A raw string comparison here
206
+ // would refuse './src/tools' against 'src/tools', which name one tree.
207
+ const refusal = dispatchIntentRefusals(
208
+ classifyDispatchIntentCompatibility({
209
+ intent: resolved.intent,
210
+ writeRoots: legacy,
211
+ ...(cwd !== undefined ? { cwd } : {}),
212
+ }),
213
+ ).find((entry) => entry.code === "intent_write_roots_contradiction");
214
+ if (refusal !== undefined) return { ok: false, message: refusal.message };
204
215
  request.writeRoots = legacy;
205
216
  } else {
206
217
  request.writeRoots = resolved.intent.writeRoots;
@@ -273,21 +284,10 @@ export function dispatchRequestsFromArgs(
273
284
  }
274
285
  const ceiling = options.resolveIntent(sharedIntent, parsed.request.cwd);
275
286
  if (!ceiling.ok) return { ok: false, message: `dispatch: task ${index + 1}: ${ceiling.message}` };
276
- const pathCeilings = {
277
- readRoots: [...ceiling.intent.readRoots, ...ceiling.intent.writeRoots],
278
- writeRoots: ceiling.intent.writeRoots,
279
- relevantPaths: [...ceiling.intent.readRoots, ...ceiling.intent.writeRoots, ...ceiling.intent.relevantPaths],
280
- };
281
- for (const field of ["readRoots", "writeRoots", "relevantPaths"] as const) {
282
- const outside = parsed.request.intent?.[field].find(
283
- (candidate) => !pathBoundaryCovers(pathCeilings[field], candidate),
284
- );
285
- if (outside !== undefined) {
286
- return {
287
- ok: false,
288
- message: `dispatch: task ${index + 1}: intent_scope_widening: ${field} entry '${outside}' is outside the top-level intent ceiling`,
289
- };
290
- }
287
+ const widening =
288
+ parsed.request.intent === undefined ? null : dispatchIntentScopeWidening(ceiling.intent, parsed.request.intent);
289
+ if (widening !== null) {
290
+ return { ok: false, message: `dispatch: task ${index + 1}: ${widening.message}` };
291
291
  }
292
292
  }
293
293
  requests.push(parsed.request);
@@ -236,15 +236,19 @@ function str(value: unknown): string | undefined {
236
236
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
237
237
  }
238
238
 
239
- /** Keep terminal control bytes and line breaks out of approval artifacts. */
240
- function safeField(value: string): string {
239
+ /** Keep terminal control bytes and line breaks out of approval artifacts without losing their identity. */
240
+ function safeField(value: string, bindChangedValue = true): string {
241
241
  let result = "";
242
242
  for (const character of value) {
243
243
  const code = character.codePointAt(0) ?? 0;
244
244
  result += code < 32 || (code >= 127 && code <= 159) ? "?" : character;
245
- if (result.length >= 256) return `${result.slice(0, 255)}…`;
245
+ if (result.length >= 256) {
246
+ result = `${result.slice(0, 255)}…`;
247
+ break;
248
+ }
246
249
  }
247
- return result;
250
+ if (!bindChangedValue || result === value) return result;
251
+ return `${result}{sha256=${createHash("sha256").update(value, "utf8").digest("hex")}}`;
248
252
  }
249
253
 
250
254
  function renderLegacyPathScope(task: DispatchPlanTaskView): string[] {
@@ -393,7 +397,7 @@ function renderPlanText(
393
397
  ? ""
394
398
  : ` posture=${routing.posture} maxCostUsd=${routing.maxCostUsd ?? "none"} deadlineMs=${routing.deadlineMs ?? "none"} minimumQuality=${routing.minimumQuality ?? "none"} locality=${routing.locality}`;
395
399
  lines.push(
396
- ` ${index + 1}.${role} agent=${safeField(task.agent)}${target}${model}${node}${failover}${routingText} task=${JSON.stringify(safeField(task.task))}`,
400
+ ` ${index + 1}.${role} agent=${safeField(task.agent)}${target}${model}${node}${failover}${routingText} task_bytes=${Buffer.byteLength(task.task, "utf8")} task_sha256=${createHash("sha256").update(task.task, "utf8").digest("hex")} task_preview=${JSON.stringify(safeField(task.task, false))}`,
397
401
  );
398
402
  if (task.council !== undefined) {
399
403
  lines.push(
@@ -420,25 +424,29 @@ function renderPlanText(
420
424
  }
421
425
  if (task.agentSelection !== null) {
422
426
  lines.push(
423
- ` agent-selection=auto baseline=${safeField(task.agentSelection.baselineAgentId)} authority=${task.agentSelection.approvedAuthorities.map(safeField).join(",")} basis=${task.agentSelection.authorityBasis}`,
427
+ ` agent-selection=auto baseline=${safeField(task.agentSelection.baselineAgentId)} authority=${task.agentSelection.approvedAuthorities.map((authority) => safeField(authority)).join(",")} basis=${task.agentSelection.authorityBasis}`,
424
428
  );
425
429
  }
426
430
  if (task.stepId !== null) {
427
431
  lines.push(
428
- ` step=${safeField(task.stepId)} wave=${task.wave ?? "?"} role=${task.executionRole} dependencies=${task.dependencies.map(safeField).join(",") || "none"} result=${task.expectedResultContract ?? "none"} authority=${task.authorityGrant?.requested ?? "none"} basis=${task.authorityGrant?.basis ?? "none"}`,
432
+ ` step=${safeField(task.stepId)} wave=${task.wave ?? "?"} role=${task.executionRole} dependencies=${task.dependencies.map((dependency) => safeField(dependency)).join(",") || "none"} result=${task.expectedResultContract ?? "none"} authority=${task.authorityGrant?.requested ?? "none"} basis=${task.authorityGrant?.basis ?? "none"}`,
429
433
  );
430
434
  const agentReasons = task.agentDecision?.agentSelection.evaluations
431
435
  .filter((evaluation) => evaluation.rejections.length > 0)
432
436
  .slice(0, 8)
433
437
  .map(
434
- (evaluation) => `${safeField(evaluation.agentId)}:${evaluation.rejections.slice(0, 4).map(safeField).join(",")}`,
438
+ (evaluation) =>
439
+ `${safeField(evaluation.agentId)}:${evaluation.rejections
440
+ .slice(0, 4)
441
+ .map((rejection) => safeField(rejection))
442
+ .join(",")}`,
435
443
  );
436
444
  if (agentReasons !== undefined && agentReasons.length > 0)
437
445
  lines.push(` agent-exclusions=${agentReasons.join(";")}`);
438
446
  }
439
447
  if (task.briefing !== undefined) {
440
448
  lines.push(
441
- ` briefing_bytes=${Buffer.byteLength(task.briefing, "utf8")} briefing_sha256=${createHash("sha256").update(task.briefing, "utf8").digest("hex")} briefing_preview=${JSON.stringify(safeField(task.briefing))}`,
449
+ ` briefing_bytes=${Buffer.byteLength(task.briefing, "utf8")} briefing_sha256=${createHash("sha256").update(task.briefing, "utf8").digest("hex")} briefing_preview=${JSON.stringify(safeField(task.briefing, false))}`,
442
450
  );
443
451
  }
444
452
  if (task.intent !== undefined) {
@@ -2,6 +2,7 @@ import { BusChannels } from "../core/bus-events.js";
2
2
  import type { SafeEventBus } from "../core/event-bus.js";
3
3
  import type { DispatchContract } from "../domains/dispatch/contract.js";
4
4
  import { durableAssistantTextFromEvent } from "../domains/dispatch/event-pump.js";
5
+ import { defaultRunEventJournal, type RunEventJournalSink } from "../domains/dispatch/run-event-journal.js";
5
6
  import type { RunReceipt } from "../domains/dispatch/types.js";
6
7
  import { assistantTextFromEvent } from "./dispatch-event-text.js";
7
8
  import { truncateUtf8 } from "./truncate-utf8.js";
@@ -77,10 +78,95 @@ function eventDetail(event: unknown): string | undefined {
77
78
  return undefined;
78
79
  }
79
80
 
80
- export function createDispatchRunEventRegistry(): DispatchRunEventRegistry {
81
+ /**
82
+ * Project one worker/ACP event into the display tail, or null when the event is
83
+ * not tail-visible. Heartbeats and streaming `message_update` increments are
84
+ * noise on a transcript: the tail keeps message boundaries, not deltas.
85
+ *
86
+ * The durable journal writes exactly this projection, so a transcript read back
87
+ * by `clio-coder fleet view` and the monitor's live peek cannot disagree about
88
+ * what a run did. Both the registry below and the domain-owned journal bridge
89
+ * (src/domains/dispatch/run-event-journal-bridge.ts) call it.
90
+ */
91
+ export function runTailEntryFromEvent(event: unknown, at: string = new Date().toISOString()): RunTailEntry | null {
92
+ const type = isRecord(event) && typeof event.type === "string" ? event.type : "unknown";
93
+ if (type === "heartbeat" || type === "message_update") return null;
94
+ const entry: RunTailEntry = { at, type };
95
+ const detail = eventDetail(event);
96
+ if (detail !== undefined) entry.detail = detail;
97
+ return entry;
98
+ }
99
+
100
+ export interface DispatchRunEventRegistryOptions {
101
+ /**
102
+ * Durable tee for the display tail. Omitted takes the process-wide default
103
+ * journal (settings-gated by `panes.journal`); `null` turns it off for this
104
+ * registry. This is the one wiring choke point: every registry in the
105
+ * process is built by this factory, so the sink attaches here rather than at
106
+ * each of the three construction sites that call it.
107
+ */
108
+ journal?: RunEventJournalSink | null;
109
+ }
110
+
111
+ /** Outcome recorded for a run whose completion rejected before a receipt existed. */
112
+ const REGISTRY_FAILURE_OUTCOME = "failed";
113
+ /** Outcome recorded when a receipt settled without a readable outcome field. */
114
+ const REGISTRY_UNKNOWN_OUTCOME = "unknown";
115
+
116
+ function errorText(error: unknown): string {
117
+ return error instanceof Error ? error.message : String(error);
118
+ }
119
+
120
+ export function createDispatchRunEventRegistry(
121
+ options: DispatchRunEventRegistryOptions = {},
122
+ ): DispatchRunEventRegistry {
81
123
  const runTails = new Map<string, RunTailState>();
82
124
  const activeRuns = new Set<string>();
83
125
  const activeBatches = new Set<string>();
126
+ const journal: RunEventJournalSink | null = options.journal === undefined ? defaultRunEventJournal() : options.journal;
127
+
128
+ /**
129
+ * Seal one logical run in the journal. `logicalRunId` is the id an operator
130
+ * asked about; a retried run's receipt carries the terminal attempt's id
131
+ * instead, and that only ever appears as a field on the line.
132
+ */
133
+ const journalSeal = (logicalRunId: string, receipt: RunReceipt): void => {
134
+ if (journal === null || !isRecord(receipt)) return;
135
+ // Every field is read defensively. The journal sits on the completion path
136
+ // of every dispatch, and a receipt that is missing a block it is typed to
137
+ // have (a stubbed contract, a truncated read) must degrade the transcript,
138
+ // never reject the completion the caller is awaiting.
139
+ const digest = receipt.integrity?.digest;
140
+ const outcome = typeof receipt.outcome === "string" ? receipt.outcome : REGISTRY_UNKNOWN_OUTCOME;
141
+ journal.receipt(logicalRunId, {
142
+ outcome,
143
+ exitCode: typeof receipt.exitCode === "number" ? receipt.exitCode : null,
144
+ ...(typeof digest === "string" ? { digest } : {}),
145
+ ...(receipt.runId !== logicalRunId ? { attemptRunId: receipt.runId } : {}),
146
+ });
147
+ journal.terminal(logicalRunId, outcome, receipt.outcomeDetail ?? undefined);
148
+ };
149
+
150
+ /**
151
+ * Seal a batch's journals. `assignmentIds` are the logical work ids in
152
+ * admission order and `dispatchBatch` resolves one receipt per request, so
153
+ * equal lengths pair by index. Anything else pairs by the receipt's own run
154
+ * id and leaves unmatched assignments without a terminal line rather than
155
+ * inventing an outcome for them.
156
+ */
157
+ const sealBatchJournals = (assignmentIds: ReadonlyArray<string>, receipts: ReadonlyArray<RunReceipt>): void => {
158
+ if (journal === null || !Array.isArray(receipts)) return;
159
+ if (assignmentIds.length === receipts.length) {
160
+ for (const [index, runId] of assignmentIds.entries()) {
161
+ const receipt = receipts[index];
162
+ if (receipt !== undefined) journalSeal(runId, receipt);
163
+ }
164
+ return;
165
+ }
166
+ for (const receipt of receipts) {
167
+ if (receipt != null && typeof receipt.runId === "string") journalSeal(receipt.runId, receipt);
168
+ }
169
+ };
84
170
 
85
171
  const pruneRunTails = (): void => {
86
172
  while (runTails.size > RUN_TAIL_RUN_LIMIT) {
@@ -97,19 +183,20 @@ export function createDispatchRunEventRegistry(): DispatchRunEventRegistry {
97
183
  };
98
184
 
99
185
  const recordRunEvent = (runId: string, agentId: string, event: unknown): void => {
100
- const type = isRecord(event) && typeof event.type === "string" ? event.type : "unknown";
101
- if (type === "heartbeat" || type === "message_update") return;
186
+ const entry = runTailEntryFromEvent(event);
187
+ if (entry === null) return;
102
188
  const state = runTails.get(runId) ?? { agentId, entries: [], lastSeenAt: Date.now() };
103
189
  state.lastSeenAt = Date.now();
104
- const entry: RunTailEntry = { at: new Date().toISOString(), type };
105
- const detail = eventDetail(event);
106
- if (detail !== undefined) entry.detail = detail;
107
190
  state.entries.push(entry);
108
191
  if (state.entries.length > RUN_TAIL_ENTRY_LIMIT) {
109
192
  state.entries.splice(0, state.entries.length - RUN_TAIL_ENTRY_LIMIT);
110
193
  }
111
194
  runTails.set(runId, state);
112
195
  pruneRunTails();
196
+ // The journal is a tee of exactly this projection, appended after the
197
+ // in-memory tail is already updated so a sink that degrades cannot change
198
+ // what `eventTail` returns.
199
+ journal?.append(runId, entry);
113
200
  };
114
201
 
115
202
  const drainSingle = async (
@@ -172,6 +259,7 @@ export function createDispatchRunEventRegistry(): DispatchRunEventRegistry {
172
259
  throw new Error(`dispatch event registry: run '${handle.runId}' is already registered`);
173
260
  }
174
261
  activeRuns.add(handle.runId);
262
+ journal?.open(handle.runId, agentId);
175
263
  const summaryPromise = drainSingle(handle.runId, agentId, handle.events, bus);
176
264
  const completion = Promise.allSettled([summaryPromise, handle.finalPromise]).then(
177
265
  ([summaryResult, receiptResult]) => {
@@ -180,12 +268,24 @@ export function createDispatchRunEventRegistry(): DispatchRunEventRegistry {
180
268
  return { receipt: receiptResult.value, summary: summaryResult.value };
181
269
  },
182
270
  );
183
- void completion
184
- .finally(() => {
185
- activeRuns.delete(handle.runId);
186
- pruneRunTails();
187
- })
188
- .catch(() => {});
271
+ // One subscription, not a `.then().finally()` chain. Chaining pushes the
272
+ // tail release a microtask later than it used to land, and a caller that
273
+ // awaits `completion` and then reads `eventTail` observes the run as
274
+ // still active. Journal and release settle together in this handler.
275
+ const releaseSingle = (): void => {
276
+ activeRuns.delete(handle.runId);
277
+ pruneRunTails();
278
+ };
279
+ void completion.then(
280
+ ({ receipt }) => {
281
+ journalSeal(handle.runId, receipt);
282
+ releaseSingle();
283
+ },
284
+ (error: unknown) => {
285
+ journal?.terminal(handle.runId, REGISTRY_FAILURE_OUTCOME, errorText(error));
286
+ releaseSingle();
287
+ },
288
+ );
189
289
  return { runId: handle.runId, completion };
190
290
  },
191
291
  registerBatch(handle, agentIds, bus) {
@@ -204,6 +304,9 @@ export function createDispatchRunEventRegistry(): DispatchRunEventRegistry {
204
304
  }
205
305
  activeBatches.add(handle.batchId);
206
306
  for (const runId of handle.assignmentIds) activeRuns.add(runId);
307
+ for (const [index, runId] of handle.assignmentIds.entries()) {
308
+ journal?.open(runId, agentIds[index] ?? "unknown");
309
+ }
207
310
  const completion = Promise.allSettled([drainBatch(handle.batchId, handle.events, bus), handle.finalPromise]).then(
208
311
  ([summariesResult, receiptsResult]) => {
209
312
  if (summariesResult.status === "rejected") throw summariesResult.reason;
@@ -211,13 +314,25 @@ export function createDispatchRunEventRegistry(): DispatchRunEventRegistry {
211
314
  return { receipts: receiptsResult.value, summaries: summariesResult.value };
212
315
  },
213
316
  );
214
- void completion
215
- .finally(() => {
216
- activeBatches.delete(handle.batchId);
217
- for (const runId of handle.assignmentIds) activeRuns.delete(runId);
218
- pruneRunTails();
219
- })
220
- .catch(() => {});
317
+ // Single subscription for the same reason as registerSingle above.
318
+ const releaseBatch = (): void => {
319
+ activeBatches.delete(handle.batchId);
320
+ for (const runId of handle.assignmentIds) activeRuns.delete(runId);
321
+ pruneRunTails();
322
+ };
323
+ void completion.then(
324
+ ({ receipts }) => {
325
+ sealBatchJournals(handle.assignmentIds, receipts);
326
+ releaseBatch();
327
+ },
328
+ (error: unknown) => {
329
+ const detail = errorText(error);
330
+ for (const runId of handle.assignmentIds) {
331
+ journal?.terminal(runId, REGISTRY_FAILURE_OUTCOME, detail);
332
+ }
333
+ releaseBatch();
334
+ },
335
+ );
221
336
  for (const [index, runId] of handle.assignmentIds.entries()) {
222
337
  if (!runTails.has(runId)) {
223
338
  runTails.set(runId, {
@@ -40,6 +40,7 @@ import {
40
40
  REVIEWER_GATE_PROMPT,
41
41
  renderCouncilVoteMemberTask,
42
42
  } from "../domains/dispatch/gate-role-prompts.js";
43
+ import { narrowDispatchIntentToReadOnly } from "../domains/dispatch/intent.js";
43
44
  import { renderDispatchReviewerTask } from "../domains/dispatch/intent-requirements.js";
44
45
  import { UNVERIFIABLE_RECEIPT_VERIFICATION } from "../domains/dispatch/receipt-findings.js";
45
46
  import { type ReceiptIntegrityResult, verifyReceiptIntegrity } from "../domains/dispatch/receipt-integrity.js";
@@ -56,7 +57,7 @@ import {
56
57
  claimCompeteGroup,
57
58
  cleanupCompeteGroup,
58
59
  commitCandidateWork,
59
- createCandidateWorktree,
60
+ createCandidateWorktreeMapped,
60
61
  isGitRepository,
61
62
  loadCompeteGroup,
62
63
  markCompeteGroupCleanupReady,
@@ -65,7 +66,7 @@ import {
65
66
  protectedPathsChangedByCompeteBranch,
66
67
  recoverCleanupReadyCompeteGroups,
67
68
  registerCompeteGroupRun,
68
- removeCandidateWorktree,
69
+ removeCandidateWorktreeMapped,
69
70
  settleCompeteGroupRun,
70
71
  settleRecoveredCompeteDecision,
71
72
  } from "./compete-worktrees.js";
@@ -1255,10 +1256,14 @@ async function runCompete(
1255
1256
  // every branch and worktree created below is covered by finalization.
1256
1257
  ownership = claimCompeteGroup(requestedRoot, group);
1257
1258
  const root = ownership.root;
1258
- const createCandidate = deps.competeWorktrees?.createCandidate ?? createCandidateWorktree;
1259
1259
  for (let index = 1; index <= compete.candidates; index += 1) {
1260
1260
  throwIfStopped();
1261
- worktrees.push(createCandidate(ownership, index, "HEAD"));
1261
+ const customCreate = deps.competeWorktrees?.createCandidate;
1262
+ worktrees.push(
1263
+ await (customCreate
1264
+ ? customCreate(ownership, index, "HEAD")
1265
+ : createCandidateWorktreeMapped(ownership, index, "HEAD", deps.competeWorktrees?.mux)),
1266
+ );
1262
1267
  }
1263
1268
 
1264
1269
  if (timeoutMs !== undefined) {
@@ -1287,7 +1292,12 @@ async function runCompete(
1287
1292
  executionRole: "builder",
1288
1293
  cwd: worktree.path,
1289
1294
  protectedArtifactRemap: { sourceRoot: root, workerRoot: worktree.path },
1290
- gate: { role: "candidate", group, cycle: worktree.index },
1295
+ gate: {
1296
+ role: "candidate",
1297
+ group,
1298
+ cycle: worktree.index,
1299
+ ...(worktree.provenance ? { worktree: worktree.provenance } : {}),
1300
+ },
1291
1301
  ledger,
1292
1302
  competeStance: COMPETE_STANCES[(worktree.index - 1) % COMPETE_STANCES.length] as CompeteStance,
1293
1303
  };
@@ -1523,7 +1533,7 @@ async function runCompete(
1523
1533
  for (const worktree of worktrees) {
1524
1534
  if (worktree.index === winnerAtFinalization.index) continue;
1525
1535
  try {
1526
- removeCandidateWorktree(ownership, worktree, true);
1536
+ await removeCandidateWorktreeMapped(ownership, worktree, true, deps.competeWorktrees?.mux);
1527
1537
  } catch (err) {
1528
1538
  finalizationErrors.push(err);
1529
1539
  }
@@ -1540,8 +1550,13 @@ async function runCompete(
1540
1550
  finalizationErrors.push(err);
1541
1551
  }
1542
1552
  try {
1553
+ if (deps.competeWorktrees?.mux) {
1554
+ for (const worktree of worktrees) {
1555
+ await removeCandidateWorktreeMapped(ownership, worktree, true, deps.competeWorktrees.mux);
1556
+ }
1557
+ }
1543
1558
  const cleanupGroup = deps.competeWorktrees?.cleanupGroup ?? cleanupCompeteGroup;
1544
- cleanupGroup(ownership);
1559
+ await cleanupGroup(ownership);
1545
1560
  } catch (err) {
1546
1561
  finalizationErrors.push(err);
1547
1562
  }
@@ -1885,6 +1900,13 @@ async function runCouncil(
1885
1900
  executionRole: "researcher",
1886
1901
  autonomy: "read-only",
1887
1902
  toolProfile: "council-read-only",
1903
+ // Admission already demoted the caller's declared write roots to
1904
+ // read roots for every planned member, and the resolved-plan pin
1905
+ // below carries that narrowed intent in. Repeat it here so the
1906
+ // no-plan fallback path lands on the same request: a member spread
1907
+ // from `base` would otherwise inherit a write scope its read-only
1908
+ // autonomy cannot grant, and the two paths would disagree.
1909
+ ...(base.intent === undefined ? {} : { intent: narrowDispatchIntentToReadOnly(base.intent) }),
1888
1910
  // A vote is a majority over the members' verdict fields, so a vote
1889
1911
  // council asks each member for one and seals the ballot it asked
1890
1912
  // for. The seated recipe is untouched: the ask is a task suffix and
@@ -256,7 +256,7 @@ export async function runScoutContinuationPlan<T, S>(input: {
256
256
  };
257
257
  },
258
258
  cancel: (assignmentId) => input.dispatch.abort(assignmentId),
259
- release: (ownerId) => input.dispatch.reservations?.rollbackUnconsumed(ownerId),
259
+ release: (ownerId) => input.dispatch.reservations?.release(ownerId),
260
260
  releaseUnconsumed: (ownerId) => input.dispatch.reservations?.rollbackUnconsumed(ownerId),
261
261
  },
262
262
  input.signal,
@@ -3,7 +3,13 @@ import type { AgentSpec } from "../domains/agents/spec.js";
3
3
  import type { DispatchContract, DispatchRequest } from "../domains/dispatch/contract.js";
4
4
  import type { AgentRoleFactsResolver } from "../domains/dispatch/execution-role.js";
5
5
  import type { AutonomyLevel } from "../domains/safety/autonomy.js";
6
- import type { cleanupCompeteGroup, createCandidateWorktree, mergeWinnerBranch } from "./compete-worktrees.js";
6
+ import type {
7
+ CandidateWorktree,
8
+ CompeteGroupOwnership,
9
+ CompeteMuxWorktrees,
10
+ cleanupCompeteGroup,
11
+ mergeWinnerBranch,
12
+ } from "./compete-worktrees.js";
7
13
  import type { DispatchBackgroundRegistry } from "./dispatch-background.js";
8
14
  import type { DispatchPlanView, ResolvedDispatchPlanArtifact } from "./dispatch-plan.js";
9
15
  import type { DispatchRunEventRegistry } from "./dispatch-run-events.js";
@@ -83,9 +89,15 @@ export interface DispatchToolDeps {
83
89
  background?: DispatchBackgroundRegistry;
84
90
  /** Optional compete storage overrides for alternate backends and deterministic fault tests. */
85
91
  competeWorktrees?: {
86
- createCandidate?: typeof createCandidateWorktree;
87
- cleanupGroup?: typeof cleanupCompeteGroup;
92
+ createCandidate?: (
93
+ ownership: CompeteGroupOwnership,
94
+ index: number,
95
+ baseline: string,
96
+ ) => CandidateWorktree | Promise<CandidateWorktree>;
97
+ cleanupGroup?: (...args: Parameters<typeof cleanupCompeteGroup>) => void | Promise<void>;
88
98
  mergeWinner?: typeof mergeWinnerBranch;
99
+ /** Optional herdr route; every operation retains native Git fallback. */
100
+ mux?: CompeteMuxWorktrees;
89
101
  };
90
102
  getAgentCatalog?: () => string;
91
103
  getAgentSpecs: () => ReadonlyArray<AgentSpec>;