@iowarp/clio-coder 0.4.1 → 0.4.2

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 (437) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/CONTRIBUTING.md +59 -36
  3. package/README.md +404 -472
  4. package/SECURITY.md +2 -1
  5. package/dist/{acp-ZILU3AUO.js → acp-TMDQZDIG.js} +7 -7
  6. package/dist/{agents-HYWGBGQR.js → agents-5N5NG3XG.js} +28 -28
  7. package/dist/assets/codewiki.json +1 -1
  8. package/dist/{auth-N3QT7CBO.js → auth-Z5CCBXKQ.js} +8 -9
  9. package/dist/{builtins-UJLMOVOV.js → builtins-K6TNDT24.js} +4 -4
  10. package/dist/{chunk-GVQJ5CCZ.js → chunk-2HFQNRV3.js} +7 -7
  11. package/dist/{chunk-QMXC4JB7.js → chunk-2NHR3NAY.js} +163 -1401
  12. package/dist/chunk-2X4RYJTJ.js +39 -0
  13. package/dist/{chunk-Y45G3AXC.js → chunk-2Z2IKEXI.js} +6 -10
  14. package/dist/{chunk-EIMVLWB3.js → chunk-34BHNEE3.js} +7 -3
  15. package/dist/{chunk-GIZNH63R.js → chunk-35MSIRKH.js} +9 -4
  16. package/dist/chunk-3EBYEESD.js +314 -0
  17. package/dist/{chunk-CTJ4RNAA.js → chunk-3F7VUY77.js} +2 -2
  18. package/dist/{chunk-AP73CFDC.js → chunk-3KIPBMUA.js} +2 -2
  19. package/dist/{chunk-J5LZHVIT.js → chunk-3M6DQK6S.js} +113 -35
  20. package/dist/{chunk-VEGN6WIQ.js → chunk-462T4EGZ.js} +2 -2
  21. package/dist/{chunk-AFKWHWXF.js → chunk-4JDLP6ZS.js} +33 -16
  22. package/dist/{chunk-6FN3E6KX.js → chunk-4O6MANBS.js} +2 -2
  23. package/dist/{chunk-AKB4GYDL.js → chunk-54ODD65L.js} +5 -5
  24. package/dist/{chunk-BBTJOK6Y.js → chunk-5KW52TEP.js} +3 -3
  25. package/dist/{chunk-6CCS4G3W.js → chunk-5PFYMY2V.js} +2 -2
  26. package/dist/chunk-77QIVUZB.js +1334 -0
  27. package/dist/{chunk-7OBGU7UB.js → chunk-7BHIY2MW.js} +7 -13
  28. package/dist/{chunk-3QSOM6PA.js → chunk-AZ4WMN4W.js} +2 -2
  29. package/dist/{chunk-6NJQITNH.js → chunk-B74PXLU7.js} +6 -3
  30. package/dist/{chunk-R23Z6K6I.js → chunk-B7HM5Z7T.js} +15 -15
  31. package/dist/{chunk-R32CLGZ6.js → chunk-BO7Y52RY.js} +81 -20
  32. package/dist/{chunk-UEDMSP56.js → chunk-BYMNWQ7O.js} +123 -148
  33. package/dist/{chunk-ZJLUDYFY.js → chunk-CRFOIAX3.js} +4 -4
  34. package/dist/{chunk-2NM363SV.js → chunk-CYZW7JHJ.js} +7 -7
  35. package/dist/{chunk-6HMJX2VU.js → chunk-DYHAXKHD.js} +38 -10
  36. package/dist/{chunk-THYWACCR.js → chunk-DZAW46HP.js} +3 -3
  37. package/dist/{chunk-FYUN5KZ3.js → chunk-DZEK6CJN.js} +17 -17
  38. package/dist/{chunk-3I5NY75V.js → chunk-E7GT7O5N.js} +5 -5
  39. package/dist/{chunk-VKFQTNDV.js → chunk-F2I26BDK.js} +4 -4
  40. package/dist/{chunk-HLW2MRKE.js → chunk-F4EKGO4N.js} +3 -1
  41. package/dist/{chunk-IXJT6DCX.js → chunk-FVDGR2ZL.js} +3 -3
  42. package/dist/{chunk-TZSKNMZG.js → chunk-GTUD2WMY.js} +2 -1
  43. package/dist/{chunk-7EPLI7VL.js → chunk-HIICAHCJ.js} +2 -2
  44. package/dist/{chunk-E67WX76H.js → chunk-HKMD33FO.js} +29 -80
  45. package/dist/chunk-HLAFFSEK.js +360 -0
  46. package/dist/{chunk-UAPGZHYC.js → chunk-I64IFBLB.js} +9 -2
  47. package/dist/{chunk-XKA2ICR3.js → chunk-I66ZTYNP.js} +440 -175
  48. package/dist/{chunk-7PWAODYW.js → chunk-I7XBWTYH.js} +2 -2
  49. package/dist/{chunk-PVAMAVBB.js → chunk-IDNA72AH.js} +102 -2
  50. package/dist/{chunk-GCSMB2KY.js → chunk-IKOZFYBN.js} +1 -1
  51. package/dist/{chunk-2VG7KLYV.js → chunk-IKSLQ4XV.js} +5460 -3241
  52. package/dist/{chunk-QKIFBZKT.js → chunk-IMXMHHMQ.js} +166 -25
  53. package/dist/{chunk-74YWRRU5.js → chunk-JBCS7CRR.js} +2 -2
  54. package/dist/{chunk-BDPT6GTK.js → chunk-JWJGP5DQ.js} +2 -2
  55. package/dist/{chunk-K6BF4U2H.js → chunk-KKOJXO6R.js} +62 -14
  56. package/dist/chunk-KPXDY6QF.js +47 -0
  57. package/dist/{chunk-ABLSQ6JX.js → chunk-LJID3DYZ.js} +7 -1
  58. package/dist/{chunk-VKRH2TCS.js → chunk-M2DAX4F6.js} +2 -2
  59. package/dist/{chunk-6I5ILFOF.js → chunk-M2WXEHER.js} +2 -2
  60. package/dist/{chunk-YPI3QQCF.js → chunk-MCEPRMZW.js} +2 -4
  61. package/dist/{chunk-N5UK64DP.js → chunk-MCMZMDAC.js} +2 -2
  62. package/dist/{chunk-Y4CAGMM6.js → chunk-MNJGS2IN.js} +5 -6
  63. package/dist/{chunk-TVHHYFHE.js → chunk-NEDJ26B5.js} +2 -2
  64. package/dist/{chunk-U2WB7TZS.js → chunk-NMJXSHBJ.js} +97 -85
  65. package/dist/{chunk-HUAS7ITX.js → chunk-O3YUNJZ2.js} +13 -21
  66. package/dist/{chunk-MA3H6DM5.js → chunk-P75RZCJW.js} +25 -3
  67. package/dist/{chunk-IG7BCQBA.js → chunk-PGF63K6I.js} +2 -2
  68. package/dist/chunk-PJX3WQUQ.js +42 -0
  69. package/dist/{chunk-6DWBAZ5U.js → chunk-Q4XWMHX6.js} +4 -6
  70. package/dist/{chunk-OJTRZGR3.js → chunk-QQLGQY2A.js} +8 -8
  71. package/dist/{chunk-J4HBWF6Y.js → chunk-RLYRBIYQ.js} +115 -20
  72. package/dist/{chunk-NLFAQR7Z.js → chunk-S66XZJOF.js} +3 -23
  73. package/dist/{chunk-C537JADH.js → chunk-SSEYRH53.js} +6 -7
  74. package/dist/chunk-SZAA6XDG.js +30 -0
  75. package/dist/{chunk-MOPSG2X7.js → chunk-TPEQIQIE.js} +6 -6
  76. package/dist/{chunk-JA5QWE4Z.js → chunk-UBRFI4HS.js} +1879 -1650
  77. package/dist/{chunk-BTGG6BG2.js → chunk-UH347SHR.js} +154 -15
  78. package/dist/{chunk-5YHDIDBP.js → chunk-UH632ZYL.js} +2 -2
  79. package/dist/{chunk-BWW4HLO4.js → chunk-UXCU4E3T.js} +8 -6
  80. package/dist/{chunk-6VC4OV3Z.js → chunk-VIA6RFQZ.js} +3 -11
  81. package/dist/{chunk-ZAZB4JMW.js → chunk-VKPAQYEB.js} +27 -8
  82. package/dist/{chunk-UXN6JT4W.js → chunk-W4YEMFBX.js} +2 -2
  83. package/dist/{chunk-TD3PGPQA.js → chunk-W6NIE6OW.js} +2 -2
  84. package/dist/{chunk-TVH4ONAM.js → chunk-X7IARSHT.js} +3 -3
  85. package/dist/{chunk-PJJ6MY27.js → chunk-XE3PCIXH.js} +3 -3
  86. package/dist/{chunk-FEFIFZTL.js → chunk-XGDPUNND.js} +2 -2
  87. package/dist/{chunk-SCYB3HA4.js → chunk-XOXV5GKE.js} +51 -16
  88. package/dist/{chunk-QTFGO774.js → chunk-XQRY4DTA.js} +24 -11
  89. package/dist/{chunk-BJGUKIG4.js → chunk-YJISEZKC.js} +2 -2
  90. package/dist/{chunk-GPPB3JBE.js → chunk-ZGNYYXQ6.js} +2 -2
  91. package/dist/{chunk-SINK3QR6.js → chunk-ZNT2M6TG.js} +7 -7
  92. package/dist/{chunk-7RY5VZPH.js → chunk-ZW4HH5JJ.js} +6 -6
  93. package/dist/cli/index.js +33 -32
  94. package/dist/{clio-IT3G3VQH.js → clio-7VB377CC.js} +7 -7
  95. package/dist/{code-nav-RK6S7F6E.js → code-nav-YVLCYA7V.js} +85 -17
  96. package/dist/{config-3QZRWZJF.js → config-4HVOS65E.js} +88 -43
  97. package/dist/{configure-FL7Y3KJF.js → configure-PIWO7B24.js} +10 -10
  98. package/dist/{context-5HE7ODYK.js → context-IYEHL3WQ.js} +33 -31
  99. package/dist/{context-XNHL75JV.js → context-KQYIWPWT.js} +47 -34
  100. package/dist/{context-KYQFRVDC.js → context-N6ZE3LGJ.js} +11 -11
  101. package/dist/{context-clear-N545L53A.js → context-clear-G4OGZJDS.js} +33 -31
  102. package/dist/{context-working-set-QHKXSV2F.js → context-working-set-BWLF6LJP.js} +7 -7
  103. package/dist/{dispatch-runner-RGIE5PCT.js → dispatch-runner-2QQAITS3.js} +38 -38
  104. package/dist/{docs-5NAF6AU7.js → docs-PD3EXDKU.js} +21 -20
  105. package/dist/{doctor-ZGPEGHIP.js → doctor-LHBD36VU.js} +23 -22
  106. package/dist/{eval-GXLL44RD.js → eval-C45FYRJ6.js} +21 -20
  107. package/dist/{eval-inventory-HBWSWQOK.js → eval-inventory-6DEJPLBF.js} +2 -2
  108. package/dist/{evidence-HWLBRH3Q.js → evidence-6SHONYAF.js} +30 -28
  109. package/dist/{evolve-FTZBMNVW.js → evolve-KRKMV72X.js} +30 -28
  110. package/dist/{extensions-VHRBEID7.js → extensions-KPZ2UHBB.js} +5 -3
  111. package/dist/{fleet-CKZHJWZJ.js → fleet-IVTCKDHT.js} +62 -61
  112. package/dist/{fleet-commands-EXDXBMV6.js → fleet-commands-EDWL3IT7.js} +5 -5
  113. package/dist/{fleet-decisions-OTHB6KRL.js → fleet-decisions-YP3YEFGK.js} +4 -4
  114. package/dist/{fleet-graph-YTEZUCUT.js → fleet-graph-ZFWKHY2M.js} +16 -14
  115. package/dist/{fleet-inspect-SS6YMDCK.js → fleet-inspect-FVUNCBML.js} +31 -29
  116. package/dist/{fleet-preflight-PBY4VYOM.js → fleet-preflight-UN5XED4R.js} +2 -2
  117. package/dist/{fleet-validate-KMEM5L3S.js → fleet-validate-XOWC4HSX.js} +17 -15
  118. package/dist/{fleet-verify-QD5M7E7Q.js → fleet-verify-UN3SODEL.js} +30 -28
  119. package/dist/{fleet-view-WAMJYNDT.js → fleet-view-TWHJKCN6.js} +31 -29
  120. package/dist/{init-5XQRBOFV.js → init-T2QORQ3Y.js} +50 -49
  121. package/dist/{interop-34TVO25M.js → interop-IN5I2A66.js} +5 -5
  122. package/dist/{library-3QY6KF57.js → library-LSCATDLZ.js} +15 -13
  123. package/dist/{memory-L4UTIIIW.js → memory-HYOKAGGJ.js} +31 -29
  124. package/dist/{models-ZVX3QOWE.js → models-2GPMFYCM.js} +22 -21
  125. package/dist/{monitor-CEKVSYTS.js → monitor-E4ASVUJH.js} +34 -32
  126. package/dist/{orchestrator-77BAP6BC.js → orchestrator-DDMPR3PY.js} +984 -583
  127. package/dist/{panes-7STHOAUJ.js → panes-E3RUXOW5.js} +4 -4
  128. package/dist/{panes-SHAUIRXY.js → panes-IXKLOKA2.js} +23 -8
  129. package/dist/{reset-EOLM7GVE.js → reset-OAQP3W4O.js} +4 -4
  130. package/dist/{resources-74GKTLSF.js → resources-OTRSN34L.js} +15 -13
  131. package/dist/{run-HBAUJNNZ.js → run-5DEYH5QK.js} +60 -59
  132. package/dist/{share-G3APVLVP.js → share-IHWTLO3M.js} +19 -15
  133. package/dist/{skills-35HHUKCR.js → skills-IYMXMKW4.js} +17 -15
  134. package/dist/{skills-eval-QN4HSHDC.js → skills-eval-DROHSJAR.js} +36 -36
  135. package/dist/{skills-inventory-J357J34F.js → skills-inventory-D7X4L4ZX.js} +15 -13
  136. package/dist/{slash-commands-JZZCQA32.js → slash-commands-QBM7UZ3B.js} +21 -18
  137. package/dist/{steer-XAVHJM22.js → steer-Z5DO23FJ.js} +2 -2
  138. package/dist/{targets-DSM6CY3M.js → targets-P2FUC4IL.js} +25 -28
  139. package/dist/{terminal-lease-JOPFUVEM.js → terminal-lease-YREJ3JX2.js} +5 -5
  140. package/dist/{tools-MKNWVPBH.js → tools-5B7RO6MV.js} +4 -4
  141. package/dist/{trace-ECQ7TIYZ.js → trace-YMGMUM6A.js} +55 -7
  142. package/dist/{upgrade-H7TOM7YL.js → upgrade-PXK3S2YM.js} +11 -9
  143. package/dist/{usage-X52N3IDJ.js → usage-ME5MPXGX.js} +36 -34
  144. package/dist/{verifiers-EJTVVSMA.js → verifiers-BVZ7IWOO.js} +5 -5
  145. package/dist/{verify-YJL6XET2.js → verify-5K7ZKQFC.js} +4 -4
  146. package/dist/{web-fetch-MPIFL3LL.js → web-fetch-MPARV2K7.js} +2 -2
  147. package/dist/{wiki-generate-4NDZTQ4B.js → wiki-generate-F5W5QTYY.js} +48 -47
  148. package/dist/{with-panes-OBOBFIIR.js → with-panes-BYOJCLAM.js} +51 -255
  149. package/dist/worker/entry.js +45 -30
  150. package/docs/README.md +176 -81
  151. package/docs/{acp.md → architecture/acp.md} +36 -20
  152. package/docs/{alcf-provider.md → architecture/alcf-provider.md} +8 -5
  153. package/docs/{architecture.md → architecture/architecture.md} +43 -22
  154. package/docs/{artifact-placement.md → architecture/artifact-placement.md} +26 -23
  155. package/docs/architecture/artifact-versions.md +90 -0
  156. package/docs/{capacity-and-scheduling.md → architecture/capacity-and-scheduling.md} +26 -13
  157. package/docs/{context-engine.md → architecture/context-engine.md} +25 -25
  158. package/docs/{context-working-set.md → architecture/context-working-set.md} +13 -10
  159. package/docs/{dispatch-architecture-rationale.md → architecture/dispatch-architecture-rationale.md} +12 -9
  160. package/docs/{dispatch-typed-intent.md → architecture/dispatch-typed-intent.md} +68 -46
  161. package/docs/{evidence-and-memory.md → architecture/evidence-and-memory.md} +23 -16
  162. package/docs/{middleware-and-components.md → architecture/middleware-and-components.md} +11 -5
  163. package/docs/{model-catalog.md → architecture/model-catalog.md} +40 -17
  164. package/docs/{observability.md → architecture/observability.md} +26 -13
  165. package/docs/{pi-boundary.md → architecture/pi-boundary.md} +24 -11
  166. package/docs/{prompt-envelope-and-tools.md → architecture/prompt-envelope-and-tools.md} +55 -20
  167. package/docs/{provider-adapter-cookbook.md → architecture/provider-adapter-cookbook.md} +35 -24
  168. package/docs/{safety-model.md → architecture/safety-model.md} +20 -15
  169. package/docs/{session-lifecycle.md → architecture/session-lifecycle.md} +8 -5
  170. package/docs/architecture/time-conventions.md +125 -0
  171. package/docs/{trace-store.md → architecture/trace-store.md} +13 -5
  172. package/docs/{tui-design.md → architecture/tui-design.md} +13 -13
  173. package/docs/{worker-dispatch-mechanics.md → architecture/worker-dispatch-mechanics.md} +27 -30
  174. package/docs/{built-in-agents.md → guide/built-in-agents.md} +50 -34
  175. package/docs/{commands-and-modes.md → guide/commands-and-modes.md} +65 -60
  176. package/docs/{configuration-and-targets.md → guide/configuration-and-targets.md} +227 -289
  177. package/docs/guide/configuration-reference.md +1158 -0
  178. package/docs/{environment-variables.md → guide/environment-variables.md} +31 -28
  179. package/docs/{exit-codes-and-output.md → guide/exit-codes-and-output.md} +6 -3
  180. package/docs/{extensions-and-sharing.md → guide/extensions-and-sharing.md} +41 -14
  181. package/docs/{fleet-dispatch.md → guide/fleet-dispatch.md} +39 -43
  182. package/docs/{glossary.md → guide/glossary.md} +14 -11
  183. package/docs/{installation-and-lifecycle.md → guide/installation-and-lifecycle.md} +44 -13
  184. package/docs/guide/panes-and-files.md +290 -0
  185. package/docs/{proactive-memory.md → guide/proactive-memory.md} +79 -66
  186. package/docs/{resource-library.md → guide/resource-library.md} +13 -4
  187. package/docs/{skills-marketplace.md → guide/skills-marketplace.md} +7 -3
  188. package/docs/{tool-usage.md → guide/tool-usage.md} +87 -23
  189. package/docs/{troubleshooting.md → guide/troubleshooting.md} +9 -4
  190. package/docs/{config-knobs-audit.md → history/config-knobs-audit.md} +11 -11
  191. package/docs/{release-cut-checklist.md → history/release-cut-checklist.md} +29 -2
  192. package/docs/{development-pipeline.md → process/development-pipeline.md} +24 -26
  193. package/docs/process/documentation-coverage.md +100 -0
  194. package/docs/process/documentation-guide.md +187 -0
  195. package/docs/{eval-runner.md → process/eval-runner.md} +41 -50
  196. package/docs/{evals-internal.md → process/evals-internal.md} +10 -10
  197. package/docs/{evolution.md → process/evolution.md} +2 -2
  198. package/docs/{fleet-demo-runbook.md → process/fleet-demo-runbook.md} +11 -7
  199. package/docs/{git-commit-provenance.md → process/git-commit-provenance.md} +11 -4
  200. package/docs/{performance-methodology.md → process/performance-methodology.md} +87 -69
  201. package/docs/{scientific-validation.md → process/scientific-validation.md} +4 -4
  202. package/evals/README.md +2 -2
  203. package/package.json +9 -7
  204. package/skills/README.md +46 -37
  205. package/skills/coding/ast-grep/SKILL.md +2 -2
  206. package/skills/coding/coding-standards/SKILL.md +2 -2
  207. package/skills/coding/prototype/SKILL.md +2 -2
  208. package/skills/coding/tdd/SKILL.md +2 -2
  209. package/skills/context/context-handoff/SKILL.md +2 -2
  210. package/skills/context/context-prime/SKILL.md +2 -2
  211. package/skills/git/file-ticket/SKILL.md +2 -2
  212. package/skills/git/fix-issue/SKILL.md +3 -3
  213. package/skills/git/resolve-merge-conflicts/SKILL.md +2 -2
  214. package/skills/git/ship/SKILL.md +2 -2
  215. package/skills/git/worktree-create/SKILL.md +2 -2
  216. package/skills/git/worktree-merge/SKILL.md +2 -2
  217. package/skills/meta/clio-coder-dev/SKILL.md +9 -5
  218. package/skills/meta/clio-coder-dev/evals.md +3 -2
  219. package/skills/meta/clio-coder-test/SKILL.md +102 -95
  220. package/skills/meta/clio-coder-test/evals.md +9 -4
  221. package/skills/meta/clio-coder-test/references/harness.md +100 -124
  222. package/skills/meta/clio-coder-test/references/test-map.md +77 -50
  223. package/skills/meta/credentials/SKILL.md +2 -2
  224. package/skills/meta/find-skills/SKILL.md +2 -2
  225. package/skills/meta/herdr/SKILL.md +2 -2
  226. package/skills/meta/skill-craft/SKILL.md +22 -16
  227. package/skills/planning/architecture/SKILL.md +2 -2
  228. package/skills/planning/backlog/SKILL.md +2 -2
  229. package/skills/planning/prd/SKILL.md +2 -2
  230. package/skills/planning/product-intent/SKILL.md +2 -2
  231. package/skills/planning/tech-spec/SKILL.md +2 -2
  232. package/skills/registry.yaml +62 -62
  233. package/skills/research/arxiv-literature/SKILL.md +2 -2
  234. package/skills/research/experiment-protocol/SKILL.md +2 -2
  235. package/skills/research/scientific-debugging/SKILL.md +2 -2
  236. package/skills/research/scientific-modernization/SKILL.md +2 -2
  237. package/skills/skill-marketplace.json +62 -62
  238. package/skills/workflow/cut-it/SKILL.md +2 -2
  239. package/skills/workflow/design-council/SKILL.md +2 -2
  240. package/skills/workflow/grill-me/SKILL.md +2 -2
  241. package/skills/workflow/workflow-distiller/SKILL.md +2 -2
  242. package/src/cli/args.ts +2 -2
  243. package/src/cli/bootstrap-generate.ts +1 -1
  244. package/src/cli/config-inspect.ts +65 -12
  245. package/src/cli/configure.ts +0 -4
  246. package/src/cli/docs.ts +22 -14
  247. package/src/cli/doctor-naming.ts +5 -5
  248. package/src/cli/doctor-toolchain.ts +3 -3
  249. package/src/cli/eval.ts +1 -2
  250. package/src/cli/extensions.ts +2 -1
  251. package/src/cli/fleet.ts +1 -1
  252. package/src/cli/index.ts +2 -1
  253. package/src/cli/internal-dispatch.ts +3 -4
  254. package/src/cli/panes.ts +19 -5
  255. package/src/cli/run.ts +2 -2
  256. package/src/cli/share.ts +5 -1
  257. package/src/cli/skills-eval.ts +3 -3
  258. package/src/cli/targets.ts +2 -6
  259. package/src/cli/trace.ts +55 -4
  260. package/src/cli/wiki-generate.ts +1 -1
  261. package/src/core/artifact-paths.ts +1 -1
  262. package/src/core/bash-exec.ts +131 -86
  263. package/src/core/bus-events.ts +51 -6
  264. package/src/core/config.ts +5 -1
  265. package/src/core/defaults.ts +7 -4
  266. package/src/core/dispatch-outcome.ts +16 -0
  267. package/src/core/guardrails.ts +10 -49
  268. package/src/core/prompt-hint.ts +9 -0
  269. package/src/domains/agents/builtins/architect.md +2 -3
  270. package/src/domains/agents/builtins/coder.md +3 -2
  271. package/src/domains/agents/builtins/debugger.md +2 -2
  272. package/src/domains/agents/builtins/documenter.md +2 -2
  273. package/src/domains/agents/builtins/git-master.md +1 -1
  274. package/src/domains/agents/builtins/oracle.md +1 -1
  275. package/src/domains/agents/builtins/provenance.md +1 -1
  276. package/src/domains/agents/builtins/researcher.md +1 -1
  277. package/src/domains/agents/builtins/scout.md +1 -1
  278. package/src/domains/agents/builtins/tester.md +2 -2
  279. package/src/domains/agents/builtins/verifier.md +2 -2
  280. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  281. package/src/domains/agents/catalog.ts +12 -14
  282. package/src/domains/agents/contract.ts +2 -0
  283. package/src/domains/agents/extension.ts +23 -1
  284. package/src/domains/config/keybindings.ts +8 -0
  285. package/src/domains/context/extension.ts +0 -3
  286. package/src/domains/context/working-set/path-index.ts +1 -0
  287. package/src/domains/dispatch/capability-match.ts +10 -0
  288. package/src/domains/dispatch/extension.ts +105 -22
  289. package/src/domains/dispatch/host-verification.ts +435 -39
  290. package/src/domains/dispatch/intent-requirements.ts +10 -0
  291. package/src/domains/dispatch/intent.ts +18 -1
  292. package/src/domains/dispatch/path-scope.ts +235 -24
  293. package/src/domains/dispatch/run-event-journal.ts +4 -15
  294. package/src/domains/dispatch/state.ts +2 -3
  295. package/src/domains/dispatch/transport.ts +45 -21
  296. package/src/domains/dispatch/types.ts +55 -3
  297. package/src/domains/eval/artifacts/store.ts +5 -0
  298. package/src/domains/eval/store.ts +8 -1
  299. package/src/domains/evidence/trust-status.ts +10 -1
  300. package/src/domains/extensions/contract.ts +15 -1
  301. package/src/domains/extensions/discovery.ts +238 -41
  302. package/src/domains/extensions/extension.ts +105 -6
  303. package/src/domains/extensions/index.ts +24 -0
  304. package/src/domains/extensions/integrity.ts +189 -0
  305. package/src/domains/extensions/manager.ts +17 -1
  306. package/src/domains/extensions/resource-path.ts +27 -0
  307. package/src/domains/extensions/resources.ts +18 -38
  308. package/src/domains/extensions/snapshot-store.ts +39 -0
  309. package/src/domains/extensions/snapshot.ts +180 -0
  310. package/src/domains/extensions/state.ts +385 -57
  311. package/src/domains/extensions/types.ts +118 -1
  312. package/src/domains/lifecycle/migrations/2026-09-01-extension-install-digests.ts +27 -0
  313. package/src/domains/lifecycle/migrations/index.ts +2 -0
  314. package/src/domains/lifecycle/naming-resources.ts +19 -4
  315. package/src/domains/lifecycle/naming-yazi.ts +10 -5
  316. package/src/domains/middleware/contract.ts +26 -0
  317. package/src/domains/middleware/extension.ts +24 -24
  318. package/src/domains/middleware/hook-receipts.ts +27 -4
  319. package/src/domains/middleware/hooks-io.ts +65 -32
  320. package/src/domains/middleware/hooks.ts +64 -0
  321. package/src/domains/middleware/index.ts +28 -4
  322. package/src/domains/middleware/registrations.ts +326 -0
  323. package/src/domains/middleware/runtime.ts +28 -0
  324. package/src/domains/middleware/snapshot.ts +20 -7
  325. package/src/domains/mux/contract.ts +38 -0
  326. package/src/domains/mux/detect.ts +6 -13
  327. package/src/domains/mux/index.ts +1 -1
  328. package/src/domains/mux/operations.ts +44 -5
  329. package/src/domains/mux/yazi/assets/yazi.toml +2 -2
  330. package/src/domains/mux/yazi/session.ts +53 -4
  331. package/src/domains/mux/yazi/theme.ts +117 -17
  332. package/src/domains/observability/contract.ts +10 -11
  333. package/src/domains/observability/extension.ts +11 -3
  334. package/src/domains/observability/projection.ts +14 -90
  335. package/src/domains/observability/trace-store.ts +43 -7
  336. package/src/domains/prompts/compiler.ts +73 -53
  337. package/src/domains/prompts/contract.ts +15 -3
  338. package/src/domains/prompts/extension.ts +97 -9
  339. package/src/domains/prompts/fragments/identity/clio-worker.md +1 -3
  340. package/src/domains/prompts/fragments/identity/clio.md +6 -12
  341. package/src/domains/prompts/fragments/identity/docs-routing.md +1 -2
  342. package/src/domains/prompts/fragments/identity/self-awareness.md +3 -11
  343. package/src/domains/prompts/fragments/operating/contract.md +7 -15
  344. package/src/domains/prompts/fragments/operating/delegation.md +32 -34
  345. package/src/domains/prompts/fragments/operating/skills.md +10 -24
  346. package/src/domains/prompts/fragments/operating/worker.md +1 -8
  347. package/src/domains/providers/index.ts +1 -1
  348. package/src/domains/providers/model-runtime-capabilities.ts +85 -21
  349. package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +669 -104
  350. package/src/domains/providers/runtime-resolution.ts +31 -0
  351. package/src/domains/providers/runtimes/common/probe-helpers.ts +7 -2
  352. package/src/domains/providers/runtimes/local-native/llamacpp.ts +9 -1
  353. package/src/domains/providers/types/cost-provenance.ts +19 -0
  354. package/src/domains/providers/types/local-model-quirks.ts +85 -37
  355. package/src/domains/resources/skills/loader.ts +16 -19
  356. package/src/domains/safety/call-target.ts +1 -1
  357. package/src/domains/safety/loop-detector.ts +7 -4
  358. package/src/domains/session/task-board.ts +10 -9
  359. package/src/domains/share/archive.ts +164 -7
  360. package/src/engine/acp/server.ts +62 -9
  361. package/src/engine/apis/llamacpp-residency.ts +3 -4
  362. package/src/engine/apis/lmstudio.ts +3 -3
  363. package/src/engine/apis/ollama-native.ts +6 -6
  364. package/src/engine/apis/openai-completions.ts +28 -25
  365. package/src/engine/apis/output-budget.ts +8 -18
  366. package/src/engine/apis/residency.ts +8 -27
  367. package/src/engine/gemma-channel-filter.ts +19 -0
  368. package/src/engine/loop-guard.ts +92 -12
  369. package/src/engine/worker-runtime.ts +40 -11
  370. package/src/engine/worker-tools.ts +3 -1
  371. package/src/entry/extension-hook-sources.ts +28 -0
  372. package/src/entry/extension-reload.ts +309 -0
  373. package/src/entry/orchestrator.ts +59 -35
  374. package/src/interactive/application-controller.ts +2 -1
  375. package/src/interactive/bus-notices.ts +8 -1
  376. package/src/interactive/chat-loop-messages.ts +3 -13
  377. package/src/interactive/chat-loop.ts +10 -1
  378. package/src/interactive/chat-panel.ts +36 -13
  379. package/src/interactive/chat-renderer.ts +71 -7
  380. package/src/interactive/dispatch-board.ts +6 -11
  381. package/src/interactive/footer/widgets.ts +13 -0
  382. package/src/interactive/interactive-application.ts +39 -4
  383. package/src/interactive/interactive-input-runtime.ts +4 -0
  384. package/src/interactive/interactive-presentation.ts +2 -2
  385. package/src/interactive/interactive-slash-runtime.ts +2 -0
  386. package/src/interactive/overlays/extensions.ts +9 -1
  387. package/src/interactive/overlays/help-reference.ts +13 -0
  388. package/src/interactive/overlays/settings.ts +27 -16
  389. package/src/interactive/panes-runtime.ts +111 -35
  390. package/src/interactive/prompt-cache-identity.ts +88 -0
  391. package/src/interactive/slash-commands.ts +129 -14
  392. package/src/interactive/stream-pacing-policy.ts +0 -23
  393. package/src/interactive/turn-context.ts +30 -15
  394. package/src/interactive/yazi-bridge.ts +60 -6
  395. package/src/tools/agent-tools.ts +30 -1
  396. package/src/tools/artifact.ts +2 -2
  397. package/src/tools/ask-user.ts +3 -3
  398. package/src/tools/bash.ts +1 -1
  399. package/src/tools/bootstrap.ts +4 -0
  400. package/src/tools/builtin-tool-catalog.ts +52 -22
  401. package/src/tools/codewiki/code-nav-surface.ts +6 -0
  402. package/src/tools/codewiki/code-nav.ts +99 -13
  403. package/src/tools/context/docs-engine.ts +20 -7
  404. package/src/tools/context/index.ts +29 -12
  405. package/src/tools/core-bootstrap.ts +28 -6
  406. package/src/tools/credential-present.ts +1 -2
  407. package/src/tools/dispatch-arguments.ts +5 -1
  408. package/src/tools/dispatch-plan.ts +48 -4
  409. package/src/tools/dispatch-run-events.ts +1 -1
  410. package/src/tools/dispatch-schema.ts +338 -0
  411. package/src/tools/dispatch-types.ts +3 -0
  412. package/src/tools/dispatch.ts +9 -254
  413. package/src/tools/ledger.ts +3 -5
  414. package/src/tools/monitor-surface.ts +5 -13
  415. package/src/tools/observation.ts +4 -5
  416. package/src/tools/panes-surface.ts +4 -11
  417. package/src/tools/panes.ts +4 -2
  418. package/src/tools/policy.ts +15 -2
  419. package/src/tools/read.ts +5 -6
  420. package/src/tools/registry.ts +30 -7
  421. package/src/tools/result-shaping.ts +18 -14
  422. package/src/tools/steer-surface.ts +1 -1
  423. package/src/tools/tasks.ts +1 -1
  424. package/src/tools/truncate.ts +6 -5
  425. package/src/tools/verify/surface.ts +6 -12
  426. package/src/tools/web-fetch-surface.ts +1 -3
  427. package/dist/chunk-5QIAJV2D.js +0 -48
  428. package/dist/chunk-JZWT5J3Y.js +0 -814
  429. package/dist/chunk-K7VKOLQQ.js +0 -15
  430. package/dist/chunk-PMZCIOCJ.js +0 -25
  431. package/dist/chunk-SUW5DORT.js +0 -819
  432. package/dist/chunk-UOV2BYIW.js +0 -107
  433. package/dist/chunk-WR6U3OVP.js +0 -45
  434. package/docs/artifact-versions.md +0 -67
  435. package/docs/documentation-coverage.md +0 -46
  436. package/docs/documentation-guide.md +0 -167
  437. package/docs/time-conventions.md +0 -101
