@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
@@ -78,13 +78,13 @@ export interface MemoryInterventionDeps {
78
78
  everyNTools?: number;
79
79
  /** Lazily resolves the explicitly configured background role. Null means rules-only. */
80
80
  getModelClient?: () => TaskMemoryModelClient | null;
81
+ /** One alternative route after a client error; never used after timeout, cancellation or model output. */
82
+ getFallbackModelClient?: () => TaskMemoryModelClient | null;
81
83
  /** Completion budget derived from the resolved background model capability. */
82
84
  getModelMaxTokens?: (configuredMaxTokens: number) => number;
83
85
  /**
84
- * True when the background target's inference endpoint is already serving the
85
- * chat target's stream. A memory step then either queues behind the operator's
86
- * own turn on a single-slot server or makes the server evict the resident
87
- * model to serve it, so the boundary is skipped and the skip is recorded.
86
+ * True when known endpoint occupancy exhausts the resolved capacity bound.
87
+ * A shared gateway URL alone is not evidence that its request slots are full.
88
88
  */
89
89
  backgroundEndpointBusy?: () => boolean;
90
90
  /**
@@ -92,6 +92,8 @@ export interface MemoryInterventionDeps {
92
92
  * routes it to the cost ledger; the middleware never prices anything.
93
93
  */
94
94
  onStepUsage?: (usage: TaskMemoryStepUsage) => void;
95
+ /** Capture immutable accounting ownership at launch, before awaiting inference. */
96
+ captureStepUsage?: () => (usage: TaskMemoryStepUsage, isCurrent: boolean) => void;
95
97
  /**
96
98
  * Bank entries an llm-tier reminder cited when it reached the operator. The
97
99
  * composition root proposes them into the durable memory store, which is what
@@ -139,6 +141,10 @@ export interface MemoryPromptedStepResult extends TaskMemoryPolicyResult {
139
141
  }
140
142
 
141
143
  export interface MemoryInterventionRegistration extends MiddlewareHookRegistration {
144
+ /** Invalidate pending content and discard all transient session/branch state. */
145
+ reset(): void;
146
+ /** Invalidate immediately without waiting for the model; refuse further work. */
147
+ dispose(): void;
142
148
  evaluateAsync(
143
149
  input: MiddlewareHookInput,
144
150
  context?: MiddlewareHookEvaluationContext,
@@ -154,10 +160,9 @@ export interface MemoryInterventionRegistration extends MiddlewareHookRegistrati
154
160
  /** True while a detached background memory step is still running. */
155
161
  stepInFlight(): boolean;
156
162
  /**
157
- * Resolves once no detached memory step is outstanding. Teardown does not
158
- * await it: a step runs tens of seconds on a local route and shutdown cannot
159
- * wait that long, which is why a surface with no next turn declines to start
160
- * one at all rather than starting one it will abandon.
163
+ * Resolves when this generation's detached policy settles. Reset/shutdown
164
+ * release the policy immediately; an abort-ignoring transport can still
165
+ * finish later, with authority only to report its originating usage.
161
166
  */
162
167
  whenIdle(): Promise<void>;
163
168
  }
@@ -167,6 +172,10 @@ export interface MemoryInterventionRegistration extends MiddlewareHookRegistrati
167
172
  * emits only cited, advisory reminders through the existing visible channel.
168
173
  */
169
174
  export function createMemoryInterventionRegistration(deps: MemoryInterventionDeps): MemoryInterventionRegistration {
175
+ let generation = 0;
176
+ let generationController = new AbortController();
177
+ let observedSessionId: string | undefined;
178
+ let disposed = false;
170
179
  const pending = new Map<string, PendingToolStep>();
171
180
  const trajectory: TrajectoryStep[] = [];
172
181
  const failures = new Map<string, FailedAttempt>();
@@ -194,11 +203,17 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
194
203
  let consecutiveLlmTimeouts = 0;
195
204
 
196
205
  return {
206
+ reset,
207
+ dispose(): void {
208
+ disposed = true;
209
+ reset();
210
+ },
197
211
  id: MEMORY_INTERVENTION_REGISTRATION_ID,
198
212
  description: "maintain bounded task execution memory and selectively remind after repeated failures or compaction",
199
213
  hooks: ["before_tool", "after_tool", "turn_start", "turn_end", "on_compaction"],
200
214
  evaluate(input): ReadonlyArray<MiddlewareEffect> {
201
- if (!settings().enabled) return NO_EFFECTS;
215
+ observeSession(input);
216
+ if (disposed || !settings().enabled) return NO_EFFECTS;
202
217
  try {
203
218
  switch (input.hook) {
204
219
  case "before_tool":
@@ -274,7 +289,8 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
274
289
  * would have been buffered anyway.
275
290
  */
276
291
  async evaluateAsync(input, context): Promise<ReadonlyArray<MiddlewareEffect>> {
277
- if (!settings().enabled || input.hook !== "turn_end" || pendingTriggers.size === 0) return NO_EFFECTS;
292
+ observeSession(input);
293
+ if (disposed || !settings().enabled || input.hook !== "turn_end" || pendingTriggers.size === 0) return NO_EFFECTS;
278
294
  const boundary = input.turnId ?? input.metadata?.userTurnId?.toString() ?? `tool-step:${toolStep}`;
279
295
  if (boundary === lastPromptedBoundary) return NO_EFFECTS;
280
296
  // One row rather than none, so a headless operator reading the log sees
@@ -316,6 +332,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
316
332
  ) ??
317
333
  false);
318
334
  rulesInjectedSincePromptedStep = false;
335
+ const stepGeneration = generation;
319
336
  promptedStepInFlight = true;
320
337
  outstandingStep = runPromptedStep({
321
338
  deterministicTrigger: triggers.some((trigger) => trigger !== "interval"),
@@ -323,6 +340,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
323
340
  triggerReasons: triggers,
324
341
  })
325
342
  .then((result) => {
343
+ if (stepGeneration !== generation || disposed) return;
326
344
  // A rules-only reminder can win the visible boundary while the optional
327
345
  // background route resolves to null. Preserve the operator-visible
328
346
  // injected outcome instead of overwriting it with that no-client silence.
@@ -336,13 +354,13 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
336
354
  // covers a throwing delivery sink, which must not surface anywhere.
337
355
  })
338
356
  .finally(() => {
339
- promptedStepInFlight = false;
357
+ if (stepGeneration === generation) promptedStepInFlight = false;
340
358
  });
341
359
  return NO_EFFECTS;
342
360
  },
343
361
  runPromptedStep,
344
362
  signalLoop(): void {
345
- if (settings().enabled) pendingTriggers.add("loop_signal");
363
+ if (!disposed && settings().enabled) pendingTriggers.add("loop_signal");
346
364
  },
347
365
  lastDecision: () => lastDecision,
348
366
  recentActivity: () => [...activity],
@@ -350,6 +368,43 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
350
368
  whenIdle: () => outstandingStep,
351
369
  };
352
370
 
371
+ function observeSession(input: MiddlewareHookInput): void {
372
+ if (input.sessionId === undefined) return;
373
+ if (observedSessionId !== undefined && observedSessionId !== input.sessionId) reset();
374
+ observedSessionId = input.sessionId;
375
+ }
376
+
377
+ function reset(): void {
378
+ generation += 1;
379
+ generationController.abort();
380
+ generationController = new AbortController();
381
+ deps.bank.clear();
382
+ pending.clear();
383
+ trajectory.length = 0;
384
+ failures.clear();
385
+ toolStep = 0;
386
+ lastTurnEndStep = 0;
387
+ reactivateAfterCompaction = false;
388
+ lastInjectedOperationFingerprint = null;
389
+ currentTask = "(current task unavailable)";
390
+ toolsSinceMemoryStep = 0;
391
+ consecutiveErrors = 0;
392
+ lastPromptedBoundary = null;
393
+ lastInjectedMessage = null;
394
+ lastDecision = null;
395
+ pendingTriggers.clear();
396
+ activity.length = 0;
397
+ annotatedThisTurn.clear();
398
+ telemetryBankSnapshot = deps.bank.snapshot();
399
+ promptedStepInFlight = false;
400
+ promptedStepTier = "rules";
401
+ outstandingStep = Promise.resolve();
402
+ rulesInjectedSincePromptedStep = false;
403
+ annotatedSinceTurnEnd = false;
404
+ consecutiveLlmTimeouts = 0;
405
+ observedSessionId = undefined;
406
+ }
407
+
353
408
  function settings(): MemoryInterventionSettings {
354
409
  const live = deps.getSettings?.();
355
410
  return {
@@ -377,12 +432,16 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
377
432
  effects: NO_EFFECTS,
378
433
  });
379
434
  const live = settings();
380
- if (!live.enabled) {
435
+ const stepGeneration = generation;
436
+ const isCurrent = () => !disposed && stepGeneration === generation;
437
+ const usageSink = deps.captureStepUsage?.();
438
+ if (disposed || !live.enabled) {
381
439
  const result = silent("no_client");
382
440
  lastDecision = result.decision;
383
441
  return result;
384
442
  }
385
443
  const started = process.hrtime.bigint();
444
+ let attemptStarted = started;
386
445
  const triggers = input.triggerReasons?.length ? input.triggerReasons : ["manual" as const];
387
446
  let tier: TaskMemoryTelemetryTier = "rules";
388
447
  promptedStepTier = tier;
@@ -407,17 +466,58 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
407
466
  } else {
408
467
  tier = "llm";
409
468
  promptedStepTier = tier;
410
- promptedResult = await runTaskMemoryPolicy(deps.bank, client, {
411
- task: input.task?.trim() || currentTask,
412
- trajectory: [...trajectory],
413
- deterministicTrigger: input.deterministicTrigger,
414
- maxTokens: live.maxTokens,
415
- modelMaxTokens: positiveInteger(deps.getModelMaxTokens?.(live.maxTokens), live.maxTokens),
416
- ...(input.suppressIntervention === undefined ? {} : { suppressIntervention: input.suppressIntervention }),
417
- previousReminder: lastInjectedMessage,
418
- timeoutMs: live.timeoutMs,
419
- ...(deps.onEnvelope === undefined ? {} : { onEnvelope: deps.onEnvelope }),
420
- });
469
+ const runClient = (selected: TaskMemoryModelClient, timeoutMs: number) =>
470
+ runTaskMemoryPolicy(deps.bank, selected, {
471
+ isCurrent,
472
+ signal: generationController.signal,
473
+ onStepUsage: (usage) => {
474
+ if (usageSink) usageSink(usage, isCurrent());
475
+ else deps.onStepUsage?.(usage);
476
+ },
477
+ task: input.task?.trim() || currentTask,
478
+ trajectory: [...trajectory],
479
+ deterministicTrigger: input.deterministicTrigger,
480
+ maxTokens: live.maxTokens,
481
+ modelMaxTokens: positiveInteger(deps.getModelMaxTokens?.(live.maxTokens), live.maxTokens),
482
+ ...(input.suppressIntervention === undefined ? {} : { suppressIntervention: input.suppressIntervention }),
483
+ previousReminder: lastInjectedMessage,
484
+ timeoutMs,
485
+ ...(deps.onEnvelope === undefined ? {} : { onEnvelope: deps.onEnvelope }),
486
+ });
487
+ const remainingMs = () => Math.floor(live.timeoutMs - Number(process.hrtime.bigint() - started) / 1_000_000);
488
+ const initialTimeoutMs = remainingMs();
489
+ promptedResult =
490
+ initialTimeoutMs <= 0
491
+ ? { ...silent("deadline"), decision: "timeout" }
492
+ : await runClient(client, initialTimeoutMs);
493
+ if (promptedResult.reason === "client_error" && isCurrent() && remainingMs() > 0) {
494
+ let fallback: TaskMemoryModelClient | null = null;
495
+ let fallbackReady = false;
496
+ try {
497
+ fallback = deps.getFallbackModelClient?.() ?? null;
498
+ fallbackReady = fallback !== null && deps.backgroundEndpointBusy?.() !== true;
499
+ } catch {
500
+ /* Fail closed and preserve the original call if routing or capacity is unreadable. */
501
+ }
502
+ const fallbackTimeoutMs = remainingMs();
503
+ if (fallback !== null && fallbackReady && isCurrent() && fallbackTimeoutMs > 0) {
504
+ // Each attempted call keeps its own telemetry and origin usage.
505
+ // The returned policy result describes the final attempt only.
506
+ emitTelemetry(
507
+ triggers,
508
+ tier,
509
+ promptedResult.decision,
510
+ promptedResult.reason,
511
+ 0,
512
+ promptedResult.inputTokens,
513
+ promptedResult.outputTokens,
514
+ started,
515
+ { bankOperations: promptedResult.bankOperations, droppedOperations: promptedResult.droppedOperations },
516
+ );
517
+ attemptStarted = process.hrtime.bigint();
518
+ promptedResult = await runClient(fallback, fallbackTimeoutMs);
519
+ }
520
+ }
421
521
  }
422
522
  }
423
523
  } catch (error) {
@@ -436,16 +536,11 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
436
536
  error: error instanceof Error ? error.message : "resolving the background model client failed",
437
537
  });
