@iowarp/clio-coder 0.4.2 → 0.4.3

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 (369) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/CONTRIBUTING.md +86 -19
  3. package/README.md +35 -6
  4. package/dist/{acp-TMDQZDIG.js → acp-H2NGRPWO.js} +11 -11
  5. package/dist/{agents-5N5NG3XG.js → agents-TL5LLUQP.js} +54 -53
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-Z5CCBXKQ.js → auth-E5SW4HMS.js} +19 -16
  8. package/dist/{builtins-K6TNDT24.js → builtins-IA7V7FUC.js} +9 -4
  9. package/dist/{chunk-ZW4HH5JJ.js → chunk-2APPQIER.js} +6 -6
  10. package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
  11. package/dist/{chunk-UBRFI4HS.js → chunk-2UG5F4C5.js} +127 -47
  12. package/dist/{chunk-UH632ZYL.js → chunk-2UH2KFUP.js} +2 -2
  13. package/dist/{chunk-3F7VUY77.js → chunk-2VIKGWFZ.js} +2 -2
  14. package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
  15. package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
  16. package/dist/{chunk-2X4RYJTJ.js → chunk-4UVU7BJ5.js} +2 -2
  17. package/dist/{chunk-M2DAX4F6.js → chunk-4WR7VSYB.js} +2 -2
  18. package/dist/{chunk-5KW52TEP.js → chunk-54CBCGIR.js} +5 -5
  19. package/dist/{chunk-3KIPBMUA.js → chunk-5ICU3EUH.js} +2 -2
  20. package/dist/{chunk-77QIVUZB.js → chunk-5MEZN6CB.js} +4 -4
  21. package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
  22. package/dist/{chunk-LJID3DYZ.js → chunk-64I3JVYM.js} +2 -2
  23. package/dist/{chunk-4JDLP6ZS.js → chunk-6PTFB5VS.js} +7 -7
  24. package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
  25. package/dist/{chunk-HLAFFSEK.js → chunk-7DRAWPTZ.js} +2 -2
  26. package/dist/chunk-7E7I3WLS.js +3762 -0
  27. package/dist/{chunk-YJISEZKC.js → chunk-7ZYNNDKC.js} +6 -6
  28. package/dist/{chunk-I66ZTYNP.js → chunk-AF4YM7Z4.js} +236 -101
  29. package/dist/{chunk-2HFQNRV3.js → chunk-AX2THNSA.js} +12 -12
  30. package/dist/{chunk-PGF63K6I.js → chunk-B4OAX3SI.js} +65 -3
  31. package/dist/{chunk-W6NIE6OW.js → chunk-B4VEBZKF.js} +3 -3
  32. package/dist/{chunk-JBCS7CRR.js → chunk-BEPZRGGU.js} +10 -10
  33. package/dist/{chunk-XGDPUNND.js → chunk-CE5AX47J.js} +2 -2
  34. package/dist/{chunk-I64IFBLB.js → chunk-DWUOQKRU.js} +17 -10
  35. package/dist/{chunk-DZAW46HP.js → chunk-E3TPLWFX.js} +3 -3
  36. package/dist/{chunk-HIICAHCJ.js → chunk-EKCHAPYA.js} +2 -2
  37. package/dist/{chunk-XE3PCIXH.js → chunk-F5JHEYZM.js} +7 -7
  38. package/dist/{chunk-5PFYMY2V.js → chunk-FTMGRKEF.js} +2 -2
  39. package/dist/{chunk-ZNT2M6TG.js → chunk-G76U63X4.js} +17 -17
  40. package/dist/{chunk-34BHNEE3.js → chunk-GHS5EBTQ.js} +58 -7
  41. package/dist/{chunk-2NHR3NAY.js → chunk-GI7YYQ3F.js} +40 -34
  42. package/dist/{chunk-DYHAXKHD.js → chunk-GWZNEVM2.js} +12 -8
  43. package/dist/chunk-GYV6VZOC.js +26 -0
  44. package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
  45. package/dist/{chunk-W4YEMFBX.js → chunk-HEQY7ZFI.js} +2 -2
  46. package/dist/{chunk-IKOZFYBN.js → chunk-I7ZPNEJM.js} +145 -102
  47. package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
  48. package/dist/{chunk-XQRY4DTA.js → chunk-IGLP3ODT.js} +10 -10
  49. package/dist/chunk-IJNZMHLA.js +101 -0
  50. package/dist/{chunk-JWJGP5DQ.js → chunk-INY6HTFL.js} +7 -7
  51. package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
  52. package/dist/{chunk-B74PXLU7.js → chunk-IWT4SF4R.js} +3 -3
  53. package/dist/{chunk-B7HM5Z7T.js → chunk-JDAY6FIL.js} +5 -5
  54. package/dist/{chunk-PJX3WQUQ.js → chunk-JEQ3XTHC.js} +2 -2
  55. package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
  56. package/dist/{chunk-X7IARSHT.js → chunk-JKKCYP3C.js} +9 -9
  57. package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
  58. package/dist/{chunk-SSEYRH53.js → chunk-KK4JZPBQ.js} +19 -140
  59. package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
  60. package/dist/{chunk-Q4XWMHX6.js → chunk-L47TF46W.js} +2 -2
  61. package/dist/{chunk-O3YUNJZ2.js → chunk-LDJG7DW3.js} +81 -24
  62. package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
  63. package/dist/{chunk-F2I26BDK.js → chunk-MUW2BDDH.js} +4 -4
  64. package/dist/{chunk-HKMD33FO.js → chunk-MWUZBSAQ.js} +79 -76
  65. package/dist/{chunk-QQLGQY2A.js → chunk-N2Z7HLVY.js} +20 -20
  66. package/dist/{chunk-DZEK6CJN.js → chunk-NIQJ66N4.js} +19 -19
  67. package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
  68. package/dist/{chunk-462T4EGZ.js → chunk-O5CVSAG5.js} +2 -2
  69. package/dist/{chunk-TPEQIQIE.js → chunk-OML5D5V5.js} +8 -8
  70. package/dist/{chunk-IKSLQ4XV.js → chunk-PAJQJ7BS.js} +558 -216
  71. package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
  72. package/dist/{chunk-UH347SHR.js → chunk-QWGDJJYJ.js} +11 -11
  73. package/dist/chunk-R6Q67RJH.js +134 -0
  74. package/dist/{chunk-CRFOIAX3.js → chunk-RRNP2ANY.js} +6 -6
  75. package/dist/{chunk-IDNA72AH.js → chunk-RSJ25QSL.js} +2 -2
  76. package/dist/chunk-SKHCAU7K.js +385 -0
  77. package/dist/{chunk-RLYRBIYQ.js → chunk-TM6LQDI3.js} +20 -12
  78. package/dist/chunk-UOIZ7DA4.js +41 -0
  79. package/dist/{chunk-P75RZCJW.js → chunk-UPZU6GE4.js} +3 -3
  80. package/dist/{chunk-MCMZMDAC.js → chunk-V2ANDPVT.js} +4 -4
  81. package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
  82. package/dist/{chunk-IMXMHHMQ.js → chunk-VW6DOEDG.js} +332 -57
  83. package/dist/{chunk-XOXV5GKE.js → chunk-W6RRQCPQ.js} +16 -7
  84. package/dist/{chunk-CYZW7JHJ.js → chunk-WBKFA554.js} +8 -8
  85. package/dist/{chunk-BO7Y52RY.js → chunk-WCXUNS7U.js} +7 -7
  86. package/dist/{chunk-ZGNYYXQ6.js → chunk-WRBAGUNF.js} +3 -3
  87. package/dist/{chunk-FVDGR2ZL.js → chunk-XIVNBFZS.js} +85 -30
  88. package/dist/{chunk-BYMNWQ7O.js → chunk-XPWWI35G.js} +299 -58
  89. package/dist/{chunk-KPXDY6QF.js → chunk-XRZT5WY5.js} +2 -2
  90. package/dist/{chunk-AZ4WMN4W.js → chunk-Y3CBHOR6.js} +2 -2
  91. package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
  92. package/dist/{chunk-54ODD65L.js → chunk-YQWYVTMC.js} +4 -4
  93. package/dist/{chunk-M2WXEHER.js → chunk-ZA4VCIGV.js} +2 -2
  94. package/dist/{chunk-7BHIY2MW.js → chunk-ZDN3Y73Y.js} +6 -6
  95. package/dist/{chunk-E7GT7O5N.js → chunk-ZWPRK62N.js} +7 -4
  96. package/dist/cli/index.js +38 -37
  97. package/dist/{clio-7VB377CC.js → clio-CMMK4KRR.js} +7 -7
  98. package/dist/{code-nav-YVLCYA7V.js → code-nav-MDZNQS33.js} +7 -7
  99. package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
  100. package/dist/{config-4HVOS65E.js → config-SVM5P5YI.js} +76 -74
  101. package/dist/{configure-PIWO7B24.js → configure-LE3IK2TJ.js} +26 -24
  102. package/dist/{context-IYEHL3WQ.js → context-2OHRKS42.js} +66 -63
  103. package/dist/{context-N6ZE3LGJ.js → context-E3VC7RX5.js} +15 -11
  104. package/dist/{context-KQYIWPWT.js → context-VNCR7KAG.js} +60 -45
  105. package/dist/{context-clear-G4OGZJDS.js → context-clear-BW4O37TG.js} +61 -59
  106. package/dist/context-map-COB37XXN.js +505 -0
  107. package/dist/{context-working-set-BWLF6LJP.js → context-working-set-VDS25HXZ.js} +17 -16
  108. package/dist/{dispatch-runner-2QQAITS3.js → dispatch-runner-5AHT53RF.js} +85 -74
  109. package/dist/{doctor-LHBD36VU.js → doctor-WNNVO6FY.js} +37 -37
  110. package/dist/{eval-C45FYRJ6.js → eval-7G7SGAYO.js} +285 -114
  111. package/dist/{eval-inventory-6DEJPLBF.js → eval-inventory-Y6QRFOH5.js} +4 -4
  112. package/dist/{evidence-6SHONYAF.js → evidence-VD6736FQ.js} +63 -62
  113. package/dist/{evolve-KRKMV72X.js → evolve-AL3NGVRL.js} +62 -61
  114. package/dist/{extensions-KPZ2UHBB.js → extensions-MOVJ32NM.js} +7 -7
  115. package/dist/{fleet-IVTCKDHT.js → fleet-QZHUMAGI.js} +110 -108
  116. package/dist/{fleet-commands-EDWL3IT7.js → fleet-commands-BAYT5FJZ.js} +10 -10
  117. package/dist/{fleet-decisions-YP3YEFGK.js → fleet-decisions-IREVMRU4.js} +7 -6
  118. package/dist/{fleet-graph-ZFWKHY2M.js → fleet-graph-YCTT3HTI.js} +19 -18
  119. package/dist/{fleet-inspect-FVUNCBML.js → fleet-inspect-QVJTDAVB.js} +55 -54
  120. package/dist/{fleet-preflight-UN5XED4R.js → fleet-preflight-25QAFPK4.js} +4 -4
  121. package/dist/{fleet-validate-XOWC4HSX.js → fleet-validate-5O57AAJ7.js} +23 -22
  122. package/dist/{fleet-verify-UN3SODEL.js → fleet-verify-CPH2W2T6.js} +56 -55
  123. package/dist/{fleet-view-TWHJKCN6.js → fleet-view-SWBR3VGQ.js} +55 -54
  124. package/dist/{init-T2QORQ3Y.js → init-J477LKZH.js} +78 -76
  125. package/dist/{interop-IN5I2A66.js → interop-3FCM6XLG.js} +11 -11
  126. package/dist/{library-LSCATDLZ.js → library-QUQEIUG6.js} +28 -27
  127. package/dist/{memory-HYOKAGGJ.js → memory-SGGSEP65.js} +64 -63
  128. package/dist/{models-2GPMFYCM.js → models-HEKUAXXK.js} +49 -43
  129. package/dist/{monitor-E4ASVUJH.js → monitor-HKU57TYQ.js} +61 -60
  130. package/dist/{orchestrator-DDMPR3PY.js → orchestrator-VDFAEFAI.js} +919 -546
  131. package/dist/{panes-E3RUXOW5.js → panes-DN2SSFOH.js} +3 -3
  132. package/dist/{panes-IXKLOKA2.js → panes-TALGNPZT.js} +8 -8
  133. package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
  134. package/dist/reset-EAJFFJVB.js +344 -0
  135. package/dist/{resources-OTRSN34L.js → resources-OVKSEFVE.js} +27 -20
  136. package/dist/{run-5DEYH5QK.js → run-7DP7ZF2J.js} +113 -109
  137. package/dist/{share-IHWTLO3M.js → share-WML67FT3.js} +26 -25
  138. package/dist/{skills-IYMXMKW4.js → skills-SG662R2K.js} +39 -31
  139. package/dist/{skills-eval-DROHSJAR.js → skills-eval-VVZEUU46.js} +74 -73
  140. package/dist/{skills-inventory-D7X4L4ZX.js → skills-inventory-I2E23GET.js} +21 -20
  141. package/dist/{slash-commands-QBM7UZ3B.js → slash-commands-S7MBJDQK.js} +35 -34
  142. package/dist/{steer-Z5DO23FJ.js → steer-2LQOMCPB.js} +3 -3
  143. package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
  144. package/dist/{targets-P2FUC4IL.js → targets-4QC3HIEW.js} +48 -45
  145. package/dist/{terminal-lease-YREJ3JX2.js → terminal-lease-TUHIJ6Y2.js} +2 -2
  146. package/dist/{tools-5B7RO6MV.js → tools-TFGJICCU.js} +8 -8
  147. package/dist/{trace-YMGMUM6A.js → trace-FXMXUZUF.js} +7 -7
  148. package/dist/uninstall-5PEVOE5B.js +408 -0
  149. package/dist/upgrade-M4WXY6KN.js +303 -0
  150. package/dist/{usage-ME5MPXGX.js → usage-N7ZNVLEM.js} +147 -102
  151. package/dist/{verifiers-BVZ7IWOO.js → verifiers-DJTP4XX6.js} +15 -15
  152. package/dist/{verify-5K7ZKQFC.js → verify-RWE4PPEK.js} +9 -9
  153. package/dist/{wiki-generate-F5W5QTYY.js → wiki-generate-C7IQOXSP.js} +84 -82
  154. package/dist/{with-panes-BYOJCLAM.js → with-panes-4GCGSL7J.js} +9 -9
  155. package/dist/worker/entry.js +61 -60
  156. package/docs/architecture/artifact-placement.md +1 -0
  157. package/docs/architecture/artifact-versions.md +1 -1
  158. package/docs/architecture/context-engine.md +4 -0
  159. package/docs/architecture/middleware-and-components.md +1 -1
  160. package/docs/architecture/model-catalog.md +21 -10
  161. package/docs/architecture/observability.md +12 -1
  162. package/docs/architecture/prompt-envelope-and-tools.md +2 -0
  163. package/docs/architecture/provider-adapter-cookbook.md +63 -0
  164. package/docs/architecture/safety-model.md +15 -5
  165. package/docs/guide/built-in-agents.md +17 -3
  166. package/docs/guide/commands-and-modes.md +1 -1
  167. package/docs/guide/configuration-and-targets.md +97 -9
  168. package/docs/guide/configuration-reference.md +7 -2
  169. package/docs/guide/environment-variables.md +2 -0
  170. package/docs/guide/installation-and-lifecycle.md +37 -4
  171. package/docs/guide/proactive-memory.md +66 -55
  172. package/docs/guide/skills-marketplace.md +18 -0
  173. package/docs/process/development-pipeline.md +34 -1
  174. package/docs/process/eval-runner.md +67 -3
  175. package/evals/behavioral-model.yaml +3 -2
  176. package/package.json +2 -2
  177. package/skills/README.md +7 -5
  178. package/skills/coding/ast-grep/SKILL.md +101 -30
  179. package/skills/coding/ast-grep/evals.md +26 -0
  180. package/skills/coding/coding-standards/SKILL.md +40 -5
  181. package/skills/coding/coding-standards/evals.md +23 -0
  182. package/skills/coding/prototype/SKILL.md +87 -28
  183. package/skills/coding/prototype/evals.md +19 -0
  184. package/skills/coding/tdd/SKILL.md +80 -53
  185. package/skills/coding/tdd/evals.md +20 -0
  186. package/skills/context/context-handoff/SKILL.md +43 -2
  187. package/skills/context/context-handoff/evals.md +44 -0
  188. package/skills/context/context-prime/SKILL.md +45 -15
  189. package/skills/context/context-prime/evals.md +45 -0
  190. package/skills/git/branch-closeout/SKILL.md +132 -0
  191. package/skills/git/branch-closeout/evals.md +133 -0
  192. package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
  193. package/skills/git/file-ticket/SKILL.md +77 -63
  194. package/skills/git/file-ticket/assets/issue-template.md +22 -0
  195. package/skills/git/file-ticket/evals.md +31 -26
  196. package/skills/git/file-ticket/references/issue-discovery.md +49 -0
  197. package/skills/git/fix-issue/SKILL.md +87 -64
  198. package/skills/git/fix-issue/evals.md +35 -31
  199. package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
  200. package/skills/git/resolve-merge-conflicts/SKILL.md +100 -51
  201. package/skills/git/resolve-merge-conflicts/evals.md +52 -25
  202. package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
  203. package/skills/git/ship/SKILL.md +103 -67
  204. package/skills/git/ship/assets/pr-template.md +21 -0
  205. package/skills/git/ship/evals.md +44 -28
  206. package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
  207. package/skills/git/worktree-create/SKILL.md +80 -50
  208. package/skills/git/worktree-create/evals.md +40 -33
  209. package/skills/git/worktree-create/references/worktree-setup.md +62 -66
  210. package/skills/git/worktree-merge/SKILL.md +112 -65
  211. package/skills/git/worktree-merge/evals.md +42 -34
  212. package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
  213. package/skills/planning/archify/SKILL.md +196 -0
  214. package/skills/planning/archify/evals.md +65 -0
  215. package/skills/planning/architecture/SKILL.md +61 -12
  216. package/skills/planning/architecture/evals.md +65 -0
  217. package/skills/planning/backlog/SKILL.md +130 -14
  218. package/skills/planning/backlog/evals.md +142 -0
  219. package/skills/planning/prd/SKILL.md +46 -6
  220. package/skills/planning/prd/evals.md +54 -0
  221. package/skills/planning/product-intent/SKILL.md +57 -2
  222. package/skills/planning/product-intent/evals.md +70 -0
  223. package/skills/planning/tech-spec/SKILL.md +53 -2
  224. package/skills/planning/tech-spec/evals.md +73 -0
  225. package/skills/registry.yaml +58 -50
  226. package/skills/remote.yaml +13 -0
  227. package/skills/research/arxiv-literature/SKILL.md +76 -18
  228. package/skills/research/arxiv-literature/evals.md +50 -0
  229. package/skills/research/experiment-protocol/SKILL.md +20 -1
  230. package/skills/research/experiment-protocol/evals.md +23 -0
  231. package/skills/research/scientific-debugging/SKILL.md +23 -1
  232. package/skills/research/scientific-debugging/evals.md +18 -0
  233. package/skills/research/scientific-modernization/SKILL.md +26 -1
  234. package/skills/research/scientific-modernization/evals.md +27 -0
  235. package/skills/skill-marketplace.json +63 -28
  236. package/skills/workflow/cut-it/SKILL.md +65 -5
  237. package/skills/workflow/cut-it/evals.md +101 -0
  238. package/skills/workflow/design-council/SKILL.md +117 -27
  239. package/skills/workflow/design-council/evals.md +161 -0
  240. package/skills/workflow/grill-me/SKILL.md +86 -10
  241. package/skills/workflow/grill-me/evals.md +153 -0
  242. package/skills/workflow/workflow-distiller/SKILL.md +76 -17
  243. package/skills/workflow/workflow-distiller/evals.md +118 -0
  244. package/src/cli/configure-interop.ts +105 -13
  245. package/src/cli/configure-oauth.ts +57 -0
  246. package/src/cli/configure-onboarding.ts +980 -0
  247. package/src/cli/configure-target.ts +594 -0
  248. package/src/cli/configure.ts +1082 -528
  249. package/src/cli/context-map.ts +114 -0
  250. package/src/cli/context.ts +4 -0
  251. package/src/cli/index.ts +1 -0
  252. package/src/cli/lifecycle-presenter.ts +436 -0
  253. package/src/cli/models.ts +10 -2
  254. package/src/cli/modes/print.ts +5 -1
  255. package/src/cli/reset.ts +228 -106
  256. package/src/cli/run.ts +7 -2
  257. package/src/cli/select.ts +664 -0
  258. package/src/cli/skills.ts +9 -2
  259. package/src/cli/targets.ts +3 -0
  260. package/src/cli/uninstall.ts +233 -165
  261. package/src/cli/upgrade.ts +204 -149
  262. package/src/cli/usage.ts +86 -27
  263. package/src/cli/validate-model.ts +3 -3
  264. package/src/core/config.ts +56 -0
  265. package/src/core/external-diagnostic.ts +44 -0
  266. package/src/core/gateway-routing.ts +157 -0
  267. package/src/core/safe-exec.ts +17 -2
  268. package/src/core/skill-activation.ts +89 -2
  269. package/src/domains/agents/builtins/world-knowledge.md +31 -0
  270. package/src/domains/agents/catalog.ts +1 -1
  271. package/src/domains/agents/result-contract.ts +70 -0
  272. package/src/domains/context/wiki/map-seed.ts +589 -0
  273. package/src/domains/context/wiki/plan.ts +2 -2
  274. package/src/domains/dispatch/admission.ts +29 -0
  275. package/src/domains/dispatch/agent-candidates.ts +10 -0
  276. package/src/domains/dispatch/budget-envelope.ts +86 -1
  277. package/src/domains/dispatch/capability-match.ts +1 -0
  278. package/src/domains/dispatch/capacity-lease.ts +17 -0
  279. package/src/domains/dispatch/contract.ts +11 -1
  280. package/src/domains/dispatch/extension.ts +134 -29
  281. package/src/domains/dispatch/types.ts +3 -0
  282. package/src/domains/dispatch/worker-model-metadata.ts +38 -0
  283. package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
  284. package/src/domains/eval/metrics/token-stream.ts +201 -31
  285. package/src/domains/eval/metrics/tracked.ts +40 -4
  286. package/src/domains/eval/runners/clio-run.ts +5 -2
  287. package/src/domains/eval/schema/suite.ts +28 -0
  288. package/src/domains/eval/schema/verdict.ts +2 -2
  289. package/src/domains/eval/suites/resolve.ts +13 -1
  290. package/src/domains/eval/suites/run.ts +24 -3
  291. package/src/domains/interop/registry.ts +6 -2
  292. package/src/domains/interop/types.ts +4 -0
  293. package/src/domains/lifecycle/migrations/index.ts +4 -0
  294. package/src/domains/memory/task-memory-policy.ts +70 -26
  295. package/src/domains/memory/task-memory-telemetry.ts +1 -0
  296. package/src/domains/middleware/index.ts +0 -1
  297. package/src/domains/middleware/marketplace-offer.ts +3 -35
  298. package/src/domains/middleware/memory-intervention.ts +127 -32
  299. package/src/domains/middleware/memory-step-endpoint.ts +3 -2
  300. package/src/domains/middleware/skills-reminder.ts +31 -2
  301. package/src/domains/observability/compaction-usage.ts +118 -0
  302. package/src/domains/observability/cost.ts +1 -1
  303. package/src/domains/observability/extension.ts +6 -1
  304. package/src/domains/observability/out-of-turn-usage.ts +52 -21
  305. package/src/domains/providers/contract.ts +4 -1
  306. package/src/domains/providers/extension.ts +40 -9
  307. package/src/domains/providers/model-capabilities.ts +9 -0
  308. package/src/domains/providers/model-discovery.ts +2 -0
  309. package/src/domains/providers/model-runtime-capabilities.ts +15 -5
  310. package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +32 -12
  311. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
  312. package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
  313. package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
  314. package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
  315. package/src/domains/providers/support.ts +11 -5
  316. package/src/domains/providers/target-model-cache.ts +25 -2
  317. package/src/domains/providers/types/capability-flags.ts +2 -0
  318. package/src/domains/providers/types/runtime-descriptor.ts +20 -1
  319. package/src/domains/providers/types/target-descriptor.ts +19 -0
  320. package/src/domains/resources/index.ts +3 -0
  321. package/src/domains/resources/skills/install.ts +72 -7
  322. package/src/domains/resources/skills/loader.ts +7 -0
  323. package/src/domains/resources/skills/marketplace.ts +63 -11
  324. package/src/domains/safety/autonomy.ts +15 -0
  325. package/src/domains/safety/index.ts +1 -0
  326. package/src/domains/safety/path-policy.ts +1 -1
  327. package/src/domains/safety/policy-engine.ts +34 -11
  328. package/src/domains/safety/protected-artifacts.ts +191 -88
  329. package/src/domains/safety/run-effects.ts +2 -22
  330. package/src/domains/safety/skill-authority.ts +55 -0
  331. package/src/domains/session/compaction/compact.ts +72 -22
  332. package/src/domains/session/entries.ts +6 -0
  333. package/src/domains/session/usage.ts +3 -3
  334. package/src/engine/agent.ts +13 -3
  335. package/src/engine/ai.ts +26 -8
  336. package/src/engine/antigravity/subprocess-runtime.ts +386 -120
  337. package/src/engine/api-registry.ts +3 -0
  338. package/src/engine/apis/openai-completions.ts +117 -14
  339. package/src/engine/external-subprocess.ts +114 -6
  340. package/src/entry/background-model-metadata.ts +18 -0
  341. package/src/entry/compaction-prompt.ts +57 -0
  342. package/src/entry/orchestrator.ts +405 -216
  343. package/src/entry/task-memory-lifecycle.ts +35 -0
  344. package/src/interactive/chat-loop-messages.ts +13 -4
  345. package/src/interactive/chat-loop.ts +65 -2
  346. package/src/interactive/chat-renderer.ts +1 -0
  347. package/src/interactive/cost-overlay.ts +26 -2
  348. package/src/interactive/interactive-slash-runtime.ts +2 -1
  349. package/src/interactive/renderers/worker-entry.ts +32 -0
  350. package/src/interactive/slash-commands.ts +24 -6
  351. package/src/interactive/theme/labels.ts +19 -13
  352. package/src/interactive/turn-context.ts +9 -5
  353. package/src/interactive/turn-recovery.ts +8 -0
  354. package/src/interactive/turn-runtime.ts +27 -11
  355. package/src/interactive/turn-state.ts +7 -0
  356. package/src/interactive/worker-receipts.ts +1 -0
  357. package/src/interactive/worker-stream.ts +6 -1
  358. package/src/tools/context/index.ts +30 -9
  359. package/src/tools/dispatch-arguments.ts +1 -0
  360. package/src/tools/dispatch-event-text.ts +10 -0
  361. package/src/tools/dispatch-plan.ts +1 -0
  362. package/src/tools/dispatch-runner.ts +12 -0
  363. package/src/tools/registry.ts +11 -5
  364. package/src/tools/worker-evidence.ts +3 -1
  365. package/src/worker/spec-contract.ts +4 -0
  366. package/dist/chunk-2Z2IKEXI.js +0 -1554
  367. package/dist/reset-OAQP3W4O.js +0 -230
  368. package/dist/uninstall-N34PCTGJ.js +0 -331
  369. package/dist/upgrade-PXK3S2YM.js +0 -325