@@ -51,12 +51,47 @@ export const USER_HOOK_COMMAND_OUTPUT_MAX_CHARS = 4_000;
51
51
  /** Cap on a prompt hook's injected message, in characters. */
52
52
  export const USER_HOOK_PROMPT_MAX_CHARS = 2_000;
53
53
 
54
+ /**
55
+ * Provenance of an installed package that supplied hook declarations, as the
56
+ * composition root attributes it. Middleware treats it as opaque identity
57
+ * data; it neither reads packages nor knows how the digests were produced.
58
+ */
59
+ export interface UserHookPackageProvenance {
60
+ id: string;
61
+ /** Install scope label of the package (for example "user" or "project"). */
62
+ scope: string;
63
+ /** Path recorded at install, when known. */
64
+ sourcePath?: string;
65
+ /** Canonical filesystem identity of the installed package root. */
66
+ canonicalRoot: string;
67
+ /** SHA-256 of the manifest bytes covered by the installed-tree digest. */
68
+ manifestDigest: string;
69
+ /** Installed-tree digest recorded at install and reverified by the supplier. */
70
+ contentDigest: string;
71
+ }
72
+
73
+ /**
74
+ * Attribution for a hook declared by an installed package. The declaration
75
+ * bytes behind `declarationsDigest` are the ones the supplier hashed during
76
+ * content verification and captured; nothing here was re-read from a mutable
77
+ * path after verification.
78
+ */
79
+ export interface UserHookExtensionSource {
80
+ provenance: UserHookPackageProvenance;
81
+ /** Generation the declarations were admitted under; 0 for an ephemeral build. */
82
+ generation: number;
83
+ /** SHA-256 of the captured hooks.yaml bytes. */
84
+ declarationsDigest: string;
85
+ }
86
+
54
87
  export interface UserHookSource {
55
88
  origin: UserHookOrigin;
56
89
  /** File path or `extensionId:path` the declaration was read from. */
57
90
  sourcePath: string;
58
91
  /** Extension id when origin is "extension". */
59
92
  sourceId?: string;
93
+ /** Present exactly when origin is "extension". */
94
+ extension?: UserHookExtensionSource;
60
95
  }