438
538
  }
539
+ if (!isCurrent()) return { ...promptedResult, reminder: null, effects: NO_EFFECTS };
540
+ if (promptedResult.reason === "endpoint_busy") telemetryDecision = "dropped";
439
541
  if (tier === "llm" && promptedResult.decision === "timeout") consecutiveLlmTimeouts += 1;
440
542
  else if (tier === "llm" && telemetryDecision !== "dropped") consecutiveLlmTimeouts = 0;
441
543
  lastDecision = promptedResult.decision;
442
- if (promptedResult.usage !== null) {
443
- try {
444
- deps.onStepUsage?.(promptedResult.usage);
445
- } catch {
446
- // Accounting is bookkeeping. A failing sink never changes memory behavior.
447
- }
448
- }
449
544
  if (promptedResult.decision === "injected") reportInjectedEntries(promptedResult.reminder);
450
545
  emitTelemetry(
451
546
  triggers,
@@ -455,7 +550,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
455
550
  citedEntryCount(promptedResult.reminder),
456
551
  promptedResult.inputTokens,
457
552
  promptedResult.outputTokens,
458
- started,
553
+ attemptStarted,
459
554
  { bankOperations: promptedResult.bankOperations, droppedOperations: promptedResult.droppedOperations },
460
555
  );