@@ -28,6 +28,17 @@ export interface BudgetEnvelopeReason {
28
28
 
29
29
  export interface RunToolBudgetEnvelope {
30
30
  version: 1;
31
+ enforcement:
32
+ | {
33
+ classification: "native-per-tool";
34
+ perTool: "enforced";
35
+ clioControls: ReadonlyArray<"tool-calls" | "read-reserve" | "synthesis" | "attempt-cap">;
36
+ }
37
+ | {
38
+ classification: "external-one-shot";
39
+ perTool: "unobserved-not-enforced";
40
+ clioControls: ReadonlyArray<"single-launch" | "wall-clock" | "output-cap" | "cancellation" | "result-contract">;
41
+ };
31
42
  policy: {
32
43
  recipeId: string;
33
44
  default: AgentBudgetPhase & { synthesis: boolean };
@@ -39,6 +50,15 @@ export interface RunToolBudgetEnvelope {
39
50
  reasons: ReadonlyArray<BudgetEnvelopeReason>;
40
51
  }
41
52
 
53
+ const NATIVE_CLIO_CONTROLS = ["tool-calls", "read-reserve", "synthesis", "attempt-cap"] as const;
54
+ const EXTERNAL_CLIO_CONTROLS = [
55
+ "single-launch",
56
+ "wall-clock",
57
+ "output-cap",
58
+ "cancellation",
59
+ "result-contract",
60
+ ] as const;
61
+
42
62
  export type BudgetAdmissionDenialCode =
43
63
  | "exact-recipe-policy"
44
64
  | "recipe-maximum"
@@ -94,6 +114,8 @@ export function cloneDispatchBudgetRequest(value: unknown, prefix = "budget"): D
94
114
  }
95
115
 
96
116
  function freezeEnvelope(envelope: RunToolBudgetEnvelope): RunToolBudgetEnvelope {
117
+ Object.freeze(envelope.enforcement.clioControls);
118
+ Object.freeze(envelope.enforcement);
97
119
  Object.freeze(envelope.policy.default);
98
120
  Object.freeze(envelope.policy.maximum);
99
121
  Object.freeze(envelope.policy);
@@ -172,6 +194,7 @@ export interface ResolveToolBudgetEnvelopeInput {
172
194
  hasReadTool: boolean;
173
195
  retry: boolean;
174
196
  revision: boolean;
197
+ enforcement?: "native-per-tool" | "external-one-shot";
175
198
  }
176
199
 
177
200
  /** Resolve the one immutable envelope used by admission, enforcement, and evidence. */
@@ -253,6 +276,18 @@ export function resolveToolBudgetEnvelope(input: ResolveToolBudgetEnvelopeInput)
253
276
  const authoredMaximum = input.policy.maximum ?? input.policy;
254
277
  return freezeEnvelope({
255
278
  version: 1,
279
+ enforcement:
280
+ input.enforcement === "external-one-shot"
281
+ ? {
282
+ classification: "external-one-shot",
283
+ perTool: "unobserved-not-enforced",
284
+ clioControls: [...EXTERNAL_CLIO_CONTROLS],
285
+ }
286
+ : {
287
+ classification: "native-per-tool",
288
+ perTool: "enforced",
289
+ clioControls: [...NATIVE_CLIO_CONTROLS],
290
+ },
256
291
  policy: {
257
292
  recipeId: input.recipeId,
258
293
  default: {
@@ -297,7 +332,11 @@ export function formatEffectiveBudget(envelope: RunToolBudgetEnvelope): string {
297
332
  const revision = budget.revision
298
333
  ? `, result revision ${budget.revision.toolCalls}/${budget.revision.readReserve}`
299
334
  : "";
300
- return `${budget.toolCalls}/${budget.readReserve}${revision}, lifetime cap ${budget.hardCap}, synthesis=${budget.synthesis ? "on" : "off"}`;
335
+ const enforcement =
336
+ envelope.enforcement.classification === "external-one-shot"
337
+ ? "external one-shot; per-tool unobserved/not enforced"
338
+ : "native per-tool enforced";
339
+ return `${budget.toolCalls}/${budget.readReserve}${revision}, lifetime cap ${budget.hardCap}, synthesis=${budget.synthesis ? "on" : "off"}; ${enforcement}`;
301
340
  }
302
341
 
303
342
  export function formatBudgetReasons(envelope: RunToolBudgetEnvelope): string {
@@ -314,6 +353,10 @@ const BUDGET_REASON_CODES: ReadonlySet<string> = new Set<BudgetEnvelopeReasonCod
314
353
  "revision-growth-denied",
315
354
  ]);
316
355
 
356
+ function isExactStringArray(value: unknown[], expected: readonly string[]): boolean {
357
+ return value.length === expected.length && value.every((item, index) => item === expected[index]);
358
+ }
359
+
317
360
  /** Safely project an envelope that crossed a persistence or event boundary. */
318
361
  export function cloneRunToolBudgetEnvelope(value: unknown): RunToolBudgetEnvelope | undefined {
319
362
  try {
@@ -373,8 +416,50 @@ export function cloneRunToolBudgetEnvelope(value: unknown): RunToolBudgetEnvelop
373
416
  }
374
417
  reasons.push({ code: reason.code as BudgetEnvelopeReasonCode, detail: reason.detail });
375
418
  }
419
+ const enforcement = (() => {
420
+ if (value.enforcement === undefined) {
421
+ return {
422
+ classification: "native-per-tool" as const,
423
+ perTool: "enforced" as const,
424
+ clioControls: [...NATIVE_CLIO_CONTROLS],
425
+ };
426
+ }
427
+ if (!isRecord(value.enforcement) || !Array.isArray(value.enforcement.clioControls)) return null;
428
+ if (
429
+ Object.keys(value.enforcement).some(
430
+ (key) => key !== "classification" && key !== "perTool" && key !== "clioControls",
431
+ )
432
+ ) {
433
+ return null;
434
+ }
435
+ if (
436
+ value.enforcement.classification === "external-one-shot" &&
437
+ value.enforcement.perTool === "unobserved-not-enforced" &&
438
+ isExactStringArray(value.enforcement.clioControls, EXTERNAL_CLIO_CONTROLS)
439
+ ) {
440
+ return {
441
+ classification: "external-one-shot" as const,
442
+ perTool: "unobserved-not-enforced" as const,
443
+ clioControls: [...EXTERNAL_CLIO_CONTROLS],
444
+ };
445
+ }
446
+ if (
447
+ value.enforcement.classification === "native-per-tool" &&
448
+ value.enforcement.perTool === "enforced" &&
449
+ isExactStringArray(value.enforcement.clioControls, NATIVE_CLIO_CONTROLS)
450
+ ) {
451
+ return {
452
+ classification: "native-per-tool" as const,
453
+ perTool: "enforced" as const,
454
+ clioControls: [...NATIVE_CLIO_CONTROLS],
455
+ };
456
+ }
457
+ return null;
458
+ })();
459
+ if (enforcement === null) return undefined;
376
460
  return freezeEnvelope({
377
461
  version: 1,
462
+ enforcement,
378
463
  policy: {
379
464
  recipeId,
380
465
  default: { ...defaultPhase, synthesis: value.policy.default.synthesis },
@@ -76,6 +76,7 @@ const REPORTING_CONTRACT_KINDS: ReadonlySet<ResultContract["kind"]> = new Set([
76
76
  "scout-report",
77
77
  "verifier-report",
78
78
  "research-report",
79
+ "world-knowledge-report",
79
80
  "provenance-report",
80
81
  "debugger-report",
81
82
  "oracle-report",
@@ -481,6 +481,23 @@ export function capacityLeaseUsage(options?: { nowMs?: number; probe?: LeaseOwne
481
481
  return { global: leases.length, nodes, endpoints, endpointHolders };
482
482
  }
483
483
 
484
+ /** Coherent current endpoint occupancy, including held reservation waves.
485
+ * The caller still owns admission; process-local streams are not global leases.
486
+ */
487
+ export function endpointCapacityUsage(): Readonly<Record<string, number>> {
488
+ return withStateFileLockSync(capacityStateLockPath(), () => {
489
+ const file = readCapacityStateUnsafe();
490
+ reclaim(file, Date.now(), defaultProbe);
491
+ const held = heldReservationUsage(file.reservations);
492
+ const usage: Record<string, number> = { ...foregroundStreamUsage() };
493
+ for (const [key, count] of Object.entries(held.endpoints)) usage[key] = (usage[key] ?? 0) + count;
494
+ for (const lease of file.leases) {
495
+ if (lease.endpointKey !== undefined) usage[lease.endpointKey] = (usage[lease.endpointKey] ?? 0) + 1;
496
+ }
497
+ return usage;
498
+ });
499
+ }
500
+
484
501
  /**
485
502
  * Per-node lease counts for display and for advisory placement spreading. Every
486
503
  * read takes the admission state lock, so a render loop or a multi-node
@@ -86,6 +86,12 @@ export interface DispatchAdmissionObserver {
86
86
  onAdmitted(run: { runId: string; pid: number | null; runtimeKind: RunEnvelope["runtimeKind"] }): void;
87
87
  }
88
88
 
89
+ /** Invocation-owned admission bounds; never serialized into model-authored requests. */
90
+ export interface DispatchPreparationOptions {
91
+ signal?: AbortSignal;
92
+ deadlineAt?: number;
93
+ }
94
+
89
95
  /** Side-effect-free effective routing used to construct a dispatch approval artifact. */
90
96
  export interface DispatchPlanTaskResolution {
91
97
  agentId: string;
@@ -225,6 +231,7 @@ export interface DispatchContract {
225
231
  dispatch(
226
232
  req: DispatchRequest,
227
233
  observer?: DispatchAdmissionObserver,
234
+ preparation?: DispatchPreparationOptions,
228
235
  ): Promise<{
229
236
  runId: string;
230
237
  events: AsyncIterableIterator<unknown>;
@@ -232,7 +239,10 @@ export interface DispatchContract {
232
239
  }>;
233
240
 
234
241
  /** Spawn a group of dispatches and expose one merged batch event stream. */
235
- dispatchBatch(reqs: ReadonlyArray<DispatchRequest>): Promise<{
242
+ dispatchBatch(
243
+ reqs: ReadonlyArray<DispatchRequest>,
244
+ preparation?: DispatchPreparationOptions,
245
+ ): Promise<{
236
246
  batchId: string;
237
247
  /** Logical work ids, one per request in admission order. */
238
248
  assignmentIds: ReadonlyArray<string>;
@@ -16,6 +16,7 @@ import { performance } from "node:perf_hooks";
16
16
  import { BusChannels, type DispatchCompletedPayload, type DispatchRunIdentity } from "../../core/bus-events.js";
17
17
  import { DEFAULT_SETTINGS, type DelegationToolGovernance } from "../../core/defaults.js";
18
18
  import type { DomainBundle, DomainContext, DomainExtension } from "../../core/domain-loader.js";
19
+ import { gatewayRoutingObservationFromRecord } from "../../core/gateway-routing.js";
19
20
  import { GUARDRAIL_DEFAULTS } from "../../core/guardrails.js";
20
21
  import { readClioVersion, readPiMonoVersion } from "../../core/package-root.js";
21
22
  import { canonicalizeExistingPath } from "../../core/path-canonical.js";
@@ -158,6 +159,7 @@ import type {
158
159
  DispatchAdmissionObserver,
159
160
  DispatchContract,
160
161
  DispatchPlanTaskResolution,
162
+ DispatchPreparationOptions,
161
163
  DispatchRequest,
162
164
  DispatchSnapshot,
163
165
  } from "./contract.js";
@@ -297,6 +299,7 @@ import {
297
299
  validateJobSpec,
298
300
  } from "./validation.js";
299
301
  import { describeUngroundedValidations, groundClaimedValidations, invalidatesQuality } from "./validation-grounding.js";
302
+ import { prepareWorkerModelMetadata } from "./worker-model-metadata.js";
300
303
  import {
301
304
  type AgentLedgerBody,
302
305
  computeSettingsFingerprint,
@@ -1439,6 +1442,13 @@ function runtimeLimitations(runtimeKind: RunKind, runtimeId: string): string[] {
1439
1442
  "Claude CLI subprocess executes Claude Code tools; Clio constrains permission mode and forbids dangerous bypass unless explicitly gated",
1440
1443
  ];
1441
1444
  }
1445
+ if (runtimeKind === "subprocess" && runtimeId === "antigravity-code") {
1446
+ return [
1447
+ "Antigravity CLI owns its internal tools, network activity, prompts, and approvals; Clio observes only structured stream output and does not provide per-tool mediation or complete tool telemetry",
1448
+ "Antigravity conversation ids are recorded only as opaque provider observations; Clio does not resume them",
1449
+ "Antigravity runs are one-shot and never retried automatically",
1450
+ ];
1451
+ }
1442
1452
  // HTTP/native runtimes run through pi-agent-core, which Clio observes and
1443
1453
  // controls directly, so there are no runtime-imposed dispatch limitations.
1444
1454
  return [];
@@ -1479,13 +1489,6 @@ function assertWriteRootsEnforceable(runtime: RuntimeDescriptor, writeRoots: Rea
1479
1489
  );
1480
1490
  }
1481
1491
 
1482
- function assertWorkerBudgetEnforceable(runtime: RuntimeDescriptor, hasDeclaredBudget: boolean): void {
1483
- if (!hasDeclaredBudget || runtime.kind !== "subprocess") return;
1484
- throw new Error(
1485
- `dispatch: runtime '${runtime.id}' cannot enforce an explicit dispatch budget because subprocess workers do not expose per-tool mediation; choose a native or claude-sdk worker`,
1486
- );
1487
- }
1488
-
1489
1492
  /**
1490
1493
  * API families whose wire protocol carries tool calls. Membership is a property
1491
1494
  * of the protocol, not of any one model: every server speaking one of these can
@@ -1614,13 +1617,38 @@ function workerToolCallHardCap(settings: EffectiveSettings): number {
1614
1617
  return settings?.fleet.limits.toolCallsPerRun ?? GUARDRAIL_DEFAULTS.workerToolCallCap;
1615
1618
  }
1616
1619
 
1620
+ /**
1621
+ * Only a runtime that declares its external agent loop may accept a declared
1622
+ * per-tool budget: Clio records that budget as unobserved rather than enforced.
1623
+ * Any other subprocess runtime cannot mediate tool calls, so a declared budget
1624
+ * would be a claim nobody enforces.
1625
+ */
1626
+ export function assertWorkerBudgetEnforceable(
1627
+ runtime: Pick<RuntimeDescriptor, "id" | "kind" | "externalAgentLoop">,
1628
+ hasDeclaredBudget: boolean,
1629
+ ): void {
1630
+ if (!hasDeclaredBudget || runtime.kind !== "subprocess" || runtime.externalAgentLoop !== undefined) return;
1631
+ throw new Error(
1632
+ `dispatch: runtime '${runtime.id}' cannot enforce an explicit dispatch budget because subprocess workers do not expose per-tool mediation; choose a native or claude-sdk worker`,
1633
+ );
1634
+ }
1635
+
1636
+ /** Per-tool budget enforcement is real only where Clio observes each tool call. */
1637
+ export function budgetEnforcementForRuntime(
1638
+ runtime: Pick<RuntimeDescriptor, "kind">,
1639
+ ): "native-per-tool" | "external-one-shot" {
1640
+ return runtime.kind === "subprocess" ? "external-one-shot" : "native-per-tool";
1641
+ }
1642
+
1617
1643
  function resolveEffectiveWorkerBudget(input: {
1618
1644
  req: DispatchRequest;
1619
1645
  recipeId: string;
1620
1646
  declared: ReturnType<typeof normalizeAgentSpec>["budget"];
1621
1647
  allowedTools: ReadonlyArray<ToolName>;
1622
1648
  settings: EffectiveSettings;
1649
+ runtime: RuntimeDescriptor;
1623
1650
  }): RunToolBudgetEnvelope {
1651
+ assertWorkerBudgetEnforceable(input.runtime, input.declared !== null || input.req.budget !== undefined);
1624
1652
  const hardCap = workerToolCallHardCap(input.settings);
1625
1653
  const declared = input.declared ?? {
1626
1654
  toolCalls: hardCap,
@@ -1635,6 +1663,7 @@ function resolveEffectiveWorkerBudget(input: {
1635
1663
  hasReadTool: input.allowedTools.includes(ToolNames.Read),
1636
1664
  retry: (input.req.lineage?.attempt ?? 0) > 0,
1637
1665
  revision: input.req.gate?.role === "builder" && input.req.gate.cycle > 1 && input.req.gate.verdict === "revise",
1666
+ enforcement: budgetEnforcementForRuntime(input.runtime),
1638
1667
  });
1639
1668
  }
1640
1669
 
@@ -1975,6 +2004,15 @@ function clampWorkerAutonomy(session: AutonomyLevel, requested: AutonomyLevel |
1975
2004
  return AUTONOMY_ORDER[requested] < AUTONOMY_ORDER[session] ? requested : session;
1976
2005
  }
1977
2006
 
2007
+ /** Read-only recipes are an authority boundary, including on opaque external loops. */
2008
+ export function effectiveWorkerAutonomy(
2009
+ session: AutonomyLevel,
2010
+ requested: AutonomyLevel | undefined,
2011
+ capabilityClass: AgentCapabilityClass,
2012
+ ): AutonomyLevel {
2013
+ return clampWorkerAutonomy(session, capabilityClass === "read-only" ? "read-only" : requested);
2014
+ }
2015
+
1978
2016
  function requestedAutonomyEvidence(
1979
2017
  sessionAutonomy: AutonomyLevel,
1980
2018
  requestedAutonomy: AutonomyLevel | undefined,
@@ -2662,6 +2700,7 @@ export function createDispatchBundle(
2662
2700
  nodeId: string,
2663
2701
  timing: RunPhaseMarks,
2664
2702
  endpoint?: EndpointCapacity | null,
2703
+ signal?: AbortSignal,
2665
2704
  ) {
2666
2705
  const queuedAt = now();
2667
2706
  timing.queuedAt = new Date(queuedAt).toISOString();
@@ -2677,7 +2716,12 @@ export function createDispatchBundle(
2677
2716
  : planQueueSlot(req.reservation.ownerId, req.reservation.memberId, (error) =>
2678
2717
  reportDispatchDiagnostic("read plan queue identity", error),
2679
2718
  );
2719
+ const cancel = (): void => {
2720
+ capacityAdmission.cancel(assignmentId);
2721
+ };
2722
+ signal?.addEventListener("abort", cancel, { once: true });
2680
2723
  try {
2724
+ signal?.throwIfAborted();
2681
2725
  const admitted = await capacityAdmission.admit({
2682
2726
  assignmentId,
2683
2727
  nodeId,
@@ -2700,6 +2744,8 @@ export function createDispatchBundle(
2700
2744
  else await failQueuedAssignment(assignmentId);
2701
2745
  }
2702
2746
  throw error;
2747
+ } finally {
2748
+ signal?.removeEventListener("abort", cancel);
2703
2749
  }
2704
2750
  }
2705
2751
 
@@ -2849,6 +2895,14 @@ export function createDispatchBundle(
2849
2895
  if (draining) return { scheduled: false };
2850
2896
  const rootRunId = run.lineage.rootRunId;
2851
2897
  if (!retryChainIsLive(run)) return { scheduled: false };
2898
+ if (providers.getRuntime(run.runtimeId)?.externalAgentLoop?.generatingRetry === "forbidden") {
2899
+ retryBackoff.delete(rootRunId);
2900
+ return {
2901
+ scheduled: false,
2902
+ settlementDetail:
2903
+ "automatic retry suppressed because this external agent loop is one-shot and Clio cannot prove replay is side-effect-free",
2904
+ };
2905
+ }
2852
2906
  if (!RETRYABLE_OUTCOMES.has(outcome)) {
2853
2907
  retryBackoff.delete(rootRunId);
2854
2908
  return { scheduled: false };
@@ -3224,6 +3278,9 @@ export function createDispatchBundle(
3224
3278
  const tickMonotonic = monotonicNow();
3225
3279
  for (const run of active.values()) {
3226
3280
  if (run.aborted || run.stallKilled || !run.heartbeatAt) continue;
3281
+ // Finalizers retain active entries while awaiting ledger persistence.
3282
+ // Their terminal status is already sealed into the receipt digest.
3283
+ if (ledger.get(run.runId)?.endedAt !== null) continue;
3227
3284
  const heartbeatMonotonic = heartbeatMonotonicAt(run.heartbeatAt);
3228
3285
  if (!Number.isFinite(heartbeatMonotonic) || !Number.isFinite(run.heartbeatAt.current)) continue;
3229
3286
  if (run.runtimeKind === "acp-delegation") {
@@ -3415,7 +3472,12 @@ export function createDispatchBundle(
3415
3472
  }
3416
3473
  }
3417
3474
 
3418
- async function resolveLifecycle(req: DispatchRequest, settings: EffectiveSettings): Promise<DispatchLifecycleStage> {
3475
+ async function resolveLifecycle(
3476
+ req: DispatchRequest,
3477
+ settings: EffectiveSettings,
3478
+ metadataDeadlineAt: number,
3479
+ signal?: AbortSignal,
3480
+ ): Promise<DispatchLifecycleStage> {
3419
3481
  const recipe = agents.get(req.agentId);
3420
3482
  if (!recipe) {
3421
3483
  throw new Error(`dispatch: unknown agent recipe: ${req.agentId}`);
@@ -3453,22 +3515,35 @@ export function createDispatchBundle(
3453
3515
  publishDispatchPathScope(req, pathScope);
3454
3516
  const admission = resolveDispatchAdmissionStage(req, recipe, safety, pathScope);
3455
3517
  const targets = readWorkerTargets(settings);
3456
- const target = resolveDispatchTarget(
3457
- req,
3458
- recipe,
3459
- targets.workerDefault,
3460
- targets.workerProfiles,
3461
- targets.agentBindings,
3462
- targets.targetOrder,
3463
- providers,
3464
- );
3518
+ const resolveTarget = () =>
3519
+ resolveDispatchTarget(
3520
+ req,
3521
+ recipe,
3522
+ targets.workerDefault,
3523
+ targets.workerProfiles,
3524
+ targets.agentBindings,
3525
+ targets.targetOrder,
3526
+ providers,
3527
+ );
3528
+ let target = resolveTarget();
3529
+ const identity = (resolved: ResolvedTarget): string =>
3530
+ JSON.stringify([
3531
+ resolved.target.id,
3532
+ resolved.runtime.id,
3533
+ resolved.wireModelId,
3534
+ endpointIdentityHash(resolved.target.url),
3535
+ ]);
3536
+ const selectedIdentity = identity(target);
3537
+ await prepareWorkerModelMetadata(providers, target.target.id, metadataDeadlineAt, signal, now);
3538
+ target = resolveTarget();
3539
+ if (identity(target) !== selectedIdentity) {
3540
+ throw new Error("dispatch: worker route changed during model metadata preparation; request a fresh admission");
3541
+ }
3465
3542
  enforceCapabilityGate(target.target.id, target.modelCapabilities, req.requiredCapabilities);
3466
3543
  assertRuntimeCanHonorWorkerPermissionMode(target.runtime, settings?.fleet.permissions.mode ?? "deny");
3467
- assertWorkerBudgetEnforceable(target.runtime, spec.budget !== null || req.budget !== undefined);
3468
-
3469
3544
  const cwd = req.cwd ?? process.cwd();
3470
3545
  const sessionAutonomy = settings?.safety.autonomy ?? "auto-edit";
3471
- const effectiveAutonomy = clampWorkerAutonomy(sessionAutonomy, req.autonomy);
3546
+ const effectiveAutonomy = effectiveWorkerAutonomy(sessionAutonomy, req.autonomy, spec.capabilityClass);
3472
3547
  const effectiveTools = withLedgerToolNarrowing(
3473
3548
  effectiveToolNames(admission.allowedTools, target, pathScope.writeBoundaries.length > 0, deniedToolNames(req)),
3474
3549
  req,
@@ -3507,6 +3582,7 @@ export function createDispatchBundle(
3507
3582
  declared: spec.budget,
3508
3583
  allowedTools: effectiveTools,
3509
3584
  settings,
3585
+ runtime: target.runtime,
3510
3586
  });
3511
3587
  // Fetch structured project context only for tiers that receive it, so
3512
3588
  // read-only scouts never pay the CLIO-CODER.md read. The tier is spec policy
@@ -3827,11 +3903,13 @@ export function createDispatchBundle(
3827
3903
  const responseModelIdObservation = responseModelIdObservationFromRecord(event.message, "not-observed");
3828
3904
  const differingResponseModelId = readStringOrNull(event.message.responseModel);
3829
3905
  const providerResponseId = readStringOrNull(event.message.responseId);
3906
+ const gatewayRouting = gatewayRoutingObservationFromRecord(event.message);
3830
3907
  upstreamResponses.push({
3831
3908
  requestedModelId,
3832
3909
  responseModelIdObservation,
3833
3910
  differingResponseModelId,
3834
3911
  providerResponseId,
3912
+ ...(gatewayRouting !== null ? { gatewayRouting } : {}),
3835
3913
  });
3836
3914
  if (event.message.stopReason === "error") {
3837
3915
  const message = readStringOrNull(event.message.errorMessage);
@@ -4389,6 +4467,7 @@ export function createDispatchBundle(
4389
4467
  async function dispatchAttempt(
4390
4468
  req: DispatchRequest,
4391
4469
  observer?: DispatchAdmissionObserver,
4470
+ preparation?: DispatchPreparationOptions,
4392
4471
  settlement?: BatchVerificationGate,
4393
4472
  ): Promise<{
4394
4473
  runId: string;
@@ -4494,7 +4573,10 @@ export function createDispatchBundle(
4494
4573
  }
4495
4574
 
4496
4575
  req = routeAroundCoolingTarget(req, settings) ?? req;
4497
- const lifecycle = await resolveLifecycle(req, settings);
4576
+ const metadataDeadlineAt =
4577
+ req.assignmentDeadlineAt ?? Date.parse(requestedAt) + (req.routingIntent?.deadlineMs ?? 60_000);
4578
+ const lifecycle = await resolveLifecycle(req, settings, metadataDeadlineAt, preparation?.signal);
4579
+ preparation?.signal?.throwIfAborted();
4498
4580
  timing.decisionCompletedAt = new Date(now()).toISOString();
4499
4581
  assertResponseSchemaEnforceable(
4500
4582
  lifecycle.target.runtime,
@@ -4571,7 +4653,13 @@ export function createDispatchBundle(
4571
4653
  if (queuedIdentity !== null) publishCapacityQueued(queuedIdentity, timing, placement?.node ?? null);
4572
4654
  let capacityLease: Awaited<ReturnType<typeof admitAssignmentCapacity>>;
4573
4655
  try {
4574
- capacityLease = await admitAssignmentCapacity(req, placement?.node.id ?? "local", timing, endpoint);
4656
+ capacityLease = await admitAssignmentCapacity(
4657
+ req,
4658
+ placement?.node.id ?? "local",
4659
+ timing,
4660
+ endpoint,
4661
+ preparation?.signal,
4662
+ );
4575
4663
  } catch (error) {
4576
4664
  if (queuedIdentity !== null) publishCapacityAdmissionFailure(queuedIdentity, error);
4577
4665
  throw error;
@@ -4582,6 +4670,7 @@ export function createDispatchBundle(
4582
4670
 
4583
4671
  const ledgerRef = (() => {
4584
4672
  try {
4673
+ preparation?.signal?.throwIfAborted();
4585
4674
  return requireLedger();
4586
4675
  } catch (error) {
4587
4676
  leaseSlot.release();
@@ -4644,6 +4733,7 @@ export function createDispatchBundle(
4644
4733
  };
4645
4734
  let worker: SpawnedWorker;
4646
4735
  try {
4736
+ preparation?.signal?.throwIfAborted();
4647
4737
  worker = (placement?.spawn ?? spawnWorker)(spec, {
4648
4738
  cwd: lifecycle.cwd,
4649
4739
  now,
@@ -4865,11 +4955,13 @@ export function createDispatchBundle(
4865
4955
  const responseModelIdObservation = responseModelIdObservationFromRecord(event.message, "not-observed");
4866
4956
  const differingResponseModelId = readStringOrNull(event.message.responseModel);
4867
4957
  const providerResponseId = readStringOrNull(event.message.responseId);
4958
+ const gatewayRouting = gatewayRoutingObservationFromRecord(event.message);
4868
4959
  upstreamResponses.push({
4869
4960
  requestedModelId,
4870
4961
  responseModelIdObservation,
4871
4962
  differingResponseModelId,
4872
4963
  providerResponseId,
4964
+ ...(gatewayRouting !== null ? { gatewayRouting } : {}),
4873
4965
  });
4874
4966
  if (event.message.stopReason === "error") {
4875
4967
  const message = readStringOrNull(event.message.errorMessage);
@@ -5493,7 +5585,9 @@ export function createDispatchBundle(
5493
5585
  reachedTerminalResult: resultContractWasDue(finalOutcome, outcomeCode),
5494
5586
  output: capturedOutput?.state === "final" ? capturedOutput.text : null,
5495
5587
  cwd: lifecycle.cwd,
5496
- networkAllowed: lifecycle.admission.allowedTools.includes(ToolNames.WebFetch),
5588
+ networkAllowed:
5589
+ lifecycle.admission.allowedTools.includes(ToolNames.WebFetch) ||
5590
+ lifecycle.target.runtime.externalAgentLoop?.network === "externally-governed-unobserved",
5497
5591
  observedRunEffects,
5498
5592
  filesystem: nodeResultContractFilesystem(),
5499
5593
  });
@@ -5754,13 +5848,20 @@ export function createDispatchBundle(
5754
5848
  async function dispatch(
5755
5849
  req: DispatchRequest,
5756
5850
  observer?: DispatchAdmissionObserver,
5851
+ preparation?: DispatchPreparationOptions,
5757
5852
  settlement?: BatchVerificationGate,
5758
5853
  ): Promise<{
5759
5854
  runId: string;
5760
5855
  events: AsyncIterableIterator<unknown>;
5761
5856
  finalPromise: Promise<RunReceipt>;
5762
5857
  }> {
5763
- let prepared = req;
5858
+ let prepared =
5859
+ preparation?.deadlineAt === undefined
5860
+ ? req
5861
+ : {
5862
+ ...req,
5863
+ assignmentDeadlineAt: Math.min(req.assignmentDeadlineAt ?? Number.POSITIVE_INFINITY, preparation.deadlineAt),
5864
+ };
5764
5865
  let createdWorktree: DispatchRequest["taskWorktree"];
5765
5866
  let writerLease: CheckoutWriterLease | undefined;
5766
5867
  const writerRecipe = agents.get(req.agentId);
@@ -5792,7 +5893,7 @@ export function createDispatchBundle(
5792
5893
  return rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel) ? entry : resolvePath(taskWorktree.path, rel);
5793
5894
  });
5794
5895
  prepared = {
5795
- ...req,
5896
+ ...prepared,
5796
5897
  runIdHint: runId,
5797
5898
  taskWorktree,
5798
5899
  cwd: workerCwd,
@@ -5802,7 +5903,8 @@ export function createDispatchBundle(
5802
5903
  }
5803
5904
  let handle: Awaited<ReturnType<typeof dispatchAttempt>>;
5804
5905
  try {
5805
- handle = await dispatchAttempt(prepared, observer, settlement);
5906
+ preparation?.signal?.throwIfAborted();
5907
+ handle = await dispatchAttempt(prepared, observer, preparation, settlement);
5806
5908
  } catch (error) {
5807
5909
  writerLease?.release();
5808
5910
  if (createdWorktree !== undefined) {
@@ -5929,7 +6031,6 @@ export function createDispatchBundle(
5929
6031
  );
5930
6032
  assertPostRuntimeToolCompatibility(req.agentId, agentSpec, effectiveTools, target);
5931
6033
  assertRuntimeCanHonorWorkerPermissionMode(target.runtime, settings?.fleet.permissions.mode ?? "deny");
5932
- assertWorkerBudgetEnforceable(target.runtime, agentSpec.budget !== null || req.budget !== undefined);
5933
6034
  assertResponseSchemaEnforceable(target.runtime, target.modelCapabilities, req.responseSchema, effectiveTools.length);
5934
6035
  assertWriteRootsEnforceable(target.runtime, pathScope.writeBoundaries);
5935
6036
  assertProtectedArtifactsEnforceable(
@@ -5943,6 +6044,7 @@ export function createDispatchBundle(
5943
6044
  declared: agentSpec.budget,
5944
6045
  allowedTools: effectiveTools,
5945
6046
  settings,
6047
+ runtime: target.runtime,
5946
6048
  });
5947
6049
  const endpoint = endpointCapacityForTarget(target.target.id);
5948
6050
  return {
@@ -6191,7 +6293,10 @@ export function createDispatchBundle(
6191
6293
  })();
6192
6294
  }
6193
6295
 
6194
- async function dispatchBatch(reqs: ReadonlyArray<DispatchRequest>): Promise<{
6296
+ async function dispatchBatch(
6297
+ reqs: ReadonlyArray<DispatchRequest>,
6298
+ preparation?: DispatchPreparationOptions,
6299
+ ): Promise<{
6195
6300
  batchId: string;
6196
6301
  assignmentIds: ReadonlyArray<string>;
6197
6302
  events: AsyncIterableIterator<unknown>;
@@ -6210,7 +6315,7 @@ export function createDispatchBundle(
6210
6315
  const handles: Array<Awaited<ReturnType<typeof dispatch>> & { agentId: string }> = [];
6211
6316
  try {
6212
6317
  for (const req of reqs) {
6213
- const handle = await dispatch(req, undefined, settlement);
6318
+ const handle = await dispatch(req, undefined, preparation, settlement);
6214
6319
  handles.push({ ...handle, agentId: req.agentId });
6215
6320
  }
6216
6321
  } catch (err) {
@@ -6,6 +6,7 @@
6
6
  * are pure data: no class methods, no engine refs.
7
7
  */
8
8
 
9
+ import type { GatewayRoutingObservation } from "../../core/gateway-routing.js";
9
10
  import type { ResponseModelIdObservation } from "../../core/response-model-id.js";
10
11
  import type { SkillActivation } from "../../core/skill-activation.js";
11
12
  import type { ToolProfileName } from "../../tools/profiles.js";
@@ -652,6 +653,8 @@ export interface RunReceiptUpstreamResponse {
652
653
  responseModelIdObservation: ResponseModelIdObservation;
653
654
  differingResponseModelId: string | null;
654
655
  providerResponseId: string | null;
656
+ /** Physical route and proxy attempts reported by LiteLLM, when this call used that gateway. */
657
+ gatewayRouting?: GatewayRoutingObservation;
655
658
  }
656
659
 
657
660
  /**
@@ -0,0 +1,38 @@
1
+ import type { ProvidersContract } from "../providers/contract.js";
2
+
3
+ /** Preparation owns its wait; a late HTTP body cannot start an expired worker. */
4
+ export async function prepareWorkerModelMetadata(
5
+ providers: ProvidersContract,
6
+ targetId: string,
7
+ deadlineAt: number,
8
+ signal?: AbortSignal,
9
+ now: () => number = Date.now,
10
+ ): Promise<void> {
11
+ signal?.throwIfAborted();
12
+ const status = providers.list().find((entry) => entry.target.id === targetId);
13
+ if (status?.target.runtime !== "litellm" || status.health.lastCheckAt !== null) return;
14
+ const remainingMs = deadlineAt - now();
15
+ const deadlineError = new Error("dispatch: admission deadline expired during worker model metadata preparation");
16
+ if (remainingMs <= 0) throw deadlineError;
17
+ const controller = new AbortController();
18
+ const abort = (): void => controller.abort(signal?.reason);
19
+ signal?.addEventListener("abort", abort, { once: true });
20
+ const timer = setTimeout(() => controller.abort(deadlineError), Math.min(remainingMs, 2_147_483_647));
21
+ let rejectAborted!: (reason: unknown) => void;
22
+ const aborted = new Promise<never>((_resolve, reject) => {
23
+ rejectAborted = reject;
24
+ });
25
+ const onAbort = (): void => rejectAborted(controller.signal.reason);
26
+ controller.signal.addEventListener("abort", onAbort, { once: true });
27
+ try {
28
+ // The provider also fences publication after each await. Promise.race
29
+ // observes the probe's eventual rejection if an HTTP body settles late.
30
+ await Promise.race([providers.probeTarget(targetId, { reasoning: false, signal: controller.signal }), aborted]);
31
+ controller.signal.throwIfAborted();
32
+ if (now() >= deadlineAt) throw deadlineError;
33
+ } finally {
34
+ clearTimeout(timer);
35
+ signal?.removeEventListener("abort", abort);
36
+ controller.signal.removeEventListener("abort", onAbort);
37
+ }
38
+ }