@iowarp/clio-coder 0.4.1 → 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 (604) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/CONTRIBUTING.md +142 -52
  3. package/README.md +434 -473
  4. package/SECURITY.md +2 -1
  5. package/dist/{acp-ZILU3AUO.js → acp-H2NGRPWO.js} +12 -12
  6. package/dist/{agents-HYWGBGQR.js → agents-TL5LLUQP.js} +56 -55
  7. package/dist/assets/codewiki.json +1 -1
  8. package/dist/{auth-N3QT7CBO.js → auth-E5SW4HMS.js} +23 -21
  9. package/dist/builtins-IA7V7FUC.js +22 -0
  10. package/dist/{chunk-7RY5VZPH.js → chunk-2APPQIER.js} +8 -8
  11. package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
  12. package/dist/{chunk-JA5QWE4Z.js → chunk-2UG5F4C5.js} +1973 -1664
  13. package/dist/{chunk-5YHDIDBP.js → chunk-2UH2KFUP.js} +2 -2
  14. package/dist/{chunk-CTJ4RNAA.js → chunk-2VIKGWFZ.js} +2 -2
  15. package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
  16. package/dist/{chunk-GIZNH63R.js → chunk-35MSIRKH.js} +9 -4
  17. package/dist/chunk-3EBYEESD.js +314 -0
  18. package/dist/{chunk-J5LZHVIT.js → chunk-3M6DQK6S.js} +113 -35
  19. package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
  20. package/dist/{chunk-6FN3E6KX.js → chunk-4O6MANBS.js} +2 -2
  21. package/dist/chunk-4UVU7BJ5.js +39 -0
  22. package/dist/{chunk-VKRH2TCS.js → chunk-4WR7VSYB.js} +2 -2
  23. package/dist/{chunk-BBTJOK6Y.js → chunk-54CBCGIR.js} +5 -5
  24. package/dist/{chunk-AP73CFDC.js → chunk-5ICU3EUH.js} +2 -2
  25. package/dist/chunk-5MEZN6CB.js +1334 -0
  26. package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
  27. package/dist/{chunk-ABLSQ6JX.js → chunk-64I3JVYM.js} +8 -2
  28. package/dist/{chunk-AFKWHWXF.js → chunk-6PTFB5VS.js} +39 -22
  29. package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
  30. package/dist/chunk-7DRAWPTZ.js +360 -0
  31. package/dist/chunk-7E7I3WLS.js +3762 -0
  32. package/dist/{chunk-BJGUKIG4.js → chunk-7ZYNNDKC.js} +7 -7
  33. package/dist/{chunk-XKA2ICR3.js → chunk-AF4YM7Z4.js} +652 -252
  34. package/dist/{chunk-GVQJ5CCZ.js → chunk-AX2THNSA.js} +12 -12
  35. package/dist/{chunk-IG7BCQBA.js → chunk-B4OAX3SI.js} +65 -3
  36. package/dist/{chunk-TD3PGPQA.js → chunk-B4VEBZKF.js} +3 -3
  37. package/dist/{chunk-74YWRRU5.js → chunk-BEPZRGGU.js} +10 -10
  38. package/dist/{chunk-FEFIFZTL.js → chunk-CE5AX47J.js} +2 -2
  39. package/dist/{chunk-UAPGZHYC.js → chunk-DWUOQKRU.js} +25 -11
  40. package/dist/{chunk-THYWACCR.js → chunk-E3TPLWFX.js} +3 -3
  41. package/dist/{chunk-7EPLI7VL.js → chunk-EKCHAPYA.js} +2 -2
  42. package/dist/{chunk-HLW2MRKE.js → chunk-F4EKGO4N.js} +3 -1
  43. package/dist/{chunk-PJJ6MY27.js → chunk-F5JHEYZM.js} +7 -7
  44. package/dist/{chunk-6CCS4G3W.js → chunk-FTMGRKEF.js} +3 -3
  45. package/dist/{chunk-SINK3QR6.js → chunk-G76U63X4.js} +17 -17
  46. package/dist/{chunk-EIMVLWB3.js → chunk-GHS5EBTQ.js} +64 -9
  47. package/dist/{chunk-QMXC4JB7.js → chunk-GI7YYQ3F.js} +187 -1419
  48. package/dist/{chunk-TZSKNMZG.js → chunk-GTUD2WMY.js} +2 -1
  49. package/dist/{chunk-6HMJX2VU.js → chunk-GWZNEVM2.js} +44 -12
  50. package/dist/chunk-GYV6VZOC.js +26 -0
  51. package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
  52. package/dist/{chunk-UXN6JT4W.js → chunk-HEQY7ZFI.js} +3 -3
  53. package/dist/{chunk-7PWAODYW.js → chunk-I7XBWTYH.js} +2 -2
  54. package/dist/{chunk-GCSMB2KY.js → chunk-I7ZPNEJM.js} +145 -102
  55. package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
  56. package/dist/{chunk-QTFGO774.js → chunk-IGLP3ODT.js} +29 -16
  57. package/dist/chunk-IJNZMHLA.js +101 -0
  58. package/dist/{chunk-BDPT6GTK.js → chunk-INY6HTFL.js} +7 -7
  59. package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
  60. package/dist/{chunk-6NJQITNH.js → chunk-IWT4SF4R.js} +6 -3
  61. package/dist/{chunk-R23Z6K6I.js → chunk-JDAY6FIL.js} +19 -19
  62. package/dist/chunk-JEQ3XTHC.js +42 -0
  63. package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
  64. package/dist/{chunk-TVH4ONAM.js → chunk-JKKCYP3C.js} +10 -10
  65. package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
  66. package/dist/{chunk-C537JADH.js → chunk-KK4JZPBQ.js} +19 -141
  67. package/dist/{chunk-K6BF4U2H.js → chunk-KKOJXO6R.js} +62 -14
  68. package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
  69. package/dist/{chunk-6DWBAZ5U.js → chunk-L47TF46W.js} +5 -7
  70. package/dist/{chunk-HUAS7ITX.js → chunk-LDJG7DW3.js} +91 -42
  71. package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
  72. package/dist/{chunk-YPI3QQCF.js → chunk-MCEPRMZW.js} +2 -4
  73. package/dist/{chunk-Y4CAGMM6.js → chunk-MNJGS2IN.js} +5 -6
  74. package/dist/{chunk-VKFQTNDV.js → chunk-MUW2BDDH.js} +4 -4
  75. package/dist/{chunk-E67WX76H.js → chunk-MWUZBSAQ.js} +104 -152
  76. package/dist/{chunk-OJTRZGR3.js → chunk-N2Z7HLVY.js} +21 -21
  77. package/dist/{chunk-TVHHYFHE.js → chunk-NEDJ26B5.js} +2 -2
  78. package/dist/{chunk-FYUN5KZ3.js → chunk-NIQJ66N4.js} +21 -21
  79. package/dist/{chunk-U2WB7TZS.js → chunk-NMJXSHBJ.js} +97 -85
  80. package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
  81. package/dist/{chunk-VEGN6WIQ.js → chunk-O5CVSAG5.js} +3 -3
  82. package/dist/{chunk-MOPSG2X7.js → chunk-OML5D5V5.js} +8 -8
  83. package/dist/{chunk-2VG7KLYV.js → chunk-PAJQJ7BS.js} +5816 -3255
  84. package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
  85. package/dist/{chunk-BTGG6BG2.js → chunk-QWGDJJYJ.js} +158 -19
  86. package/dist/chunk-R6Q67RJH.js +134 -0
  87. package/dist/{chunk-ZJLUDYFY.js → chunk-RRNP2ANY.js} +6 -6
  88. package/dist/{chunk-PVAMAVBB.js → chunk-RSJ25QSL.js} +102 -2
  89. package/dist/{chunk-NLFAQR7Z.js → chunk-S66XZJOF.js} +3 -23
  90. package/dist/chunk-SKHCAU7K.js +385 -0
  91. package/dist/chunk-SZAA6XDG.js +30 -0
  92. package/dist/{chunk-J4HBWF6Y.js → chunk-TM6LQDI3.js} +131 -28
  93. package/dist/chunk-UOIZ7DA4.js +41 -0
  94. package/dist/{chunk-MA3H6DM5.js → chunk-UPZU6GE4.js} +25 -3
  95. package/dist/{chunk-BWW4HLO4.js → chunk-UXCU4E3T.js} +8 -6
  96. package/dist/{chunk-N5UK64DP.js → chunk-V2ANDPVT.js} +4 -4
  97. package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
  98. package/dist/{chunk-6VC4OV3Z.js → chunk-VIA6RFQZ.js} +3 -11
  99. package/dist/{chunk-ZAZB4JMW.js → chunk-VKPAQYEB.js} +27 -8
  100. package/dist/{chunk-QKIFBZKT.js → chunk-VW6DOEDG.js} +497 -81
  101. package/dist/{chunk-SCYB3HA4.js → chunk-W6RRQCPQ.js} +63 -19
  102. package/dist/{chunk-2NM363SV.js → chunk-WBKFA554.js} +10 -10
  103. package/dist/{chunk-R32CLGZ6.js → chunk-WCXUNS7U.js} +82 -21
  104. package/dist/{chunk-GPPB3JBE.js → chunk-WRBAGUNF.js} +3 -3
  105. package/dist/{chunk-IXJT6DCX.js → chunk-XIVNBFZS.js} +85 -30
  106. package/dist/{chunk-UEDMSP56.js → chunk-XPWWI35G.js} +417 -201
  107. package/dist/chunk-XRZT5WY5.js +47 -0
  108. package/dist/{chunk-3QSOM6PA.js → chunk-Y3CBHOR6.js} +2 -2
  109. package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
  110. package/dist/{chunk-AKB4GYDL.js → chunk-YQWYVTMC.js} +5 -5
  111. package/dist/{chunk-6I5ILFOF.js → chunk-ZA4VCIGV.js} +3 -3
  112. package/dist/{chunk-7OBGU7UB.js → chunk-ZDN3Y73Y.js} +12 -18
  113. package/dist/{chunk-3I5NY75V.js → chunk-ZWPRK62N.js} +8 -5
  114. package/dist/cli/index.js +41 -39
  115. package/dist/{clio-IT3G3VQH.js → clio-CMMK4KRR.js} +9 -9
  116. package/dist/{code-nav-RK6S7F6E.js → code-nav-MDZNQS33.js} +89 -21
  117. package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
  118. package/dist/{config-3QZRWZJF.js → config-SVM5P5YI.js} +131 -84
  119. package/dist/{configure-FL7Y3KJF.js → configure-LE3IK2TJ.js} +28 -26
  120. package/dist/{context-5HE7ODYK.js → context-2OHRKS42.js} +69 -64
  121. package/dist/{context-KYQFRVDC.js → context-E3VC7RX5.js} +15 -11
  122. package/dist/{context-XNHL75JV.js → context-VNCR7KAG.js} +93 -65
  123. package/dist/{context-clear-N545L53A.js → context-clear-BW4O37TG.js} +64 -60
  124. package/dist/context-map-COB37XXN.js +505 -0
  125. package/dist/{context-working-set-QHKXSV2F.js → context-working-set-VDS25HXZ.js} +19 -18
  126. package/dist/{dispatch-runner-RGIE5PCT.js → dispatch-runner-5AHT53RF.js} +93 -82
  127. package/dist/{docs-5NAF6AU7.js → docs-PD3EXDKU.js} +21 -20
  128. package/dist/{doctor-ZGPEGHIP.js → doctor-WNNVO6FY.js} +48 -47
  129. package/dist/{eval-GXLL44RD.js → eval-7G7SGAYO.js} +287 -115
  130. package/dist/{eval-inventory-HBWSWQOK.js → eval-inventory-Y6QRFOH5.js} +4 -4
  131. package/dist/{evidence-HWLBRH3Q.js → evidence-VD6736FQ.js} +67 -64
  132. package/dist/{evolve-FTZBMNVW.js → evolve-AL3NGVRL.js} +65 -62
  133. package/dist/{extensions-VHRBEID7.js → extensions-MOVJ32NM.js} +9 -7
  134. package/dist/{fleet-CKZHJWZJ.js → fleet-QZHUMAGI.js} +114 -111
  135. package/dist/{fleet-commands-EXDXBMV6.js → fleet-commands-BAYT5FJZ.js} +10 -10
  136. package/dist/{fleet-decisions-OTHB6KRL.js → fleet-decisions-IREVMRU4.js} +7 -6
  137. package/dist/{fleet-graph-YTEZUCUT.js → fleet-graph-YCTT3HTI.js} +22 -19
  138. package/dist/{fleet-inspect-SS6YMDCK.js → fleet-inspect-QVJTDAVB.js} +58 -55
  139. package/dist/{fleet-preflight-PBY4VYOM.js → fleet-preflight-25QAFPK4.js} +4 -4
  140. package/dist/{fleet-validate-KMEM5L3S.js → fleet-validate-5O57AAJ7.js} +26 -23
  141. package/dist/{fleet-verify-QD5M7E7Q.js → fleet-verify-CPH2W2T6.js} +59 -56
  142. package/dist/{fleet-view-WAMJYNDT.js → fleet-view-SWBR3VGQ.js} +58 -55
  143. package/dist/{init-5XQRBOFV.js → init-J477LKZH.js} +82 -79
  144. package/dist/{interop-34TVO25M.js → interop-3FCM6XLG.js} +11 -11
  145. package/dist/{library-3QY6KF57.js → library-QUQEIUG6.js} +30 -27
  146. package/dist/{memory-L4UTIIIW.js → memory-SGGSEP65.js} +67 -64
  147. package/dist/{models-ZVX3QOWE.js → models-HEKUAXXK.js} +53 -46
  148. package/dist/{monitor-CEKVSYTS.js → monitor-HKU57TYQ.js} +63 -60
  149. package/dist/{orchestrator-77BAP6BC.js → orchestrator-VDFAEFAI.js} +1831 -1057
  150. package/dist/{panes-7STHOAUJ.js → panes-DN2SSFOH.js} +5 -5
  151. package/dist/{panes-SHAUIRXY.js → panes-TALGNPZT.js} +29 -14
  152. package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
  153. package/dist/reset-EAJFFJVB.js +344 -0
  154. package/dist/{resources-74GKTLSF.js → resources-OVKSEFVE.js} +29 -20
  155. package/dist/{run-HBAUJNNZ.js → run-7DP7ZF2J.js} +120 -115
  156. package/dist/{share-G3APVLVP.js → share-WML67FT3.js} +32 -27
  157. package/dist/{skills-35HHUKCR.js → skills-SG662R2K.js} +41 -31
  158. package/dist/{skills-eval-QN4HSHDC.js → skills-eval-VVZEUU46.js} +78 -77
  159. package/dist/{skills-inventory-J357J34F.js → skills-inventory-I2E23GET.js} +23 -20
  160. package/dist/{slash-commands-JZZCQA32.js → slash-commands-S7MBJDQK.js} +40 -36
  161. package/dist/{steer-XAVHJM22.js → steer-2LQOMCPB.js} +3 -3
  162. package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
  163. package/dist/{targets-DSM6CY3M.js → targets-4QC3HIEW.js} +54 -54
  164. package/dist/{terminal-lease-JOPFUVEM.js → terminal-lease-TUHIJ6Y2.js} +5 -5
  165. package/dist/{tools-MKNWVPBH.js → tools-TFGJICCU.js} +10 -10
  166. package/dist/{trace-ECQ7TIYZ.js → trace-FXMXUZUF.js} +55 -7
  167. package/dist/uninstall-5PEVOE5B.js +408 -0
  168. package/dist/upgrade-M4WXY6KN.js +303 -0
  169. package/dist/{usage-X52N3IDJ.js → usage-N7ZNVLEM.js} +151 -104
  170. package/dist/{verifiers-EJTVVSMA.js → verifiers-DJTP4XX6.js} +15 -15
  171. package/dist/{verify-YJL6XET2.js → verify-RWE4PPEK.js} +9 -9
  172. package/dist/{web-fetch-MPIFL3LL.js → web-fetch-MPARV2K7.js} +2 -2
  173. package/dist/{wiki-generate-4NDZTQ4B.js → wiki-generate-C7IQOXSP.js} +89 -86
  174. package/dist/{with-panes-OBOBFIIR.js → with-panes-4GCGSL7J.js} +53 -257
  175. package/dist/worker/entry.js +90 -74
  176. package/docs/README.md +176 -81
  177. package/docs/{acp.md → architecture/acp.md} +36 -20
  178. package/docs/{alcf-provider.md → architecture/alcf-provider.md} +8 -5
  179. package/docs/{architecture.md → architecture/architecture.md} +43 -22
  180. package/docs/{artifact-placement.md → architecture/artifact-placement.md} +27 -23
  181. package/docs/architecture/artifact-versions.md +90 -0
  182. package/docs/{capacity-and-scheduling.md → architecture/capacity-and-scheduling.md} +26 -13
  183. package/docs/{context-engine.md → architecture/context-engine.md} +29 -25
  184. package/docs/{context-working-set.md → architecture/context-working-set.md} +13 -10
  185. package/docs/{dispatch-architecture-rationale.md → architecture/dispatch-architecture-rationale.md} +12 -9
  186. package/docs/{dispatch-typed-intent.md → architecture/dispatch-typed-intent.md} +68 -46
  187. package/docs/{evidence-and-memory.md → architecture/evidence-and-memory.md} +23 -16
  188. package/docs/{middleware-and-components.md → architecture/middleware-and-components.md} +11 -5
  189. package/docs/{model-catalog.md → architecture/model-catalog.md} +61 -27
  190. package/docs/{observability.md → architecture/observability.md} +38 -14
  191. package/docs/{pi-boundary.md → architecture/pi-boundary.md} +24 -11
  192. package/docs/{prompt-envelope-and-tools.md → architecture/prompt-envelope-and-tools.md} +57 -20
  193. package/docs/{provider-adapter-cookbook.md → architecture/provider-adapter-cookbook.md} +99 -25
  194. package/docs/{safety-model.md → architecture/safety-model.md} +35 -20
  195. package/docs/{session-lifecycle.md → architecture/session-lifecycle.md} +8 -5
  196. package/docs/architecture/time-conventions.md +125 -0
  197. package/docs/{trace-store.md → architecture/trace-store.md} +13 -5
  198. package/docs/{tui-design.md → architecture/tui-design.md} +13 -13
  199. package/docs/{worker-dispatch-mechanics.md → architecture/worker-dispatch-mechanics.md} +27 -30
  200. package/docs/{built-in-agents.md → guide/built-in-agents.md} +65 -35
  201. package/docs/{commands-and-modes.md → guide/commands-and-modes.md} +66 -61
  202. package/docs/{configuration-and-targets.md → guide/configuration-and-targets.md} +323 -297
  203. package/docs/guide/configuration-reference.md +1163 -0
  204. package/docs/{environment-variables.md → guide/environment-variables.md} +33 -28
  205. package/docs/{exit-codes-and-output.md → guide/exit-codes-and-output.md} +6 -3
  206. package/docs/{extensions-and-sharing.md → guide/extensions-and-sharing.md} +41 -14
  207. package/docs/{fleet-dispatch.md → guide/fleet-dispatch.md} +39 -43
  208. package/docs/{glossary.md → guide/glossary.md} +14 -11
  209. package/docs/{installation-and-lifecycle.md → guide/installation-and-lifecycle.md} +81 -17
  210. package/docs/guide/panes-and-files.md +290 -0
  211. package/docs/{proactive-memory.md → guide/proactive-memory.md} +131 -107
  212. package/docs/{resource-library.md → guide/resource-library.md} +13 -4
  213. package/docs/{skills-marketplace.md → guide/skills-marketplace.md} +25 -3
  214. package/docs/{tool-usage.md → guide/tool-usage.md} +87 -23
  215. package/docs/{troubleshooting.md → guide/troubleshooting.md} +9 -4
  216. package/docs/{config-knobs-audit.md → history/config-knobs-audit.md} +11 -11
  217. package/docs/{release-cut-checklist.md → history/release-cut-checklist.md} +29 -2
  218. package/docs/process/development-pipeline.md +152 -0
  219. package/docs/process/documentation-coverage.md +100 -0
  220. package/docs/process/documentation-guide.md +187 -0
  221. package/docs/{eval-runner.md → process/eval-runner.md} +108 -53
  222. package/docs/{evals-internal.md → process/evals-internal.md} +10 -10
  223. package/docs/{evolution.md → process/evolution.md} +2 -2
  224. package/docs/{fleet-demo-runbook.md → process/fleet-demo-runbook.md} +11 -7
  225. package/docs/{git-commit-provenance.md → process/git-commit-provenance.md} +11 -4
  226. package/docs/{performance-methodology.md → process/performance-methodology.md} +87 -69
  227. package/docs/{scientific-validation.md → process/scientific-validation.md} +4 -4
  228. package/evals/README.md +2 -2
  229. package/evals/behavioral-model.yaml +3 -2
  230. package/package.json +10 -8
  231. package/skills/README.md +52 -41
  232. package/skills/coding/ast-grep/SKILL.md +102 -31
  233. package/skills/coding/ast-grep/evals.md +26 -0
  234. package/skills/coding/coding-standards/SKILL.md +41 -6
  235. package/skills/coding/coding-standards/evals.md +23 -0
  236. package/skills/coding/prototype/SKILL.md +88 -29
  237. package/skills/coding/prototype/evals.md +19 -0
  238. package/skills/coding/tdd/SKILL.md +81 -54
  239. package/skills/coding/tdd/evals.md +20 -0
  240. package/skills/context/context-handoff/SKILL.md +44 -3
  241. package/skills/context/context-handoff/evals.md +44 -0
  242. package/skills/context/context-prime/SKILL.md +46 -16
  243. package/skills/context/context-prime/evals.md +45 -0
  244. package/skills/git/branch-closeout/SKILL.md +132 -0
  245. package/skills/git/branch-closeout/evals.md +133 -0
  246. package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
  247. package/skills/git/file-ticket/SKILL.md +78 -64
  248. package/skills/git/file-ticket/assets/issue-template.md +22 -0
  249. package/skills/git/file-ticket/evals.md +31 -26
  250. package/skills/git/file-ticket/references/issue-discovery.md +49 -0
  251. package/skills/git/fix-issue/SKILL.md +88 -65
  252. package/skills/git/fix-issue/evals.md +35 -31
  253. package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
  254. package/skills/git/resolve-merge-conflicts/SKILL.md +101 -52
  255. package/skills/git/resolve-merge-conflicts/evals.md +52 -25
  256. package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
  257. package/skills/git/ship/SKILL.md +103 -67
  258. package/skills/git/ship/assets/pr-template.md +21 -0
  259. package/skills/git/ship/evals.md +44 -28
  260. package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
  261. package/skills/git/worktree-create/SKILL.md +80 -50
  262. package/skills/git/worktree-create/evals.md +40 -33
  263. package/skills/git/worktree-create/references/worktree-setup.md +62 -66
  264. package/skills/git/worktree-merge/SKILL.md +112 -65
  265. package/skills/git/worktree-merge/evals.md +42 -34
  266. package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
  267. package/skills/meta/clio-coder-dev/SKILL.md +9 -5
  268. package/skills/meta/clio-coder-dev/evals.md +3 -2
  269. package/skills/meta/clio-coder-test/SKILL.md +102 -95
  270. package/skills/meta/clio-coder-test/evals.md +9 -4
  271. package/skills/meta/clio-coder-test/references/harness.md +100 -124
  272. package/skills/meta/clio-coder-test/references/test-map.md +77 -50
  273. package/skills/meta/credentials/SKILL.md +2 -2
  274. package/skills/meta/find-skills/SKILL.md +2 -2
  275. package/skills/meta/herdr/SKILL.md +2 -2
  276. package/skills/meta/skill-craft/SKILL.md +22 -16
  277. package/skills/planning/archify/SKILL.md +196 -0
  278. package/skills/planning/archify/evals.md +65 -0
  279. package/skills/planning/architecture/SKILL.md +62 -13
  280. package/skills/planning/architecture/evals.md +65 -0
  281. package/skills/planning/backlog/SKILL.md +131 -15
  282. package/skills/planning/backlog/evals.md +142 -0
  283. package/skills/planning/prd/SKILL.md +47 -7
  284. package/skills/planning/prd/evals.md +54 -0
  285. package/skills/planning/product-intent/SKILL.md +58 -3
  286. package/skills/planning/product-intent/evals.md +70 -0
  287. package/skills/planning/tech-spec/SKILL.md +54 -3
  288. package/skills/planning/tech-spec/evals.md +73 -0
  289. package/skills/registry.yaml +70 -62
  290. package/skills/remote.yaml +13 -0
  291. package/skills/research/arxiv-literature/SKILL.md +77 -19
  292. package/skills/research/arxiv-literature/evals.md +50 -0
  293. package/skills/research/experiment-protocol/SKILL.md +21 -2
  294. package/skills/research/experiment-protocol/evals.md +23 -0
  295. package/skills/research/scientific-debugging/SKILL.md +24 -2
  296. package/skills/research/scientific-debugging/evals.md +18 -0
  297. package/skills/research/scientific-modernization/SKILL.md +27 -2
  298. package/skills/research/scientific-modernization/evals.md +27 -0
  299. package/skills/skill-marketplace.json +97 -62
  300. package/skills/workflow/cut-it/SKILL.md +66 -6
  301. package/skills/workflow/cut-it/evals.md +101 -0
  302. package/skills/workflow/design-council/SKILL.md +118 -28
  303. package/skills/workflow/design-council/evals.md +161 -0
  304. package/skills/workflow/grill-me/SKILL.md +87 -11
  305. package/skills/workflow/grill-me/evals.md +153 -0
  306. package/skills/workflow/workflow-distiller/SKILL.md +77 -18
  307. package/skills/workflow/workflow-distiller/evals.md +118 -0
  308. package/src/cli/args.ts +2 -2
  309. package/src/cli/bootstrap-generate.ts +1 -1
  310. package/src/cli/config-inspect.ts +65 -12
  311. package/src/cli/configure-interop.ts +105 -13
  312. package/src/cli/configure-oauth.ts +57 -0
  313. package/src/cli/configure-onboarding.ts +980 -0
  314. package/src/cli/configure-target.ts +594 -0
  315. package/src/cli/configure.ts +1082 -532
  316. package/src/cli/context-map.ts +114 -0
  317. package/src/cli/context.ts +4 -0
  318. package/src/cli/docs.ts +22 -14
  319. package/src/cli/doctor-naming.ts +5 -5
  320. package/src/cli/doctor-toolchain.ts +3 -3
  321. package/src/cli/eval.ts +1 -2
  322. package/src/cli/extensions.ts +2 -1
  323. package/src/cli/fleet.ts +1 -1
  324. package/src/cli/index.ts +3 -1
  325. package/src/cli/internal-dispatch.ts +3 -4
  326. package/src/cli/lifecycle-presenter.ts +436 -0
  327. package/src/cli/models.ts +10 -2
  328. package/src/cli/modes/print.ts +5 -1
  329. package/src/cli/panes.ts +19 -5
  330. package/src/cli/reset.ts +228 -106
  331. package/src/cli/run.ts +9 -4
  332. package/src/cli/select.ts +664 -0
  333. package/src/cli/share.ts +5 -1
  334. package/src/cli/skills-eval.ts +3 -3
  335. package/src/cli/skills.ts +9 -2
  336. package/src/cli/targets.ts +5 -6
  337. package/src/cli/trace.ts +55 -4
  338. package/src/cli/uninstall.ts +233 -165
  339. package/src/cli/upgrade.ts +204 -149
  340. package/src/cli/usage.ts +86 -27
  341. package/src/cli/validate-model.ts +3 -3
  342. package/src/cli/wiki-generate.ts +1 -1
  343. package/src/core/artifact-paths.ts +1 -1
  344. package/src/core/bash-exec.ts +131 -86
  345. package/src/core/bus-events.ts +51 -6
  346. package/src/core/config.ts +61 -1
  347. package/src/core/defaults.ts +7 -4
  348. package/src/core/dispatch-outcome.ts +16 -0
  349. package/src/core/external-diagnostic.ts +44 -0
  350. package/src/core/gateway-routing.ts +157 -0
  351. package/src/core/guardrails.ts +10 -49
  352. package/src/core/prompt-hint.ts +9 -0
  353. package/src/core/safe-exec.ts +17 -2
  354. package/src/core/skill-activation.ts +89 -2
  355. package/src/domains/agents/builtins/architect.md +2 -3
  356. package/src/domains/agents/builtins/coder.md +3 -2
  357. package/src/domains/agents/builtins/debugger.md +2 -2
  358. package/src/domains/agents/builtins/documenter.md +2 -2
  359. package/src/domains/agents/builtins/git-master.md +1 -1
  360. package/src/domains/agents/builtins/oracle.md +1 -1
  361. package/src/domains/agents/builtins/provenance.md +1 -1
  362. package/src/domains/agents/builtins/researcher.md +1 -1
  363. package/src/domains/agents/builtins/scout.md +1 -1
  364. package/src/domains/agents/builtins/tester.md +2 -2
  365. package/src/domains/agents/builtins/verifier.md +2 -2
  366. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  367. package/src/domains/agents/builtins/world-knowledge.md +31 -0
  368. package/src/domains/agents/catalog.ts +13 -15
  369. package/src/domains/agents/contract.ts +2 -0
  370. package/src/domains/agents/extension.ts +23 -1
  371. package/src/domains/agents/result-contract.ts +70 -0
  372. package/src/domains/config/keybindings.ts +8 -0
  373. package/src/domains/context/extension.ts +0 -3
  374. package/src/domains/context/wiki/map-seed.ts +589 -0
  375. package/src/domains/context/wiki/plan.ts +2 -2
  376. package/src/domains/context/working-set/path-index.ts +1 -0
  377. package/src/domains/dispatch/admission.ts +29 -0
  378. package/src/domains/dispatch/agent-candidates.ts +10 -0
  379. package/src/domains/dispatch/budget-envelope.ts +86 -1
  380. package/src/domains/dispatch/capability-match.ts +11 -0
  381. package/src/domains/dispatch/capacity-lease.ts +17 -0
  382. package/src/domains/dispatch/contract.ts +11 -1
  383. package/src/domains/dispatch/extension.ts +237 -49
  384. package/src/domains/dispatch/host-verification.ts +435 -39
  385. package/src/domains/dispatch/intent-requirements.ts +10 -0
  386. package/src/domains/dispatch/intent.ts +18 -1
  387. package/src/domains/dispatch/path-scope.ts +235 -24
  388. package/src/domains/dispatch/run-event-journal.ts +4 -15
  389. package/src/domains/dispatch/state.ts +2 -3
  390. package/src/domains/dispatch/transport.ts +45 -21
  391. package/src/domains/dispatch/types.ts +58 -3
  392. package/src/domains/dispatch/worker-model-metadata.ts +38 -0
  393. package/src/domains/eval/artifacts/store.ts +5 -0
  394. package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
  395. package/src/domains/eval/metrics/token-stream.ts +201 -31
  396. package/src/domains/eval/metrics/tracked.ts +40 -4
  397. package/src/domains/eval/runners/clio-run.ts +5 -2
  398. package/src/domains/eval/schema/suite.ts +28 -0
  399. package/src/domains/eval/schema/verdict.ts +2 -2
  400. package/src/domains/eval/store.ts +8 -1
  401. package/src/domains/eval/suites/resolve.ts +13 -1
  402. package/src/domains/eval/suites/run.ts +24 -3
  403. package/src/domains/evidence/trust-status.ts +10 -1
  404. package/src/domains/extensions/contract.ts +15 -1
  405. package/src/domains/extensions/discovery.ts +238 -41
  406. package/src/domains/extensions/extension.ts +105 -6
  407. package/src/domains/extensions/index.ts +24 -0
  408. package/src/domains/extensions/integrity.ts +189 -0
  409. package/src/domains/extensions/manager.ts +17 -1
  410. package/src/domains/extensions/resource-path.ts +27 -0
  411. package/src/domains/extensions/resources.ts +18 -38
  412. package/src/domains/extensions/snapshot-store.ts +39 -0
  413. package/src/domains/extensions/snapshot.ts +180 -0
  414. package/src/domains/extensions/state.ts +385 -57
  415. package/src/domains/extensions/types.ts +118 -1
  416. package/src/domains/interop/registry.ts +6 -2
  417. package/src/domains/interop/types.ts +4 -0
  418. package/src/domains/lifecycle/migrations/2026-09-01-extension-install-digests.ts +27 -0
  419. package/src/domains/lifecycle/migrations/index.ts +6 -0
  420. package/src/domains/lifecycle/naming-resources.ts +19 -4
  421. package/src/domains/lifecycle/naming-yazi.ts +10 -5
  422. package/src/domains/memory/task-memory-policy.ts +70 -26
  423. package/src/domains/memory/task-memory-telemetry.ts +1 -0
  424. package/src/domains/middleware/contract.ts +26 -0
  425. package/src/domains/middleware/extension.ts +24 -24
  426. package/src/domains/middleware/hook-receipts.ts +27 -4
  427. package/src/domains/middleware/hooks-io.ts +65 -32
  428. package/src/domains/middleware/hooks.ts +64 -0
  429. package/src/domains/middleware/index.ts +28 -5
  430. package/src/domains/middleware/marketplace-offer.ts +3 -35
  431. package/src/domains/middleware/memory-intervention.ts +127 -32
  432. package/src/domains/middleware/memory-step-endpoint.ts +3 -2
  433. package/src/domains/middleware/registrations.ts +326 -0
  434. package/src/domains/middleware/runtime.ts +28 -0
  435. package/src/domains/middleware/skills-reminder.ts +31 -2
  436. package/src/domains/middleware/snapshot.ts +20 -7
  437. package/src/domains/mux/contract.ts +38 -0
  438. package/src/domains/mux/detect.ts +6 -13
  439. package/src/domains/mux/index.ts +1 -1
  440. package/src/domains/mux/operations.ts +44 -5
  441. package/src/domains/mux/yazi/assets/yazi.toml +2 -2
  442. package/src/domains/mux/yazi/session.ts +53 -4
  443. package/src/domains/mux/yazi/theme.ts +117 -17
  444. package/src/domains/observability/compaction-usage.ts +118 -0
  445. package/src/domains/observability/contract.ts +10 -11
  446. package/src/domains/observability/cost.ts +1 -1
  447. package/src/domains/observability/extension.ts +17 -4
  448. package/src/domains/observability/out-of-turn-usage.ts +52 -21
  449. package/src/domains/observability/projection.ts +14 -90
  450. package/src/domains/observability/trace-store.ts +43 -7
  451. package/src/domains/prompts/compiler.ts +73 -53
  452. package/src/domains/prompts/contract.ts +15 -3
  453. package/src/domains/prompts/extension.ts +97 -9
  454. package/src/domains/prompts/fragments/identity/clio-worker.md +1 -3
  455. package/src/domains/prompts/fragments/identity/clio.md +6 -12
  456. package/src/domains/prompts/fragments/identity/docs-routing.md +1 -2
  457. package/src/domains/prompts/fragments/identity/self-awareness.md +3 -11
  458. package/src/domains/prompts/fragments/operating/contract.md +7 -15
  459. package/src/domains/prompts/fragments/operating/delegation.md +32 -34
  460. package/src/domains/prompts/fragments/operating/skills.md +10 -24
  461. package/src/domains/prompts/fragments/operating/worker.md +1 -8
  462. package/src/domains/providers/contract.ts +4 -1
  463. package/src/domains/providers/extension.ts +40 -9
  464. package/src/domains/providers/index.ts +1 -1
  465. package/src/domains/providers/model-capabilities.ts +9 -0
  466. package/src/domains/providers/model-discovery.ts +2 -0
  467. package/src/domains/providers/model-runtime-capabilities.ts +99 -25
  468. package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +699 -114
  469. package/src/domains/providers/runtime-resolution.ts +31 -0
  470. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
  471. package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
  472. package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
  473. package/src/domains/providers/runtimes/common/probe-helpers.ts +7 -2
  474. package/src/domains/providers/runtimes/local-native/llamacpp.ts +9 -1
  475. package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
  476. package/src/domains/providers/support.ts +11 -5
  477. package/src/domains/providers/target-model-cache.ts +25 -2
  478. package/src/domains/providers/types/capability-flags.ts +2 -0
  479. package/src/domains/providers/types/cost-provenance.ts +19 -0
  480. package/src/domains/providers/types/local-model-quirks.ts +85 -37
  481. package/src/domains/providers/types/runtime-descriptor.ts +20 -1
  482. package/src/domains/providers/types/target-descriptor.ts +19 -0
  483. package/src/domains/resources/index.ts +3 -0
  484. package/src/domains/resources/skills/install.ts +72 -7
  485. package/src/domains/resources/skills/loader.ts +23 -19
  486. package/src/domains/resources/skills/marketplace.ts +63 -11
  487. package/src/domains/safety/autonomy.ts +15 -0
  488. package/src/domains/safety/call-target.ts +1 -1
  489. package/src/domains/safety/index.ts +1 -0
  490. package/src/domains/safety/loop-detector.ts +7 -4
  491. package/src/domains/safety/path-policy.ts +1 -1
  492. package/src/domains/safety/policy-engine.ts +34 -11
  493. package/src/domains/safety/protected-artifacts.ts +191 -88
  494. package/src/domains/safety/run-effects.ts +2 -22
  495. package/src/domains/safety/skill-authority.ts +55 -0
  496. package/src/domains/session/compaction/compact.ts +72 -22
  497. package/src/domains/session/entries.ts +6 -0
  498. package/src/domains/session/task-board.ts +10 -9
  499. package/src/domains/session/usage.ts +3 -3
  500. package/src/domains/share/archive.ts +164 -7
  501. package/src/engine/acp/server.ts +62 -9
  502. package/src/engine/agent.ts +13 -3
  503. package/src/engine/ai.ts +26 -8
  504. package/src/engine/antigravity/subprocess-runtime.ts +386 -120
  505. package/src/engine/api-registry.ts +3 -0
  506. package/src/engine/apis/llamacpp-residency.ts +3 -4
  507. package/src/engine/apis/lmstudio.ts +3 -3
  508. package/src/engine/apis/ollama-native.ts +6 -6
  509. package/src/engine/apis/openai-completions.ts +145 -39
  510. package/src/engine/apis/output-budget.ts +8 -18
  511. package/src/engine/apis/residency.ts +8 -27
  512. package/src/engine/external-subprocess.ts +114 -6
  513. package/src/engine/gemma-channel-filter.ts +19 -0
  514. package/src/engine/loop-guard.ts +92 -12
  515. package/src/engine/worker-runtime.ts +40 -11
  516. package/src/engine/worker-tools.ts +3 -1
  517. package/src/entry/background-model-metadata.ts +18 -0
  518. package/src/entry/compaction-prompt.ts +57 -0
  519. package/src/entry/extension-hook-sources.ts +28 -0
  520. package/src/entry/extension-reload.ts +309 -0
  521. package/src/entry/orchestrator.ts +464 -251
  522. package/src/entry/task-memory-lifecycle.ts +35 -0
  523. package/src/interactive/application-controller.ts +2 -1
  524. package/src/interactive/bus-notices.ts +8 -1
  525. package/src/interactive/chat-loop-messages.ts +16 -17
  526. package/src/interactive/chat-loop.ts +75 -3
  527. package/src/interactive/chat-panel.ts +36 -13
  528. package/src/interactive/chat-renderer.ts +72 -7
  529. package/src/interactive/cost-overlay.ts +26 -2
  530. package/src/interactive/dispatch-board.ts +6 -11
  531. package/src/interactive/footer/widgets.ts +13 -0
  532. package/src/interactive/interactive-application.ts +39 -4
  533. package/src/interactive/interactive-input-runtime.ts +4 -0
  534. package/src/interactive/interactive-presentation.ts +2 -2
  535. package/src/interactive/interactive-slash-runtime.ts +4 -1
  536. package/src/interactive/overlays/extensions.ts +9 -1
  537. package/src/interactive/overlays/help-reference.ts +13 -0
  538. package/src/interactive/overlays/settings.ts +27 -16
  539. package/src/interactive/panes-runtime.ts +111 -35
  540. package/src/interactive/prompt-cache-identity.ts +88 -0
  541. package/src/interactive/renderers/worker-entry.ts +32 -0
  542. package/src/interactive/slash-commands.ts +153 -20
  543. package/src/interactive/stream-pacing-policy.ts +0 -23
  544. package/src/interactive/theme/labels.ts +19 -13
  545. package/src/interactive/turn-context.ts +39 -20
  546. package/src/interactive/turn-recovery.ts +8 -0
  547. package/src/interactive/turn-runtime.ts +27 -11
  548. package/src/interactive/turn-state.ts +7 -0
  549. package/src/interactive/worker-receipts.ts +1 -0
  550. package/src/interactive/worker-stream.ts +6 -1
  551. package/src/interactive/yazi-bridge.ts +60 -6
  552. package/src/tools/agent-tools.ts +30 -1
  553. package/src/tools/artifact.ts +2 -2
  554. package/src/tools/ask-user.ts +3 -3
  555. package/src/tools/bash.ts +1 -1
  556. package/src/tools/bootstrap.ts +4 -0
  557. package/src/tools/builtin-tool-catalog.ts +52 -22
  558. package/src/tools/codewiki/code-nav-surface.ts +6 -0
  559. package/src/tools/codewiki/code-nav.ts +99 -13
  560. package/src/tools/context/docs-engine.ts +20 -7
  561. package/src/tools/context/index.ts +59 -21
  562. package/src/tools/core-bootstrap.ts +28 -6
  563. package/src/tools/credential-present.ts +1 -2
  564. package/src/tools/dispatch-arguments.ts +6 -1
  565. package/src/tools/dispatch-event-text.ts +10 -0
  566. package/src/tools/dispatch-plan.ts +49 -4
  567. package/src/tools/dispatch-run-events.ts +1 -1
  568. package/src/tools/dispatch-runner.ts +12 -0
  569. package/src/tools/dispatch-schema.ts +338 -0
  570. package/src/tools/dispatch-types.ts +3 -0
  571. package/src/tools/dispatch.ts +9 -254
  572. package/src/tools/ledger.ts +3 -5
  573. package/src/tools/monitor-surface.ts +5 -13
  574. package/src/tools/observation.ts +4 -5
  575. package/src/tools/panes-surface.ts +4 -11
  576. package/src/tools/panes.ts +4 -2
  577. package/src/tools/policy.ts +15 -2
  578. package/src/tools/read.ts +5 -6
  579. package/src/tools/registry.ts +41 -12
  580. package/src/tools/result-shaping.ts +18 -14
  581. package/src/tools/steer-surface.ts +1 -1
  582. package/src/tools/tasks.ts +1 -1
  583. package/src/tools/truncate.ts +6 -5
  584. package/src/tools/verify/surface.ts +6 -12
  585. package/src/tools/web-fetch-surface.ts +1 -3
  586. package/src/tools/worker-evidence.ts +3 -1
  587. package/src/worker/spec-contract.ts +4 -0
  588. package/dist/builtins-UJLMOVOV.js +0 -17
  589. package/dist/chunk-5QIAJV2D.js +0 -48
  590. package/dist/chunk-JZWT5J3Y.js +0 -814
  591. package/dist/chunk-K7VKOLQQ.js +0 -15
  592. package/dist/chunk-PMZCIOCJ.js +0 -25
  593. package/dist/chunk-SUW5DORT.js +0 -819
  594. package/dist/chunk-UOV2BYIW.js +0 -107
  595. package/dist/chunk-WR6U3OVP.js +0 -45
  596. package/dist/chunk-Y45G3AXC.js +0 -1558
  597. package/dist/reset-EOLM7GVE.js +0 -230
  598. package/dist/uninstall-N34PCTGJ.js +0 -331
  599. package/dist/upgrade-H7TOM7YL.js +0 -323
  600. package/docs/artifact-versions.md +0 -67
  601. package/docs/development-pipeline.md +0 -121
  602. package/docs/documentation-coverage.md +0 -46
  603. package/docs/documentation-guide.md +0 -167
  604. package/docs/time-conventions.md +0 -101
