@iowarp/clio-coder 0.3.9 → 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 (416) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/NOTICE +33 -0
  3. package/README.md +7 -2
  4. package/dist/{acp-7LOELQFP.js → acp-G5WJBNCT.js} +13 -12
  5. package/dist/{agents-FIBG2SHA.js → agents-FMV2Q5G4.js} +39 -36
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-OI4LIH2I.js → auth-3IDSJEIK.js} +16 -15
  8. package/dist/{builtins-AD25UL3C.js → builtins-XCZWXSC7.js} +3 -3
  9. package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
  10. package/dist/{chunk-56KB5IJP.js → chunk-2OQE55CK.js} +3 -3
  11. package/dist/{chunk-N3PBVRTZ.js → chunk-32KWKNSF.js} +9 -7
  12. package/dist/{chunk-VKBMFOYV.js → chunk-36EJLSQQ.js} +23 -27
  13. package/dist/{chunk-465CC7FK.js → chunk-3BT2XMV4.js} +16 -13
  14. package/dist/{chunk-NQ6UCCOD.js → chunk-3URVFKWK.js} +7 -7
  15. package/dist/{chunk-WIE7ZOSW.js → chunk-3XML7CDN.js} +2 -2
  16. package/dist/chunk-42FMPA75.js +101 -0
  17. package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
  18. package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
  19. package/dist/{chunk-JEQQR47K.js → chunk-6DB53AJS.js} +168 -9
  20. package/dist/{chunk-KV2AOLDF.js → chunk-76ONBSIA.js} +5 -25
  21. package/dist/{chunk-FALJGAWU.js → chunk-7MCTRUCE.js} +2 -2
  22. package/dist/{chunk-5T7RBWN2.js → chunk-AB44T6BB.js} +5 -5
  23. package/dist/chunk-B7OBL7PK.js +1405 -0
  24. package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
  25. package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
  26. package/dist/{chunk-O6I4CIEU.js → chunk-BKFJHQCA.js} +6 -6
  27. package/dist/chunk-BKFM6EJV.js +462 -0
  28. package/dist/chunk-BMS5RKQY.js +27 -0
  29. package/dist/{chunk-MV2VUEJC.js → chunk-BPKCPIL7.js} +2 -2
  30. package/dist/{chunk-TEO2TLVN.js → chunk-BUMFYQFY.js} +964 -1120
  31. package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
  32. package/dist/chunk-C2LTL2W6.js +2447 -0
  33. package/dist/{chunk-EBOC7MT3.js → chunk-CODPRO7Q.js} +8 -8
  34. package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
  35. package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
  36. package/dist/{chunk-MIX5N5AC.js → chunk-DQITNCXG.js} +394 -154
  37. package/dist/{chunk-S4COXYBG.js → chunk-DYJP44XW.js} +129 -106
  38. package/dist/{chunk-N5XKWMDW.js → chunk-F4CKPOEQ.js} +6 -6
  39. package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
  40. package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
  41. package/dist/{chunk-7C6RYZGQ.js → chunk-GKF55TAZ.js} +3 -3
  42. package/dist/{chunk-B5XRQOLB.js → chunk-GR5G2PVF.js} +9 -8
  43. package/dist/{chunk-XDOQXGFO.js → chunk-GXNLGKAB.js} +64 -8
  44. package/dist/chunk-HHV2GANA.js +88 -0
  45. package/dist/{chunk-774ILSRL.js → chunk-HI63TFOG.js} +4 -3
  46. package/dist/{chunk-R7LNVMCS.js → chunk-HJJTYUHX.js} +64 -72
  47. package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
  48. package/dist/{chunk-CA42X6KT.js → chunk-HWHKMHUA.js} +6 -6
  49. package/dist/chunk-HZHHCK24.js +1631 -0
  50. package/dist/{chunk-HJB5IUKP.js → chunk-I5VEOC6I.js} +12 -12
  51. package/dist/chunk-IBEBSCYA.js +564 -0
  52. package/dist/chunk-IQ7KR472.js +362 -0
  53. package/dist/{chunk-4H6ULJ3H.js → chunk-J4W7KFM7.js} +921 -990
  54. package/dist/{chunk-4LJX2PUC.js → chunk-JDG2WCRO.js} +5 -5
  55. package/dist/{chunk-NZU6YDNV.js → chunk-K5C3NCBD.js} +4 -4
  56. package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
  57. package/dist/{chunk-NNNWO6F2.js → chunk-KFZI4NIL.js} +93 -3
  58. package/dist/chunk-KMVISBZR.js +132 -0
  59. package/dist/{chunk-BVDVID7E.js → chunk-LDQ2ZF2M.js} +2 -2
  60. package/dist/{chunk-OEDBCISO.js → chunk-LQ3DZAMX.js} +2 -2
  61. package/dist/{chunk-PZ4I4JE2.js → chunk-LY4S7GJC.js} +124 -116
  62. package/dist/{chunk-3DUR4WUA.js → chunk-MLKNTWH2.js} +19 -19
  63. package/dist/chunk-NEKRRTYW.js +56 -0
  64. package/dist/{chunk-5DQRIYDZ.js → chunk-NHCZP4K7.js} +2 -2
  65. package/dist/chunk-NHLBIGRH.js +1506 -0
  66. package/dist/chunk-NQQH3YT7.js +302 -0
  67. package/dist/chunk-NYS75XW5.js +15 -0
  68. package/dist/{chunk-TD7UE2L5.js → chunk-O4XIVISU.js} +7 -7
  69. package/dist/{chunk-WXCJ7VME.js → chunk-O6TL7WWY.js} +6 -6
  70. package/dist/chunk-OQBA45DZ.js +97 -0
  71. package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
  72. package/dist/chunk-PMZCIOCJ.js +25 -0
  73. package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
  74. package/dist/{chunk-HKO36JWF.js → chunk-QBJA7R7N.js} +31 -3
  75. package/dist/chunk-QDC3K2U3.js +262 -0
  76. package/dist/{chunk-5HFBWUMU.js → chunk-QLFS5GO2.js} +4 -4
  77. package/dist/{chunk-GAYUJ7LE.js → chunk-QLL7ILRG.js} +41 -32
  78. package/dist/{chunk-LXPJXFM5.js → chunk-QREDIESB.js} +7 -7
  79. package/dist/chunk-QSNYB6ZV.js +195 -0
  80. package/dist/chunk-R346GLFC.js +31 -0
  81. package/dist/{chunk-VPTUJU4P.js → chunk-SJ5ZKQ4S.js} +2 -2
  82. package/dist/{chunk-QQ7EKM72.js → chunk-SP2RXXYO.js} +6 -54
  83. package/dist/chunk-SUCTJL45.js +45 -0
  84. package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
  85. package/dist/chunk-T56WDKA5.js +183 -0
  86. package/dist/chunk-TVHHYFHE.js +255 -0
  87. package/dist/{chunk-IHKBWSXF.js → chunk-TZ3SGWZZ.js} +2 -2
  88. package/dist/{chunk-ECUO3KDP.js → chunk-U77AMWDL.js} +47 -7
  89. package/dist/{chunk-3UUY7R3Z.js → chunk-ULC6OTWO.js} +7 -7
  90. package/dist/{chunk-AEYBF3TB.js → chunk-UM7N4G5A.js} +2 -2
  91. package/dist/{chunk-3V5AYSEQ.js → chunk-UXMFQ54G.js} +43 -36
  92. package/dist/{chunk-YW7UVM5V.js → chunk-V5DHCITQ.js} +34 -1
  93. package/dist/{chunk-47CMYGET.js → chunk-VAZSBTKF.js} +2 -2
  94. package/dist/{chunk-3MRC2YSQ.js → chunk-VEO4AP2K.js} +2 -2
  95. package/dist/{chunk-PNY46YEY.js → chunk-VFA6GDY5.js} +47 -3
  96. package/dist/chunk-VO67MWHC.js +75 -0
  97. package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
  98. package/dist/{chunk-AD7Y7STJ.js → chunk-VYMXRQI6.js} +36 -22
  99. package/dist/{chunk-T3Z6VAAF.js → chunk-W5VSYASO.js} +19 -17
  100. package/dist/{chunk-5PVQ4SRS.js → chunk-WZR7K7ZX.js} +7 -123
  101. package/dist/{chunk-DG4M6ZUE.js → chunk-X3YGUTOB.js} +4 -4
  102. package/dist/chunk-X75E3D2N.js +686 -0
  103. package/dist/{chunk-P3JGPQFL.js → chunk-YDFRH54B.js} +4 -4
  104. package/dist/chunk-YJX4SHTD.js +40 -0
  105. package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
  106. package/dist/{chunk-YSEHGPCT.js → chunk-Z2RR6MAK.js} +3 -3
  107. package/dist/{chunk-HCBCAYZU.js → chunk-Z4TXYIEG.js} +5 -5
  108. package/dist/cli/index.js +47 -36
  109. package/dist/{clio-LT5V7SSZ.js → clio-2JXHBBY5.js} +7 -7
  110. package/dist/{code-nav-LMW275PA.js → code-nav-3YYRMYNF.js} +6 -6
  111. package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
  112. package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
  113. package/dist/{config-RXS5T3JT.js → config-QZPCMYSO.js} +58 -50
  114. package/dist/{configure-2WYWSCSD.js → configure-TEGEBYCA.js} +21 -19
  115. package/dist/{context-I3BTOTCS.js → context-AV7OEZ4D.js} +11 -11
  116. package/dist/{context-MVOORGMF.js → context-E6H5RNMC.js} +49 -41
  117. package/dist/{context-PALKKQYL.js → context-GSXUE4CT.js} +25 -23
  118. package/dist/{context-clear-N2WOYZ2K.js → context-clear-SHIBYK6T.js} +48 -40
  119. package/dist/{context-working-set-MIEVECVZ.js → context-working-set-5ZGKPGZQ.js} +11 -10
  120. package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-EFMJT4LD.js} +88 -60
  121. package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
  122. package/dist/doctor-QOA5FNY5.js +313 -0
  123. package/dist/{eval-IJ5VEZDJ.js → eval-TFBYQH4H.js} +66 -64
  124. package/dist/eval-inventory-SXH7PDKX.js +316 -0
  125. package/dist/{evidence-L5APPXNV.js → evidence-ERGESKGN.js} +198 -44
  126. package/dist/{evolve-RGNKFJ52.js → evolve-VDXTSYCJ.js} +46 -38
  127. package/dist/{extensions-7WYWUX5A.js → extensions-7BGBHN57.js} +6 -6
  128. package/dist/{fleet-6CNVBZZP.js → fleet-2RRVDF2V.js} +189 -101
  129. package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-VJ726XIA.js} +10 -10
  130. package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
  131. package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-JF5QOATM.js} +16 -15
  132. package/dist/fleet-inspect-VLY4S7QM.js +442 -0
  133. package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-AIZUEJOY.js} +6 -5
  134. package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-AJRPDMDV.js} +20 -18
  135. package/dist/fleet-verify-JFEL2L3H.js +175 -0
  136. package/dist/fleet-view-ZCON35AG.js +102 -0
  137. package/dist/{init-VBN2ACVA.js → init-DN2WWLFE.js} +64 -56
  138. package/dist/install-XGLBQY5E.js +13 -0
  139. package/dist/interop-OZBKXAYL.js +114 -0
  140. package/dist/{library-JHGUMLY2.js → library-YWZG7IMW.js} +19 -18
  141. package/dist/{memory-K4OQIYWG.js → memory-I4C4HMLW.js} +48 -40
  142. package/dist/{models-2NCZUWDD.js → models-CEYXJBO6.js} +30 -28
  143. package/dist/{monitor-MMVTJABD.js → monitor-NZ6GCI3P.js} +53 -47
  144. package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-GCGQ4N5I.js} +6311 -7145
  145. package/dist/panes-HMABYVO4.js +58 -0
  146. package/dist/panes-KY6W3V2E.js +103 -0
  147. package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
  148. package/dist/{reset-DD5JGOY3.js → reset-DQ6FGCSH.js} +13 -11
  149. package/dist/resources-BB3MVJMD.js +111 -0
  150. package/dist/{run-QEGNX7FL.js → run-H2GQDUER.js} +113 -82
  151. package/dist/{share-JKD3BQMW.js → share-GTJN6A5O.js} +18 -17
  152. package/dist/{skills-LMQIKDOZ.js → skills-L55TEW6R.js} +31 -24
  153. package/dist/{skills-eval-I7X2774U.js → skills-eval-XVXPH2JI.js} +61 -52
  154. package/dist/skills-inventory-S4MXPJFV.js +126 -0
  155. package/dist/slash-commands-ZSGASKJC.js +77 -0
  156. package/dist/{steer-CF5TDANS.js → steer-RZGSCY4R.js} +3 -3
  157. package/dist/{support-I7LOJLIF.js → support-PKEUNNQL.js} +4 -4
  158. package/dist/{targets-RUSR6B5Z.js → targets-NCPZ644J.js} +31 -29
  159. package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-44SV3YCN.js} +4 -4
  160. package/dist/tools-DAF3DI3C.js +27 -0
  161. package/dist/{trace-ODOQIVIW.js → trace-FYVW2MQA.js} +149 -7
  162. package/dist/tui-primitives-2AKXQNZK.js +13 -0
  163. package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
  164. package/dist/{upgrade-XANW3FXB.js → upgrade-3XPP6OQL.js} +26 -24
  165. package/dist/{usage-4H7ZRXQT.js → usage-3NLHGTU2.js} +57 -49
  166. package/dist/{verifiers-UZXNBZEB.js → verifiers-SSQONKRT.js} +171 -12
  167. package/dist/{verify-BVKWTNDL.js → verify-3U6J7FZI.js} +9 -9
  168. package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
  169. package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-CEHYGPGQ.js} +67 -59
  170. package/dist/with-panes-MKB46MPQ.js +782 -0
  171. package/dist/worker/entry.js +101 -66
  172. package/docs/README.md +3 -2
  173. package/docs/acp.md +24 -3
  174. package/docs/alcf-provider.md +1 -1
  175. package/docs/architecture.md +2 -2
  176. package/docs/artifact-versions.md +4 -1
  177. package/docs/built-in-agents.md +1 -1
  178. package/docs/capacity-and-scheduling.md +43 -5
  179. package/docs/commands-and-modes.md +31 -2
  180. package/docs/configuration-and-targets.md +40 -10
  181. package/docs/context-engine.md +1 -1
  182. package/docs/development-pipeline.md +19 -0
  183. package/docs/dispatch-typed-intent.md +385 -0
  184. package/docs/documentation-coverage.md +2 -2
  185. package/docs/documentation-guide.md +1 -1
  186. package/docs/environment-variables.md +1 -0
  187. package/docs/eval-runner.md +1 -1
  188. package/docs/evals-internal.md +1 -1
  189. package/docs/evidence-and-memory.md +2 -2
  190. package/docs/evolution.md +1 -1
  191. package/docs/exit-codes-and-output.md +1 -1
  192. package/docs/extensions-and-sharing.md +25 -1
  193. package/docs/fleet-dispatch.md +22 -1
  194. package/docs/installation-and-lifecycle.md +15 -2
  195. package/docs/middleware-and-components.md +1 -1
  196. package/docs/model-catalog.md +10 -1
  197. package/docs/observability.md +3 -3
  198. package/docs/proactive-memory.md +1 -1
  199. package/docs/prompt-envelope-and-tools.md +1 -1
  200. package/docs/provider-adapter-cookbook.md +1 -1
  201. package/docs/safety-model.md +2 -2
  202. package/docs/scientific-validation.md +3 -3
  203. package/docs/session-lifecycle.md +1 -1
  204. package/docs/skills-marketplace.md +1 -1
  205. package/docs/tool-usage.md +18 -8
  206. package/docs/trace-store.md +1 -1
  207. package/docs/troubleshooting.md +1 -1
  208. package/docs/tui-design.md +1 -1
  209. package/docs/worker-dispatch-mechanics.md +1 -1
  210. package/package.json +4 -2
  211. package/src/cli/acp.ts +6 -2
  212. package/src/cli/argv.ts +25 -0
  213. package/src/cli/configure.ts +23 -21
  214. package/src/cli/doctor-panes.ts +124 -0
  215. package/src/cli/doctor-toolchain.ts +57 -0
  216. package/src/cli/doctor.ts +20 -1
  217. package/src/cli/eval-inventory.ts +436 -0
  218. package/src/cli/eval.ts +13 -0
  219. package/src/cli/evidence-detail.ts +88 -0
  220. package/src/cli/evidence-inventory.ts +183 -0
  221. package/src/cli/evidence.ts +30 -5
  222. package/src/cli/fleet-decisions.ts +69 -0
  223. package/src/cli/fleet-inspect.ts +334 -0
  224. package/src/cli/fleet-verify.ts +133 -0
  225. package/src/cli/fleet-view.ts +810 -0
  226. package/src/cli/fleet.ts +148 -37
  227. package/src/cli/index.ts +14 -2
  228. package/src/cli/interop-inspect.ts +128 -0
  229. package/src/cli/interop.ts +34 -0
  230. package/src/cli/panes.ts +35 -0
  231. package/src/cli/reset.ts +5 -2
  232. package/src/cli/run.ts +58 -0
  233. package/src/cli/skills-inventory.ts +185 -0
  234. package/src/cli/skills.ts +16 -13
  235. package/src/cli/tools.ts +321 -0
  236. package/src/cli/trace-inspect.ts +252 -0
  237. package/src/cli/trace.ts +23 -2
  238. package/src/cli/verifiers-inspect.ts +347 -0
  239. package/src/cli/verifiers.ts +9 -0
  240. package/src/core/bus-events.ts +4 -0
  241. package/src/core/config.ts +49 -0
  242. package/src/core/defaults.ts +93 -7
  243. package/src/core/response-schema.ts +44 -4
  244. package/src/core/theme-token-hex.ts +43 -0
  245. package/src/core/tool-names.ts +2 -1
  246. package/src/core/xdg.ts +1 -1
  247. package/src/domains/agents/fleets/build-review.md +0 -3
  248. package/src/domains/agents/fleets/build-test.md +0 -3
  249. package/src/domains/agents/result-contract-filesystem.ts +32 -0
  250. package/src/domains/agents/result-contract.ts +164 -35
  251. package/src/domains/config/classify.ts +3 -0
  252. package/src/domains/dispatch/admission-error.ts +9 -0
  253. package/src/domains/dispatch/admission.ts +22 -21
  254. package/src/domains/dispatch/capacity-lease.ts +21 -1
  255. package/src/domains/dispatch/council-topology.ts +398 -0
  256. package/src/domains/dispatch/extension.ts +222 -50
  257. package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
  258. package/src/domains/dispatch/fleet-plan.ts +7 -2
  259. package/src/domains/dispatch/fleet-run.ts +64 -1
  260. package/src/domains/dispatch/gate-decisions.ts +11 -1
  261. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  262. package/src/domains/dispatch/gate-topology.ts +289 -0
  263. package/src/domains/dispatch/index.ts +19 -0
  264. package/src/domains/dispatch/intent-compatibility.ts +330 -0
  265. package/src/domains/dispatch/intent.ts +85 -1
  266. package/src/domains/dispatch/reservation-store.ts +24 -4
  267. package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
  268. package/src/domains/dispatch/run-event-journal.ts +598 -0
  269. package/src/domains/dispatch/state.ts +45 -1
  270. package/src/domains/dispatch/types.ts +13 -0
  271. package/src/domains/dispatch/validation.ts +33 -8
  272. package/src/domains/eval/compare/compare.ts +3 -16
  273. package/src/domains/eval/inventory.ts +113 -0
  274. package/src/domains/eval/schema/serving.ts +31 -0
  275. package/src/domains/evidence/store.ts +6 -0
  276. package/src/domains/memory/index.ts +0 -1
  277. package/src/domains/memory/task-memory-policy.ts +6 -10
  278. package/src/domains/memory/task-memory-telemetry.ts +1 -0
  279. package/src/domains/middleware/memory-intervention.ts +33 -21
  280. package/src/domains/mux/contract.ts +434 -0
  281. package/src/domains/mux/detect.ts +158 -0
  282. package/src/domains/mux/extension.ts +47 -0
  283. package/src/domains/mux/index.ts +96 -0
  284. package/src/domains/mux/manifest.ts +6 -0
  285. package/src/domains/mux/operations.ts +164 -0
  286. package/src/domains/mux/pane-registry.ts +90 -0
  287. package/src/domains/mux/protocol.ts +49 -0
  288. package/src/domains/mux/socket-client.ts +816 -0
  289. package/src/domains/mux/types.ts +222 -0
  290. package/src/domains/mux/viewer-command.ts +59 -0
  291. package/src/domains/mux/yazi/assets/init.lua +2 -0
  292. package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
  293. package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
  294. package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
  295. package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
  296. package/src/domains/mux/yazi/assets/yazi.toml +17 -0
  297. package/src/domains/mux/yazi/event-stream.ts +180 -0
  298. package/src/domains/mux/yazi/profile.ts +299 -0
  299. package/src/domains/mux/yazi/session.ts +228 -0
  300. package/src/domains/mux/yazi/theme.ts +30 -0
  301. package/src/domains/observability/cost.ts +21 -0
  302. package/src/domains/observability/index.ts +2 -0
  303. package/src/domains/observability/trace-store.ts +42 -0
  304. package/src/domains/providers/endpoint-capacity.ts +154 -22
  305. package/src/domains/providers/endpoint-slots-store.ts +189 -0
  306. package/src/domains/providers/extension.ts +20 -3
  307. package/src/domains/providers/index.ts +22 -0
  308. package/src/domains/providers/model-runtime-capabilities.ts +32 -0
  309. package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
  310. package/src/domains/providers/runtimes/builtins.ts +2 -0
  311. package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
  312. package/src/domains/providers/support.ts +1 -0
  313. package/src/domains/providers/target-model-cache.ts +124 -0
  314. package/src/domains/resources/index.ts +3 -0
  315. package/src/domains/resources/skills/loader.ts +33 -0
  316. package/src/domains/safety/action-classifier.ts +6 -0
  317. package/src/domains/toolchain/archive.ts +175 -0
  318. package/src/domains/toolchain/contract.ts +28 -0
  319. package/src/domains/toolchain/extension.ts +47 -0
  320. package/src/domains/toolchain/index.ts +39 -0
  321. package/src/domains/toolchain/install.ts +327 -0
  322. package/src/domains/toolchain/manifest.ts +8 -0
  323. package/src/domains/toolchain/paths.ts +34 -0
  324. package/src/domains/toolchain/registry.ts +265 -0
  325. package/src/domains/toolchain/remove.ts +218 -0
  326. package/src/domains/toolchain/resolve.ts +182 -0
  327. package/src/domains/toolchain/types.ts +113 -0
  328. package/src/domains/toolchain/version.ts +88 -0
  329. package/src/engine/acp/server.ts +413 -70
  330. package/src/engine/acp/types.ts +19 -1
  331. package/src/engine/claude/sdk-module.ts +98 -0
  332. package/src/engine/claude/sdk-runtime.ts +19 -11
  333. package/src/engine/tui-primitives.ts +21 -0
  334. package/src/engine/tui.ts +1 -0
  335. package/src/engine/worker-runtime.ts +2 -13
  336. package/src/entry/boot-options.ts +2 -0
  337. package/src/entry/orchestrator.ts +103 -5
  338. package/src/entry/panes-activation.ts +31 -0
  339. package/src/entry/with-panes.ts +20 -0
  340. package/src/interactive/context-overlay.ts +1 -0
  341. package/src/interactive/cost-overlay.ts +2 -0
  342. package/src/interactive/council-grid.ts +1 -3
  343. package/src/interactive/council.ts +11 -0
  344. package/src/interactive/dispatch-board.ts +26 -16
  345. package/src/interactive/interactive-application.ts +153 -6
  346. package/src/interactive/interactive-input-runtime.ts +7 -0
  347. package/src/interactive/interactive-slash-runtime.ts +36 -6
  348. package/src/interactive/memory-overlay.ts +1 -0
  349. package/src/interactive/modal-marker.ts +170 -0
  350. package/src/interactive/mux-bridge.ts +214 -0
  351. package/src/interactive/overlay-frame.ts +58 -2
  352. package/src/interactive/overlay-general-openers.ts +1 -0
  353. package/src/interactive/overlay-key-routing.ts +14 -3
  354. package/src/interactive/overlay-lifecycle.ts +19 -3
  355. package/src/interactive/overlay-model-selectors.ts +40 -3
  356. package/src/interactive/overlay-permission-lifecycle.ts +90 -22
  357. package/src/interactive/overlay-transitions.ts +18 -4
  358. package/src/interactive/overlays/agents.ts +1 -0
  359. package/src/interactive/overlays/ask-user.ts +136 -30
  360. package/src/interactive/overlays/auth-dialog.ts +1 -0
  361. package/src/interactive/overlays/context-reset.ts +1 -0
  362. package/src/interactive/overlays/cwd-fallback.ts +1 -0
  363. package/src/interactive/overlays/decisions.ts +11 -11
  364. package/src/interactive/overlays/extensions.ts +1 -0
  365. package/src/interactive/overlays/fleet-run-approval.ts +1 -0
  366. package/src/interactive/overlays/handoff-review.ts +1 -0
  367. package/src/interactive/overlays/help-reference.ts +2 -0
  368. package/src/interactive/overlays/interop.ts +1 -0
  369. package/src/interactive/overlays/library-install-confirm.ts +1 -0
  370. package/src/interactive/overlays/library-tabs.ts +28 -0
  371. package/src/interactive/overlays/list-overlay.ts +10 -1
  372. package/src/interactive/overlays/message-picker.ts +1 -0
  373. package/src/interactive/overlays/model-scope.ts +86 -0
  374. package/src/interactive/overlays/model-selector.ts +1 -0
  375. package/src/interactive/overlays/prompts.ts +1 -0
  376. package/src/interactive/overlays/session-selector.ts +1 -0
  377. package/src/interactive/overlays/settings-sections.ts +30 -0
  378. package/src/interactive/overlays/settings.ts +579 -44
  379. package/src/interactive/overlays/side-question.ts +1 -0
  380. package/src/interactive/overlays/skills-hub.ts +3 -11
  381. package/src/interactive/overlays/tree-selector.ts +1 -0
  382. package/src/interactive/pane-policy.ts +46 -0
  383. package/src/interactive/panes-runtime.ts +292 -0
  384. package/src/interactive/renderers/compaction-summary.ts +29 -0
  385. package/src/interactive/renderers/worker-entry.ts +122 -14
  386. package/src/interactive/slash-commands.ts +251 -15
  387. package/src/interactive/tasks-overlay.ts +1 -0
  388. package/src/interactive/theme/tokens.ts +3 -14
  389. package/src/interactive/turn-context.ts +47 -2
  390. package/src/interactive/view/artifacts.ts +109 -1
  391. package/src/interactive/view/view-overlay.ts +1 -0
  392. package/src/interactive/watch-pane.ts +152 -0
  393. package/src/interactive/worker-progress.ts +7 -1
  394. package/src/interactive/worker-receipts.ts +19 -1
  395. package/src/interactive/worker-stream.ts +5 -0
  396. package/src/interactive/yazi-bridge.ts +444 -0
  397. package/src/tools/bootstrap.ts +26 -2
  398. package/src/tools/builtin-tool-catalog.ts +15 -0
  399. package/src/tools/compete-worktrees.ts +83 -2
  400. package/src/tools/core-bootstrap.ts +2 -1
  401. package/src/tools/dispatch-admission.ts +14 -3
  402. package/src/tools/dispatch-arguments.ts +20 -20
  403. package/src/tools/dispatch-run-events.ts +134 -19
  404. package/src/tools/dispatch-runner.ts +29 -7
  405. package/src/tools/dispatch-types.ts +15 -3
  406. package/src/tools/dispatch.ts +1 -1
  407. package/src/tools/executables.ts +17 -14
  408. package/src/tools/observation.ts +54 -4
  409. package/src/tools/panes-surface.ts +38 -0
  410. package/src/tools/panes.ts +112 -0
  411. package/src/tools/policy.ts +10 -1
  412. package/src/tools/presentation.ts +1 -0
  413. package/dist/chunk-D73KXYPF.js +0 -37
  414. package/dist/chunk-MLOK6ZOS.js +0 -2888
  415. package/dist/chunk-YKOFT37S.js +0 -279
  416. package/dist/doctor-TWBWFK5V.js +0 -165
