@iowarp/clio-coder 0.3.8 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (552) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/NOTICE +33 -0
  3. package/README.md +12 -3
  4. package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
  5. package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
  8. package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
  9. package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
  10. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  11. package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
  12. package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
  13. package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
  14. package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
  15. package/dist/chunk-3DPEIQKN.js +113 -0
  16. package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
  17. package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
  18. package/dist/chunk-42FMPA75.js +101 -0
  19. package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
  20. package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
  21. package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
  22. package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
  23. package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
  24. package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
  25. package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
  26. package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
  27. package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
  28. package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
  29. package/dist/chunk-BKFM6EJV.js +462 -0
  30. package/dist/chunk-BMS5RKQY.js +27 -0
  31. package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
  32. package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
  33. package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
  34. package/dist/chunk-C2LTL2W6.js +2447 -0
  35. package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
  36. package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
  37. package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
  38. package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
  39. package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
  40. package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
  41. package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
  42. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  43. package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
  44. package/dist/chunk-GKF55TAZ.js +391 -0
  45. package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
  46. package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
  47. package/dist/chunk-HHV2GANA.js +88 -0
  48. package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
  49. package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
  50. package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
  51. package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
  52. package/dist/chunk-HZHHCK24.js +1631 -0
  53. package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
  54. package/dist/chunk-IBEBSCYA.js +564 -0
  55. package/dist/chunk-IQ7KR472.js +362 -0
  56. package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
  57. package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
  58. package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
  59. package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
  60. package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
  61. package/dist/chunk-KMVISBZR.js +132 -0
  62. package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
  63. package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
  64. package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
  65. package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
  66. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  67. package/dist/chunk-NEKRRTYW.js +56 -0
  68. package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
  69. package/dist/chunk-NHLBIGRH.js +1506 -0
  70. package/dist/chunk-NQQH3YT7.js +302 -0
  71. package/dist/chunk-NYS75XW5.js +15 -0
  72. package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
  73. package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
  74. package/dist/chunk-OQBA45DZ.js +97 -0
  75. package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
  76. package/dist/chunk-PMZCIOCJ.js +25 -0
  77. package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
  78. package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
  79. package/dist/chunk-QDC3K2U3.js +262 -0
  80. package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
  81. package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
  82. package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
  83. package/dist/chunk-QSNYB6ZV.js +195 -0
  84. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  85. package/dist/chunk-RKKLTLYB.js +45 -0
  86. package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
  87. package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
  88. package/dist/chunk-SUCTJL45.js +45 -0
  89. package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
  90. package/dist/chunk-T56WDKA5.js +183 -0
  91. package/dist/chunk-TVHHYFHE.js +255 -0
  92. package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
  93. package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
  94. package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
  95. package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
  96. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  97. package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
  98. package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
  99. package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
  100. package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
  101. package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
  102. package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
  103. package/dist/chunk-VO67MWHC.js +75 -0
  104. package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
  105. package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
  106. package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
  107. package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
  108. package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
  109. package/dist/chunk-X75E3D2N.js +686 -0
  110. package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
  111. package/dist/chunk-YJX4SHTD.js +40 -0
  112. package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
  113. package/dist/chunk-Z2RR6MAK.js +127 -0
  114. package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
  115. package/dist/cli/index.js +47 -36
  116. package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
  117. package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
  118. package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
  119. package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
  120. package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
  121. package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
  122. package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
  123. package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
  124. package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
  125. package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
  126. package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
  127. package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
  128. package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
  129. package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
  130. package/dist/doctor-QOA5FNY5.js +313 -0
  131. package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
  132. package/dist/eval-inventory-SXH7PDKX.js +316 -0
  133. package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
  134. package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
  135. package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
  136. package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
  137. package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
  138. package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
  139. package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
  140. package/dist/fleet-inspect-VLY4S7QM.js +442 -0
  141. package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
  142. package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
  143. package/dist/fleet-verify-JFEL2L3H.js +175 -0
  144. package/dist/fleet-view-ZCON35AG.js +102 -0
  145. package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
  146. package/dist/install-XGLBQY5E.js +13 -0
  147. package/dist/interop-OZBKXAYL.js +114 -0
  148. package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
  149. package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
  150. package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
  151. package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
  152. package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
  153. package/dist/panes-HMABYVO4.js +58 -0
  154. package/dist/panes-KY6W3V2E.js +103 -0
  155. package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
  156. package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
  157. package/dist/resources-BB3MVJMD.js +111 -0
  158. package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
  159. package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
  160. package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
  161. package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
  162. package/dist/skills-inventory-S4MXPJFV.js +126 -0
  163. package/dist/slash-commands-ZSGASKJC.js +77 -0
  164. package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
  165. package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
  166. package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
  167. package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
  168. package/dist/tools-DAF3DI3C.js +27 -0
  169. package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
  170. package/dist/tui-primitives-2AKXQNZK.js +13 -0
  171. package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
  172. package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
  173. package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
  174. package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
  175. package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
  176. package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
  177. package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
  178. package/dist/with-panes-MKB46MPQ.js +782 -0
  179. package/dist/worker/entry.js +106 -75
  180. package/docs/README.md +3 -2
  181. package/docs/acp.md +24 -3
  182. package/docs/alcf-provider.md +1 -1
  183. package/docs/architecture.md +2 -2
  184. package/docs/artifact-versions.md +9 -1
  185. package/docs/built-in-agents.md +1 -1
  186. package/docs/capacity-and-scheduling.md +62 -3
  187. package/docs/commands-and-modes.md +31 -2
  188. package/docs/configuration-and-targets.md +69 -12
  189. package/docs/context-engine.md +63 -4
  190. package/docs/development-pipeline.md +19 -0
  191. package/docs/dispatch-typed-intent.md +385 -0
  192. package/docs/documentation-coverage.md +5 -5
  193. package/docs/documentation-guide.md +1 -1
  194. package/docs/environment-variables.md +3 -0
  195. package/docs/eval-runner.md +262 -11
  196. package/docs/evals-internal.md +72 -2
  197. package/docs/evidence-and-memory.md +12 -11
  198. package/docs/evolution.md +1 -1
  199. package/docs/exit-codes-and-output.md +1 -1
  200. package/docs/extensions-and-sharing.md +27 -1
  201. package/docs/fleet-dispatch.md +25 -4
  202. package/docs/installation-and-lifecycle.md +15 -2
  203. package/docs/middleware-and-components.md +1 -1
  204. package/docs/model-catalog.md +10 -1
  205. package/docs/observability.md +55 -4
  206. package/docs/proactive-memory.md +127 -14
  207. package/docs/prompt-envelope-and-tools.md +19 -1
  208. package/docs/provider-adapter-cookbook.md +1 -1
  209. package/docs/release-cut-checklist.md +19 -3
  210. package/docs/safety-model.md +2 -2
  211. package/docs/scientific-validation.md +3 -3
  212. package/docs/session-lifecycle.md +1 -1
  213. package/docs/skills-marketplace.md +1 -1
  214. package/docs/tool-usage.md +18 -8
  215. package/docs/trace-store.md +1 -1
  216. package/docs/troubleshooting.md +88 -1
  217. package/docs/tui-design.md +1 -1
  218. package/docs/worker-dispatch-mechanics.md +1 -1
  219. package/package.json +5 -2
  220. package/src/cli/acp.ts +6 -2
  221. package/src/cli/agents.ts +1 -1
  222. package/src/cli/argv.ts +25 -0
  223. package/src/cli/config-inspect.ts +33 -6
  224. package/src/cli/config.ts +1 -1
  225. package/src/cli/configure.ts +23 -21
  226. package/src/cli/doctor-panes.ts +124 -0
  227. package/src/cli/doctor-state-size.ts +82 -0
  228. package/src/cli/doctor-toolchain.ts +57 -0
  229. package/src/cli/doctor.ts +22 -1
  230. package/src/cli/eval-inventory.ts +436 -0
  231. package/src/cli/eval.ts +93 -16
  232. package/src/cli/evidence-detail.ts +88 -0
  233. package/src/cli/evidence-inventory.ts +183 -0
  234. package/src/cli/evidence.ts +30 -5
  235. package/src/cli/extensions.ts +5 -1
  236. package/src/cli/fleet-decisions.ts +69 -0
  237. package/src/cli/fleet-inspect.ts +334 -0
  238. package/src/cli/fleet-verify.ts +133 -0
  239. package/src/cli/fleet-view.ts +810 -0
  240. package/src/cli/fleet.ts +179 -39
  241. package/src/cli/index.ts +14 -2
  242. package/src/cli/interop-inspect.ts +128 -0
  243. package/src/cli/interop.ts +34 -0
  244. package/src/cli/panes.ts +35 -0
  245. package/src/cli/reset.ts +5 -2
  246. package/src/cli/run.ts +58 -0
  247. package/src/cli/skills-inventory.ts +185 -0
  248. package/src/cli/skills.ts +16 -13
  249. package/src/cli/targets.ts +44 -13
  250. package/src/cli/tools.ts +321 -0
  251. package/src/cli/trace-inspect.ts +252 -0
  252. package/src/cli/trace.ts +85 -5
  253. package/src/cli/usage.ts +63 -14
  254. package/src/cli/verifiers-inspect.ts +347 -0
  255. package/src/cli/verifiers.ts +9 -0
  256. package/src/core/bus-events.ts +33 -1
  257. package/src/core/cache-telemetry.ts +42 -0
  258. package/src/core/config.ts +67 -0
  259. package/src/core/defaults.ts +124 -8
  260. package/src/core/endpoint-key.ts +27 -0
  261. package/src/core/residency-target-key.ts +25 -0
  262. package/src/core/response-schema.ts +80 -6
  263. package/src/core/theme-token-hex.ts +43 -0
  264. package/src/core/tool-names.ts +2 -1
  265. package/src/core/xdg.ts +1 -1
  266. package/src/domains/agents/fleets/build-review.md +0 -3
  267. package/src/domains/agents/fleets/build-test.md +0 -3
  268. package/src/domains/agents/result-contract-filesystem.ts +32 -0
  269. package/src/domains/agents/result-contract.ts +164 -35
  270. package/src/domains/config/classify.ts +6 -0
  271. package/src/domains/context/codewiki/coordinator.ts +12 -4
  272. package/src/domains/dispatch/admission-error.ts +9 -0
  273. package/src/domains/dispatch/admission.ts +52 -14
  274. package/src/domains/dispatch/capacity-lease.ts +118 -9
  275. package/src/domains/dispatch/contract.ts +11 -0
  276. package/src/domains/dispatch/council-topology.ts +398 -0
  277. package/src/domains/dispatch/execution-plan.ts +44 -4
  278. package/src/domains/dispatch/extension.ts +378 -82
  279. package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
  280. package/src/domains/dispatch/fleet-plan.ts +7 -2
  281. package/src/domains/dispatch/fleet-run.ts +87 -4
  282. package/src/domains/dispatch/gate-decisions.ts +11 -1
  283. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  284. package/src/domains/dispatch/gate-topology.ts +289 -0
  285. package/src/domains/dispatch/heartbeat.ts +32 -8
  286. package/src/domains/dispatch/index.ts +22 -0
  287. package/src/domains/dispatch/intent-compatibility.ts +330 -0
  288. package/src/domains/dispatch/intent.ts +85 -1
  289. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  290. package/src/domains/dispatch/reservation-store.ts +139 -11
  291. package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
  292. package/src/domains/dispatch/run-event-journal.ts +598 -0
  293. package/src/domains/dispatch/state.ts +49 -1
  294. package/src/domains/dispatch/types.ts +13 -0
  295. package/src/domains/dispatch/validation.ts +33 -8
  296. package/src/domains/dispatch/worker-spawn.ts +25 -11
  297. package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
  298. package/src/domains/dispatch/write-boundary.ts +62 -1
  299. package/src/domains/eval/artifacts/store.ts +62 -0
  300. package/src/domains/eval/compare/behavioral.ts +224 -0
  301. package/src/domains/eval/compare/compare.ts +342 -2
  302. package/src/domains/eval/compare/envelope.ts +128 -0
  303. package/src/domains/eval/compare/gates.ts +24 -6
  304. package/src/domains/eval/compare/thresholds.ts +30 -3
  305. package/src/domains/eval/execution-provenance.ts +240 -0
  306. package/src/domains/eval/inventory.ts +113 -0
  307. package/src/domains/eval/metrics/aggregate.ts +136 -0
  308. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  309. package/src/domains/eval/metrics/tracked.ts +413 -0
  310. package/src/domains/eval/provenance.ts +117 -0
  311. package/src/domains/eval/reports/comparison.ts +128 -0
  312. package/src/domains/eval/reports/junit.ts +17 -3
  313. package/src/domains/eval/reports/markdown.ts +3 -3
  314. package/src/domains/eval/reports/text.ts +14 -0
  315. package/src/domains/eval/run-compare.ts +20 -0
  316. package/src/domains/eval/runners/clio-run.ts +127 -0
  317. package/src/domains/eval/runners/external-command.ts +28 -3
  318. package/src/domains/eval/schema/adapter.ts +111 -0
  319. package/src/domains/eval/schema/artifact.ts +20 -0
  320. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  321. package/src/domains/eval/schema/behavioral.ts +520 -0
  322. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  323. package/src/domains/eval/schema/serving.ts +105 -0
  324. package/src/domains/eval/schema/suite.ts +38 -8
  325. package/src/domains/eval/schema/validate.ts +58 -3
  326. package/src/domains/eval/schema/verdict.ts +237 -0
  327. package/src/domains/eval/suites/resolve.ts +2 -0
  328. package/src/domains/eval/suites/run.ts +264 -33
  329. package/src/domains/eval/verifiers/command.ts +2 -1
  330. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  331. package/src/domains/evidence/build.ts +2 -13
  332. package/src/domains/evidence/eval.ts +2 -12
  333. package/src/domains/evidence/findings-markdown.ts +33 -0
  334. package/src/domains/evidence/run-trust.ts +7 -113
  335. package/src/domains/evidence/store.ts +6 -0
  336. package/src/domains/evidence/trust-projection.ts +2 -2
  337. package/src/domains/extensions/compatibility.ts +285 -0
  338. package/src/domains/extensions/discovery.ts +38 -3
  339. package/src/domains/extensions/resources.ts +1 -1
  340. package/src/domains/extensions/state.ts +12 -3
  341. package/src/domains/extensions/types.ts +2 -0
  342. package/src/domains/lifecycle/doctor.ts +69 -1
  343. package/src/domains/memory/index.ts +14 -1
  344. package/src/domains/memory/task-bank-promotion.ts +64 -0
  345. package/src/domains/memory/task-memory-policy.ts +82 -17
  346. package/src/domains/memory/task-memory-spend.ts +131 -0
  347. package/src/domains/memory/task-memory-status.ts +7 -0
  348. package/src/domains/memory/task-memory-telemetry.ts +3 -0
  349. package/src/domains/middleware/index.ts +1 -0
  350. package/src/domains/middleware/memory-intervention.ts +97 -21
  351. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  352. package/src/domains/mux/contract.ts +434 -0
  353. package/src/domains/mux/detect.ts +158 -0
  354. package/src/domains/mux/extension.ts +47 -0
  355. package/src/domains/mux/index.ts +96 -0
  356. package/src/domains/mux/manifest.ts +6 -0
  357. package/src/domains/mux/operations.ts +164 -0
  358. package/src/domains/mux/pane-registry.ts +90 -0
  359. package/src/domains/mux/protocol.ts +49 -0
  360. package/src/domains/mux/socket-client.ts +816 -0
  361. package/src/domains/mux/types.ts +222 -0
  362. package/src/domains/mux/viewer-command.ts +59 -0
  363. package/src/domains/mux/yazi/assets/init.lua +2 -0
  364. package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
  365. package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
  366. package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
  367. package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
  368. package/src/domains/mux/yazi/assets/yazi.toml +17 -0
  369. package/src/domains/mux/yazi/event-stream.ts +180 -0
  370. package/src/domains/mux/yazi/profile.ts +299 -0
  371. package/src/domains/mux/yazi/session.ts +228 -0
  372. package/src/domains/mux/yazi/theme.ts +30 -0
  373. package/src/domains/observability/background-memory-usage.ts +140 -0
  374. package/src/domains/observability/cost.ts +22 -1
  375. package/src/domains/observability/index.ts +9 -0
  376. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  377. package/src/domains/observability/trace-store.ts +234 -2
  378. package/src/domains/prompts/compiler.ts +100 -13
  379. package/src/domains/providers/endpoint-capacity.ts +228 -0
  380. package/src/domains/providers/endpoint-slots-store.ts +189 -0
  381. package/src/domains/providers/extension.ts +20 -3
  382. package/src/domains/providers/index.ts +32 -0
  383. package/src/domains/providers/model-runtime-capabilities.ts +32 -0
  384. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  385. package/src/domains/providers/runtime-resolution.ts +8 -1
  386. package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
  387. package/src/domains/providers/runtimes/builtins.ts +2 -0
  388. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  389. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  390. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  391. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  392. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  393. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  394. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  395. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  396. package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
  397. package/src/domains/providers/support.ts +1 -0
  398. package/src/domains/providers/target-model-cache.ts +124 -0
  399. package/src/domains/providers/types/capability-flags.ts +2 -0
  400. package/src/domains/providers/types/target-descriptor.ts +2 -0
  401. package/src/domains/resources/index.ts +3 -0
  402. package/src/domains/resources/prompts/loader.ts +95 -33
  403. package/src/domains/resources/skills/loader.ts +33 -0
  404. package/src/domains/safety/action-classifier.ts +6 -0
  405. package/src/domains/safety/call-target.ts +52 -0
  406. package/src/domains/safety/run-effects.ts +35 -4
  407. package/src/domains/session/context-accounting.ts +52 -1
  408. package/src/domains/session/context-ledger.ts +37 -13
  409. package/src/domains/session/index.ts +6 -0
  410. package/src/domains/session/prompt-cache.ts +140 -0
  411. package/src/domains/session/prompt-manifest.ts +42 -0
  412. package/src/domains/toolchain/archive.ts +175 -0
  413. package/src/domains/toolchain/contract.ts +28 -0
  414. package/src/domains/toolchain/extension.ts +47 -0
  415. package/src/domains/toolchain/index.ts +39 -0
  416. package/src/domains/toolchain/install.ts +327 -0
  417. package/src/domains/toolchain/manifest.ts +8 -0
  418. package/src/domains/toolchain/paths.ts +34 -0
  419. package/src/domains/toolchain/registry.ts +265 -0
  420. package/src/domains/toolchain/remove.ts +218 -0
  421. package/src/domains/toolchain/resolve.ts +182 -0
  422. package/src/domains/toolchain/types.ts +113 -0
  423. package/src/domains/toolchain/version.ts +88 -0
  424. package/src/engine/acp/adapter.ts +18 -3
  425. package/src/engine/acp/server.ts +413 -70
  426. package/src/engine/acp/types.ts +19 -1
  427. package/src/engine/ai.ts +35 -0
  428. package/src/engine/apis/llamacpp-residency.ts +55 -3
  429. package/src/engine/apis/lmstudio.ts +25 -5
  430. package/src/engine/apis/ollama-native.ts +2 -1
  431. package/src/engine/apis/openai-completions.ts +80 -17
  432. package/src/engine/apis/residency-lock.ts +3 -1
  433. package/src/engine/apis/residency.ts +34 -1
  434. package/src/engine/claude/sdk-module.ts +98 -0
  435. package/src/engine/claude/sdk-runtime.ts +19 -11
  436. package/src/engine/provider-payload.ts +29 -1
  437. package/src/engine/tui-primitives.ts +21 -0
  438. package/src/engine/tui.ts +1 -0
  439. package/src/engine/worker-runtime.ts +2 -13
  440. package/src/entry/boot-options.ts +2 -0
  441. package/src/entry/orchestrator.ts +279 -35
  442. package/src/entry/panes-activation.ts +31 -0
  443. package/src/entry/with-panes.ts +20 -0
  444. package/src/interactive/chat-loop-messages.ts +26 -7
  445. package/src/interactive/chat-loop.ts +318 -41
  446. package/src/interactive/chat-panel.ts +62 -8
  447. package/src/interactive/clio-editor.ts +45 -8
  448. package/src/interactive/context-activity.ts +5 -1
  449. package/src/interactive/context-meter.ts +1 -1
  450. package/src/interactive/context-overlay.ts +41 -10
  451. package/src/interactive/cost-overlay.ts +66 -6
  452. package/src/interactive/council-grid.ts +1 -3
  453. package/src/interactive/council.ts +11 -0
  454. package/src/interactive/dispatch-board.ts +102 -20
  455. package/src/interactive/fleet-run-preview.ts +41 -15
  456. package/src/interactive/handoff-round.ts +41 -2
  457. package/src/interactive/interactive-application.ts +177 -7
  458. package/src/interactive/interactive-input-runtime.ts +15 -0
  459. package/src/interactive/interactive-presentation.ts +4 -0
  460. package/src/interactive/interactive-shell.ts +20 -17
  461. package/src/interactive/interactive-slash-runtime.ts +63 -10
  462. package/src/interactive/memory-overlay.ts +9 -0
  463. package/src/interactive/modal-marker.ts +170 -0
  464. package/src/interactive/mutation-preview.ts +295 -0
  465. package/src/interactive/mux-bridge.ts +214 -0
  466. package/src/interactive/overlay-frame.ts +58 -2
  467. package/src/interactive/overlay-general-openers.ts +17 -0
  468. package/src/interactive/overlay-key-routing.ts +52 -3
  469. package/src/interactive/overlay-lifecycle.ts +56 -7
  470. package/src/interactive/overlay-model-selectors.ts +40 -3
  471. package/src/interactive/overlay-permission-lifecycle.ts +112 -24
  472. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  473. package/src/interactive/overlay-transitions.ts +18 -4
  474. package/src/interactive/overlays/agents.ts +1 -0
  475. package/src/interactive/overlays/ask-user.ts +227 -49
  476. package/src/interactive/overlays/auth-dialog.ts +1 -0
  477. package/src/interactive/overlays/context-reset.ts +1 -0
  478. package/src/interactive/overlays/cwd-fallback.ts +1 -0
  479. package/src/interactive/overlays/decisions.ts +11 -11
  480. package/src/interactive/overlays/extensions.ts +1 -0
  481. package/src/interactive/overlays/fleet-run-approval.ts +1 -0
  482. package/src/interactive/overlays/handoff-review.ts +1 -0
  483. package/src/interactive/overlays/help-reference.ts +6 -0
  484. package/src/interactive/overlays/interop.ts +1 -0
  485. package/src/interactive/overlays/library-install-confirm.ts +1 -0
  486. package/src/interactive/overlays/library-tabs.ts +28 -0
  487. package/src/interactive/overlays/list-overlay.ts +10 -1
  488. package/src/interactive/overlays/message-picker.ts +1 -0
  489. package/src/interactive/overlays/model-scope.ts +86 -0
  490. package/src/interactive/overlays/model-selector.ts +1 -0
  491. package/src/interactive/overlays/prompts.ts +12 -1
  492. package/src/interactive/overlays/session-selector.ts +1 -0
  493. package/src/interactive/overlays/settings-sections.ts +30 -0
  494. package/src/interactive/overlays/settings.ts +614 -45
  495. package/src/interactive/overlays/side-question.ts +1 -0
  496. package/src/interactive/overlays/skills-hub.ts +3 -11
  497. package/src/interactive/overlays/tree-selector.ts +1 -0
  498. package/src/interactive/pane-policy.ts +46 -0
  499. package/src/interactive/panes-runtime.ts +292 -0
  500. package/src/interactive/permission-hint.ts +34 -2
  501. package/src/interactive/permission-overlay.ts +159 -9
  502. package/src/interactive/prewarm.ts +197 -0
  503. package/src/interactive/render-trace.ts +162 -15
  504. package/src/interactive/renderers/compaction-summary.ts +29 -0
  505. package/src/interactive/renderers/tool-execution.ts +4 -0
  506. package/src/interactive/renderers/worker-entry.ts +122 -14
  507. package/src/interactive/side-question.ts +58 -1
  508. package/src/interactive/slash-commands.ts +251 -15
  509. package/src/interactive/status/controller.ts +11 -0
  510. package/src/interactive/status/state-machine.ts +54 -2
  511. package/src/interactive/status/types.ts +7 -0
  512. package/src/interactive/tasks-overlay.ts +1 -0
  513. package/src/interactive/terminal-lease.ts +2 -0
  514. package/src/interactive/theme/tokens.ts +3 -14
  515. package/src/interactive/turn-context.ts +346 -33
  516. package/src/interactive/turn-persistence.ts +14 -4
  517. package/src/interactive/turn-prewarm.ts +364 -0
  518. package/src/interactive/turn-queues.ts +7 -4
  519. package/src/interactive/turn-runtime.ts +8 -1
  520. package/src/interactive/turn-state.ts +23 -0
  521. package/src/interactive/view/artifacts.ts +109 -1
  522. package/src/interactive/view/view-overlay.ts +29 -3
  523. package/src/interactive/watch-pane.ts +152 -0
  524. package/src/interactive/worker-progress.ts +7 -1
  525. package/src/interactive/worker-receipts.ts +19 -1
  526. package/src/interactive/worker-stream.ts +5 -0
  527. package/src/interactive/yazi-bridge.ts +444 -0
  528. package/src/tools/ask-user.ts +43 -2
  529. package/src/tools/bootstrap.ts +26 -2
  530. package/src/tools/builtin-tool-catalog.ts +15 -0
  531. package/src/tools/compete-worktrees.ts +83 -2
  532. package/src/tools/core-bootstrap.ts +2 -1
  533. package/src/tools/dispatch-admission.ts +14 -3
  534. package/src/tools/dispatch-arguments.ts +20 -20
  535. package/src/tools/dispatch-plan.ts +17 -9
  536. package/src/tools/dispatch-run-events.ts +134 -19
  537. package/src/tools/dispatch-runner.ts +29 -7
  538. package/src/tools/dispatch-scout.ts +1 -1
  539. package/src/tools/dispatch-types.ts +15 -3
  540. package/src/tools/dispatch.ts +1 -1
  541. package/src/tools/executables.ts +17 -14
  542. package/src/tools/observation.ts +54 -4
  543. package/src/tools/panes-surface.ts +38 -0
  544. package/src/tools/panes.ts +112 -0
  545. package/src/tools/policy.ts +10 -1
  546. package/src/tools/presentation.ts +1 -0
  547. package/src/tools/registry.ts +16 -0
  548. package/dist/chunk-AOCYTWAV.js +0 -449
  549. package/dist/chunk-HLE42MG7.js +0 -37
  550. package/dist/chunk-HWUFFB6L.js +0 -83
  551. package/dist/chunk-JOZYP4GM.js +0 -279
  552. package/dist/doctor-M7YEDGAE.js +0 -91