461
556
  return {
@@ -50,8 +50,9 @@ export function announceMemoryStepEndpoint<Request, Response>(
50
50
  const { bus, endpointKey, targetId } = deps;
51
51
  if (endpointKey === null) return complete;
52
52
  return async (request: Request): Promise<Response> => {
53
- // `runPromptedStep` performs its busy check before it invokes `complete`,
54
- // so this registration counts the outgoing request without self-refusing.
53
+ // The production client rechecks capacity after asynchronous preparation,
54
+ // immediately before calling this wrapper. Register synchronously so no
55
+ // local foreground launch can interleave between that check and this hold.
55
56
  const releaseEndpointSlot = registerForegroundStream(endpointKey);
56
57
  try {
57
58
  return await complete(request);
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Ordered, copy-on-write registration table behind a middleware contract.
3
+ *
4
+ * Three tiers share one id namespace and one evaluation list:
5
+ *
6
+ * - fixed: declarative rules (builtin plus composition-root definitions),
7
+ * immutable for the life of the contract and always evaluated first;
8
+ * - host: coded registrations appended by the composition root through
9
+ * registerHook, append-only, first id wins;
10
+ * - owned: registration sets replaced as one unit by an owner under a
11
+ * strictly increasing generation. Today the only owner is "user-hooks".
12
+ *
13
+ * The whole table is one immutable state object held behind a single
14
+ * reference. Every writer computes a complete next state and publishes it
15
+ * with one assignment; readers capture the reference once per evaluation, so
16
+ * an evaluation that started before a publish finishes against the state it
17
+ * started with, including across an await. Preparation never runs user code:
18
+ * conflicts are returned as frozen data and a caller emits them through the
19
+ * diagnostic sink only after publication.
20
+ */
21
+
22
+ import type { MiddlewareDiagnostic, MiddlewareDiagnosticSink, MiddlewareHookRegistration } from "./runtime.js";
23
+
24
+ export const MIDDLEWARE_REGISTRATION_OWNERS = ["user-hooks"] as const;
25
+
26
+ export type MiddlewareRegistrationOwner = (typeof MIDDLEWARE_REGISTRATION_OWNERS)[number];
27
+
28
+ export type MiddlewareRegistrationConflictTier = "builtin" | "host" | "owned";
29
+
30
+ export interface MiddlewareRegistrationConflict {
31
+ id: string;
32
+ conflictsWith: MiddlewareRegistrationConflictTier;
33
+ }
34
+
35
+ export type ReplaceRegistrationsRejection = "stale" | "unknown-owner";
36
+
37
+ export type RegistrationConflictDiagnostic = Extract<MiddlewareDiagnostic, { kind: "registration_conflict" }>;
38
+
39
+ export interface ReplaceRegistrationsReport {
40
+ applied: boolean;
41
+ owner: MiddlewareRegistrationOwner;
42
+ /** Generation active for the owner after the call. */
43
+ activeGeneration: number;
44
+ reason?: ReplaceRegistrationsRejection;
45
+ /** Offered registrations dropped for colliding with a builtin, host, or earlier owned id. */
46
+ dropped: ReadonlyArray<MiddlewareRegistrationConflict>;
47
+ /**
48
+ * Remove this generation's registrations if the owner still holds it. A
49
+ * disposer for a superseded generation is a no-op, so a late disposal can
50
+ * never remove a newer generation's registrations.
51
+ */
52
+ dispose(): void;
53
+ }
54
+
55
+ /**
56
+ * A validated replacement whose complete next table state is already built.
57
+ * `publish` is one reference assignment: it does not validate, refuse,
58
+ * throw, or call out. The caller checks `current()` on the same stack
59
+ * immediately before publishing, then emits `conflicts` afterwards.
60
+ */
61
+ export interface MiddlewareRegistrationReplacement {
62
+ owner: MiddlewareRegistrationOwner;
63
+ generation: number;
64
+ dropped: ReadonlyArray<MiddlewareRegistrationConflict>;
65
+ /** Diagnostics for `dropped`, as data. Nothing was emitted during preparation. */
66
+ conflicts: ReadonlyArray<RegistrationConflictDiagnostic>;
67
+ /** Registrations that will be active for the owner after publish. */
68
+ size: number;
69
+ /** True while the table state this replacement was prepared against is still the live one. */
70
+ current(): boolean;
71
+ /** Assignment-only publication of the prepared state. */
72
+ publish(): void;
73
+ /** Send `conflicts` to the diagnostic sink. Call only after publication. */
74
+ emitConflicts(): void;
75
+ /** Remove this generation's registrations if the owner still holds it. */
76
+ dispose(): void;
77
+ discard(): void;
78
+ }
79
+
80
+ export type PrepareRegistrationReplacementResult =
81
+ | { status: "prepared"; replacement: MiddlewareRegistrationReplacement }
82
+ | {
83
+ status: "rejected";
84
+ owner: MiddlewareRegistrationOwner;
85
+ reason: ReplaceRegistrationsRejection;
86
+ activeGeneration: number;
87
+ };
88
+
89
+ export interface MiddlewareRegistrationTable {
90
+ /** The current frozen evaluation list. Capture once per evaluation. */
91
+ list(): ReadonlyArray<MiddlewareHookRegistration>;
92
+ registerHook(registration: MiddlewareHookRegistration): void;
93
+ prepareReplacement(
94
+ owner: MiddlewareRegistrationOwner,
95
+ generation: number,
96
+ registrations: ReadonlyArray<MiddlewareHookRegistration>,
97
+ ): PrepareRegistrationReplacementResult;
98
+ replaceRegistrations(
99
+ owner: MiddlewareRegistrationOwner,
100
+ generation: number,
101
+ registrations: ReadonlyArray<MiddlewareHookRegistration>,
102
+ ): ReplaceRegistrationsReport;
103
+ ownedGeneration(owner: MiddlewareRegistrationOwner): number;
104
+ }
105
+
106
+ interface OwnerSlot {
107
+ generation: number;
108
+ registrations: ReadonlyArray<MiddlewareHookRegistration>;
109
+ /** Host index the slot sits before; fixed at the owner's first replacement. */
110
+ anchor: number;
111
+ }
112
+
113
+ /** One immutable table state. Replaced wholesale, never mutated. */
114
+ interface TableState {
115
+ host: ReadonlyArray<MiddlewareHookRegistration>;
116
+ hostIds: ReadonlySet<string>;
117
+ slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>;
118
+ list: ReadonlyArray<MiddlewareHookRegistration>;
119
+ }
120
+
121
+ export interface MiddlewareRegistrationTableOptions {
122
+ fixed: ReadonlyArray<MiddlewareHookRegistration>;
123
+ /** Resolved per emission so the composition root can swap the sink later. */
124
+ diagnosticSink: () => MiddlewareDiagnosticSink;
125
+ }
126
+
127
+ function isRegistrationOwner(value: string): value is MiddlewareRegistrationOwner {
128
+ return (MIDDLEWARE_REGISTRATION_OWNERS as ReadonlyArray<string>).includes(value);
129
+ }
130
+
131
+ export function createMiddlewareRegistrationTable(
132
+ options: MiddlewareRegistrationTableOptions,
133
+ ): MiddlewareRegistrationTable {
134
+ const fixed = Object.freeze([...options.fixed]);
135
+ const fixedIds = new Set(fixed.map((registration) => registration.id));
136
+
137
+ const buildList = (
138
+ host: ReadonlyArray<MiddlewareHookRegistration>,
139
+ slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>,
140
+ ): ReadonlyArray<MiddlewareHookRegistration> => {
141
+ const list: MiddlewareHookRegistration[] = [...fixed];
142
+ const slotAt = (index: number): void => {
143
+ for (const owner of MIDDLEWARE_REGISTRATION_OWNERS) {
144
+ const slot = slots.get(owner);
145
+ if (slot !== undefined && slot.anchor === index) list.push(...slot.registrations);
146
+ }
147
+ };
148
+ for (let index = 0; index < host.length; index += 1) {
149
+ slotAt(index);
150
+ list.push(host[index] as MiddlewareHookRegistration);
151
+ }
152
+ slotAt(host.length);
153
+ return Object.freeze(list);
154
+ };
155
+
156
+ const makeState = (
157
+ host: ReadonlyArray<MiddlewareHookRegistration>,
158
+ slots: ReadonlyMap<MiddlewareRegistrationOwner, OwnerSlot>,
159
+ ): TableState =>
160
+ Object.freeze({
161
+ host: Object.freeze([...host]),
162
+ hostIds: new Set(host.map((registration) => registration.id)),
163
+ slots: new Map(slots),
164
+ list: buildList(host, slots),
165
+ });
166
+
167
+ // The single live reference. Every publish below is `state = next`.
168
+ let state: TableState = makeState([], new Map());
169
+
170
+ const emit = (diagnostic: MiddlewareDiagnostic): void => {
171
+ try {
172
+ options.diagnosticSink()(diagnostic);
173
+ } catch {
174
+ // A diagnostics sink must never affect registration bookkeeping.
175
+ }
176
+ };
177
+
178
+ const slotFor = (base: TableState, owner: MiddlewareRegistrationOwner): OwnerSlot =>
179
+ base.slots.get(owner) ?? { generation: 0, registrations: [], anchor: base.host.length };
180
+
181
+ const disposeGeneration = (owner: MiddlewareRegistrationOwner, generation: number): void => {
182
+ const base = state;
183
+ const held = base.slots.get(owner);
184
+ if (held === undefined || held.generation !== generation || held.registrations.length === 0) return;
185
+ const slots = new Map(base.slots);
186
+ slots.set(owner, { ...held, registrations: Object.freeze([]) });
187
+ state = makeState(base.host, slots);
188
+ };
189
+
190
+ const table: MiddlewareRegistrationTable = {
191
+ list: () => state.list,
192
+ registerHook(registration) {
193
+ const base = state;
194
+ if (fixedIds.has(registration.id) || base.hostIds.has(registration.id)) return;
195
+ const evictions: RegistrationConflictDiagnostic[] = [];
196
+ const slots = new Map(base.slots);
197
+ for (const [owner, slot] of base.slots) {
198
+ if (!slot.registrations.some((entry) => entry.id === registration.id)) continue;
199
+ slots.set(owner, {
200
+ ...slot,
201
+ registrations: Object.freeze(slot.registrations.filter((entry) => entry.id !== registration.id)),
202
+ });
203
+ evictions.push({
204
+ kind: "registration_conflict",
205
+ registrationId: registration.id,
206
+ owner,
207
+ generation: slot.generation,
208
+ conflictsWith: "host",
209
+ action: "evicted",
210
+ });
211
+ }
212
+ state = makeState([...base.host, registration], slots);
213
+ // Diagnostics only after the publish; a sink that registers another
214
+ // host hook re-enters against the already-published state.
215
+ for (const eviction of evictions) emit(eviction);
216
+ },
217
+ prepareReplacement(owner, generation, registrations) {
218
+ if (!isRegistrationOwner(owner)) {
219
+ return { status: "rejected", owner, reason: "unknown-owner", activeGeneration: 0 };
220
+ }
221
+ const base = state;
222
+ const slot = slotFor(base, owner);
223
+ if (!Number.isInteger(generation) || generation <= slot.generation) {
224
+ return { status: "rejected", owner, reason: "stale", activeGeneration: slot.generation };
225
+ }
226
+ const dropped: MiddlewareRegistrationConflict[] = [];
227
+ const conflicts: RegistrationConflictDiagnostic[] = [];
228
+ const accepted: MiddlewareHookRegistration[] = [];
229
+ const seen = new Set<string>();
230
+ for (const registration of registrations) {
231
+ const conflictsWith: MiddlewareRegistrationConflictTier | null = fixedIds.has(registration.id)
232
+ ? "builtin"
233
+ : base.hostIds.has(registration.id)
234
+ ? "host"
235
+ : seen.has(registration.id)
236
+ ? "owned"
237
+ : null;
238
+ if (conflictsWith !== null) {
239
+ dropped.push({ id: registration.id, conflictsWith });
240
+ conflicts.push({
241
+ kind: "registration_conflict",
242
+ registrationId: registration.id,
243
+ owner,
244
+ generation,
245
+ conflictsWith,
246
+ action: "dropped",
247
+ });
248
+ continue;
249
+ }
250
+ seen.add(registration.id);
251
+ accepted.push(registration);
252
+ }
253
+ const slots = new Map(base.slots);
254
+ slots.set(owner, { generation, registrations: Object.freeze(accepted), anchor: slot.anchor });
255
+ const prepared = makeState(base.host, slots);
256
+ let settled = false;
257
+ const frozenDropped = Object.freeze(dropped);
258
+ const frozenConflicts = Object.freeze(conflicts);
259
+ const replacement: MiddlewareRegistrationReplacement = {
260
+ owner,
261
+ generation,
262
+ dropped: frozenDropped,
263
+ conflicts: frozenConflicts,
264
+ size: accepted.length,
265
+ // Reference identity on the base state covers every kind of
266
+ // intervening change: host appends, other replacements, disposals.
267
+ current: () => !settled && state === base,
268
+ publish() {
269
+ settled = true;
270
+ state = prepared;
271
+ },
272
+ emitConflicts() {
273
+ for (const conflict of frozenConflicts) emit(conflict);
274
+ },
275
+ dispose() {
276
+ disposeGeneration(owner, generation);
277
+ },
278
+ discard() {
279
+ settled = true;
280
+ },
281
+ };
282
+ return { status: "prepared", replacement };
283
+ },
284
+ replaceRegistrations(owner, generation, registrations) {
285
+ const prepared = table.prepareReplacement(owner, generation, registrations);
286
+ if (prepared.status === "rejected") {
287
+ return {
288
+ applied: false,
289
+ owner: prepared.owner,
290
+ activeGeneration: prepared.activeGeneration,
291
+ reason: prepared.reason,
292
+ dropped: [],
293
+ dispose: () => undefined,
294
+ };
295
+ }
296
+ const replacement = prepared.replacement;
297
+ // Nothing ran between prepare and here, so current() holds; the
298
+ // check is kept so the one-call form has the same shape as a caller
299
+ // that validates on its own stack.
300
+ if (!replacement.current()) {
301
+ replacement.discard();
302
+ return {
303
+ applied: false,
304
+ owner,
305
+ activeGeneration: table.ownedGeneration(owner),
306
+ reason: "stale",
307
+ dropped: replacement.dropped,
308
+ dispose: () => undefined,
309
+ };
310
+ }
311
+ replacement.publish();
312
+ replacement.emitConflicts();
313
+ return {
314
+ applied: true,
315
+ owner,
316
+ activeGeneration: generation,
317
+ dropped: replacement.dropped,
318
+ dispose: () => replacement.dispose(),
319
+ };
320
+ },
321
+ ownedGeneration(owner) {
322
+ return state.slots.get(owner)?.generation ?? 0;
323
+ },
324
+ };
325
+ return table;
326
+ }
@@ -1,4 +1,5 @@
1
1
  import { createHookBudgetTracker, type HookBudgetStats, type HookBudgetTracker } from "./budget.js";
2
+ import type { MiddlewareRegistrationConflictTier, MiddlewareRegistrationOwner } from "./registrations.js";
2
3
  import { listMiddlewareRuleDefinitions } from "./rules.js";
3
4
  import {
4
5
  MIDDLEWARE_HOOK_TEXT_MAX_CHARS,
@@ -90,6 +91,20 @@ export type MiddlewareDiagnostic =
90
91
  steadyStateWarn: boolean;
91
92
  /** Rolling-window stats (p50/p95/over-count) for diagnosis. */
92
93
  stats: HookBudgetStats;
94
+ }
95
+ | {
96
+ /**
97
+ * An owned registration set offered an id already held by a builtin
98
+ * rule or a host registration (dropped), or a later host registration
99
+ * took an id an owner held (evicted). Bookkeeping only; nothing was
100
+ * evaluated.
101
+ */
102
+ kind: "registration_conflict";
103
+ registrationId: string;
104
+ owner: MiddlewareRegistrationOwner;
105
+ generation: number;
106
+ conflictsWith: MiddlewareRegistrationConflictTier;
107
+ action: "dropped" | "evicted";
93
108
  };
94
109
 
95
110
  export type MiddlewareDiagnosticSink = (diagnostic: MiddlewareDiagnostic) => void;
@@ -106,6 +121,10 @@ export function writeMiddlewareDiagnosticToStderr(diagnostic: MiddlewareDiagnost
106
121
  );
107
122
  return;
108
123
  }
124
+ if (diagnostic.kind === "registration_conflict") {
125
+ process.stderr.write(`[clio-coder:middleware] ${formatRegistrationConflict(diagnostic)}\n`);
126
+ return;
127
+ }
109
128
  // A single post-warmup spike is telemetry, not operator-facing noise: only
110
129
  // consistent slowness prints, unless CLIO_CODER_HOOK_BUDGET_DEBUG=1 asks for all.
111
130
  if (!diagnostic.steadyStateWarn && process.env.CLIO_CODER_HOOK_BUDGET_DEBUG !== "1") return;
@@ -120,6 +139,15 @@ export function writeMiddlewareDiagnosticToStderr(diagnostic: MiddlewareDiagnost
120
139
  );
121
140
  }
122
141
 
142
+ /** One operator line for a registration_conflict diagnostic. */
143
+ export function formatRegistrationConflict(
144
+ diagnostic: Extract<MiddlewareDiagnostic, { kind: "registration_conflict" }>,
145
+ ): string {
146
+ return diagnostic.action === "dropped"
147
+ ? `${diagnostic.owner} registration '${diagnostic.registrationId}' (generation ${diagnostic.generation}) dropped: id is held by a ${diagnostic.conflictsWith} registration`
148
+ : `${diagnostic.owner} registration '${diagnostic.registrationId}' (generation ${diagnostic.generation}) evicted by a ${diagnostic.conflictsWith} registration with the same id`;
149
+ }
150
+
123
151
  /**
124
152
  * Wrap a declarative rule definition as a degenerate coded registration so a
125
153
  * single ordered evaluation path serves both. The wrapped `evaluate` keeps the