@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
@@ -1,7 +1,15 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { realpathSync } from "node:fs";
3
3
  import { isAbsolute, resolve as resolvePath } from "node:path";
4
- import { BusChannels, type LoopBlockedPayload } from "../../core/bus-events.js";
4
+ import {
5
+ BusChannels,
6
+ type DispatchCompletedPayload,
7
+ type DispatchEnqueuedPayload,
8
+ type DispatchFailedPayload,
9
+ type DispatchProgressPayload,
10
+ type DispatchStartedPayload,
11
+ type LoopBlockedPayload,
12
+ } from "../../core/bus-events.js";
5
13
  import { DEFAULT_DELEGATION_PERMISSION_TIMEOUT_MS } from "../../core/defaults.js";
6
14
  import type { SafeEventBus } from "../../core/event-bus.js";
7
15
  import { MAX_TIMER_DELAY_MS } from "../../core/timers.js";
@@ -33,6 +41,7 @@ import type {
33
41
  AcpToolKind,
34
42
  } from "./types.js";
35
43
  import {
44
+ ACP_AGENT_META_KEY,
36
45
  ACP_MAX_CHUNK_BYTES,
37
46
  ACP_MAX_RAW_RECORD_BYTES,
38
47
  ACP_MAX_STRING_BYTES,
@@ -173,6 +182,25 @@ interface ActivePrompt {
173
182
  interface AcpToolCallSnapshot {
174
183
  rawInput: Record<string, unknown>;
175
184
  locations?: AcpToolCallLocation[];
185
+ /** Exact title and kind this call was announced under, replayed by later updates. */
186
+ title: string;
187
+ kind: AcpToolKind;
188
+ /**
189
+ * Delegated agents this call spawned, oldest first, bounded by
190
+ * {@link ACP_MAX_TOOL_CALL_AGENTS}. A dispatch tool that fans out reports one
191
+ * entry per run, which is what lets a client label the segment with the
192
+ * agents that actually ran under it rather than with the product name.
193
+ */
194
+ agents?: AcpAgentAttribution[];
195
+ }
196
+
197
+ /** One `clio-coder/agent` attribution entry. `role` names where the identity came from. */
198
+ interface AcpAgentAttribution {
199
+ version: 1;
200
+ role: "orchestrator" | "worker";
201
+ agentId: string;
202
+ runId?: string;
203
+ node?: string;
176
204
  }
177
205
 
178
206
  interface AcpServerUsage {
@@ -299,6 +327,74 @@ const ACP_MAX_TOOL_TITLE_BYTES = 512;
299
327
  const ACP_MAX_LIVE_TOOL_CALLS = 128;
300
328
  const ACP_MAX_REPLAY_TOOL_CALLS = 8192;
301
329
 
330
+ /**
331
+ * Bus channels this server is willing to forward over the opt-in
332
+ * `clio-coder/event` notification. Nothing outside this list is forwardable:
333
+ * the list is the allowlist, and a client's requested kinds are intersected
334
+ * with it rather than trusted. `safety.loopBlocked` was the first member; the
335
+ * dispatch lifecycle joined it so a client can draw a live fleet board from
336
+ * reported facts instead of inferring one from tool titles or timing.
337
+ */
338
+ const ACP_FORWARDABLE_EVENT_KINDS = [
339
+ "safety.loopBlocked",
340
+ "dispatch.enqueued",
341
+ "dispatch.started",
342
+ "dispatch.progress",
343
+ "dispatch.completed",
344
+ "dispatch.failed",
345
+ ] as const;
346
+
347
+ type AcpForwardableEventKind = (typeof ACP_FORWARDABLE_EVENT_KINDS)[number];
348
+
349
+ /** A client may name at most this many kinds; an over-long list refuses the whole opt-in. */
350
+ const ACP_MAX_REQUESTED_EVENT_KINDS = 16;
351
+
352
+ /**
353
+ * Sanitized, bounded preview of a dispatched task. The exact task is the
354
+ * operator's own prose and can be arbitrarily long, so what crosses is a
355
+ * control-character-stripped prefix carrying the standard truncation marker;
356
+ * the exact text never leaves the process.
357
+ */
358
+ const ACP_MAX_DISPATCH_TASK_PREVIEW_BYTES = 160;
359
+
360
+ /** Wire bound for the short identifiers a dispatch event carries. */
361
+ const ACP_MAX_DISPATCH_ID_BYTES = 128;
362
+
363
+ /**
364
+ * Progress events forwarded per run before the stream is capped. One run
365
+ * publishes one progress fact per worker event, which is unbounded; a client
366
+ * only needs enough to know the run is alive, so the cap is announced with a
367
+ * final `truncated` frame rather than by silently going quiet.
368
+ */
369
+ const ACP_MAX_DISPATCH_PROGRESS_EVENTS = 256;
370
+
371
+ /** Live dispatch runs whose progress counters this server tracks at once. */
372
+ const ACP_MAX_TRACKED_DISPATCH_RUNS = 512;
373
+
374
+ /** Delegated agents recorded against one tool call before further ones are dropped. */
375
+ const ACP_MAX_TOOL_CALL_AGENTS = 16;
376
+
377
+ /**
378
+ * Attribution for a frame this server produced on the main session. Every live
379
+ * frame carries it, so a client never has to decide whether an unattributed
380
+ * frame means "the orchestrator" or "identity unavailable".
381
+ */
382
+ const ORCHESTRATOR_ATTRIBUTION: AcpAgentAttribution = {
383
+ version: 1,
384
+ role: "orchestrator",
385
+ agentId: "orchestrator",
386
+ };
387
+
388
+ const ORCHESTRATOR_UPDATE_META: Record<string, unknown> = {
389
+ [ACP_AGENT_META_KEY]: [ORCHESTRATOR_ATTRIBUTION],
390
+ };
391
+
392
+ /** The `_meta` a tool-call frame carries: its own agents when it spawned any, else the orchestrator. */
393
+ function toolCallUpdateMeta(snapshot: AcpToolCallSnapshot | undefined): Record<string, unknown> {
394
+ if (snapshot?.agents === undefined || snapshot.agents.length === 0) return ORCHESTRATOR_UPDATE_META;
395
+ return { [ACP_AGENT_META_KEY]: [ORCHESTRATOR_ATTRIBUTION, ...snapshot.agents] };
396
+ }
397
+
302
398
  /** Depth past which `boundRawRecord` stops walking and elides the subtree. */
303
399
  const ACP_MAX_RAW_RECORD_DEPTH = 8;
304
400
 
@@ -691,8 +787,9 @@ function sendUpdate(
691
787
  sessionId: string,
692
788
  active: ActivePrompt,
693
789
  update: Record<string, unknown>,
790
+ meta: Record<string, unknown> = ORCHESTRATOR_UPDATE_META,
694
791
  ): void {
695
- const params: AcpSessionUpdateParams = { sessionId, update };
792
+ const params: AcpSessionUpdateParams = { sessionId, update, _meta: meta };
696
793
  active.updatesSent += 1;
697
794
  transport.notify("session/update", params);
698
795
  }
@@ -722,12 +819,18 @@ function settleOpenToolCalls(
722
819
  text: string,
723
820
  ): void {
724
821
  for (const toolCallId of active.openToolCalls) {
725
- sendUpdate(transport, sessionId, active, {
726
- sessionUpdate: "tool_call_update",
727
- toolCallId,
728
- status: "failed" satisfies AcpToolCallStatus,
729
- content: toolCallContent(text),
730
- });
822
+ sendUpdate(
823
+ transport,
824
+ sessionId,
825
+ active,
826
+ {
827
+ sessionUpdate: "tool_call_update",
828
+ toolCallId,
829
+ status: "failed" satisfies AcpToolCallStatus,
830
+ content: toolCallContent(text),
831
+ },
832
+ toolCallUpdateMeta(active.toolCallSnapshots.get(toolCallId)),
833
+ );
731
834
  // The sweep is a terminal update like any other, so a late end for a swept
732
835
  // id cannot reopen the call the client has already seen fail.
733
836
  active.terminalToolCalls.add(toolCallId);
@@ -794,13 +897,15 @@ function handleChatEvent(
794
897
  const snapshot: AcpToolCallSnapshot = {
795
898
  rawInput: boundRawRecord(event.args),
796
899
  ...(locations !== null ? { locations } : {}),
900
+ title: boundString(toolName ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
901
+ kind: toolKind(toolName),
797
902
  };
798
903
  active.toolCallSnapshots.set(toolCallId, snapshot);
799
904
  sendUpdate(transport, sessionId, active, {
800
905
  sessionUpdate: "tool_call",
801
906
  toolCallId,
802
- title: boundString(toolName ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
803
- kind: toolKind(toolName),
907
+ title: snapshot.title,
908
+ kind: snapshot.kind,
804
909
  status: "in_progress" satisfies AcpToolCallStatus,
805
910
  rawInput: snapshot.rawInput,
806
911
  ...(snapshot.locations !== undefined ? { locations: snapshot.locations } : {}),
@@ -826,15 +931,21 @@ function handleChatEvent(
826
931
  active.openToolCalls.delete(toolCallId);
827
932
  active.terminalToolCalls.add(toolCallId);
828
933
  const output = boundString(outputText(event.result), ACP_MAX_CHUNK_BYTES);
829
- sendUpdate(transport, sessionId, active, {
830
- sessionUpdate: "tool_call_update",
831
- toolCallId,
832
- title: boundString(toolName ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
833
- kind: toolKind(toolName),
834
- status: toolStatus(event),
835
- ...(output.length > 0 ? { content: toolCallContent(output) } : {}),
836
- rawOutput: boundRawRecord({ result: event.result, isError: event.isError === true }),
837
- });
934
+ sendUpdate(
935
+ transport,
936
+ sessionId,
937
+ active,
938
+ {
939
+ sessionUpdate: "tool_call_update",
940
+ toolCallId,
941
+ title: boundString(toolName ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
942
+ kind: toolKind(toolName),
943
+ status: toolStatus(event),
944
+ ...(output.length > 0 ? { content: toolCallContent(output) } : {}),
945
+ rawOutput: boundRawRecord({ result: event.result, isError: event.isError === true }),
946
+ },
947
+ toolCallUpdateMeta(active.toolCallSnapshots.get(toolCallId)),
948
+ );
838
949
  return;
839
950
  }
840
951
  if (event.type === "message_end") {
@@ -1500,9 +1611,24 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1500
1611
  const sessions = new Map<string, AcpServerSession>();
1501
1612
  const workspaceInstanceId = randomUUID();
1502
1613
  let initialized = false;
1503
- let loopBlockedEventsEnabled = false;
1614
+ const enabledEventKinds = new Set<AcpForwardableEventKind>();
1504
1615
  let eventSequence = 0;
1616
+ /**
1617
+ * Per-run progress counters for the forwarded dispatch stream, insertion
1618
+ * ordered. A terminal event removes its run; the cap evicts the oldest live
1619
+ * run rather than refusing the newest, so a leaked run cannot starve the
1620
+ * board of the run an operator is actually watching.
1621
+ */
1622
+ const dispatchProgress = new Map<string, { count: number; capped: boolean }>();
1505
1623
  let activeSessionId: string | null = null;
1624
+ /**
1625
+ * The one session this process hosts, from the moment it is bound until it is
1626
+ * closed. Distinct from {@link activeSessionId}, which is only set while a
1627
+ * prompt is running: a detached dispatch run legitimately finishes after the
1628
+ * turn that started it, and a client keyed on the bound session still needs
1629
+ * that outcome so its board does not leave the run running forever.
1630
+ */
1631
+ let boundSessionId: string | null = null;
1506
1632
  let activePromptState: ActivePrompt | null = null;
1507
1633
  let sessionCreated = false;
1508
1634
  let promptSettled: Promise<void> | null = null;
@@ -1541,48 +1667,244 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1541
1667
  options.chat.cancel();
1542
1668
  },
1543
1669
  });
1544
- const unsubscribeLoopBlocked =
1545
- options.bus?.on(BusChannels.LoopBlocked, (payload: LoopBlockedPayload) => {
1546
- if (!initialized || !loopBlockedEventsEnabled || activeSessionId === null || activePromptState === null) return;
1547
- if (
1548
- !Number.isSafeInteger(payload.repeatCount) ||
1549
- payload.repeatCount < 1 ||
1550
- !Number.isSafeInteger(payload.blocksThisTurn) ||
1551
- payload.blocksThisTurn < 1 ||
1552
- !Number.isSafeInteger(payload.budget) ||
1553
- payload.budget < 1 ||
1554
- !(["block", "lockout", "stop"] as ReadonlyArray<string>).includes(payload.disposition) ||
1555
- payload.interrupted !== (payload.disposition === "stop")
1556
- ) {
1557
- return;
1558
- }
1559
- const tool = safeStoredString(payload.tool, 64).trim();
1560
- if (tool.length === 0) return;
1561
- eventSequence += 1;
1562
- try {
1563
- options.transport.notify("clio-coder/event", {
1564
- version: 1,
1565
- workspaceInstanceId,
1566
- sessionId: activeSessionId,
1567
- turnId: safeStoredIdentifier(payload.turnId, ACP_MAX_SESSION_ID_BYTES),
1568
- sequence: eventSequence,
1569
- kind: "safety.loopBlocked",
1570
- terminal: false,
1571
- payload: {
1572
- toolCallId: null,
1573
- tool,
1574
- repeatCount: payload.repeatCount,
1575
- blocksThisTurn: payload.blocksThisTurn,
1576
- budget: payload.budget,
1577
- disposition: payload.disposition,
1578
- interrupted: payload.interrupted,
1579
- shape: null,
1580
- },
1670
+ /**
1671
+ * Sends one frame of the opt-in stream. Every forwarded channel goes through
1672
+ * here so the envelope, the sequence, and the opt-in check cannot drift per
1673
+ * channel. Nothing is sent before a session exists: the envelope's
1674
+ * `sessionId` is the client's only way to bind a fact to what it is showing.
1675
+ */
1676
+ const forwardEvent = (
1677
+ kind: AcpForwardableEventKind,
1678
+ turnId: string | null,
1679
+ terminal: boolean,
1680
+ payload: Record<string, unknown>,
1681
+ ): void => {
1682
+ const sessionId = activeSessionId ?? boundSessionId;
1683
+ if (!initialized || !enabledEventKinds.has(kind) || sessionId === null) return;
1684
+ eventSequence += 1;
1685
+ try {
1686
+ options.transport.notify("clio-coder/event", {
1687
+ version: 1,
1688
+ workspaceInstanceId,
1689
+ sessionId,
1690
+ turnId,
1691
+ sequence: eventSequence,
1692
+ kind,
1693
+ terminal,
1694
+ payload,
1695
+ });
1696
+ } catch {
1697
+ options.diagnostics?.("failed to send an opted-in ACP event");
1698
+ }
1699
+ };
1700
+
1701
+ /**
1702
+ * The identity every dispatch frame carries. The exact task never crosses:
1703
+ * what goes on the wire is a control-character-stripped, byte-bounded prefix
1704
+ * carrying the standard truncation marker, so a client can label a run
1705
+ * without receiving the operator's prose. A run whose id or agent cannot be
1706
+ * represented safely is dropped rather than forwarded under a repaired
1707
+ * identity, because a board keyed on a rewritten id merges distinct runs.
1708
+ */
1709
+ const dispatchIdentity = (payload: {
1710
+ runId: string;
1711
+ agentId: string;
1712
+ task?: string | undefined;
1713
+ node?: string | undefined;
1714
+ }): { runId: string; agentId: string; taskPreview: string | null; node: string | null } | null => {
1715
+ const runId = safeStoredIdentifier(payload.runId, ACP_MAX_DISPATCH_ID_BYTES);
1716
+ const agentId = safeStoredIdentifier(payload.agentId, ACP_MAX_DISPATCH_ID_BYTES);
1717
+ if (runId === null || agentId === null) return null;
1718
+ const preview =
1719
+ payload.task === undefined ? "" : safeStoredString(payload.task, ACP_MAX_DISPATCH_TASK_PREVIEW_BYTES).trim();
1720
+ return {
1721
+ runId,
1722
+ agentId,
1723
+ taskPreview: preview.length === 0 ? null : preview,
1724
+ node: safeStoredIdentifier(payload.node, ACP_MAX_DISPATCH_ID_BYTES),
1725
+ };
1726
+ };
1727
+
1728
+ /** Forgets a run's progress counter and keeps the live map inside its cap. */
1729
+ const trackDispatchRun = (runId: string): { count: number; capped: boolean } => {
1730
+ const existing = dispatchProgress.get(runId);
1731
+ if (existing !== undefined) return existing;
1732
+ if (dispatchProgress.size >= ACP_MAX_TRACKED_DISPATCH_RUNS) {
1733
+ const oldest = dispatchProgress.keys().next();
1734
+ if (!oldest.done) dispatchProgress.delete(oldest.value);
1735
+ }
1736
+ const created = { count: 0, capped: false };
1737
+ dispatchProgress.set(runId, created);
1738
+ return created;
1739
+ };
1740
+
1741
+ const safeCount = (value: unknown): number | null =>
1742
+ typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
1743
+
1744
+ const unsubscribeEvents: Array<() => void> = [];
1745
+ if (options.bus !== undefined) {
1746
+ const bus = options.bus;
1747
+ unsubscribeEvents.push(
1748
+ bus.on(BusChannels.LoopBlocked, (payload: LoopBlockedPayload) => {
1749
+ // Loop blocks describe the turn that is running, so unlike a dispatch
1750
+ // run they are meaningless outside one.
1751
+ if (activePromptState === null) return;
1752
+ if (
1753
+ !Number.isSafeInteger(payload.repeatCount) ||
1754
+ payload.repeatCount < 1 ||
1755
+ !Number.isSafeInteger(payload.blocksThisTurn) ||
1756
+ payload.blocksThisTurn < 1 ||
1757
+ !Number.isSafeInteger(payload.budget) ||
1758
+ payload.budget < 1 ||
1759
+ !(["block", "lockout", "stop"] as ReadonlyArray<string>).includes(payload.disposition) ||
1760
+ payload.interrupted !== (payload.disposition === "stop")
1761
+ ) {
1762
+ return;
1763
+ }
1764
+ const tool = safeStoredString(payload.tool, 64).trim();
1765
+ if (tool.length === 0) return;
1766
+ forwardEvent("safety.loopBlocked", safeStoredIdentifier(payload.turnId, ACP_MAX_SESSION_ID_BYTES), false, {
1767
+ toolCallId: null,
1768
+ tool,
1769
+ repeatCount: payload.repeatCount,
1770
+ blocksThisTurn: payload.blocksThisTurn,
1771
+ budget: payload.budget,
1772
+ disposition: payload.disposition,
1773
+ interrupted: payload.interrupted,
1774
+ shape: null,
1581
1775
  });
1582
- } catch {
1583
- options.diagnostics?.("failed to send an opted-in ACP event");
1584
- }
1585
- }) ?? (() => {});
1776
+ }),
1777
+ );
1778
+ unsubscribeEvents.push(
1779
+ bus.on(BusChannels.DispatchEnqueued, (payload: DispatchEnqueuedPayload) => {
1780
+ const identity = dispatchIdentity(payload);
1781
+ if (identity === null) return;
1782
+ trackDispatchRun(identity.runId);
1783
+ forwardEvent("dispatch.enqueued", null, false, {
1784
+ ...identity,
1785
+ origin: safeStoredIdentifier(payload.requestOrigin, 64),
1786
+ attempt: null,
1787
+ });
1788
+ }),
1789
+ );
1790
+ unsubscribeEvents.push(
1791
+ bus.on(BusChannels.DispatchStarted, (payload: DispatchStartedPayload) => {
1792
+ const identity = dispatchIdentity(payload);
1793
+ if (identity === null) return;
1794
+ trackDispatchRun(identity.runId);
1795
+ // A run started by a tool call this turn already put on the wire is
1796
+ // the one place the harness knows which agent produced a tool
1797
+ // segment. Record it and re-announce the call so a client can label
1798
+ // the segment while the worker is still running.
1799
+ attributeRunToToolCall(payload.parentToolCallId, identity);
1800
+ forwardEvent("dispatch.started", null, false, {
1801
+ ...identity,
1802
+ origin: safeStoredIdentifier(payload.requestOrigin, 64),
1803
+ attempt: safeCount(payload.attempt),
1804
+ });
1805
+ }),
1806
+ );
1807
+ unsubscribeEvents.push(
1808
+ bus.on(BusChannels.DispatchProgress, (payload: DispatchProgressPayload) => {
1809
+ const identity = dispatchIdentity(payload);
1810
+ if (identity === null) return;
1811
+ const state = trackDispatchRun(identity.runId);
1812
+ if (state.capped) return;
1813
+ state.count += 1;
1814
+ const capped = state.count > ACP_MAX_DISPATCH_PROGRESS_EVENTS;
1815
+ if (capped) state.capped = true;
1816
+ // The worker/ACP event that triggered this crossed a process boundary
1817
+ // and is typed `unknown`; none of it goes on the wire. What a board
1818
+ // needs is that the run is alive and roughly how much it has done.
1819
+ forwardEvent("dispatch.progress", null, false, {
1820
+ runId: identity.runId,
1821
+ agentId: identity.agentId,
1822
+ progressCount: state.count,
1823
+ truncated: capped,
1824
+ });
1825
+ }),
1826
+ );
1827
+ unsubscribeEvents.push(
1828
+ bus.on(BusChannels.DispatchCompleted, (payload: DispatchCompletedPayload) => {
1829
+ const identity = dispatchIdentity(payload);
1830
+ if (identity === null) return;
1831
+ dispatchProgress.delete(identity.runId);
1832
+ forwardEvent("dispatch.completed", null, true, {
1833
+ runId: identity.runId,
1834
+ agentId: identity.agentId,
1835
+ outcome: safeStoredIdentifier(payload.outcome, 64),
1836
+ outcomeCode: safeStoredIdentifier(payload.outcomeCode, 64),
1837
+ durationMs: safeCount(payload.durationMs),
1838
+ tokenCount: safeCount(payload.tokenCount),
1839
+ });
1840
+ }),
1841
+ );
1842
+ unsubscribeEvents.push(
1843
+ bus.on(BusChannels.DispatchFailed, (payload: DispatchFailedPayload) => {
1844
+ const identity = dispatchIdentity(payload);
1845
+ if (identity === null) return;
1846
+ dispatchProgress.delete(identity.runId);
1847
+ // `outcomeDetail` is free-form failure prose that legitimately quotes
1848
+ // paths, argv, and provider bodies. The taxonomy crosses; the prose
1849
+ // does not.
1850
+ forwardEvent("dispatch.failed", null, true, {
1851
+ runId: identity.runId,
1852
+ agentId: identity.agentId,
1853
+ outcome: safeStoredIdentifier(payload.outcome, 64),
1854
+ reason: safeStoredIdentifier(payload.reason, 64),
1855
+ durationMs: safeCount(payload.durationMs),
1856
+ });
1857
+ }),
1858
+ );
1859
+ }
1860
+ const unsubscribeEventStream = (): void => {
1861
+ for (const unsubscribe of unsubscribeEvents) unsubscribe();
1862
+ unsubscribeEvents.length = 0;
1863
+ dispatchProgress.clear();
1864
+ };
1865
+
1866
+ /**
1867
+ * Records a delegated agent against the tool call that spawned it and
1868
+ * re-announces that call so the attribution reaches the client while the
1869
+ * worker is running. Nothing is minted here: an id with no open call this
1870
+ * turn binds to nothing, exactly as on the permission path.
1871
+ */
1872
+ function attributeRunToToolCall(
1873
+ parentToolCallId: string | undefined,
1874
+ identity: { runId: string; agentId: string; node: string | null },
1875
+ ): void {
1876
+ const active = activePromptState;
1877
+ if (active === null || activeSessionId === null) return;
1878
+ if (parentToolCallId === undefined || parentToolCallId.length === 0) return;
1879
+ const wireId = openWireIdFor(active, parentToolCallId);
1880
+ if (wireId === null) return;
1881
+ const snapshot = active.toolCallSnapshots.get(wireId);
1882
+ if (snapshot === undefined) return;
1883
+ const agents = snapshot.agents ?? [];
1884
+ if (agents.length >= ACP_MAX_TOOL_CALL_AGENTS) return;
1885
+ if (agents.some((agent) => agent.runId === identity.runId)) return;
1886
+ agents.push({
1887
+ version: 1,
1888
+ role: "worker",
1889
+ agentId: identity.agentId,
1890
+ runId: identity.runId,
1891
+ ...(identity.node !== null ? { node: identity.node } : {}),
1892
+ });
1893
+ snapshot.agents = agents;
1894
+ sendUpdate(
1895
+ options.transport,
1896
+ activeSessionId,
1897
+ active,
1898
+ {
1899
+ sessionUpdate: "tool_call_update",
1900
+ toolCallId: wireId,
1901
+ title: snapshot.title,
1902
+ kind: snapshot.kind,
1903
+ status: "in_progress" satisfies AcpToolCallStatus,
1904
+ },
1905
+ toolCallUpdateMeta(snapshot),
1906
+ );
1907
+ }
1586
1908
 
1587
1909
  const requireInitialized = (): void => {
1588
1910
  if (!initialized) throw new AcpRequestError(-32000, "initialize must be called first", { code: "not_initialized" });
@@ -1671,15 +1993,21 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1671
1993
  const eventRequest =
1672
1994
  clientMeta !== null && isRecord(clientMeta["clio-coder/events"]) ? clientMeta["clio-coder/events"] : null;
1673
1995
  const requestedEventKinds = eventRequest !== null ? eventRequest.kinds : null;
1674
- loopBlockedEventsEnabled =
1996
+ // A malformed request refuses the whole opt-in rather than the offending
1997
+ // entry: a client that sent an unrepresentable kind does not know what it
1998
+ // asked for, and silently honouring the rest of its list hides that.
1999
+ enabledEventKinds.clear();
2000
+ if (
1675
2001
  eventRequest !== null &&
1676
2002
  eventRequest.version === 1 &&
1677
2003
  Array.isArray(requestedEventKinds) &&
1678
- requestedEventKinds.length <= 16 &&
1679
- requestedEventKinds.every(
1680
- (kind) => typeof kind === "string" && utf8Bytes(kind) <= 64 && !hasControlCharacters(kind),
1681
- ) &&
1682
- requestedEventKinds.includes("safety.loopBlocked");
2004
+ requestedEventKinds.length <= ACP_MAX_REQUESTED_EVENT_KINDS &&
2005
+ requestedEventKinds.every((kind) => typeof kind === "string" && utf8Bytes(kind) <= 64 && !hasControlCharacters(kind))
2006
+ ) {
2007
+ for (const kind of ACP_FORWARDABLE_EVENT_KINDS) {
2008
+ if (requestedEventKinds.includes(kind)) enabledEventKinds.add(kind);
2009
+ }
2010
+ }
1683
2011
  const canLoadSession =
1684
2012
  options.session !== undefined &&
1685
2013
  options.readSessionEntries !== undefined &&
@@ -1717,12 +2045,16 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1717
2045
  list: options.providers !== undefined,
1718
2046
  probe: options.providers !== undefined,
1719
2047
  },
2048
+ // Per-frame agent attribution on `session/update`. Announced so a
2049
+ // client can tell "this agent produced nothing" apart from "this
2050
+ // peer does not report identity at all".
2051
+ [ACP_AGENT_META_KEY]: { version: 1, meta: ACP_AGENT_META_KEY },
1720
2052
  ...(options.bus
1721
2053
  ? {
1722
2054
  "clio-coder/events": {
1723
2055
  version: 1,
1724
2056
  notification: "clio-coder/event",
1725
- kinds: ["safety.loopBlocked"],
2057
+ kinds: ACP_FORWARDABLE_EVENT_KINDS,
1726
2058
  workspaceInstanceId,
1727
2059
  },
1728
2060
  }
@@ -1730,7 +2062,15 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1730
2062
  ...(options.toolRegistry !== undefined ? { "clio-coder/tools": "mediated" } : {}),
1731
2063
  },
1732
2064
  },
1733
- authMethods: [],
2065
+ authMethods: [
2066
+ {
2067
+ id: "clio-login",
2068
+ name: "Clio Target Auth & Setup",
2069
+ description: "Configure models, API keys, and target endpoints in terminal",
2070
+ type: "terminal",
2071
+ args: ["auth", "login"],
2072
+ },
2073
+ ],
1734
2074
  } satisfies AcpInitializeResponse;
1735
2075
  });
1736
2076
 
@@ -1767,6 +2107,7 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1767
2107
  };
1768
2108
  sessionCreated = true;
1769
2109
  sessions.set(id, session);
2110
+ boundSessionId = id;
1770
2111
  // NewSessionResponse is { sessionId, modes?, models?, _meta? }; cwd is not a
1771
2112
  // schema field. Clio runs a single-session-per-process server pinned to the
1772
2113
  // launch cwd, so no extra fields are needed.
@@ -1840,6 +2181,7 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
1840
2181
  };
1841
2182
  sessionCreated = true;
1842
2183
  sessions.set(id, session);
2184
+ boundSessionId = id;
1843
2185
  for (const replayParams of replay.params) options.transport.notify("session/update", replayParams);
1844
2186
  return {
1845
2187
  _meta: {
@@ -2134,6 +2476,7 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
2134
2476
  }
2135
2477
  if (options.session?.current()?.id === session.id) await options.session.close();
2136
2478
  sessions.delete(session.id);
2479
+ if (boundSessionId === session.id) boundSessionId = null;
2137
2480
  closedSessionIds.add(session.id);
2138
2481
  return {};
2139
2482
  });
@@ -2230,7 +2573,7 @@ export async function serveClioAcpAgent(options: ClioAcpServerOptions): Promise<
2230
2573
  return await new Promise<number>((resolve) => {
2231
2574
  options.transport.onClose(() => {
2232
2575
  permission.unregister();
2233
- unsubscribeLoopBlocked();
2576
+ unsubscribeEventStream();
2234
2577
  permission.cancelPending("ACP transport closed");
2235
2578
  for (const session of sessions.values()) cancelSession(session, "ACP transport closed");
2236
2579
  const inFlight = promptSettled;
@@ -7,6 +7,13 @@ import type { AgentMessage } from "../types.js";
7
7
  */
8
8
  export const ACP_USAGE_META_KEY = "clio-coder/usage";
9
9
  export const ACP_SESSION_META_KEY = "clio-coder/session";
10
+ /**
11
+ * Per-frame agent attribution on `session/update`. It names which agent
12
+ * produced the frame so a client can label a message, reasoning item, or tool
13
+ * call instead of attributing every frame to the product. Purely additive: a
14
+ * client that does not read it sees exactly the frames it saw before.
15
+ */
16
+ export const ACP_AGENT_META_KEY = "clio-coder/agent";
10
17
 
11
18
  /**
12
19
  * Wire bounds for one prompt turn (CONTRACT C001 §3). A client renders every
@@ -87,11 +94,20 @@ export interface AcpImplementationInfo {
87
94
  version?: string;
88
95
  }
89
96
 
97
+ export interface AcpAuthMethod {
98
+ id: string;
99
+ name: string;
100
+ description?: string;
101
+ type: "agent" | "terminal";
102
+ args?: string[];
103
+ env?: Record<string, string>;
104
+ }
105
+
90
106
  export interface AcpInitializeResponse {
91
107
  protocolVersion?: number;
92
108
  agentCapabilities?: Record<string, unknown>;
93
109
  agentInfo?: AcpImplementationInfo;
94
- authMethods?: unknown[];
110
+ authMethods?: AcpAuthMethod[];
95
111
  }
96
112
 
97
113
  export interface AcpSessionInfo {
@@ -141,6 +157,8 @@ export interface AcpToolCallUpdate {
141
157
  export interface AcpSessionUpdateParams {
142
158
  sessionId?: string;
143
159
  update?: Record<string, unknown>;
160
+ /** Namespaced extension slot; carries replay and agent-attribution metadata. */
161
+ _meta?: Record<string, unknown>;
144
162
  }
145
163
 
146
164
  export type AcpPermissionOptionKind = "allow_once" | "allow_always" | "reject_once" | "reject_always" | string;