@@ -4,7 +4,7 @@ import {
4
4
  sanitizeToolResultDigest,
5
5
  type ToolResultDigest,
6
6
  } from "../../tools/result-disposition.js";
7
- import { TASK_MEMORY_DEFAULT_PROCEDURAL_CAP, type TaskMemoryBank } from "../memory/task-bank.js";
7
+ import { TASK_MEMORY_DEFAULT_PROCEDURAL_CAP, type TaskMemoryBank, type TaskMemoryEntry } from "../memory/task-bank.js";
8
8
  import {
9
9
  runTaskMemoryPolicy,
10
10
  TASK_MEMORY_POLICY_DEFAULT_TIMEOUT_MS,
@@ -12,6 +12,7 @@ import {
12
12
  type TaskMemoryModelClient,
13
13
  type TaskMemoryPolicyReason,
14
14
  type TaskMemoryPolicyResult,
15
+ type TaskMemoryStepUsage,
15
16
  type TaskMemoryTrajectoryStep,
16
17
  } from "../memory/task-memory-policy.js";
17
18
  import type { TaskMemoryActivityEvent } from "../memory/task-memory-status.js";
@@ -30,8 +31,10 @@ import type { MiddlewareEffect, MiddlewareHookInput } from "./types.js";
30
31
 
31
32
  export const MEMORY_INTERVENTION_REGISTRATION_ID = "observer.memory-intervention";
32
33
  export const MEMORY_INTERVENTION_DEFAULT_WINDOW_STEPS = 8;
33
- export const MEMORY_INTERVENTION_DEFAULT_MAX_TOKENS = 400;
34
+ export const MEMORY_INTERVENTION_DEFAULT_MAX_TOKENS = 2_000;
34
35
  export const MEMORY_INTERVENTION_DEFAULT_EVERY_N_TOOLS = 10;
36
+ /** Two full deadlines are enough evidence to stop spending this session's endpoint. */
37
+ export const MEMORY_INTERVENTION_TIMEOUT_BACKOFF_THRESHOLD = 2;
35
38
 
36
39
  export const MEMORY_INTERVENTION_ACTIVITY_LIMIT = 20;
37
40
 
@@ -75,6 +78,27 @@ export interface MemoryInterventionDeps {
75
78
  everyNTools?: number;
76
79
  /** Lazily resolves the explicitly configured background role. Null means rules-only. */
77
80
  getModelClient?: () => TaskMemoryModelClient | null;
81
+ /** Completion budget derived from the resolved background model capability. */
82
+ getModelMaxTokens?: (configuredMaxTokens: number) => number;
83
+ /**
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.
88
+ */
89
+ backgroundEndpointBusy?: () => boolean;
90
+ /**
91
+ * Provider-reported spend for one completed model step. The composition root
92
+ * routes it to the cost ledger; the middleware never prices anything.
93
+ */
94
+ onStepUsage?: (usage: TaskMemoryStepUsage) => void;
95
+ /**
96
+ * Bank entries an llm-tier reminder cited when it reached the operator. The
97
+ * composition root proposes them into the durable memory store, which is what
98
+ * connects the session bank to the records `/memory` and `clio-coder memory`
99
+ * read. Best effort and content-bearing, exactly like `onEnvelope`.
100
+ */
101
+ onInjectedEntries?: (entries: ReadonlyArray<TaskMemoryEntry>) => void;
78
102
  /** Live next-turn settings view; individual fields above remain test-friendly fallbacks. */
79
103
  getSettings?: () => Readonly<MemoryInterventionSettings>;
80
104
  /** Best-effort content-free telemetry; sink failures never affect intervention. */
@@ -167,6 +191,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
167
191
  let outstandingStep: Promise<void> = Promise.resolve();
168
192
  let rulesInjectedSincePromptedStep = false;
169
193
  let annotatedSinceTurnEnd = false;
194
+ let consecutiveLlmTimeouts = 0;
170
195
 
171
196
  return {
172
197
  id: MEMORY_INTERVENTION_REGISTRATION_ID,
@@ -348,6 +373,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
348
373
  reminder: null,
349
374
  inputTokens: 0,
350
375
  outputTokens: 0,
376
+ usage: null,
351
377
  effects: NO_EFFECTS,
352
378
  });
353
379
  const live = settings();
@@ -361,23 +387,38 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
361
387
  let tier: TaskMemoryTelemetryTier = "rules";
362
388
  promptedStepTier = tier;
363
389
  let promptedResult: TaskMemoryPolicyResult;
390
+ // A boundary that never reached the model is a skipped boundary rather than
391
+ // a policy decision, and `dropped` is the telemetry outcome for exactly
392
+ // that. The returned decision stays `silent`, since no reminder was
393
+ // produced and the policy vocabulary has no value for a step that never ran.
394
+ let telemetryDecision: TaskMemoryTelemetryDecision | null = null;
364
395
  try {
365
- const client = deps.getModelClient?.() ?? null;
366
- if (client === null) {
367
- promptedResult = silent("no_client");
396
+ if (consecutiveLlmTimeouts >= MEMORY_INTERVENTION_TIMEOUT_BACKOFF_THRESHOLD) {
397
+ promptedResult = silent("llm_timeout_backoff");
368
398
  } else {
369
- tier = "llm";
370
- promptedStepTier = tier;
371
- promptedResult = await runTaskMemoryPolicy(deps.bank, client, {
372
- task: input.task?.trim() || currentTask,
373
- trajectory: [...trajectory],
374
- deterministicTrigger: input.deterministicTrigger,
375
- maxTokens: live.maxTokens,
376
- ...(input.suppressIntervention === undefined ? {} : { suppressIntervention: input.suppressIntervention }),
377
- previousReminder: lastInjectedMessage,
378
- timeoutMs: live.timeoutMs,
379
- ...(deps.onEnvelope === undefined ? {} : { onEnvelope: deps.onEnvelope }),
380
- });
399
+ const client = deps.getModelClient?.() ?? null;
400
+ if (client === null) {
401
+ promptedResult = silent("no_client");
402
+ } else if (deps.backgroundEndpointBusy?.() === true) {
403
+ tier = "llm";
404
+ promptedStepTier = tier;
405
+ promptedResult = silent("endpoint_busy");
406
+ telemetryDecision = "dropped";
407
+ } else {
408
+ tier = "llm";
409
+ 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
+ });
421
+ }
381
422
  }
382
423
  } catch (error) {
383
424
  // runTaskMemoryPolicy resolves its own failures, so reaching here means
@@ -395,11 +436,21 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
395
436
  error: error instanceof Error ? error.message : "resolving the background model client failed",
396
437
  });