61
96
 
62
97
  export interface NormalizedCommandHook {
@@ -314,6 +349,17 @@ export function loadUserHooks(
314
349
 
315
350
  export type UserHookOutcome = "emitted" | "command-ok" | "command-failed" | "command-timeout" | "skipped";
316
351
 
352
+ /** Bounded extension attribution carried on every receipt of an extension hook. */
353
+ export interface HookReceiptExtension {
354
+ id: string;
355
+ scope: string;
356
+ canonicalRoot: string;
357
+ manifestDigest: string;
358
+ contentDigest: string;
359
+ declarationsDigest: string;
360
+ generation: number;
361
+ }
362
+
317
363
  export interface HookReceipt {
318
364
  at: number;
319
365
  hookId: string;
@@ -327,6 +373,7 @@ export interface HookReceipt {
327
373
  exitCode?: number;
328
374
  outputChars?: number;
329
375
  toolName?: string;
376
+ extension?: HookReceiptExtension;
330
377
  }
331
378
 
332
379
  export type HookReceiptSink = (receipt: HookReceipt) => void;
@@ -372,6 +419,10 @@ export function userHookToRegistration(
372
419
  deps: UserHookRegistrationDeps,
373
420
  ): MiddlewareHookRegistration {
374
421
  const now = deps.now ?? Date.now;
422
+ // Attribution is fixed when the registration is built, so a receipt written
423
+ // by a registration from an older generation names that generation even
424
+ // after a newer one is active.
425
+ const extension = hook.source.extension === undefined ? undefined : receiptExtension(hook.source.extension);
375
426
  const baseReceipt = (input: { toolName?: string }): Omit<HookReceipt, "outcome"> => ({
376
427
  at: now(),
377
428
  hookId: hook.id,
@@ -380,6 +431,7 @@ export function userHookToRegistration(
380
431
  hash: hook.hash,
381
432
  hook: hook.on,
382
433
  kind: hook.spec.kind,
434
+ ...(extension !== undefined ? { extension: { ...extension } } : {}),
383
435
  ...(input.toolName !== undefined ? { toolName: input.toolName } : {}),
384
436
  });
385
437
  const registration: MiddlewareHookRegistration = {
@@ -401,6 +453,18 @@ export function userHookToRegistration(
401
453
  return registration;
402
454
  }
403
455
 
456
+ function receiptExtension(source: UserHookExtensionSource): HookReceiptExtension {
457
+ return {
458
+ id: source.provenance.id,
459
+ scope: source.provenance.scope,
460
+ canonicalRoot: source.provenance.canonicalRoot,
461
+ manifestDigest: source.provenance.manifestDigest,
462
+ contentDigest: source.provenance.contentDigest,
463
+ declarationsDigest: source.declarationsDigest,
464
+ generation: source.generation,
465
+ };
466
+ }
467
+
404
468
  function evaluateHook(
405
469
  hook: NormalizedUserHook,
406
470
  deps: UserHookRegistrationDeps,
@@ -41,19 +41,27 @@ export {
41
41
  } from "./dispatch-nudge.js";
42
42
  export type { MiddlewareBundleOptions } from "./extension.js";
43
43
  export { createEnvHookBudgetTracker, createMiddlewareBundle } from "./extension.js";
44
- export { createHookReceiptLog, HOOK_RECEIPT_LOG_CAPACITY, type HookReceiptLog } from "./hook-receipts.js";
44
+ export {
45
+ createHookReceiptLog,
46
+ HOOK_RECEIPT_LOG_CAPACITY,
47
+ type HookReceiptLog,
48
+ readPersistedHookReceipts,
49
+ } from "./hook-receipts.js";
45
50
  export type {
46
51
  HookReceipt,
52
+ HookReceiptExtension,
47
53
  HookReceiptSink,
48
54
  NormalizedUserHook,
49
55
  UserHookCommandResult,
50
56
  UserHookCommandRunner,
51
57
  UserHookDeclarationBatch,
58
+ UserHookExtensionSource,
52
59
  UserHookKind,
53
60
  UserHookLoadIssue,
54
61
  UserHookLoadResult,
55
62
  UserHookOrigin,
56
63
  UserHookOutcome,
64
+ UserHookPackageProvenance,
57
65
  UserHookSource,
58
66
  } from "./hooks.js";
59
67
  export {
@@ -66,10 +74,12 @@ export {
66
74
  userHookToRegistration,
67
75
  } from "./hooks.js";
68
76
  export {
69
- type ExtensionHookRoot,
77
+ type BuildUserHookRegistrationsOptions,
78
+ type BuildUserHookRegistrationsResult,
79
+ buildUserHookRegistrations,
80
+ type CapturedHookDeclarations,
81
+ type CapturedHookSourceSet,
70
82
  type HookFileIssue,
71
- type InstallUserHooksResult,
72
- installUserHooks,
73
83
  readHookSources,
74
84
  spawnSyncCommandRunner,
75
85
  } from "./hooks-io.js";
@@ -89,6 +99,19 @@ export {
89
99
  type MemoryInterventionDeps,
90
100
  } from "./memory-intervention.js";
91
101
  export { announceMemoryStepEndpoint, type MemoryStepEndpointAnnouncerDeps } from "./memory-step-endpoint.js";
102
+ export {
103
+ createMiddlewareRegistrationTable,
104
+ MIDDLEWARE_REGISTRATION_OWNERS,
105
+ type MiddlewareRegistrationConflict,
106
+ type MiddlewareRegistrationConflictTier,
107
+ type MiddlewareRegistrationOwner,
108
+ type MiddlewareRegistrationReplacement,
109
+ type MiddlewareRegistrationTable,
110
+ type MiddlewareRegistrationTableOptions,
111
+ type PrepareRegistrationReplacementResult,
112
+ type ReplaceRegistrationsRejection,
113
+ type ReplaceRegistrationsReport,
114
+ } from "./registrations.js";
92
115
  export { BUILTIN_MIDDLEWARE_RULE_IDS, listMiddlewareRuleDefinitions, listMiddlewareRules } from "./rules.js";
93
116
  export type {
94
117
  MiddlewareDiagnostic,
@@ -99,6 +122,7 @@ export type {
99
122
  RunMiddlewareRegistrationsOptions,
100
123
  } from "./runtime.js";
101
124
  export {
125
+ formatRegistrationConflict,
102
126
  registrationFromRuleDefinition,
103
127
  runMiddlewareHook,
104
128
  runMiddlewareRegistrations,
@@ -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
@@ -1,13 +1,14 @@
1
1
  import { createHookBudgetTracker, resolveHookBudgetsFromEnv, resolveHookBudgetTunablesFromEnv } from "./budget.js";
2
2
  import type { MiddlewareContract } from "./contract.js";
3
+ import { createMiddlewareRegistrationTable } from "./registrations.js";
3
4
  import { cloneMiddlewareRule, listMiddlewareRuleDefinitions, listMiddlewareRules } from "./rules.js";
4
5
  import {
5
6
  cloneMiddlewareEffect,
6
7
  type MiddlewareDiagnosticSink,
7
- type MiddlewareHookRegistration,
8
8
  type MiddlewareRuleDefinition,
9
9
  registrationFromRuleDefinition,
10
10
  runMiddlewareRegistrations,
11
+ writeMiddlewareDiagnosticToStderr,
11
12
  } from "./runtime.js";
12
13
  import type { MiddlewareRule, MiddlewareSnapshot } from "./types.js";
13
14
 
@@ -39,15 +40,20 @@ export function createMiddlewareContractFromSnapshot(snapshot: MiddlewareSnapsho
39
40
  if (builtin?.predicate !== undefined) definition.predicate = builtin.predicate;
40
41
  return definition;
41
42
  });
42
- const registrations: MiddlewareHookRegistration[] = definitions.map(registrationFromRuleDefinition);
43
- const registeredIds = new Set(registrations.map((registration) => registration.id));
43
+ let diagnosticSink: MiddlewareDiagnosticSink | undefined;
44
+ // Workers never receive owned registrations; the table exists so the
45
+ // worker contract satisfies the same interface with the same semantics.
46
+ const table = createMiddlewareRegistrationTable({
47
+ fixed: definitions.map(registrationFromRuleDefinition),
48
+ diagnosticSink: () => diagnosticSink ?? writeMiddlewareDiagnosticToStderr,
49
+ });
44
50
  const budgetTracker = createHookBudgetTracker({
45
51
  budgets: resolveHookBudgetsFromEnv(),
46
52
  ...resolveHookBudgetTunablesFromEnv(),
47
53
  });
48
- let diagnosticSink: MiddlewareDiagnosticSink | undefined;
49
54
  return {
50
55
  runHook(input) {
56
+ const registrations = table.list();
51
57
  return runMiddlewareRegistrations(input, registrations, {
52
58
  budgetTracker,
53
59
  ...(diagnosticSink !== undefined ? { onDiagnostic: diagnosticSink } : {}),
@@ -60,12 +66,19 @@ export function createMiddlewareContractFromSnapshot(snapshot: MiddlewareSnapsho
60
66
  return createMiddlewareSnapshot(definitions.map((definition) => definition.rule));
61
67
  },
62
68
  registerHook(registration) {
63
- if (registeredIds.has(registration.id)) return;
64
- registeredIds.add(registration.id);
65
- registrations.push(registration);
69
+ table.registerHook(registration);
66
70
  },
67
71
  setDiagnosticSink(sink) {
68
72
  diagnosticSink = sink;
69
73
  },
74
+ prepareRegistrationReplacement(owner, generation, registrations) {
75
+ return table.prepareReplacement(owner, generation, registrations);
76
+ },
77
+ replaceRegistrations(owner, generation, registrations) {
78
+ return table.replaceRegistrations(owner, generation, registrations);
79
+ },
80
+ ownedGeneration(owner) {
81
+ return table.ownedGeneration(owner);
82
+ },
70
83
  };
71
84
  }
@@ -119,6 +119,20 @@ export interface MuxContract extends DomainContract {
119
119
  focusPane(paneId: string): Promise<boolean>;
120
120
  /** Zoom one Clio-created pane on, off, or toggled. Zooming steals focus; same rule as focusPane. */
121
121
  zoomPane(paneId: string, mode: "on" | "off" | "toggle"): Promise<boolean>;
122
+ /**
123
+ * Bring keyboard focus back to Clio's own hosting pane. This is the return
124
+ * half of every explicit pane interaction: a pick in the files pane, a
125
+ * toggle that closed a pane the operator was looking at. False outside
126
+ * guest mode, without an anchor pane, or below the pane.focus floor.
127
+ */
128
+ focusSelf(): Promise<boolean>;
129
+ /**
130
+ * Leave zoom on the tab that hosts Clio, so a dock split from the anchor is
131
+ * visible again. A zoomed tab hides every pane but one; opening or focusing
132
+ * the files pane behind a zoom would report success for a pane the operator
133
+ * cannot see. False when nothing was zoomed or the tier is absent.
134
+ */
135
+ unzoomSelf(): Promise<boolean>;
122
136
  /** Set a dock's share of its axis. False when the slot has no dock or the tier is absent. */
123
137
  resizeDock(slot: DockSlot, share: number): Promise<boolean>;
124
138
  /** Live dock geometry states, for `/panes` status. */
@@ -425,6 +439,30 @@ export function createMuxRuntime(options: MuxRuntimeOptions): MuxRuntime {
425
439
  );
426
440
  },
427
441
 
442
+ async focusSelf(): Promise<boolean> {
443
+ if (anchorPaneId === null || !muxSupportsMethod(detection.server, "pane.focus")) return false;
444
+ return await attempt(
445
+ "focusSelf",
446
+ async (live) => {
447
+ await live.paneFocus(anchorPaneId);
448
+ return true;
449
+ },
450
+ false,
451
+ );
452
+ },
453
+
454
+ async unzoomSelf(): Promise<boolean> {
455
+ if (anchorPaneId === null || !muxSupportsMethod(detection.server, "pane.zoom")) return false;
456
+ return await attempt(
457
+ "unzoomSelf",
458
+ async (live) => {
459
+ const result = await live.paneZoom(anchorPaneId, "off");
460
+ return result.changed;
461
+ },
462
+ false,
463
+ );
464
+ },
465
+
428
466
  async resizeDock(slot: DockSlot, share: number): Promise<boolean> {
429
467
  if (!docks) return false;
430
468
  return await attempt("resizeDock", () => docks.resize(slot, share), false);