@@ -1,3 +1,5 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
1
3
  import { join } from "node:path";
2
4
  import chalk from "chalk";
3
5
  import { modelBootstrapGenerate, resolveBootstrapRoute } from "../cli/bootstrap-generate.js";
@@ -44,6 +46,7 @@ import { ConfigDomainModule, createConfigDomainModule } from "../domains/config/
44
46
  import type { ContextContract } from "../domains/context/contract.js";
45
47
  import { bootstrapInputFromInitOptions } from "../domains/context/init-options.js";
46
48
  import { createContextDomainModule } from "../domains/context/runtime.js";
49
+ import { endpointCapacityUsage } from "../domains/dispatch/capacity-lease.js";
47
50
  import type { DispatchContract } from "../domains/dispatch/contract.js";
48
51
  import { createDispatchDedupRegistration } from "../domains/dispatch/dedup.js";
49
52
  import { agentRoleFactsResolver } from "../domains/dispatch/execution-role.js";
@@ -77,6 +80,7 @@ import {
77
80
  taskMemoryTracePath,
78
81
  } from "../domains/memory/index.js";
79
82
  import { TaskMemoryBank } from "../domains/memory/task-bank.js";
83
+ import { TaskMemoryEndpointBusyError } from "../domains/memory/task-memory-policy.js";
80
84
  import {
81
85
  createDetachedDispatchNudgeRegistration,
82
86
  createReadOnlyExplorationNudgeRegistration,
@@ -88,8 +92,7 @@ import {
88
92
  createMarketplaceOfferRegistration,
89
93
  createMiddlewareToolChoiceControl,
90
94
  createSkillsReminderRegistration,
91
- type ExtensionHookRoot,
92
- installUserHooks,
95
+ formatRegistrationConflict,
93
96
  type MiddlewareContract,
94
97
  MiddlewareDomainModule,
95
98
  writeMiddlewareDiagnosticToStderr,
@@ -100,8 +103,10 @@ import { createTaskBoardReminderRegistration } from "../domains/middleware/task-
100
103
  import { createTaskNudgeRegistration } from "../domains/middleware/task-nudge.js";
101
104
  import { createWatchdogRegistration } from "../domains/middleware/watchdog.js";
102
105
  import type { MuxContract } from "../domains/mux/index.js";
106
+ import type { BackgroundMemoryUsageSink } from "../domains/observability/background-memory-usage.js";
107
+ import { recordFailedCompactionCalls } from "../domains/observability/compaction-usage.js";
103
108
  import type { ObservabilityContract } from "../domains/observability/index.js";
104
- import { ObservabilityDomainModule, recordBackgroundMemoryStep } from "../domains/observability/index.js";
109
+ import { ObservabilityDomainModule } from "../domains/observability/index.js";
105
110
  import type { PromptsContract } from "../domains/prompts/contract.js";
106
111
  import { createPromptsDomainModule } from "../domains/prompts/index.js";
107
112
  import type { ProvidersContract, TargetDescriptor, ThinkingLevel } from "../domains/providers/index.js";
@@ -110,12 +115,12 @@ import {
110
115
  applyModelCapabilityPatch,
111
116
  canonicalEndpointKey,
112
117
  firstRuntimeResolutionError,
113
- foregroundStreamUsage,
114
118
  isOrchestratorEligibleRuntime,
115
119
  normalizeCostProvenance,
116
120
  ProvidersDomainModule,
117
121
  refineRuntimeTargetWithModelHints,
118
122
  registerForegroundStream,
123
+ resolveEndpointCapacities,
119
124
  resolveModelCapabilities,
120
125
  resolveModelRuntimeCapabilitiesForProviders,
121
126
  resolveRuntimeTarget,
@@ -123,8 +128,10 @@ import {
123
128
  targetRequiresAuth,
124
129
  VALID_THINKING_LEVELS,
125
130
  } from "../domains/providers/index.js";
131
+ import { hasLiveModelCatalog, modelResidencyForStatus } from "../domains/providers/model-discovery.js";
126
132
  import { memoryInterventionModelMaxTokens } from "../domains/providers/model-runtime-capabilities.js";
127
133
  import { getRuntimeRegistry } from "../domains/providers/registry.js";
134
+ import { resolveModelReference } from "../domains/providers/resolver.js";
128
135
  import { registerBuiltinRuntimes } from "../domains/providers/runtimes/builtins.js";
129
136
  import {
130
137
  createResourcesDomainModule,
@@ -136,7 +143,12 @@ import {
136
143
  import { DEFAULT_RECENT_ENTRY_LIMIT } from "../domains/safety/finish-contract.js";
137
144
  import { createFinishContractRegistration } from "../domains/safety/finish-contract-registration.js";
138
145
  import type { AutonomyLevel, SafetyContract } from "../domains/safety/index.js";
139
- import { parseRigorOverride, resolveRigor, SafetyDomainModule } from "../domains/safety/index.js";
146
+ import {
147
+ modelMayActivateSkills,
148
+ parseRigorOverride,
149
+ resolveRigor,
150
+ SafetyDomainModule,
151
+ } from "../domains/safety/index.js";
140
152
  import type { ProtectedArtifactState } from "../domains/safety/protected-artifacts.js";
141
153
  import {
142
154
  createProtectedArtifactsRegistration,
@@ -144,6 +156,7 @@ import {
144
156
  } from "../domains/safety/protected-artifacts-registration.js";
145
157
  import type { SchedulingContract } from "../domains/scheduling/contract.js";
146
158
  import { SchedulingDomainModule } from "../domains/scheduling/index.js";
159
+ import type { CompactionCallObservation } from "../domains/session/compaction/compact.js";
147
160
  import { type CompactResult, compact } from "../domains/session/compaction/compact.js";
148
161
  import { collectSessionEntries } from "../domains/session/compaction/session-entries.js";
149
162
  import { estimateTokens } from "../domains/session/compaction/tokens.js";
@@ -168,7 +181,7 @@ import { ToolchainDomainModule } from "../domains/toolchain/index.js";
168
181
  import { createUserTasksStore } from "../domains/user-tasks/store.js";
169
182
  import { type AcpSafeSettingsPatch, type AcpSafeSettingsSnapshot, serveClioAcpAgent } from "../engine/acp/server.js";
170
183
  import { createStdioServerTransport } from "../engine/acp/transport.js";
171
- import { completeEngineText } from "../engine/ai.js";
184
+ import { completeEngineText, type EngineTextCompletionResult } from "../engine/ai.js";
172
185
  import { setProtectedModelsProvider } from "../engine/apis/residency.js";
173
186
  import {
174
187
  createLoopGuardRegistration,
@@ -180,8 +193,12 @@ import type { EngineModel } from "../engine/types.js";
180
193
  import { createChatLoop } from "../interactive/chat-loop.js";
181
194
  import { type RunIo, startInteractive } from "../interactive/index.js";
182
195
  import { buildModelReplayAgentMessagesFromTurns } from "../interactive/model-session-replay.js";
196
+ import { prepareBackgroundModelMetadata } from "./background-model-metadata.js";
183
197
  import type { BootOptions } from "./boot-options.js";
198
+ import { readCompactionSystemPrompt } from "./compaction-prompt.js";
199
+ import { createExtensionReloadCoordinator } from "./extension-reload.js";
184
200
  import { resolvePanesEnablement } from "./panes-activation.js";
201
+ import { bindTaskMemoryLifecycle, captureTaskMemoryUsage } from "./task-memory-lifecycle.js";
185
202
 
186
203
  export type { BootOptions, HeadlessSamplingOverrides } from "./boot-options.js";
187
204
 
@@ -200,6 +217,7 @@ import { type AskUserHandler, cancelledAskUserResult } from "../tools/ask-user.j
200
217
  import { registerAllTools } from "../tools/bootstrap.js";
201
218
  import { isGitRepository, recoverCleanupReadyCompeteGroups } from "../tools/compete-worktrees.js";
202
219
  import { createDispatchBackgroundRegistry } from "../tools/dispatch-background.js";
220
+ import { dispatchSchemaCompositionFor } from "../tools/dispatch-schema.js";
203
221
  import { createFileMutationObserver, createSkillActivationObserver } from "../tools/observers.js";
204
222
  import { createRegistry } from "../tools/registry.js";
205
223
  import { sweepExpiredToolOffloads } from "../tools/result-shaping.js";
@@ -286,6 +304,8 @@ interface CompactionResolution {
286
304
  model: EngineModel;
287
305
  targetId: string;
288
306
  endpointKey: string | null;
307
+ wireModelId: string;
308
+ headers?: Record<string, string>;
289
309
  apiKey?: string;
290
310
  }
291
311
 
@@ -311,53 +331,71 @@ function advanceThinkingLevel(current: ThinkingLevel, available: ReadonlyArray<T
311
331
  */
312
332
  const LOCAL_API_KEY_FALLBACK = "clio-coder-local-target";
313
333
 
314
- async function resolveApiKeyForTarget(
315
- target: TargetDescriptor,
316
- providers: ProvidersContract,
317
- signal?: AbortSignal,
318
- ): Promise<string | undefined> {
319
- const runtime = providers.getRuntime(target.runtime);
320
- if (!runtime) return undefined;
321
- // A target that needs no credential still needs the placeholder. Returning
322
- // nothing here left compaction as the one path that did not send it, so
323
- // `/context compact` and every automatic compaction at the window threshold
324
- // failed on exactly the local runtimes Clio is built for, while ordinary
325
- // turns against the same target succeeded.
326
- if (!targetRequiresAuth(target, runtime)) return LOCAL_API_KEY_FALLBACK;
327
- const resolved = await providers.auth.resolveForTarget(target, runtime, signal ? { signal } : undefined);
328
- return resolved.apiKey;
329
- }
330
-
331
334
  /**
332
335
  * The background memory role, resolved to the endpoint it would call.
333
336
  *
334
- * The endpoint key is what lets the middleware decline a step that would land
335
- * on the same inference scheduler the chat target is streaming against (#229,
336
- * #250), and it is the same key dispatch admission counts slots on.
337
+ * The endpoint key joins the existing dispatch capacity evidence and local
338
+ * request holds. A gateway key does not identify one physical model server or
339
+ * imply a one-slot limit; the configured protocol owns downstream routing.
337
340
  */
338
341
  interface BackgroundMemoryRoute {
339
342
  client: TaskMemoryModelClient;
343
+ selection: "dedicated" | "chat-fallback";
344
+ fallbackReason?: string;
340
345
  targetId: string;
341
346
  wireModelId: string;
342
347
  endpointKey: string | null;
343
348
  modelMaxTokens(configuredMaxTokens: number): number;
344
349
  }
345
350
 
346
- function createBackgroundMemoryModelClient(
351
+ export function createBackgroundMemoryModelClient(
347
352
  providers: ProvidersContract,
348
353
  settings: Readonly<ClioSettings>,
349
354
  timeoutMs: number,
350
355
  bus: Pick<SafeEventBus, "emit"> | null,
356
+ fallbackOnly = false,
351
357
  ): BackgroundMemoryRoute | null {
352
- const targetId = settings.context.memory.target?.trim();
353
- const wireModelId = settings.context.memory.model?.trim();
354
- if (!targetId || !wireModelId) return null;
355
- // One model cannot both drive the action agent and think its way through a
356
- // memory step: the memory call would contend with the agent's own decoding on
357
- // the same server, and a reasoning model spends most of a memory step
358
- // deliberating over a task it is not executing. Memory falls back to its free
359
- // deterministic tier rather than degrading the work the operator asked for.
360
- if (backgroundSharesReasoningModelWithOrchestrator(providers, settings)) return null;
358
+ const configuredTarget = settings.context.memory.target?.trim();
359
+ const configuredModel = settings.context.memory.model?.trim();
360
+ if (!configuredTarget || !configuredModel) return null;
361
+ const chatTarget = settings.chat.target?.trim();
362
+ const chatModel = settings.chat.model?.trim();
363
+ const sameRoute = configuredTarget === chatTarget && configuredModel === chatModel;
364
+ if (fallbackOnly && sameRoute) return null;
365
+ let fallbackReason: string | undefined;
366
+ if (!fallbackOnly) {
367
+ try {
368
+ return prepareBackgroundMemoryRoute(providers, configuredTarget, configuredModel, timeoutMs, bus, "dedicated");
369
+ } catch {
370
+ fallbackReason = "configured route unavailable";
371
+ }
372
+ } else fallbackReason = "configured route client error";
373
+ if (!chatTarget || !chatModel || sameRoute) {
374
+ if (fallbackOnly) return null;
375
+ throw new Error("configured memory route is unavailable and no distinct chat fallback can run");
376
+ }
377
+ try {
378
+ return {
379
+ ...prepareBackgroundMemoryRoute(providers, chatTarget, chatModel, timeoutMs, bus, "chat-fallback"),
380
+ fallbackReason,
381
+ };
382
+ } catch {
383
+ if (fallbackOnly) return null;
384
+ throw new Error("neither the configured memory route nor the active chat fallback is available");
385
+ }
386
+ }
387
+
388
+ function prepareBackgroundMemoryModel(providers: ProvidersContract, targetId: string, wireModelId: string) {
389
+ const status = providers.list().find((entry) => entry.target.id === targetId);
390
+ if (
391
+ status &&
392
+ (!status.available ||
393
+ status.health.status === "down" ||
394
+ (hasLiveModelCatalog(status) && !status.discoveredModels.includes(wireModelId)) ||
395
+ modelResidencyForStatus(status, wireModelId) === "absent" ||
396
+ modelResidencyForStatus(status, wireModelId) === "loading")
397
+ )
398
+ throw new Error("background memory route is unavailable");
361
399
  const resolved = resolveRuntimeTarget(providers, {
362
400
  targetId,
363
401
  wireModelId,
@@ -377,9 +415,37 @@ function createBackgroundMemoryModelClient(
377
415
  const model = resolved.target.runtime.synthesizeModel(resolved.target.target, resolved.target.wireModelId, kbHit);
378
416
  const refined = refineRuntimeTargetWithModelHints(resolved.target, model, providers.knowledgeBase);
379
417
  applyModelCapabilityPatch(model, refined.capabilities);
380
- const costProvenance = normalizeCostProvenance(refined.costProvenance);
418
+ return { model, refined };
419
+ }
420
+
421
+ function backgroundMemoryEndpointBusy(
422
+ providers: ProvidersContract,
423
+ endpointKey: string | null,
424
+ targets: ReadonlyArray<TargetDescriptor>,
425
+ ): boolean {
426
+ if (endpointKey === null) return false;
427
+ const capacity = resolveEndpointCapacities({
428
+ statuses: providers.list(),
429
+ targets,
430
+ runtimeFor: (id) => providers.getRuntime(id),
431
+ })[endpointKey];
432
+ // Gateways and non-fixed schedulers have no invented local one-slot cap.
433
+ return capacity !== undefined && (endpointCapacityUsage()[endpointKey] ?? 0) >= capacity.limit;
434
+ }
435
+
436
+ function prepareBackgroundMemoryRoute(
437
+ providers: ProvidersContract,
438
+ targetId: string,
439
+ wireModelId: string,
440
+ timeoutMs: number,
441
+ bus: Pick<SafeEventBus, "emit"> | null,
442
+ selection: BackgroundMemoryRoute["selection"],
443
+ ): BackgroundMemoryRoute {
444
+ const initial = prepareBackgroundMemoryModel(providers, targetId, wireModelId);
445
+ const { refined } = initial;
381
446
  const endpointKey = canonicalEndpointKey(refined.target);
382
447
  return {
448
+ selection,
383
449
  targetId,
384
450
  wireModelId: refined.wireModelId,
385
451
  endpointKey,
@@ -393,47 +459,121 @@ function createBackgroundMemoryModelClient(
393
459
  // Wrapped at the layer that knows a request left the process: the step
394
460
  // holds endpoint capacity while it is out and publishes the cache
395
461
  // disturbance even when a timeout means the usage sink never sees it.
396
- complete: announceMemoryStepEndpoint({ bus, endpointKey, targetId }, async (request) => {
462
+ complete: async (request) => {
463
+ await prepareBackgroundModelMetadata(providers, targetId, request.signal);
464
+ const { model, refined } = prepareBackgroundMemoryModel(providers, targetId, wireModelId);
465
+ if (refined.runtimeId !== initial.refined.runtimeId || canonicalEndpointKey(refined.target) !== endpointKey) {
466
+ throw new Error("background memory target changed during preparation");
467
+ }
468
+ const costProvenance = normalizeCostProvenance(refined.costProvenance);
397
469
  const apiKey = targetRequiresAuth(refined.target, refined.runtime)
398
470
  ? (await providers.auth.resolveForTarget(refined.target, refined.runtime, { signal: request.signal })).apiKey
399
471
  : LOCAL_API_KEY_FALLBACK;
400
- const startedAt = Date.now();
401
- const completion = await completeEngineText({
402
- model,
403
- systemPrompt: request.systemPrompt,
404
- userPrompt: request.userPrompt,
405
- maxTokens: request.maxTokens,
406
- // Always off, never the operator's chat thinking level. A model that
407
- // reasons anyway still works: `completeEngineText` keeps only text
408
- // blocks, and the memory output budget leaves room for the preamble.
409
- thinkingLevel: "off",
410
- signal: request.signal,
411
- timeoutMs,
412
- ...(apiKey === undefined ? {} : { apiKey }),
413
- });
414
- // The step is billed here whatever the policy later decides about the
415
- // answer. A model that read a trajectory and chose silence spent the
416
- // same prefill as one that produced a reminder.
417
- return {
418
- text: completion.text,
419
- inputTokens: completion.inputTokens,
420
- outputTokens: completion.outputTokens,
421
- usage: {
472
+ request.signal.throwIfAborted();
473
+ // Preparation yielded after the middleware's first check. Recheck current
474
+ // occupancy immediately before the synchronous foreground-slot registration;
475
+ // no await may separate this admission from announceMemoryStepEndpoint.
476
+ if (backgroundMemoryEndpointBusy(providers, endpointKey, [refined.target])) {
477
+ throw new TaskMemoryEndpointBusyError("background memory endpoint is busy");
478
+ }
479
+ return announceMemoryStepEndpoint({ bus, endpointKey, targetId }, async () => {
480
+ const startedAt = Date.now();
481
+ let observedUsage: TaskMemoryStepUsage | undefined;
482
+ const mapUsage = (completion: Pick<EngineTextCompletionResult, "usage" | "backend">): TaskMemoryStepUsage => ({
483
+ ...completion.usage,
422
484
  targetId,
423
485
  attributedModelId: refined.wireModelId,
424
- input: completion.usage.input,
425
- output: completion.usage.output,
426
- cacheRead: completion.usage.cacheRead,
427
- cacheWrite: completion.usage.cacheWrite,
428
- reasoning: completion.usage.reasoning,
429
- totalTokens: completion.usage.totalTokens,
430
- costUsd: completion.usage.costUsd,
431
486
  costProvenance,
432
487
  durationMs: Date.now() - startedAt,
433
488
  backend: completion.backend,
434
- },
435
- };
436
- }),
489
+ });
490
+ const completion = await completeEngineText({
491
+ model,
492
+ systemPrompt: request.systemPrompt,
493
+ userPrompt: request.userPrompt,
494
+ maxTokens:
495
+ refined.capabilityDecisions.maxTokens > 0
496
+ ? Math.min(request.maxTokens, refined.capabilityDecisions.maxTokens)
497
+ : request.maxTokens,
498
+ // Always off, never the operator's chat thinking level. A model that
499
+ // reasons anyway still works: `completeEngineText` keeps only text
500
+ // blocks, and the memory output budget leaves room for the preamble.
501
+ thinkingLevel: "off",
502
+ signal: request.signal,
503
+ timeoutMs,
504
+ onUsage: (observation) => {
505
+ observedUsage = mapUsage(observation);
506
+ request.onUsage?.(observedUsage);
507
+ },
508
+ ...(apiKey === undefined ? {} : { apiKey }),
509
+ ...(refined.target.auth?.headers ? { headers: refined.target.auth.headers } : {}),
510
+ });
511
+ // The step is billed here whatever the policy later decides about the
512
+ // answer. A model that read a trajectory and chose silence spent the
513
+ // same prefill as one that produced a reminder.
514
+ return {
515
+ text: completion.text,
516
+ inputTokens: completion.inputTokens,
517
+ outputTokens: completion.outputTokens,
518
+ usage: observedUsage ?? mapUsage(completion),
519
+ };
520
+ })(request);
521
+ },
522
+ },
523
+ };
524
+ }
525
+
526
+ /** Production callback composition shared with routing/capacity contracts. */
527
+ export function createBackgroundMemoryRouting(
528
+ providers: ProvidersContract,
529
+ getSettings: () => Readonly<ClioSettings> | undefined,
530
+ bus: Pick<SafeEventBus, "emit"> | null,
531
+ ) {
532
+ let route: BackgroundMemoryRoute | null = null;
533
+ let snapshot: Readonly<ClioSettings> | undefined;
534
+ let lastNotice: string | null = null;
535
+ const noteFallback = (): void => {
536
+ if (route?.selection !== "chat-fallback") {
537
+ lastNotice = null;
538
+ return;
539
+ }
540
+ const message = `Memory: ${route.fallbackReason}; selected chat fallback ${route.targetId}/${route.wireModelId} for this step, subject to available endpoint capacity.`;
541
+ if (message === lastNotice) return;
542
+ lastNotice = message;
543
+ try {
544
+ bus?.emit(BusChannels.RuntimeNotice, {
545
+ kind: "degraded",
546
+ level: "info",
547
+ message,
548
+ targetId: route.targetId,
549
+ runtimeId: providers.getTarget(route.targetId)?.runtime ?? "unknown",
550
+ model: route.wireModelId,
551
+ });
552
+ } catch {
553
+ /* Advisory only. */
554
+ }
555
+ };
556
+ return {
557
+ getModelClient: (): TaskMemoryModelClient | null => {
558
+ const current = getSettings();
559
+ snapshot = current === undefined ? undefined : structuredClone(current);
560
+ route =
561
+ snapshot === undefined
562
+ ? null
563
+ : createBackgroundMemoryModelClient(providers, snapshot, snapshot.context.memory.timeoutMs, bus);
564
+ noteFallback();
565
+ return route?.client ?? null;
566
+ },
567
+ getFallbackModelClient: (): TaskMemoryModelClient | null => {
568
+ if (route?.selection !== "dedicated" || snapshot === undefined) return null;
569
+ route = createBackgroundMemoryModelClient(providers, snapshot, snapshot.context.memory.timeoutMs, bus, true);
570
+ noteFallback();
571
+ return route?.client ?? null;
572
+ },
573
+ getModelMaxTokens: (configured: number): number => route?.modelMaxTokens(configured) ?? configured,
574
+ backgroundEndpointBusy: (): boolean => {
575
+ if (route?.endpointKey == null || snapshot === undefined) return false;
576
+ return backgroundMemoryEndpointBusy(providers, route.endpointKey, snapshot.targets);
437
577
  },
438
578
  };
439
579
  }
@@ -471,74 +611,84 @@ function agentRoleToolWarnings(providers: ProvidersContract, settings: Readonly<
471
611
  return warnings;
472
612
  }
473
613
 
474
- /**
475
- * True when the background role names the same model the orchestrator runs and
476
- * that model reasons. Distinct models, or a non-reasoning shared model, are both
477
- * fine; this only catches the one-model-does-everything configuration.
478
- */
479
- function backgroundSharesReasoningModelWithOrchestrator(
614
+ async function resolveCompactionModel(
615
+ settings: ClioSettings,
480
616
  providers: ProvidersContract,
481
- settings: Readonly<ClioSettings>,
482
- ): boolean {
483
- const backgroundModel = settings.context.memory.model?.trim();
484
- const orchestratorModel = settings.chat.model?.trim();
485
- if (!backgroundModel || backgroundModel !== orchestratorModel) return false;
486
- if (settings.context.memory.target?.trim() !== settings.chat.target?.trim()) return false;
487
- try {
488
- const status = providers.list().find((entry) => entry.target.id === settings.context.memory.target?.trim());
489
- if (!status) return false;
490
- return resolveModelCapabilities(status, backgroundModel, providers.knowledgeBase).reasoning === true;
491
- } catch {
492
- // An unresolvable capability is not evidence of a reasoning model; the
493
- // operator's explicit configuration stands.
494
- return false;
617
+ ): Promise<CompactionResolution | null> {
618
+ const override = settings.context.compaction.model;
619
+ let targetId = settings.chat.target;
620
+ let wireModelId = settings.chat.model;
621
+ if (override !== undefined && override !== null) {
622
+ let selected: ReturnType<typeof resolveModelReference>;
623
+ try {
624
+ selected = resolveModelReference(override, providers);
625
+ } catch {
626
+ throw new Error("context.compaction.model is an invalid pattern; set a unique target/model reference");
627
+ }
628
+ if (!selected.ref || selected.warning) {
629
+ throw new Error(
630
+ "context.compaction.model must match exactly one configured model; set a unique target/model reference",
631
+ );
632
+ }
633
+ targetId = selected.ref.target;
634
+ wireModelId = selected.ref.model;
495
635
  }
496
- }
497
-
498
- function synthesizeOrchestratorModel(
499
- providers: ProvidersContract,
500
- target: TargetDescriptor,
501
- wireModelId: string,
502
- ): EngineModel | null {
503
- const runtime = providers.getRuntime(target.runtime);
504
- if (!runtime) return null;
636
+ if (!targetId || !wireModelId) return null;
637
+ await prepareBackgroundModelMetadata(providers, targetId);
638
+ const status = providers.list().find((entry) => entry.target.id === targetId);
639
+ if (!status?.available) {
640
+ throw new Error("context.compaction.model target is unavailable; check the selected target with clio-coder targets");
641
+ }
642
+ const resolved = resolveRuntimeTarget(providers, {
643
+ targetId,
644
+ wireModelId,
645
+ use: "orchestrator",
646
+ requestedThinkingLevel: "off",
647
+ requireTools: false,
648
+ requireStreaming: true,
649
+ requireOutputBudget: true,
650
+ });
651
+ if (!resolved.ok) {
652
+ // Configured identifiers and provider diagnostics can contain terminal controls.
653
+ // Keep the failure actionable without echoing arbitrary provider/config text.
654
+ throw new Error(
655
+ "context.compaction.model cannot run as a summarizer; select an available HTTP chat model with an output budget",
656
+ );
657
+ }
658
+ const route = resolved.target;
505
659
  let model: EngineModel;
506
660
  try {
507
- const kbHit = providers.knowledgeBase?.lookup(wireModelId) ?? null;
508
- model = runtime.synthesizeModel(target, wireModelId, kbHit);
661
+ model = route.runtime.synthesizeModel(
662
+ route.target,
663
+ route.wireModelId,
664
+ providers.knowledgeBase?.lookup(route.wireModelId) ?? null,
665
+ );
509
666
  } catch {
510
- return null;
667
+ throw new Error("context.compaction.model could not be prepared; check the selected target/model configuration");
511
668
  }
512
- try {
513
- const status = providers.list().find((entry) => entry.target.id === target.id);
514
- if (status) {
515
- const caps = resolveModelCapabilities(status, wireModelId, providers.knowledgeBase, {
516
- detectedReasoning: providers.getDetectedReasoning(target.id, wireModelId),
517
- });
518
- applyModelCapabilityPatch(model, caps);
669
+ const refined = refineRuntimeTargetWithModelHints(route, model, providers.knowledgeBase);
670
+ if (refined.capabilityDecisions.maxTokens <= 0) {
671
+ throw new Error("context.compaction.model has no output budget; select a model with a known positive output limit");
672
+ }
673
+ applyModelCapabilityPatch(model, refined.capabilities);
674
+ let apiKey: string | undefined = LOCAL_API_KEY_FALLBACK;
675
+ if (targetRequiresAuth(route.target, route.runtime)) {
676
+ const auth = await providers.auth.resolveForTarget(route.target, route.runtime);
677
+ if (!auth.available || !auth.apiKey) {
678
+ throw new Error(
679
+ "context.compaction.model authentication is unavailable; authenticate the selected target with clio-coder auth",
680
+ );
519
681
  }
520
- } catch {
521
- // Older test doubles and degraded provider bundles may not expose live
522
- // status. The synthesized model still carries runtime and catalog caps.
682
+ apiKey = auth.apiKey;
523
683
  }
524
- return model;
525
- }
526
-
527
- async function resolveCompactionModel(
528
- settings: ClioSettings,
529
- providers: ProvidersContract,
530
- ): Promise<CompactionResolution | null> {
531
- const targetId = settings.chat?.target ?? null;
532
- const wireModelId = settings.chat?.model ?? null;
533
- if (!targetId || !wireModelId) return null;
534
- const target = resolveTarget(providers, targetId);
535
- if (!target) return null;
536
- const model = synthesizeOrchestratorModel(providers, target, wireModelId);
537
- if (!model) return null;
538
- const apiKey = await resolveApiKeyForTarget(target, providers);
539
- const resolution: CompactionResolution = { model, targetId, endpointKey: canonicalEndpointKey(target) };
540
- if (apiKey !== undefined) resolution.apiKey = apiKey;
541
- return resolution;
684
+ return {
685
+ model,
686
+ targetId: route.targetId,
687
+ wireModelId: route.wireModelId,
688
+ endpointKey: canonicalEndpointKey(route.target),
689
+ apiKey,
690
+ ...(route.target.auth?.headers ? { headers: route.target.auth.headers } : {}),
691
+ };
542
692
  }
543
693
 
544
694
  function readSessionEntriesForCompact(sessionId: string): SessionEntry[] {
@@ -643,11 +793,19 @@ async function runCompactionFlow(
643
793
  providers: ProvidersContract,
644
794
  instructions?: string,
645
795
  trigger?: CompactionTrigger,
796
+ observability?: BackgroundMemoryUsageSink,
646
797
  ): Promise<CompactResult | null> {
647
798
  const meta = session.current();
648
799
  if (!meta) {
649
800
  throw new Error("no current session to compact; start one with /new or /resume first");
650
801
  }
802
+ const stateDir = clioStateDir();
803
+ const activeLeafTurnId = session.tree(meta.id).leafId ?? undefined;
804
+ const isOriginCurrent = () =>
805
+ session.current()?.id === meta.id && (session.tree(meta.id).leafId ?? undefined) === activeLeafTurnId;
806
+ const entries = filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId);
807
+ if (entries.length === 0) return null;
808
+ const systemPrompt = await readCompactionSystemPrompt(settings.context.compaction.systemPrompt, meta.cwd);
651
809
  const resolved = await resolveCompactionModel(settings, providers);
652
810
  if (!resolved) {
653
811
  throw new Error("no model configured; set chat.target + chat.model");
@@ -660,11 +818,22 @@ async function runCompactionFlow(
660
818
  // read the full file too (last taskLedger entry in file order, with no
661
819
  // branch filter at all), which was a second, independent instance of this
662
820
  // same bug. See the taskBoard wiring below for the fix.
663
- const activeLeafTurnId = session.tree(meta.id).leafId ?? undefined;
664
- const entries = filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId);
665
- if (entries.length === 0) return null;
821
+ if (!isOriginCurrent()) throw new Error("compaction session or branch changed before summarization");
822
+ const calls: CompactionCallObservation[] = [];
823
+ const preserveCalls = () =>
824
+ recordFailedCompactionCalls(
825
+ {
826
+ stateDir,
827
+ sessionId: meta.id,
828
+ repoIdentity: meta.cwdHash || cwdHash(meta.cwd),
829
+ target: resolved.targetId,
830
+ model: resolved.wireModelId,
831
+ },
832
+ calls,
833
+ isOriginCurrent() ? observability : undefined,
834
+ );
666
835
 
667
- // A compaction summary is a full streamed request against the chat target.
836
+ // A compaction summary is a full streamed request against its resolved target.
668
837
  // Hold the same canonical endpoint slot as an ordinary turn, /btw round, or
669
838
  // pre-warm so dispatch admission and background memory see its real usage.
670
839
  const releaseEndpointSlot = resolved.endpointKey === null ? () => {} : registerForegroundStream(resolved.endpointKey);
@@ -672,17 +841,39 @@ async function runCompactionFlow(
672
841
  try {
673
842
  result = await compact({
674
843
  entries,
844
+ onCall: (call) => calls.push(call),
675
845
  model: resolved.model,
846
+ ...(systemPrompt !== undefined ? { systemPrompt } : {}),
847
+ ...(resolved.headers !== undefined ? { headers: resolved.headers } : {}),
676
848
  ...(resolved.apiKey !== undefined ? { apiKey: resolved.apiKey } : {}),
677
849
  ...(instructions !== undefined ? { instructions } : {}),
678
850
  });
851
+ } catch (error) {
852
+ try {
853
+ preserveCalls();
854
+ } catch (recordingError) {
855
+ throw new AggregateError([error, recordingError], "compaction failed and its usage could not be fully recorded");
856
+ }
857
+ throw error;
679
858
  } finally {
680
859
  releaseEndpointSlot();
681
860
  }
682
- if (result.messagesSummarized === 0 || result.summary.length === 0) return null;
861
+ if (!isOriginCurrent()) {
862
+ preserveCalls();
863
+ throw new Error("compaction session or branch changed; summary discarded and originating usage retained");
864
+ }
865
+ if (result.messagesSummarized === 0 || result.summary.length === 0) {
866
+ preserveCalls();
867
+ if (calls.length > 0) throw new Error("compaction returned no summary; reported usage retained without a checkpoint");
868
+ return null;
869
+ }
870
+ if (result.usage) {
871
+ result.usage = { ...result.usage, targetId: resolved.targetId, modelId: resolved.wireModelId };
872
+ }
683
873
 
684
- const entry: Omit<CompactionSummaryEntry, "turnId" | "timestamp"> = {
874
+ const entry: Omit<CompactionSummaryEntry, "timestamp"> = {
685
875
  kind: "compactionSummary",
876
+ turnId: randomUUID(),
686
877
  parentTurnId: result.firstKeptTurnId ?? null,
687
878
  summary: result.summary,
688
879
  tokensBefore: result.tokensBefore,
@@ -696,22 +887,61 @@ async function runCompactionFlow(
696
887
  ...(result.usage !== undefined ? { usage: result.usage } : {}),
697
888
  };
698
889
  if (trigger !== undefined) entry.trigger = trigger;
699
- session.appendEntry(entry);
890
+ try {
891
+ session.appendEntry(entry);
892
+ } catch (error) {
893
+ // A write may have reached the ledger before its caller threw. Reconcile
894
+ // this exact checkpoint identity before choosing a second accounting store.
895
+ try {
896
+ if (!compactionCheckpointWasWritten(sessionPaths(meta).current, entry.turnId)) preserveCalls();
897
+ } catch (recordingError) {
898
+ throw new AggregateError(
899
+ [error, recordingError],
900
+ "compaction checkpoint persistence is unresolved; usage was not duplicated",
901
+ );
902
+ }
903
+ throw error;
904
+ }
700
905
  return result;
701
906
  }
702
907
 
908
+ function compactionCheckpointWasWritten(path: string, turnId: string): boolean {
909
+ let malformed = false;
910
+ for (const line of readFileSync(path, "utf8").split("\n")) {
911
+ if (line.trim().length === 0) continue;
912
+ try {
913
+ const entry: unknown = JSON.parse(line);
914
+ if (
915
+ entry &&
916
+ typeof entry === "object" &&
917
+ "turnId" in entry &&
918
+ entry.turnId === turnId &&
919
+ "kind" in entry &&
920
+ entry.kind === "compactionSummary"
921
+ )
922
+ return true;
923
+ } catch {
924
+ malformed = true;
925
+ }
926
+ }
927
+ if (malformed) throw new Error("cannot prove checkpoint absence in a malformed session ledger");
928
+ return false;
929
+ }
930
+
703
931
  /**
704
932
  * Compose the production chat-loop compaction callback. Errors intentionally
705
933
  * propagate: the chat loop owns activity failure reporting and distinguishes
706
934
  * a thrown read/model/persistence failure from the legitimate null no-op that
707
935
  * `runCompactionFlow` returns for an empty session or an unavailable cut.
708
936
  */
709
- function createProductionAutoCompact(
937
+ export function createProductionAutoCompact(
710
938
  session: SessionContract,
711
939
  getSettings: () => ClioSettings,
712
940
  providers: ProvidersContract,
941
+ observability?: BackgroundMemoryUsageSink,
713
942
  ): (instructions?: string, trigger?: CompactionTrigger) => Promise<CompactResult | null> {
714
- return (instructions, trigger) => runCompactionFlow(session, getSettings(), providers, instructions, trigger);
943
+ return (instructions, trigger) =>
944
+ runCompactionFlow(session, getSettings(), providers, instructions, trigger, observability);
715
945
  }
716
946
 
717
947
  function estimateTokensFromSummary(summary: string): number {
@@ -1026,7 +1256,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1026
1256
  else resolvedResumeId = latest.id;
1027
1257
  }
1028
1258
  }
1029
- const resumeId = resolvedResumeId ?? process.env.CLIO_CODER_RESUME_SESSION_ID?.trim();
1259
+ const resumeId = resolvedResumeId;
1030
1260
  let resumedSessionAtBoot = false;
1031
1261
  if (resumeId && session && headlessResumeFailure === null) {
1032
1262
  try {
@@ -1038,7 +1268,6 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1038
1268
  else bootStderr(`Clio Coder: failed to resume session ${resumeId}: ${detail}\n`);
1039
1269
  }
1040
1270
  }
1041
- Reflect.deleteProperty(process.env, "CLIO_CODER_RESUME_SESSION_ID");
1042
1271
  if (headlessResumeFailure !== null) {
1043
1272
  bootStderr(`clio-coder run: ${headlessResumeFailure}\n`);
1044
1273
  await termination.shutdown(2);
@@ -1050,6 +1279,20 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1050
1279
  // middleware.hookFailed (the interactive warn notice consumes it) and keep
1051
1280
  // stderr for non-interactive runs, which have no notice subscriber.
1052
1281
  middleware.setDiagnosticSink((diagnostic) => {
1282
+ if (diagnostic.kind === "registration_conflict") {
1283
+ // Registration bookkeeping has no hook occurrence; the affected owner
1284
+ // today declares user hooks, which never run on on_compaction, so the
1285
+ // payload's hook slot carries that as the "no evaluation" marker.
1286
+ bus.emit(BusChannels.MiddlewareHookFailed, {
1287
+ kind: "registration_conflict",
1288
+ registrationId: diagnostic.registrationId,
1289
+ hook: "on_compaction",
1290
+ at: Date.now(),
1291
+ message: formatRegistrationConflict(diagnostic),
1292
+ });
1293
+ if (!interactive) writeMiddlewareDiagnosticToStderr(diagnostic);
1294
+ return;
1295
+ }
1053
1296
  bus.emit(BusChannels.MiddlewareHookFailed, {
1054
1297
  kind: diagnostic.kind,
1055
1298
  registrationId: diagnostic.registrationId,
@@ -1082,15 +1325,14 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1082
1325
  });
1083
1326
  }
1084
1327
 
1085
- // Guardrail policy (tool-call budgets, tool byte caps, dispatch ledger cap)
1086
- // resolves settings-first with env as emergency override; install the
1087
- // settings section before any guard registration or tool reads it.
1328
+ // Install guardrail policy before any guard registration or tool reads it.
1329
+ // The effective session view replaces this boot projection below.
1088
1330
  const resolvedSettings = config?.get() ?? readSettings();
1089
1331
  configureGuardrails(guardrailValuesFromSettings(resolvedSettings));
1090
1332
 
1091
- // The run event journal resolves the same way for the same reason: the sink
1092
- // sits on the dispatch event path, where reading settings.yaml would be both
1093
- // a cost and a throw site, so the composition root installs the value once.
1333
+ // The journal sink sits on the dispatch event path, where reading settings
1334
+ // would be both a cost and a throw site. The effective session view replaces
1335
+ // this boot projection below.
1094
1336
  configureRunEventJournal(resolvedSettings.fleet.history.journal);
1095
1337
 
1096
1338
  // Guard registrations on the middleware contract, in order: loop guard,
@@ -1104,7 +1346,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1104
1346
  safety,
1105
1347
  bus,
1106
1348
  turnBlockBudget: INTERACTIVE_LOOP_BLOCK_BUDGET,
1107
- turnToolCallBudget: readOrchTurnToolCallBudget(),
1349
+ turnToolCallBudget: () => readOrchTurnToolCallBudget(),
1108
1350
  // Interactive/headless/ACP all share this orchestrator guard: at the
1109
1351
  // block budget, lock tools for the rest of the turn so the model
1110
1352
  // answers from what it gathered instead of hard-cancelling a turn that
@@ -1154,37 +1396,12 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1154
1396
  middleware.registerHook(
1155
1397
  createSkillActivationObserver((activation) => appendSkillActivationRegistryEvent(session, activation)),
1156
1398
  );
1157
- // First-turn skills reminder: user-message-visible text is the one channel
1158
- // the battery-tested local models act on; suggestion protocol only, the
1159
- // operator load gate is untouched.
1160
- if (resources) {
1161
- middleware.registerHook(
1162
- createSkillsReminderRegistration({
1163
- countModelVisibleSkills: () => modelVisibleSkills(resources.skills(process.cwd()).items).length,
1164
- // Same lookup context(scope="skills") lists under its Marketplace
1165
- // heading, minus what is already installed, so the count the
1166
- // reminder quotes is the count the listing will show.
1167
- countInstallableSkills: () => {
1168
- const installed = new Set(resources.skills(process.cwd()).items.map((skill) => skill.name));
1169
- return discoverMarketplaceSkills({ cwd: process.cwd() }).skills.filter((skill) => !installed.has(skill.name))
1170
- .length;
1171
- },
1172
- }),
1173
- );
1174
- }
1175
1399
  // Task-board reminder: same user-message-visible channel, fired once per
1176
1400
  // session when a request literally enumerates three or more steps. The
1177
1401
  // static routing line and tasks hint ask for the same board; battery-tested
1178
1402
  // local models only comply when the instruction rides the user message.
1179
1403
  middleware.registerHook(createTaskBoardReminderRegistration());
1180
1404
  const taskMemoryBank = new TaskMemoryBank();
1181
- let taskMemorySessionId = session?.current()?.id ?? null;
1182
- const ensureTaskMemorySession = (): void => {
1183
- const currentSessionId = session?.current()?.id ?? null;
1184
- if (currentSessionId === taskMemorySessionId) return;
1185
- taskMemoryBank.clear();
1186
- taskMemorySessionId = currentSessionId;
1187
- };
1188
1405
  const memorySettings = (config?.get() ?? readSettings()).context.memory;
1189
1406
  // Bound late: the registration is built here, but the buffer a deferred
1190
1407
  // reminder lands in belongs to the chat loop that has not been composed yet.
@@ -1199,7 +1416,6 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1199
1416
  const memoryTrace = memoryTracePath === null ? null : createTaskMemoryTrace(memoryTracePath);
1200
1417
  // The route the last resolved memory client would call, kept so the endpoint
1201
1418
  // check and the cost row read the same resolution the step itself used.
1202
- let backgroundMemoryRoute: BackgroundMemoryRoute | null = null;
1203
1419
  /**
1204
1420
  * Account for one background memory step exactly as a `/btw` side question is
1205
1421
  * accounted for: the in-process cost tracker under its own label so `/cost`
@@ -1208,23 +1424,16 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1208
1424
  *
1209
1425
  * Accounting only. The client wrapper (`announceMemoryStepEndpoint`) holds the
1210
1426
  * endpoint slot and publishes the disturbance; it sees the timed-out and
1211
- * thrown steps this sink never hears about because their usage stays null.
1427
+ * thrown steps that report no usage. Late reported usage still reaches this sink.
1212
1428
  */
1213
- const recordBackgroundMemoryUsage = (usage: TaskMemoryStepUsage): void => {
1429
+ const captureBackgroundMemoryUsage = () => {
1214
1430
  const meta = session?.current() ?? null;
1215
- try {
1216
- recordBackgroundMemoryStep({
1217
- usage,
1218
- stateDir: clioStateDir(),
1219
- sessionId: meta?.id ?? null,
1220
- // The identity the session ledger is filed under, so `usage report
1221
- // --repo` selects these rows with the same hash it selects ledgers with.
1222
- repoIdentity: meta ? meta.cwdHash || cwdHash(meta.cwd || process.cwd()) : null,
1223
- ...(observability === undefined ? {} : { observability }),
1224
- });
1225
- } catch {
1226
- // Accounting is bookkeeping. Its failure never reaches the memory step.
1227
- }
1431
+ return captureTaskMemoryUsage({
1432
+ stateDir: clioStateDir(),
1433
+ sessionId: meta?.id ?? null,
1434
+ repoIdentity: meta ? meta.cwdHash || cwdHash(meta.cwd || process.cwd()) : null,
1435
+ ...(observability === undefined ? {} : { observability }),
1436
+ });
1228
1437
  };
1229
1438
  const proposeInjectedMemoryEntries = (entries: ReadonlyArray<TaskMemoryEntry>): void => {
1230
1439
  const meta = session?.current() ?? null;
@@ -1253,7 +1462,6 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1253
1462
  deliversDeferredReminders: options.headless === undefined,
1254
1463
  onDeferredReminder: (message) => deferredMemoryReminderSink?.(message),
1255
1464
  getSettings: () => {
1256
- ensureTaskMemorySession();
1257
1465
  const memory = effectiveSettingsForDispatch?.().context.memory ?? memorySettings;
1258
1466
  return {
1259
1467
  enabled: memory.enabled,
@@ -1263,34 +1471,17 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1263
1471
  timeoutMs: memory.timeoutMs,
1264
1472
  };
1265
1473
  },
1266
- getModelClient: () => {
1267
- const settings = effectiveSettingsForDispatch?.();
1268
- backgroundMemoryRoute =
1269
- settings === undefined
1270
- ? null
1271
- : createBackgroundMemoryModelClient(providers, settings, settings.context.memory.timeoutMs, bus);
1272
- return backgroundMemoryRoute?.client ?? null;
1273
- },
1274
- getModelMaxTokens: (configuredMaxTokens) =>
1275
- backgroundMemoryRoute?.modelMaxTokens(configuredMaxTokens) ?? configuredMaxTokens,
1276
- // A single-slot local server serves one request at a time, so a memory step
1277
- // started while the operator's turn is streaming either waits behind it or
1278
- // makes the server swap the resident model out to answer. The chat loop
1279
- // registers its stream on the endpoint it streams against, so the two are
1280
- // compared by the same canonical key dispatch admission counts slots on.
1281
- backgroundEndpointBusy: () => {
1282
- const endpointKey = backgroundMemoryRoute?.endpointKey ?? null;
1283
- if (endpointKey === null) return false;
1284
- // This runs before the client wrapper registers the admitted step, so the
1285
- // count contains other requests only and the step cannot refuse itself.
1286
- return (foregroundStreamUsage()[endpointKey] ?? 0) > 0;
1287
- },
1288
- onStepUsage: (usage) => recordBackgroundMemoryUsage(usage),
1474
+ ...createBackgroundMemoryRouting(providers, () => effectiveSettingsForDispatch?.(), bus),
1475
+ captureStepUsage: captureBackgroundMemoryUsage,
1289
1476
  onInjectedEntries: (entries) => proposeInjectedMemoryEntries(entries),
1290
1477
  });
1291
1478
  middleware.registerHook(memoryIntervention);
1292
1479
  const unsubscribeMemoryLoop = bus.on(BusChannels.LoopBlocked, () => memoryIntervention.signalLoop());
1293
- termination.onDrain(() => unsubscribeMemoryLoop());
1480
+ const disposeMemoryLifecycle = bindTaskMemoryLifecycle(bus, memoryIntervention);
1481
+ termination.onDrain(() => {
1482
+ unsubscribeMemoryLoop();
1483
+ disposeMemoryLifecycle();
1484
+ });
1294
1485
  if (contextDomain) {
1295
1486
  middleware.registerHook(createFileMutationObserver(({ paths }) => contextDomain.noteFileChanges(paths)));
1296
1487
  }
@@ -1299,24 +1490,26 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1299
1490
  // same effect machinery. They register after the guards, so safety stays
1300
1491
  // authoritative: a hook may add effects (including request block_tool) but
1301
1492
  // cannot grant a permission safety would deny. Loading is best-effort.
1493
+ // The coordinator is the only writer of the "user-hooks" owner and the only
1494
+ // caller of the extensions reload; it publishes the extension generation
1495
+ // and the hook registrations with two adjacent assignments on one stack
1496
+ // and emits extensions.reloaded only after both. The boot generation is
1497
+ // published here too (the extensions bundle publishes nothing at start),
1498
+ // so no consumer ever sees extension resources paired with hooks from a
1499
+ // different generation. The owner slot is anchored here, so user hooks
1500
+ // keep evaluating after the guards and before the assessors below.
1302
1501
  const hookReceiptLog = createHookReceiptLog({ persistPath: join(clioStateDir(), "hook-receipts.json") });
1303
- const extensionHookRoots: ExtensionHookRoot[] = (extensions?.list(process.cwd()) ?? [])
1304
- .filter((ext) => ext.enabled && ext.effective)
1305
- .map((ext) => ({ id: ext.id, rootPath: ext.rootPath }));
1306
- const userHooks = installUserHooks({
1307
- cwd: process.cwd(),
1308
- extensions: extensionHookRoots,
1309
- registerHook: (registration) => middleware.registerHook(registration),
1502
+ const extensionReload = createExtensionReloadCoordinator({
1503
+ extensions,
1504
+ middleware,
1505
+ cwd: () => process.cwd(),
1310
1506
  recordReceipt: (receipt) => hookReceiptLog.record(receipt),
1507
+ report: (line) => {
1508
+ if (!interactive) process.stderr.write(`${line}\n`);
1509
+ },
1510
+ onCommitted: (event) => bus.emit(BusChannels.ExtensionsReloaded, event),
1311
1511
  });
1312
- if (!interactive) {
1313
- for (const issue of userHooks.fileIssues) {
1314
- process.stderr.write(`[clio-coder:hooks] ${issue.message}\n`);
1315
- }
1316
- for (const issue of userHooks.issues) {
1317
- process.stderr.write(`[clio-coder:hooks] ${issue.source.sourcePath}#${issue.index}: ${issue.issues.join("; ")}\n`);
1318
- }
1319
- }
1512
+ extensionReload.applyBoot();
1320
1513
  termination.onDrain(() => hookReceiptLog.flush());
1321
1514
  // Autonomy is hot-reloaded for interactive and headless admissions. ACP
1322
1515
  // server prompts use the snapshot captured at session/new.
@@ -1331,17 +1524,34 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1331
1524
  (config?.get() ?? readSettings()).safety.autonomy ??
1332
1525
  "auto-edit";
1333
1526
  const resolveEffectiveAutonomy = (): AutonomyLevel => activeAcpSessionAutonomy ?? resolveBaselineAutonomy();
1527
+ // First-turn skills reminder: user-message-visible text is the one channel
1528
+ // the battery-tested local models act on. Which protocol it teaches follows
1529
+ // the effective autonomy level, resolved one line up: suggest-and-wait at
1530
+ // read-only and suggest, load-it-yourself at auto-edit and full-auto.
1531
+ if (resources) {
1532
+ middleware.registerHook(
1533
+ createSkillsReminderRegistration({
1534
+ countModelVisibleSkills: () => modelVisibleSkills(resources.skills(process.cwd()).items).length,
1535
+ // Same lookup context(scope="skills") lists under its Marketplace
1536
+ // heading, minus what is already installed, so the count the
1537
+ // reminder quotes is the count the listing will show.
1538
+ countInstallableSkills: () => {
1539
+ const installed = new Set(resources.skills(process.cwd()).items.map((skill) => skill.name));
1540
+ return discoverMarketplaceSkills({ cwd: process.cwd() }).skills.filter((skill) => !installed.has(skill.name))
1541
+ .length;
1542
+ },
1543
+ modelMayActivateSkills: () => modelMayActivateSkills(resolveEffectiveAutonomy()),
1544
+ }),
1545
+ );
1546
+ }
1334
1547
  // Marketplace self-promotion: coordinator-only by this wiring (never a
1335
- // dispatch worker), local matcher, consented installs and full-auto
1336
- // autonomous installs both pass the own-marketplace source gate inside the
1337
- // registration. Registered here because it needs the effective-autonomy
1338
- // resolution defined one line up.
1548
+ // dispatch worker), local matcher and operator-consented installs at every autonomy level. The
1549
+ // registration also checks the own-marketplace source gate before installing.
1339
1550
  if (resources) {
1340
1551
  middleware.registerHook(
1341
1552
  createMarketplaceOfferRegistration({
1342
1553
  listInstalledSkillNames: () => resources.skills(process.cwd()).items.map((skill) => skill.name),
1343
1554
  listMarketplaceEntries: () => discoverMarketplaceSkills({ cwd: process.cwd() }).skills,
1344
- getAutonomy: resolveEffectiveAutonomy,
1345
1555
  installEntry: (entry, scope) => {
1346
1556
  const installed = installSkill({ source: entry.sourceUrl, scope, name: entry.name, cwd: process.cwd() });
1347
1557
  return { path: installed.path, sourceUrl: installed.sourceUrl, installedHash: installed.installedHash };
@@ -1494,6 +1704,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1494
1704
  ...(panes && mux?.mode !== "none" ? { panes } : {}),
1495
1705
  getCostCeilingUsd: () => result.getContract<SchedulingContract>("scheduling")?.ceilingUsd() ?? 0,
1496
1706
  ...(config ? { getWorkerRosters: () => config.get().fleet.rosters } : {}),
1707
+ ...(config ? { getDispatchSchemaComposition: () => dispatchSchemaCompositionFor(config.get().fleet) } : {}),
1497
1708
  getSkillLoaderOptions: () => ({
1498
1709
  trustProjectCompatRoots: config?.get().integrations.projectResources.trustProjectImports === true,
1499
1710
  disableDiscovery: options.noSkills === true || options.headless?.noSkills === true,
@@ -1518,8 +1729,13 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1518
1729
  // view, so the live session reflects them immediately while settings.yaml
1519
1730
  // (the global default for new sessions) stays untouched until the operator
1520
1731
  // chooses to save globally.
1732
+ // Overrides are keyed by settings path, the same ids the /settings overlay
1733
+ // commits (`setAtPath` walks the dotted path). The headless `--autonomy`
1734
+ // flag was keyed by the bare word, which wrote a top-level `autonomy` key
1735
+ // nothing reads, so `run --autonomy full-auto` compiled and admitted at
1736
+ // whatever settings.yaml said.
1521
1737
  const sessionOverrides: SessionOverrides = new Map(
1522
- options.headless?.autonomy === undefined ? [] : [["autonomy", options.headless.autonomy]],
1738
+ options.headless?.autonomy === undefined ? [] : [["safety.autonomy", options.headless.autonomy]],
1523
1739
  );
1524
1740
  // The effective view is derived by deep-cloning the saved snapshot, and it
1525
1741
  // is read on the tool-admission hot path (every call resolves autonomy
@@ -1534,9 +1750,10 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1534
1750
  let cachedSettingsView: ClioSettings | null = null;
1535
1751
  const bumpSessionState = (): void => {
1536
1752
  sessionStateGeneration += 1;
1537
- // Child-process seams read the effective setting from the environment,
1538
- // and the session view may override the saved value.
1539
- setGitCommitAttributionEnabled(getCurrentSettings().integrations.git.commitAttribution);
1753
+ const settings = getCurrentSettings();
1754
+ configureGuardrails(guardrailValuesFromSettings(settings));
1755
+ configureRunEventJournal(settings.fleet.history.journal);
1756
+ setGitCommitAttributionEnabled(settings.integrations.git.commitAttribution);
1540
1757
  };
1541
1758
  const getCurrentSettings = (): ClioSettings => {
1542
1759
  // Recents live in the data dir (core/recent-models.ts), never in
@@ -1562,15 +1779,15 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1562
1779
  };
1563
1780
  effectiveSettingsForDispatch = getCurrentSettings;
1564
1781
  bumpSessionState();
1565
- // The config bundle publishes the saved value on reload; a session-scoped
1566
- // override must win, so re-derive from the session view after it.
1567
- const unsubscribeCommitAttributionSync = bus.on(BusChannels.ConfigHotReload, () => bumpSessionState());
1568
- termination.onDrain(() => unsubscribeCommitAttributionSync());
1782
+ // The config bundle publishes saved values on reload; session-scoped
1783
+ // overrides must win, so re-derive every process-local projection from the
1784
+ // effective session view after it.
1785
+ const unsubscribeSettingsProjectionSync = bus.on(BusChannels.ConfigHotReload, () => bumpSessionState());
1786
+ termination.onDrain(() => unsubscribeSettingsProjectionSync());
1569
1787
  const getTaskMemorySeedOffer = (): { source: string; count: number } | null => {
1570
1788
  return taskMemoryHandoffSeedOffer(process.cwd(), getCurrentSettings().context.memory.enabled);
1571
1789
  };
1572
1790
  const seedCurrentTaskMemoryFromHandoff = () => {
1573
- ensureTaskMemorySession();
1574
1791
  return seedTaskMemoryFromNewestHandoff(taskMemoryBank, process.cwd(), getCurrentSettings().context.memory.enabled);
1575
1792
  };
1576
1793
  if (resumedSessionAtBoot) {
@@ -1812,6 +2029,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1812
2029
  return key === null ? null : registerForegroundStream(key);
1813
2030
  },
1814
2031
  getSettings: getCurrentSettings,
2032
+ getAutonomy: resolveEffectiveAutonomy,
1815
2033
  providers,
1816
2034
  middleware,
1817
2035
  middlewareToolChoice,
@@ -1840,7 +2058,6 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1840
2058
  }
1841
2059
  },
1842
2060
  getTaskMemoryHandoffSource: () => {
1843
- ensureTaskMemorySession();
1844
2061
  const meta = session?.current();
1845
2062
  if (!meta) throw new Error("task memory handoff requires an active session");
1846
2063
  const settings = getCurrentSettings();
@@ -1865,7 +2082,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1865
2082
  ...(session
1866
2083
  ? {
1867
2084
  readSessionEntries: readCurrentSessionEntries,
1868
- autoCompact: createProductionAutoCompact(session, getCurrentSettings, providers),
2085
+ autoCompact: createProductionAutoCompact(session, getCurrentSettings, providers, observability),
1869
2086
  }
1870
2087
  : {}),
1871
2088
  toolRegistry,
@@ -1892,7 +2109,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
1892
2109
  await chat.whenSettled();
1893
2110
  });
1894
2111
 
1895
- // A boot-time resume (CLIO_CODER_RESUME_SESSION_ID) must replay the resumed
2112
+ // A boot-time resume (headless --session or --continue) must replay the resumed
1896
2113
  // session into the chat loop the same way the interactive /resume overlay
1897
2114
  // does. Without this, the first submit runs with an empty provider context
1898
2115
  // and parents its user turn at null, appending a second root that silently
@@ -2117,6 +2334,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
2117
2334
  ...(initialNotices.length > 0 ? { initialNotices } : {}),
2118
2335
  ...(resources ? { resources } : {}),
2119
2336
  ...(extensions ? { extensions } : {}),
2337
+ reloadExtensions: () => extensionReload.reload(),
2120
2338
  ...(interop ? { interop } : {}),
2121
2339
  ...(share ? { share } : {}),
2122
2340
  ...(mux ? { mux } : {}),
@@ -2141,7 +2359,6 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
2141
2359
  supersedeDecision: (interviewId, key, correction) => decisionBoard.supersede(interviewId, key, correction),
2142
2360
  userTasks,
2143
2361
  getTaskMemoryStatus: () => {
2144
- ensureTaskMemorySession();
2145
2362
  const settings = getCurrentSettings();
2146
2363
  const bank = taskMemoryBank.snapshot();
2147
2364
  return {
@@ -2295,10 +2512,8 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
2295
2512
  ? {
2296
2513
  onResumeSession: (sessionId) => {
2297
2514
  try {
2298
- const previousSessionId = session.current()?.id ?? null;
2299
2515
  session.resume(sessionId);
2300
2516
  taskBoard.snapshot();
2301
- if (previousSessionId !== sessionId) ensureTaskMemorySession();
2302
2517
  } catch (err) {
2303
2518
  process.stderr.write(
2304
2519
  `[/resume] failed to resume ${sessionId}: ${err instanceof Error ? err.message : String(err)}\n`,
@@ -2312,13 +2527,11 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
2312
2527
  if (settings.chat.model) input.model = settings.chat.model;
2313
2528
  session.create(input);
2314
2529
  taskBoard.snapshot();
2315
- ensureTaskMemorySession();
2316
2530
  },
2317
2531
  onForkSession: (parentTurnId) => {
2318
2532
  try {
2319
2533
  session.fork(parentTurnId);
2320
2534
  taskBoard.snapshot();
2321
- ensureTaskMemorySession();
2322
2535
  } catch (err) {
2323
2536
  process.stderr.write(
2324
2537
  `[/fork] failed at turn ${parentTurnId}: ${err instanceof Error ? err.message : String(err)}\n`,