397
438
  }
439
+ if (tier === "llm" && promptedResult.decision === "timeout") consecutiveLlmTimeouts += 1;
440
+ else if (tier === "llm" && telemetryDecision !== "dropped") consecutiveLlmTimeouts = 0;
398
441
  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
+ if (promptedResult.decision === "injected") reportInjectedEntries(promptedResult.reminder);
399
450
  emitTelemetry(
400
451
  triggers,
401
452
  tier,
402
- promptedResult.decision,
453
+ telemetryDecision ?? promptedResult.decision,
403
454
  promptedResult.reason,
404
455
  citedEntryCount(promptedResult.reminder),
405
456
  promptedResult.inputTokens,
@@ -462,10 +513,35 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
462
513
  if (activity.length > MEMORY_INTERVENTION_ACTIVITY_LIMIT) activity.length = MEMORY_INTERVENTION_ACTIVITY_LIMIT;
463
514
  }
464
515
 
465
- function citedEntryCount(message: string | null): number {
466
- if (message === null) return 0;
516
+ function citedEntries(message: string | null): TaskMemoryEntry[] {
517
+ if (message === null) return [];
467
518
  const snapshot = deps.bank.snapshot();
468
- return [...snapshot.knowledge, ...snapshot.procedural].filter((entry) => message.includes(`[${entry.id}]`)).length;
519
+ return [...snapshot.knowledge, ...snapshot.procedural].filter((entry) => message.includes(`[${entry.id}]`));
520
+ }
521
+
522
+ function citedEntryCount(message: string | null): number {
523
+ return citedEntries(message).length;
524
+ }
525
+
526
+ /**
527
+ * Hand the cited entries to the durable store.
528
+ *
529
+ * Only the model tier reports here. A rules-tier reminder cites an entry this
530
+ * middleware wrote itself out of one repeated tool failure, and proposing
531
+ * every one of those as a durable lesson would fill the operator's review
532
+ * queue with rows nobody asked for. The model tier's entries are the ones the
533
+ * background plane produced, which is what #229 asks to be reviewable.
534
+ */
535
+ function reportInjectedEntries(reminder: string | null): void {
536
+ if (deps.onInjectedEntries === undefined) return;
537
+ const entries = citedEntries(reminder);
538
+ if (entries.length === 0) return;
539
+ try {
540
+ deps.onInjectedEntries(entries);
541
+ } catch {
542
+ // A failing store is the composition root's problem to report, never a
543
+ // reason to fail the step that produced the reminder.
544
+ }
469
545
  }
470
546
 
471
547
  function observeBeforeTool(input: MiddlewareHookInput): void {
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Publishing and accounting for the endpoint a background memory step uses.
3
+ *
4
+ * A proactive-memory step that runs on the chat target's own endpoint moves
5
+ * that server's prefix cache, so the next turn is cold for a reason Clio caused
6
+ * and can name. The turn context turns {@link BusChannels.MemoryStepCompleted}
7
+ * into the `background_memory` expected-cold reason; without it `/context`
8
+ * reports the turn as an unexplained provider re-prefill.
9
+ *
10
+ * The disturbance is a property of the request having left the process, not of
11
+ * the answer coming back. A step that times out still had its whole trajectory
12
+ * prefilled into the single prefix slot, because aborting the HTTP request does
13
+ * not stop a llama.cpp prefill (the measurement is recorded in
14
+ * `src/interactive/turn-prewarm.ts`). Publishing from the usage sink instead
15
+ * missed exactly that case, since usage is only assigned once the call resolves.
16
+ *
17
+ * The same request also occupies real endpoint capacity. Both responsibilities
18
+ * live here around the client's `complete`: the slot is registered only after
19
+ * the middleware's `endpoint_busy` admission check, so a step never sees its
20
+ * own slot, then released in the `finally` that also announces the disturbance.
21
+ * Both happen on resolve, timeout, and transport throw, and neither happens for
22
+ * a boundary that skipped the model altogether (`endpoint_busy`, no configured
23
+ * route), because those never call `complete`.
24
+ */
25
+
26
+ import { BusChannels } from "../../core/bus-events.js";
27
+ import type { SafeEventBus } from "../../core/event-bus.js";
28
+ import { registerForegroundStream } from "../providers/endpoint-capacity.js";
29
+
30
+ /** What the announcer needs: somewhere to publish, and the route to name. */
31
+ export interface MemoryStepEndpointAnnouncerDeps {
32
+ bus: Pick<SafeEventBus, "emit"> | null;
33
+ /** Canonical endpoint the step calls, or null when the route has none. */
34
+ endpointKey: string | null;
35
+ targetId: string;
36
+ }
37
+
38
+ /**
39
+ * Wrap one background memory `complete` so every request that leaves the
40
+ * process holds one endpoint slot and publishes its endpoint exactly once,
41
+ * whatever the call does next.
42
+ *
43
+ * A route with no canonical endpoint key is unchanged. A null bus suppresses
44
+ * the announcement but still counts capacity for a route whose key is known.
45
+ */
46
+ export function announceMemoryStepEndpoint<Request, Response>(
47
+ deps: MemoryStepEndpointAnnouncerDeps,
48
+ complete: (request: Request) => Promise<Response>,
49
+ ): (request: Request) => Promise<Response> {
50
+ const { bus, endpointKey, targetId } = deps;
51
+ if (endpointKey === null) return complete;
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.
55
+ const releaseEndpointSlot = registerForegroundStream(endpointKey);
56
+ try {
57
+ return await complete(request);
58
+ } finally {
59
+ releaseEndpointSlot();
60
+ // Bookkeeping never changes memory behavior, and a crashing subscriber
61
+ // must not turn a resolved step into a failed one.
62
+ if (bus !== null) {
63
+ try {
64
+ bus.emit(BusChannels.MemoryStepCompleted, { endpointKey, targetId });
65
+ } catch {
66
+ // The safe bus already contains listener errors; this covers the rest.
67
+ }
68
+ }
69
+ }
70
+ };
71
+ }
@@ -0,0 +1,434 @@
1
+ /**
2
+ * The pane layer's cross-domain surface.
3
+ *
4
+ * Every method is best-effort. A mux failure never fails a dispatch, never
5
+ * throws at a caller, and never blocks the event loop on a dead socket: it logs
6
+ * and degrades to `available() === false`, which the consumers read as "use the
7
+ * native fleet surfaces instead". That is why every method here returns a
8
+ * fallback value rather than rejecting.
9
+ *
10
+ * Two ownership rules run through the whole file. Clio acts only on panes it
11
+ * created, tracked in `pane-registry.ts` and tagged with the `clio_owner`
12
+ * metadata token so `clio doctor` can find orphans. The one documented
13
+ * exception is Clio's own hosting pane in guest mode, which `reportSelf`
14
+ * writes to under SA-3 of the v0.4.0 cycle plan.
15
+ *
16
+ * What is deliberately absent: per-run viewer panes. The v0.4.0 phase 3/4
17
+ * integration opened a pane per dispatched run in a hidden Fleet tab, with a
18
+ * focus ladder, run-state reporting, and resume adoption keyed on run ids. All
19
+ * of that projected fleet state the native surfaces already show onto panes
20
+ * nobody had asked for. The one run-viewing surface is now the workers-view
21
+ * watch pane (src/interactive/watch-pane.ts): a single utility pane following
22
+ * a selection file, opened on operator demand and retargeted by file writes
23
+ * that never touch this socket.
24
+ */
25
+
26
+ import type { DomainContract } from "../../core/domain-loader.js";
27
+ import type { MuxDetection } from "./detect.js";
28
+ import { createPaneRegistry, type MuxPaneRegistry, paneRecord } from "./pane-registry.js";
29
+ import { muxSupportsMethod } from "./protocol.js";
30
+ import type {
31
+ MuxClient,
32
+ MuxSubscription,
33
+ MuxWorktreeCreatedResult,
34
+ MuxWorktreeCreateRequest,
35
+ } from "./socket-client.js";
36
+ import {
37
+ MuxError,
38
+ type MuxEvent,
39
+ type MuxLog,
40
+ type MuxMode,
41
+ type MuxNotificationSound,
42
+ type MuxPanePurpose,
43
+ type MuxPaneRecord,
44
+ type MuxPaneRef,
45
+ type MuxSelfReport,
46
+ } from "./types.js";
47
+
48
+ /** Metadata source for everything Clio's pane layer writes. */
49
+ const METADATA_SOURCE = "clio:mux";
50
+ /** Agent-authority source for Clio's own hosting pane, per SA-3. */
51
+ const SELF_AGENT_SOURCE = "clio:coder";
52
+ /** Token every Clio-created pane carries so orphans are findable. */
53
+ const OWNER_TOKEN_KEY = "clio_owner";
54
+ const OWNER_TOKEN_VALUE = "clio:mux";
55
+ /** herdr caps a metadata token value at 80 characters. */
56
+ const TOKEN_VALUE_MAX = 80;
57
+ /** How long `available()` stays false after a transport failure before probing again. */
58
+ const DEGRADE_COOLDOWN_MS = 5_000;
59
+
60
+ export interface MuxOpenUtilityPaneRequest {
61
+ argv: ReadonlyArray<string>;
62
+ cwd: string;
63
+ label: string;
64
+ /** Operator-facing pane title. Omitted when the caller wants the shell default. */
65
+ title?: string;
66
+ purpose?: MuxPanePurpose;
67
+ direction?: "right" | "down";
68
+ env?: Readonly<Record<string, string>>;
69
+ /**
70
+ * Absolute path the pane's stdout is redirected into. Full-screen programs
71
+ * such as Yazi reopen `/dev/tty` for their interface when stdout is not a tty.
72
+ */
73
+ stdoutPath?: string;
74
+ }
75
+
76
+ export interface MuxNotifyRequest {
77
+ title: string;
78
+ body?: string;
79
+ sound?: MuxNotificationSound;
80
+ }
81
+
82
+ export interface MuxContract extends DomainContract {
83
+ readonly mode: MuxMode;
84
+ /** `mode !== "none"` and the socket is currently healthy. */
85
+ available(): boolean;
86
+ /**
87
+ * The rung detection resolved to, with the socket it answered on and the
88
+ * protocol recorded from the handshake. `/panes` and `clio-coder doctor`
89
+ * print it; the notify and worktree paths gate on its protocol.
90
+ */
91
+ detection(): Readonly<MuxDetection>;
92
+ openUtilityPane(request: MuxOpenUtilityPaneRequest): Promise<MuxPaneRef | null>;
93
+ /** Close one Clio-created pane by pane id. Refuses a pane Clio did not create. */
94
+ closePane(paneId: string): Promise<boolean>;
95
+ /**
96
+ * Re-adopt one pane of the given purpose that outlived the process that made
97
+ * it. A fresh `session.snapshot` is scanned for a pane carrying Clio's owner
98
+ * token and a matching `role` token; the first hit is recorded and returned.
99
+ * This is what stops a restarted session's Enter-in-the-workers-view from
100
+ * opening a second watch pane beside the surviving one.
101
+ */
102
+ adoptPane(request: { purpose: MuxPanePurpose; label: string }): Promise<MuxPaneRef | null>;
103
+ notify(request: MuxNotifyRequest): Promise<void>;
104
+ /** Optional compete storage route. Protocol-gated with a native Git fallback at the caller. */
105
+ worktreeCreate(request: MuxWorktreeCreateRequest): Promise<MuxWorktreeCreatedResult | null>;
106
+ /** Remove a herdr worktree workspace. False tells the caller to use native Git cleanup. */
107
+ worktreeRemove(workspaceId: string, options?: { force?: boolean }): Promise<boolean>;
108
+ /**
109
+ * Called when a pane Clio owns leaves, whether the user closed it or the
110
+ * program in it exited. Callers record it and do not reopen: a closed pane
111
+ * is a decision, not a fault.
112
+ */
113
+ onPaneGone(handler: (record: MuxPaneRecord) => void): () => void;
114
+ /** Panes Clio created, with their purpose. */
115
+ list(): ReadonlyArray<MuxPaneRecord>;
116
+ /**
117
+ * Report Clio's own state on its hosting pane (SA-3). Returns false when
118
+ * there is no pane to report on, which is every mode but guest.
119
+ */
120
+ reportSelf(report: MuxSelfReport): Promise<boolean>;
121
+ shutdown(): Promise<void>;
122
+ }
123
+
124
+ export interface MuxRuntimeOptions {
125
+ detection: MuxDetection;
126
+ client: MuxClient | null;
127
+ log?: MuxLog;
128
+ now?: () => number;
129
+ }
130
+
131
+ /** The contract plus the lifecycle handles the domain extension drives. */
132
+ export interface MuxRuntime {
133
+ contract: MuxContract;
134
+ start(): Promise<void>;
135
+ stop(): Promise<void>;
136
+ /** Test seam: the registry the contract reconciles against. */
137
+ registry: MuxPaneRegistry;
138
+ }
139
+
140
+ /** POSIX single-quoting, so an argv element with spaces or quotes survives the shell. */
141
+ function shellQuote(argv: ReadonlyArray<string>): string {
142
+ return argv.map((arg) => `'${arg.replaceAll("'", `'\\''`)}'`).join(" ");
143
+ }
144
+
145
+ function token(value: string | undefined | null): string | null {
146
+ if (typeof value !== "string" || value.length === 0) return null;
147
+ return value.length > TOKEN_VALUE_MAX ? value.slice(0, TOKEN_VALUE_MAX) : value;
148
+ }
149
+
150
+ export function createMuxRuntime(options: MuxRuntimeOptions): MuxRuntime {
151
+ const { detection, client } = options;
152
+ const log = options.log ?? ((): void => undefined);
153
+ const now = options.now ?? Date.now;
154
+ const registry = createPaneRegistry();
155
+
156
+ let healthy = client !== null;
157
+ let probeHealthAt = 0;
158
+ let stopped = false;
159
+ let subscription: MuxSubscription | null = null;
160
+ const paneGoneHandlers = new Set<(record: MuxPaneRecord) => void>();
161
+
162
+ const degrade = (what: string, error: unknown): void => {
163
+ const message = error instanceof Error ? error.message : String(error);
164
+ const transport = error instanceof MuxError && (error.kind === "transport" || error.kind === "timeout");
165
+ if (transport) {
166
+ healthy = false;
167
+ probeHealthAt = now() + DEGRADE_COOLDOWN_MS;
168
+ }
169
+ log(transport ? "warning" : "debug", `mux ${what} failed: ${message}`);
170
+ };
171
+
172
+ const usable = (): boolean => {
173
+ if (stopped || client === null || detection.mode === "none") return false;
174
+ return healthy || now() >= probeHealthAt;
175
+ };
176
+
177
+ /**
178
+ * Runs one mux interaction and swallows everything it can throw. The fallback
179
+ * is what the caller sees when the pane layer is not there, which is the same
180
+ * value it sees in `none` mode.
181
+ */
182
+ const attempt = async <T>(what: string, run: (live: MuxClient) => Promise<T>, fallback: T): Promise<T> => {
183
+ if (!usable() || client === null) return fallback;
184
+ try {
185
+ const value = await run(client);
186
+ healthy = true;
187
+ return value;
188
+ } catch (error) {
189
+ degrade(what, error);
190
+ return fallback;
191
+ }
192
+ };
193
+
194
+ const tagOwner = async (
195
+ live: MuxClient,
196
+ paneId: string,
197
+ tokens: Readonly<Record<string, string | null>>,
198
+ title?: string,
199
+ ): Promise<void> => {
200
+ await live.paneReportMetadata({
201
+ paneId,
202
+ source: METADATA_SOURCE,
203
+ ...(title === undefined ? {} : { title }),
204
+ tokens: { [OWNER_TOKEN_KEY]: OWNER_TOKEN_VALUE, ...tokens },
205
+ });
206
+ };
207
+
208
+ const onEvent = (event: MuxEvent): void => {
209
+ const dropped = registry.forget(event.paneId);
210
+ if (dropped) {
211
+ log("debug", `mux pane ${event.paneId} left on ${event.kind}; dropped from the registry`);
212
+ for (const handler of paneGoneHandlers) {
213
+ try {
214
+ handler(dropped);
215
+ } catch (error) {
216
+ log("debug", `mux pane-gone handler threw: ${error instanceof Error ? error.message : String(error)}`);
217
+ }
218
+ }
219
+ }
220
+ };
221
+
222
+ const contract: MuxContract = {
223
+ mode: detection.mode,
224
+
225
+ available(): boolean {
226
+ return usable();
227
+ },
228
+
229
+ detection(): Readonly<MuxDetection> {
230
+ return detection;
231
+ },
232
+
233
+ async openUtilityPane(request: MuxOpenUtilityPaneRequest): Promise<MuxPaneRef | null> {
234
+ return await attempt(
235
+ "openUtilityPane",
236
+ async (live) => {
237
+ const anchor = detection.self.paneId ?? (await live.paneCurrent()).paneId;
238
+ const pane = await live.paneSplit({
239
+ direction: request.direction ?? "right",
240
+ targetPaneId: anchor,
241
+ cwd: request.cwd,
242
+ focus: false,
243
+ ...(request.env ? { env: request.env } : {}),
244
+ });
245
+ const ref: MuxPaneRef = { paneId: pane.paneId, tabId: pane.tabId, workspaceId: pane.workspaceId };
246
+ const purpose = request.purpose ?? "utility";
247
+ registry.record(paneRecord(ref, { purpose, label: request.label, openedAt: now() }));
248
+ const title = request.title;
249
+ const titleSupported = title !== undefined && muxSupportsMethod(detection.server, "pane.rename");
250
+ if (titleSupported) {
251
+ try {
252
+ await live.paneRename(pane.paneId, title);
253
+ } catch {
254
+ // Presentation is optional. A server that advertises the floor but
255
+ // lacks or refuses rename must not strand an otherwise healthy pane.
256
+ }
257
+ }
258
+ // The `role` token is what adoptPane finds again after a restart.
259
+ await tagOwner(live, pane.paneId, { role: token(purpose) }, titleSupported ? title : undefined);
260
+ if (request.argv.length > 0) {
261
+ // herdr has no argv parameter on pane.split, so the command goes in
262
+ // through the pane's shell. `exec` replaces the shell so the pane
263
+ // exits with the program and emits pane.exited for reconciliation.
264
+ const redirect = request.stdoutPath ? ` > ${shellQuote([request.stdoutPath])}` : "";
265
+ await live.paneSendText(pane.paneId, `exec ${shellQuote(request.argv)}${redirect}\n`);
266
+ }
267
+ return ref;
268
+ },
269
+ null,
270
+ );
271
+ },
272
+
273
+ async closePane(paneId: string): Promise<boolean> {
274
+ // The ownership rule, restated for the operator-facing path: `/panes
275
+ // close` addresses panes by id and must refuse anything the registry
276
+ // does not hold.
277
+ if (!registry.owns(paneId)) return false;
278
+ return await attempt(
279
+ "closePane",
280
+ async (live) => {
281
+ await live.paneClose(paneId);
282
+ registry.forget(paneId);
283
+ return true;
284
+ },
285
+ false,
286
+ );
287
+ },
288
+
289
+ async adoptPane(request: { purpose: MuxPanePurpose; label: string }): Promise<MuxPaneRef | null> {
290
+ const existing = registry.byPurpose(request.purpose);
291
+ if (existing) return existing.ref;
292
+ return await attempt(
293
+ "adoptPane",
294
+ async (live) => {
295
+ const snapshot = await live.snapshot();
296
+ for (const pane of snapshot.panes) {
297
+ if (pane.tokens[OWNER_TOKEN_KEY] !== OWNER_TOKEN_VALUE) continue;
298
+ if (pane.tokens.role !== request.purpose) continue;
299
+ if (registry.owns(pane.paneId)) continue;
300
+ // Another workspace's pane belongs to another session's screen;
301
+ // adopting it would retarget a surface the operator cannot see.
302
+ if (detection.self.workspaceId !== null && pane.workspaceId !== detection.self.workspaceId) continue;
303
+ const ref: MuxPaneRef = { paneId: pane.paneId, tabId: pane.tabId, workspaceId: pane.workspaceId };
304
+ registry.record(
305
+ paneRecord(ref, { purpose: request.purpose, label: request.label, openedAt: now(), adopted: true }),
306
+ );
307
+ log("info", `mux adopted a ${request.purpose} pane left open by a previous session`);
308
+ return ref;
309
+ }
310
+ return null;
311
+ },
312
+ null,
313
+ );
314
+ },
315
+
316
+ async notify(request: MuxNotifyRequest): Promise<void> {
317
+ if (!muxSupportsMethod(detection.server, "notification.show")) {
318
+ log("debug", `mux notify skipped, server protocol is below the notification.show floor: ${request.title}`);
319
+ return;
320
+ }
321
+ await attempt(
322
+ "notify",
323
+ async (live) => {
324
+ const result = await live.notificationShow({
325
+ title: request.title,
326
+ ...(request.body ? { body: request.body } : {}),
327
+ ...(request.sound ? { sound: request.sound } : {}),
328
+ });
329
+ // A suppressed toast is the operator's own herdr config talking
330
+ // (disabled, rate limited, no foreground client). Reporting it as a
331
+ // warning would turn their setting into Clio's error.
332
+ if (!result.shown) log("debug", `mux notify not shown (${result.reason}): ${request.title}`);
333
+ return undefined;
334
+ },
335
+ undefined,
336
+ );
337
+ },
338
+
339
+ async worktreeCreate(request: MuxWorktreeCreateRequest): Promise<MuxWorktreeCreatedResult | null> {
340
+ if (!muxSupportsMethod(detection.server, "worktree.create")) {
341
+ log("debug", "mux worktree.create skipped, server protocol is below the worktree floor");
342
+ return null;
343
+ }
344
+ return await attempt("worktreeCreate", (live) => live.worktreeCreate(request), null);
345
+ },
346
+
347
+ async worktreeRemove(workspaceId: string, removeOptions = {}): Promise<boolean> {
348
+ if (!muxSupportsMethod(detection.server, "worktree.remove")) {
349
+ log("debug", "mux worktree.remove skipped, server protocol is below the worktree floor");
350
+ return false;
351
+ }
352
+ return await attempt(
353
+ "worktreeRemove",
354
+ async (live) => {
355
+ await live.worktreeRemove(workspaceId, removeOptions);
356
+ return true;
357
+ },
358
+ false,
359
+ );
360
+ },
361
+
362
+ onPaneGone(handler: (record: MuxPaneRecord) => void): () => void {
363
+ paneGoneHandlers.add(handler);
364
+ return () => {
365
+ paneGoneHandlers.delete(handler);
366
+ };
367
+ },
368
+
369
+ list(): ReadonlyArray<MuxPaneRecord> {
370
+ return registry.list();
371
+ },
372
+
373
+ async reportSelf(report: MuxSelfReport): Promise<boolean> {
374
+ const paneId = detection.self.paneId;
375
+ if (detection.mode !== "guest" || !paneId) return false;
376
+ return await attempt(
377
+ "reportSelf",
378
+ async (live) => {
379
+ await live.paneReportAgent({
380
+ paneId,
381
+ source: SELF_AGENT_SOURCE,
382
+ agent: "clio-coder",
383
+ state: report.state,
384
+ ...(report.message ? { message: report.message } : {}),
385
+ });
386
+ if (report.tokens || report.stateLabels || report.ttlMs !== undefined) {
387
+ await live.paneReportMetadata({
388
+ paneId,
389
+ source: METADATA_SOURCE,
390
+ ...(report.tokens ? { tokens: report.tokens } : {}),
391
+ ...(report.stateLabels ? { stateLabels: report.stateLabels } : {}),
392
+ ...(report.ttlMs !== undefined ? { ttlMs: report.ttlMs } : {}),
393
+ });
394
+ }
395
+ return true;
396
+ },
397
+ false,
398
+ );
399
+ },
400
+
401
+ async shutdown(): Promise<void> {
402
+ if (stopped) return;
403
+ stopped = true;
404
+ subscription?.close();
405
+ subscription = null;
406
+ paneGoneHandlers.clear();
407
+ // Pane ownership is server-side and intentionally survives process
408
+ // shutdown. Keep the local snapshot too so the contract itself proves
409
+ // shutdown tears down sockets, never panes.
410
+ if (client) await client.close().catch(() => undefined);
411
+ },
412
+ };
413
+
414
+ const start = async (): Promise<void> => {
415
+ if (detection.mode === "none" || client === null) return;
416
+ try {
417
+ subscription = await client.subscribe(["pane.closed", "pane.exited"], onEvent, {
418
+ onResync: (snapshot) => {
419
+ // A reconnect means events were missed. The snapshot is the authority
420
+ // on which panes still exist, so anything Clio thinks it owns that is
421
+ // absent from it is gone.
422
+ const dropped = registry.reconcile(snapshot.panes.map((pane) => pane.paneId));
423
+ if (dropped.length > 0) {
424
+ log("info", `mux reconciled ${dropped.length} pane(s) closed while the socket was down`);
425
+ }
426
+ },
427
+ });
428
+ } catch (error) {
429
+ degrade("event subscription", error);
430
+ }
431
+ };
432
+
433
+ return { contract, start, stop: contract.shutdown, registry };
434
+ }