@@ -41,13 +41,8 @@ import { type CostProvenance, foregroundStreamUsage } from "../domains/providers
41
41
  import { sanitizeCallTargetText } from "../domains/safety/call-target.js";
42
42
  import { type Component, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../engine/tui.js";
43
43
  import { formatWorkerContextMeter } from "./context-meter.js";
44
- import {
45
- COUNCIL_SYNTHESIS_LABEL,
46
- type CouncilGroupView,
47
- type CouncilMemberView,
48
- councilGroupBody,
49
- councilIslandLines,
50
- } from "./council-grid.js";
44
+ import { COUNCIL_SYNTHESIS_LABEL } from "./council.js";
45
+ import { type CouncilGroupView, type CouncilMemberView, councilGroupBody, councilIslandLines } from "./council-grid.js";
51
46
  import { formatFooterTokens } from "./footer-panel.js";
52
47
  import {
53
48
  type ClioTheme,
@@ -631,9 +626,15 @@ export function renderDispatchCard(
631
626
  row: DispatchBoardRow,
632
627
  width: number,
633
628
  evidence?: RunEvidencePresentation,
634
- options: { selected?: boolean; expanded?: boolean; endpointActive?: number } = {},
629
+ options: {
630
+ selected?: boolean;
631
+ expanded?: boolean;
632
+ endpointActive?: number;
633
+ endpointQueued?: number;
634
+ theme?: ClioTheme;
635
+ } = {},
635
636
  ): string[] {
636
- const theme = clioTheme();
637
+ const theme = options.theme ?? clioTheme();
637
638
  const contentWidth = Math.max(0, width - 4);
638
639
  const agentLabel = agentDisplayLabel(row);
639
640
  const elapsed = formatCompactMs(row.elapsedMs);
@@ -683,7 +684,12 @@ export function renderDispatchCard(
683
684
  statusStr,
684
685
  theme.fg("muted", `node ${row.node ?? "local"}`),
685
686
  ...(row.endpoint !== undefined
686
- ? [theme.fg("info", `slots ${options.endpointActive ?? 0}/${row.endpoint.limit} ${row.endpoint.label}`)]
687
+ ? [
688
+ theme.fg(
689
+ "info",
690
+ `slots ${options.endpointActive ?? 0}/${row.endpoint.limit}${(options.endpointQueued ?? 0) > 0 ? ` +${options.endpointQueued} queued` : ""} ${row.endpoint.label}`,
691
+ ),
692
+ ]
687
693
  : []),
688
694
  ...(row.gate !== undefined ? [theme.fg("info", `gate ${row.gate.role} c${row.gate.cycle}`)] : []),
689
695
  ...(row.rerouteCount !== undefined && row.rerouteCount > 0
@@ -1003,13 +1009,12 @@ export function formatDispatchBoardLines(
1003
1009
  }
1004
1010
 
1005
1011
  const endpointActive: Record<string, number> = { ...foregroundStreamUsage() };
1012
+ const endpointQueued: Record<string, number> = {};
1006
1013
  for (const row of rows) {
1007
- if (
1008
- row.endpoint !== undefined &&
1009
- (row.status === "running" || row.status === "stale" || row.status === "enqueued" || row.status === "cancelling")
1010
- ) {
1014
+ if (row.endpoint === undefined) continue;
1015
+ if (row.status === "enqueued") endpointQueued[row.endpoint.key] = (endpointQueued[row.endpoint.key] ?? 0) + 1;
1016
+ else if (row.status === "running" || row.status === "stale" || row.status === "cancelling")
1011
1017
  endpointActive[row.endpoint.key] = (endpointActive[row.endpoint.key] ?? 0) + 1;
1012
- }
1013
1018
  }
1014
1019
 
1015
1020
  // A council is one question asked of several members, so its rows render as
@@ -1020,7 +1025,12 @@ export function formatDispatchBoardLines(
1020
1025
  : renderDispatchCard(item.row, width, deriveRunEvidenceState(observability, item.row.runId), {
1021
1026
  selected: item.row.runId === selectedRunId,
1022
1027
  expanded: detailExpanded && item.row.runId === selectedRunId,
1023
- ...(item.row.endpoint !== undefined ? { endpointActive: endpointActive[item.row.endpoint.key] ?? 0 } : {}),
1028
+ ...(item.row.endpoint !== undefined
1029
+ ? {
1030
+ endpointActive: endpointActive[item.row.endpoint.key] ?? 0,
1031
+ endpointQueued: endpointQueued[item.row.endpoint.key] ?? 0,
1032
+ }
1033
+ : {}),
1024
1034
  }),
1025
1035
  );
1026
1036
  const body: string[] = [];
@@ -12,6 +12,8 @@ import type { ExtensionsContract } from "../domains/extensions/index.js";
12
12
  import type { InteropContract } from "../domains/interop/index.js";
13
13
  import type { TaskMemoryOperatorStatus } from "../domains/memory/index.js";
14
14
  import { openDetachedBatchViews } from "../domains/middleware/index.js";
15
+ import type { MuxContract } from "../domains/mux/index.js";
16
+ import type { PanesOperations, PanesWatchController } from "../domains/mux/operations.js";
15
17
  import type { ObservabilityContract } from "../domains/observability/index.js";
16
18
  import type { ProvidersContract, ThinkingLevel } from "../domains/providers/index.js";
17
19
  import type { ResourcesContract } from "../domains/resources/index.js";
@@ -40,8 +42,10 @@ import { createProcessInteractiveShell, getActiveRenderTrace } from "./interacti
40
42
  import { createInteractiveSlashRuntime, resolveAvailableThinkingLevels } from "./interactive-slash-runtime.js";
41
43
  import { createInteractiveSubscriptions } from "./interactive-subscriptions.js";
42
44
  import { createInteractiveTickers } from "./interactive-tickers.js";
45
+ import type { createMuxBridge } from "./mux-bridge.js";
43
46
  import { createOverlayLifecycle, type OverlayLifecycleController, type OverlayState } from "./overlay-lifecycle.js";
44
47
  import { interopOverlaySurface } from "./overlays/interop.js";
48
+ import { paneWatchDecision } from "./pane-policy.js";
45
49
  import { writeInputWedgeDump } from "./render-trace.js";
46
50
  import { settleChatBeforeSessionSwitch } from "./session-switch-settlement.js";
47
51
  import { createSessionTranscript } from "./session-transcript.js";
@@ -53,7 +57,9 @@ import type {
53
57
  } from "./slash-commands.js";
54
58
  import { processAutoPacingAllowed, resolveSmoothStreamingMode } from "./stream-pacing-policy.js";
55
59
  import type { TerminalLease } from "./terminal-lease.js";
60
+ import type { createWatchPaneController } from "./watch-pane.js";
56
61
  import { createWorkspaceFacts } from "./workspace-facts.js";
62
+ import type { createYaziBridge, YaziBridge } from "./yazi-bridge.js";
57
63
 
58
64
  export {
59
65
  IDLE_LEADER_STATE,
@@ -130,6 +136,36 @@ export interface InteractiveDeps {
130
136
  extensions?: ExtensionsContract;
131
137
  interop?: InteropContract;
132
138
  share?: ShareContract;
139
+ /**
140
+ * Pane layer. A `none` contract still reaches the interactive surface so the
141
+ * files preset can use its terminal chooser; every mux operation remains
142
+ * best-effort and never reaches a dispatch or a turn.
143
+ */
144
+ mux?: MuxContract;
145
+ /**
146
+ * Pane-layer operations behind `/panes` and the `panes` tool. Built by the
147
+ * composition root so the tool registry and this surface drive one instance.
148
+ */
149
+ panes?: PanesOperations;
150
+ /**
151
+ * Factory seam for the dispatch-to-pane bridge, so a contract test can drive
152
+ * it without a TUI. Production leaves it unset and gets `createMuxBridge`.
153
+ */
154
+ createMuxBridge?: typeof createMuxBridge;
155
+ /** Bind the file-pane return path after the composer and TUI exist. */
156
+ attachYaziBridge?: (bridge: YaziBridge) => () => void;
157
+ /**
158
+ * Watch-pane factory from the `--with-panes` composition root; absent on a
159
+ * plain boot. The controller it builds backs Enter in the workers view.
160
+ */
161
+ createWatchPane?: typeof createWatchPaneController;
162
+ /** Bind the watch controller into the shared PanesOperations for `/panes show`. */
163
+ attachWatchPane?: (controller: PanesWatchController) => () => void;
164
+ /**
165
+ * File-pane factory. Supplied by the `--with-panes` composition root (or a
166
+ * contract test); absent on a plain boot, which therefore loads no yazi code.
167
+ */
168
+ createYaziBridge?: typeof createYaziBridge;
133
169
  /**
134
170
  * Shared tool registry. When wired, the permission overlay opens automatically
135
171
  * whenever a tool call is parked waiting for operator confirmation, and the
@@ -173,12 +209,19 @@ export interface InteractiveDeps {
173
209
  registerAskUserHandler?: (handler: AskUserHandler) => () => void;
174
210
  /** Live CLIO-CODER.md and memory state for the footer Context quadrant. */
175
211
  getContextState?: (cwd?: string) => ContextState;
176
- /** Persist a thinking level set by `/thinking <level>` or `/model <pattern>:<level>`. */
177
- onSetThinkingLevel?: (level: ThinkingLevel) => void;
212
+ /**
213
+ * Persist a thinking level set by `/thinking <level>` or `/model <pattern>:<level>`.
214
+ * Scope "session" leaves settings.yaml alone; omitted means the historical
215
+ * write-through, which is what the Shift+Tab cycle and `/thinking` still want.
216
+ */
217
+ onSetThinkingLevel?: (level: ThinkingLevel, scope?: "session" | "global") => void;
178
218
  /** Persist the next thinking level when Shift+Tab is pressed. */
179
219
  onCycleThinking?: () => void;
180
- /** Persist the orchestrator target selected in /model. */
181
- onSelectModel?: (ref: { target: string; model: string }) => void;
220
+ /**
221
+ * Apply the orchestrator target selected in /model at the scope the operator
222
+ * chose. "session" routes this session only and never touches settings.yaml.
223
+ */
224
+ onSelectModel?: (ref: { target: string; model: string }, scope: "session" | "global") => void;
182
225
  /** Write handler the /settings overlay uses to persist cycled values. */
183
226
  writeSettings?: (next: ClioSettings) => void;
184
227
  /**
@@ -567,6 +610,31 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
567
610
  chatRenderer,
568
611
  io,
569
612
  } = presentation;
613
+ // The factory arrives only from an active `--with-panes` boot (or a test); a
614
+ // plain session has no deps.panes and no factory, and loads no yazi code.
615
+ const yaziBridge =
616
+ deps.panes && deps.createYaziBridge
617
+ ? deps.createYaziBridge({
618
+ ...(deps.mux ? { mux: deps.mux } : {}),
619
+ getDraft: () => editor.getText(),
620
+ setDraft: (text) => editor.setText(text),
621
+ requestRender: () => tui.requestRender(),
622
+ notice: (level, text) => notify(level, text, `yazi:${level}`),
623
+ getCwd: () => process.cwd(),
624
+ getSettings: () =>
625
+ deps.getSettings?.().panes.yazi ?? {
626
+ mode: "companion",
627
+ profile: "managed",
628
+ followCwd: true,
629
+ },
630
+ stopUi: () => tui.stop(),
631
+ startUi: () => {
632
+ tui.start();
633
+ tui.requestRender(true);
634
+ },
635
+ })
636
+ : null;
637
+ const detachYaziBridge = yaziBridge ? deps.attachYaziBridge?.(yaziBridge) : undefined;
570
638
  refreshPresentationFooter = () => footer.refresh();
571
639
  const agentProgress = createAgentProgress(terminal);
572
640
  // Desktop notifications are a protocol write on the terminal owner, issued
@@ -681,7 +749,9 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
681
749
  openMemory: () => openMemoryOverlayState(),
682
750
  ...(deps.seedTaskMemory ? { seedTaskMemory: deps.seedTaskMemory } : {}),
683
751
  openView: (filter) => openViewOverlayState(filter),
752
+ ...(deps.panes ? { panes: deps.panes } : {}),
684
753
  openModel: () => openModelOverlayState(),
754
+ openModelScope: (ref) => openModelScopeState(ref),
685
755
  openSettings: (section, rowId) => openSettingsOverlayState(section, rowId),
686
756
  openResume: () => openResumeOverlayState(),
687
757
  startNewSession: () => startNewSession(),
@@ -789,6 +859,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
789
859
  openMemoryOverlayState,
790
860
  openViewOverlayState,
791
861
  openModelOverlayState,
862
+ openModelScopeState,
792
863
  openSettingsOverlayState,
793
864
  openResumeOverlayState,
794
865
  openTreeOverlayState,
@@ -866,6 +937,64 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
866
937
  };
867
938
  notify(outcome.ok ? "success" : "info", outcome.message, "dispatch:background");
868
939
  };
940
+ // Built only when a pane host answered detection, so a session with no
941
+ // panes subscribes to nothing and the bus handlers do not exist at all.
942
+ // The factories arrive from the `--with-panes` composition root (or a
943
+ // test); a plain session loads none of the bridge code.
944
+ const mux = deps.mux;
945
+ const muxBridge =
946
+ mux && mux.mode !== "none" && deps.createMuxBridge
947
+ ? deps.createMuxBridge({
948
+ bus: deps.bus,
949
+ mux,
950
+ notificationsPolicy: () => deps.getSettings?.().panes.notifications ?? "failures",
951
+ log: (level, message) => {
952
+ if (level === "warning") notify("warning", message, "mux:bridge");
953
+ },
954
+ notice: (level, text) => appendNotice(level, text, busNoticeSink),
955
+ })
956
+ : null;
957
+ // The workers-view watch pane: opened on Enter over a live run, retargeted
958
+ // by arrow keys through its selection file. `/panes show` and the panes
959
+ // tool drive the same controller through the shared operations object.
960
+ const watchPane =
961
+ mux && mux.mode !== "none" && deps.createWatchPane
962
+ ? deps.createWatchPane({ mux, getCwd: () => process.cwd() })
963
+ : null;
964
+ const detachWatchPane = watchPane ? deps.attachWatchPane?.(watchPane) : undefined;
965
+ const selectedWatchableRun = (): { runId: string; agentId: string } | null => {
966
+ if (!watchPane) return null;
967
+ const row = dispatchBoard.selectedRow();
968
+ if (!row) return null;
969
+ const decision = paneWatchDecision({ source: "workers-view", runStatus: row.status });
970
+ return decision.open ? { runId: row.runId, agentId: row.agentId } : null;
971
+ };
972
+ /**
973
+ * Enter in the workers view. True means the watch pane took the key; false
974
+ * (panes off, nothing watchable under the policy) falls back to the inline
975
+ * worker-progress detail, so a terminal run's Enter still expands its card.
976
+ */
977
+ const watchSelectedDispatch = (): boolean => {
978
+ const selected = selectedWatchableRun();
979
+ if (!watchPane || !selected) return false;
980
+ void watchPane.watch(selected.runId).then((result) => {
981
+ if (result.status === "watching") {
982
+ if (result.opened) {
983
+ notify("success", `watching ${selected.agentId} (${selected.runId}) in a pane`, "panes:watch");
984
+ }
985
+ } else {
986
+ notify("warning", result.reason, "panes:watch");
987
+ }
988
+ tui.requestRender();
989
+ });
990
+ return true;
991
+ };
992
+ /** Arrow keys: the watch pane follows the cursor, but only once it exists. */
993
+ const followBoardSelection = (): void => {
994
+ if (!watchPane?.isOpen()) return;
995
+ const selected = selectedWatchableRun();
996
+ if (selected) watchPane.follow(selected.runId);
997
+ };
869
998
  const interactiveSubscriptions = createInteractiveSubscriptions({
870
999
  bus: deps.bus,
871
1000
  refreshFooter: () => footer.refresh(),
@@ -916,7 +1045,18 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
916
1045
  onShutdownArmedChange: (armed) => {
917
1046
  shutdownArmed = armed;
918
1047
  },
919
- dispatchBoard,
1048
+ dispatchBoard: {
1049
+ selectPrevious: () => {
1050
+ dispatchBoard.selectPrevious();
1051
+ followBoardSelection();
1052
+ },
1053
+ selectNext: () => {
1054
+ dispatchBoard.selectNext();
1055
+ followBoardSelection();
1056
+ },
1057
+ toggleDetail: () => dispatchBoard.toggleDetail(),
1058
+ },
1059
+ watchSelectedDispatch,
920
1060
  steerSelectedDispatch,
921
1061
  cancelSelectedDispatch,
922
1062
  cancelActiveEditorBash: () => editorSubmit.cancelActiveEditorBash(),
@@ -955,7 +1095,14 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
955
1095
  disposeOverlay: overlayLifecycle.dispose,
956
1096
  stopAgentProgress: agentProgress.stop,
957
1097
  disposeChat: () => deps.chat.dispose(),
958
- disposeSubscriptions: interactiveSubscriptions.dispose,
1098
+ disposeSubscriptions: () => {
1099
+ detachYaziBridge?.();
1100
+ yaziBridge?.dispose();
1101
+ detachWatchPane?.();
1102
+ watchPane?.dispose();
1103
+ muxBridge?.dispose();
1104
+ interactiveSubscriptions.dispose();
1105
+ },
959
1106
  },
960
1107
  beforeStopUi: (() => {
961
1108
  let settlement: Promise<void> | null = null;
@@ -82,6 +82,8 @@ export interface InteractiveInputRuntimeDeps {
82
82
  selectNext(): void;
83
83
  toggleDetail(): void;
84
84
  };
85
+ /** Enter in the workers view; false falls through to the detail toggle. */
86
+ watchSelectedDispatch: () => boolean;
85
87
  steerSelectedDispatch: () => void;
86
88
  cancelSelectedDispatch: () => void;
87
89
  cancelActiveEditorBash: () => boolean;
@@ -238,6 +240,11 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
238
240
  deps.dispatchBoard.toggleDetail();
239
241
  deps.requestRender();
240
242
  },
243
+ watchSelectedDispatch: () => {
244
+ const handled = deps.watchSelectedDispatch();
245
+ if (handled) deps.requestRender();
246
+ return handled;
247
+ },
241
248
  steerSelectedDispatch: deps.steerSelectedDispatch,
242
249
  cancelSelectedDispatch: deps.cancelSelectedDispatch,
243
250
  cancelAskUser: () => deps.overlay.cancelAskUser(),
@@ -9,6 +9,7 @@ import type { AgentsContract } from "../domains/agents/contract.js";
9
9
  import type { DispatchContract } from "../domains/dispatch/contract.js";
10
10
  import { agentRoleFactsResolver } from "../domains/dispatch/execution-role.js";
11
11
  import type { ExtensionsContract } from "../domains/extensions/index.js";
12
+ import type { PanesOperations } from "../domains/mux/operations.js";
12
13
  import {
13
14
  type ProvidersContract,
14
15
  type ResolvedThinkingCapability,
@@ -36,6 +37,7 @@ import { runOperatorRecall } from "./context-recall-command.js";
36
37
  import { renderSessionHtml } from "./export-html/index.js";
37
38
  import { dateLocal } from "./format-time.js";
38
39
  import type { OracleDigestSources } from "./oracle.js";
40
+ import type { PendingModelScope } from "./overlays/model-scope.js";
39
41
  import type { SettingsCenterRowId, SettingsSectionId } from "./overlays/settings.js";
40
42
  import {
41
43
  type ContextClearCommandOptions,
@@ -48,7 +50,7 @@ import {
48
50
  type SlashCommandDispatchResult,
49
51
  type TaskMemorySeedCommandResult,
50
52
  } from "./slash-commands.js";
51
- import { verifyReceiptFile } from "./view/artifacts.js";
53
+ import { verifyReceiptFileReport } from "./view/artifacts.js";
52
54
  import type { WorkerEntryState } from "./worker-stream.js";
53
55
 
54
56
  const EXPORT_RENDER_WIDTH = 100;
@@ -89,8 +91,8 @@ export interface InteractiveSlashRuntimeDeps {
89
91
  * making a value permanent stays the Settings overlay's explicit choice.
90
92
  */
91
93
  commitSetting?: (id: string, next: ClioSettings, scope: "session" | "global") => void;
92
- onSelectModel?: (ref: { target: string; model: string }) => void;
93
- onSetThinkingLevel?: (level: ThinkingLevel) => void;
94
+ onSelectModel?: (ref: { target: string; model: string }, scope: "session" | "global") => void;
95
+ onSetThinkingLevel?: (level: ThinkingLevel, scope?: "session" | "global") => void;
94
96
  onCompact?: (instructions: string | undefined) => Promise<void>;
95
97
  onInit?: (options: InitCommandOptions, io?: RunIo) => Promise<void>;
96
98
  onContextClear?: (options: ContextClearCommandOptions) => Promise<void>;
@@ -135,7 +137,14 @@ export interface InteractiveSlashRuntimeDeps {
135
137
  openMemory: () => void;
136
138
  seedTaskMemory?: () => TaskMemorySeedCommandResult;
137
139
  openView: (filter?: string) => void;
140
+ /** Pane-layer operations behind `/panes`. Absent when the mux resolved to `none`. */
141
+ panes?: PanesOperations;
138
142
  openModel: () => void;
143
+ /**
144
+ * Ask where a resolved `/model <pattern>` swap lands before anything applies.
145
+ * Absent on a host with no overlay layer, where the swap stays session-scoped.
146
+ */
147
+ openModelScope?: (ref: PendingModelScope) => void;
139
148
  openSettings: (section?: SettingsSectionId, rowId?: SettingsCenterRowId) => void;
140
149
  openResume: () => void;
141
150
  startNewSession: () => void;
@@ -200,6 +209,7 @@ export function resolveAvailableThinkingLevels(
200
209
  export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps): InteractiveSlashRuntime {
201
210
  let activeContextInit = false;
202
211
  let latestAdmission: Promise<void> = Promise.resolve();
212
+ let latestLocalOperation: Promise<void> = Promise.resolve();
203
213
  let activeAdmissionSignal: AbortSignal | undefined;
204
214
  const cwd = (): string => deps.getCwd?.() ?? process.cwd();
205
215
  const resources = deps.resources;
@@ -436,6 +446,7 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
436
446
  return result;
437
447
  },
438
448
  openView: deps.openView,
449
+ ...(deps.panes ? { panes: deps.panes } : {}),
439
450
  setThinkingLevel: (level) => {
440
451
  const settings = deps.getSettings?.();
441
452
  if (!settings || !deps.onSetThinkingLevel) return { status: "unavailable" };
@@ -485,9 +496,20 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
485
496
  openModel: deps.openModel,
486
497
  providers: deps.providers,
487
498
  applyModelRef: (ref) => {
488
- deps.onSelectModel?.({ target: ref.target, model: ref.model });
489
- if (ref.thinkingLevel) deps.onSetThinkingLevel?.(ref.thinkingLevel);
499
+ // A mid-conversation swap used to rewrite the orchestrator role in
500
+ // settings.yaml with no prompt, so the next launch could come up on a
501
+ // dead endpoint (smoke pass 2, G3). The scope dialog owns the commit
502
+ // now, and it applies nothing until the operator answers.
503
+ if (deps.openModelScope) {
504
+ deps.openModelScope(ref);
505
+ return "pending";
506
+ }
507
+ // No overlay layer to ask with: session scope is the answer that cannot
508
+ // outlive the session that chose it.
509
+ deps.onSelectModel?.({ target: ref.target, model: ref.model }, "session");
510
+ if (ref.thinkingLevel) deps.onSetThinkingLevel?.(ref.thinkingLevel, "session");
490
511
  deps.requestRender();
512
+ return "applied";
491
513
  },
492
514
  openSettings: deps.openSettings,
493
515
  openResume: deps.openResume,
@@ -634,7 +656,7 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
634
656
  })
635
657
  .finally(deps.requestRender);
636
658
  },
637
- verifyReceipt: (runId) => verifyReceiptFile(deps.stateDir, runId),
659
+ verifyReceipt: (runId) => verifyReceiptFileReport(deps.stateDir, runId),
638
660
  ...(deps.listWorkerRuns ? { listWorkerRuns: deps.listWorkerRuns } : {}),
639
661
  // The user-turn path, minus expansion. A worker's answer is literal text:
640
662
  // running it through the prompt, skill, and @file expanders would let a
@@ -644,6 +666,9 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
644
666
  latestAdmission = admitChat(text, activeAdmissionSignal);
645
667
  void latestAdmission;
646
668
  },
669
+ runLocalOperation: (operation) => {
670
+ latestLocalOperation = latestLocalOperation.catch(() => undefined).then(operation);
671
+ },
647
672
  render: deps.requestRender,
648
673
  };
649
674
 
@@ -653,8 +678,12 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
653
678
  dispatchCommand: (text) => dispatchSlashCommand(parseSlashCommand(text), context),
654
679
  admitCommand: async (text, signal) => {
655
680
  signal?.throwIfAborted();
681
+ // Pane opens and focus changes mutate a remote registry. A following
682
+ // slash read must observe their settled state, just as the tool path does.
683
+ await latestLocalOperation;
656
684
  const command = parseSlashCommand(text);
657
685
  const before = latestAdmission;
686
+ const localBefore = latestLocalOperation;
658
687
  const previousSignal = activeAdmissionSignal;
659
688
  activeAdmissionSignal = signal;
660
689
  try {
@@ -663,6 +692,7 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
663
692
  activeAdmissionSignal = previousSignal;
664
693
  }
665
694
  if (latestAdmission !== before) await latestAdmission;
695
+ if (latestLocalOperation !== localBefore) await latestLocalOperation;
666
696
  },
667
697
  };
668
698
  }
@@ -358,6 +358,7 @@ export function openMemoryOverlay(
358
358
  const handle = showClioOverlayFrame(tui, view, {
359
359
  anchor: "center",
360
360
  width: MEMORY_OVERLAY_WIDTH,
361
+ markerId: "memory",
361
362
  title: () => "Memory",
362
363
  footerHint: () => view.getHint(),
363
364
  });
@@ -0,0 +1,170 @@
1
+ /**
2
+ * The outward signal that a modal overlay owns the keyboard.
3
+ *
4
+ * Every framed Clio overlay captures input for as long as it is up, and until
5
+ * now it announced that only by being on screen. An external driver feeding
6
+ * keys into the pane, and herdr deciding whether the pane is idle, working, or
7
+ * blocked, had to infer modality from whatever the overlay happened to draw:
8
+ * its box title, its hint row, a footer pill. Those are per-overlay strings
9
+ * that move on every reskin, and the tall modals cover the very rows a screen
10
+ * scraper reads, so the signal is weakest exactly when a modal is largest.
11
+ *
12
+ * The marker publishes the fact out of band instead, as an OSC 0 terminal
13
+ * title. Three properties make the title the reliable channel here:
14
+ *
15
+ * 1. It is not screen content. No overlay can composite over it, no
16
+ * transcript line can counterfeit it, and no terminal height changes
17
+ * whether it is readable.
18
+ * 2. herdr already consumes it. `region = "osc_title"` is a first-class
19
+ * detection region (herdr `src/detect/manifest.rs`), fed from the pane's
20
+ * own emulator, and its rules outrank every screen rule.
21
+ * 3. Clio has never written a title, so the channel carries exactly one
22
+ * meaning and nothing else contends for it.
23
+ *
24
+ * The grammar is fixed and machine-first:
25
+ *
26
+ * clio no modal owns the keys
27
+ * clio [modal:permission-confirm] one modal, named
28
+ * clio [modal:library-install+2] top modal named, two more beneath it
29
+ *
30
+ * Nothing is written until the first modal opens, so a Clio that never opens
31
+ * an overlay leaves the pane's inherited title alone. From the first modal
32
+ * onward the title toggles between the marker and the bare base, which is what
33
+ * makes the absence of a marker a positive statement rather than an unknown.
34
+ */
35
+
36
+ /** The write side of a terminal title. `ProcessTerminal` satisfies it structurally. */
37
+ export interface ModalMarkerSink {
38
+ setTitle(title: string): void;
39
+ }
40
+
41
+ /** What the title reads when nothing modal owns the keyboard. */
42
+ export const MODAL_MARKER_BASE_TITLE = "clio";
43
+
44
+ /**
45
+ * The one regular expression an external reader needs. Exported so Clio's own
46
+ * contract test and herdr's manifest rule are written against the same shape
47
+ * rather than two hand-copied spellings of it.
48
+ */
49
+ export const MODAL_MARKER_TITLE_PATTERN = /^clio \[modal:([a-z0-9][a-z0-9-]*)(?:\+([1-9]\d*))?\]$/u;
50
+
51
+ /** Render the title for a modal stack, outermost first. */
52
+ export function formatModalMarkerTitle(stack: readonly string[]): string {
53
+ const top = stack.at(-1);
54
+ if (top === undefined) return MODAL_MARKER_BASE_TITLE;
55
+ const beneath = stack.length - 1;
56
+ return `${MODAL_MARKER_BASE_TITLE} [modal:${top}${beneath > 0 ? `+${beneath}` : ""}]`;
57
+ }
58
+
59
+ /** Read a marker title back. Returns null for the base title and for anything else. */
60
+ export function parseModalMarkerTitle(title: string): { id: string; depth: number } | null {
61
+ const match = MODAL_MARKER_TITLE_PATTERN.exec(title);
62
+ const id = match?.[1];
63
+ if (id === undefined) return null;
64
+ const beneath = match?.[2];
65
+ return { id, depth: beneath === undefined ? 1 : 1 + Number.parseInt(beneath, 10) };
66
+ }
67
+
68
+ /** One modal's claim on the keyboard, released when the overlay goes away. */
69
+ export interface ModalMarkerHandle {
70
+ /** Drop this modal from the stack. Idempotent; a second call is inert. */
71
+ release(): void;
72
+ /**
73
+ * Whether this modal currently owns keys. The engine's `setHidden` takes a
74
+ * visible overlay out of the focus order without destroying it, which is how
75
+ * a surface that shells out to a child process gets off the screen, so a
76
+ * hidden modal must stop claiming the keyboard without leaving the stack.
77
+ */
78
+ setActive(active: boolean): void;
79
+ /** Bring this modal back to the top of the stack, as `handle.focus()` does on screen. */
80
+ raise(): void;
81
+ }
82
+
83
+ interface ModalMarkerRegistry {
84
+ /**
85
+ * Push a modal. The sink is taken from the caller rather than installed at
86
+ * startup so the marker has no lifecycle of its own: it exists exactly when
87
+ * an overlay exists, and a stub terminal with no `setTitle` makes the whole
88
+ * mechanism inert instead of throwing.
89
+ */
90
+ enter(id: string, sink?: ModalMarkerSink | null): ModalMarkerHandle;
91
+ /** The ids that currently own keys, outermost first. */
92
+ stack(): readonly string[];
93
+ }
94
+
95
+ interface ModalMarkerEntry {
96
+ readonly id: string;
97
+ active: boolean;
98
+ }
99
+
100
+ function createModalMarkerRegistry(): ModalMarkerRegistry {
101
+ const entries: ModalMarkerEntry[] = [];
102
+ let sink: ModalMarkerSink | null = null;
103
+ let published: string | null = null;
104
+
105
+ function activeIds(): string[] {
106
+ return entries.filter((entry) => entry.active).map((entry) => entry.id);
107
+ }
108
+
109
+ function publish(): void {
110
+ if (sink === null) return;
111
+ const title = formatModalMarkerTitle(activeIds());
112
+ // Before the first marker there is no stale claim to clear, so the pane
113
+ // keeps whatever title the shell or the multiplexer gave it.
114
+ if (published === null && title === MODAL_MARKER_BASE_TITLE) return;
115
+ if (title === published) return;
116
+ published = title;
117
+ sink.setTitle(title);
118
+ }
119
+
120
+ function enter(id: string, nextSink?: ModalMarkerSink | null): ModalMarkerHandle {
121
+ if (nextSink) sink = nextSink;
122
+ const entry: ModalMarkerEntry = { id, active: true };
123
+ entries.push(entry);
124
+ publish();
125
+ let released = false;
126
+ return {
127
+ release(): void {
128
+ if (released) return;
129
+ released = true;
130
+ const index = entries.indexOf(entry);
131
+ if (index !== -1) entries.splice(index, 1);
132
+ publish();
133
+ },
134
+ setActive(active: boolean): void {
135
+ if (released || entry.active === active) return;
136
+ entry.active = active;
137
+ publish();
138
+ },
139
+ raise(): void {
140
+ if (released) return;
141
+ entry.active = true;
142
+ const index = entries.indexOf(entry);
143
+ if (index !== -1 && index !== entries.length - 1) {
144
+ entries.splice(index, 1);
145
+ entries.push(entry);
146
+ }
147
+ publish();
148
+ },
149
+ };
150
+ }
151
+
152
+ return { enter, stack: (): readonly string[] => activeIds() };
153
+ }
154
+
155
+ let registry = createModalMarkerRegistry();
156
+
157
+ /** Push a modal onto the process-wide stack. See {@link ModalMarkerRegistry.enter}. */
158
+ export function enterModal(id: string, sink?: ModalMarkerSink | null): ModalMarkerHandle {
159
+ return registry.enter(id, sink);
160
+ }
161
+
162
+ /** The ids that currently own keys, outermost first. */
163
+ export function modalMarkerStack(): readonly string[] {
164
+ return registry.stack();
165
+ }
166
+
167
+ /** Drop every claim and forget the sink. Tests use it to isolate; nothing in the app does. */
168
+ export function resetModalMarker(): void {
169
+ registry = createModalMarkerRegistry();
170
+ }