@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
@@ -6,7 +6,16 @@ import {
6
6
  setFleetProfileInSettings,
7
7
  useTargetInSettings,
8
8
  } from "../../core/config.js";
9
- import { DEFAULT_SETTINGS, THINKING_LEVELS } from "../../core/defaults.js";
9
+ import {
10
+ ACTIVE_ROUTING_POSTURES,
11
+ ACTIVE_ROUTING_ROLES,
12
+ type ActiveRoutingPosture,
13
+ type ActiveRoutingRole,
14
+ DEFAULT_SETTINGS,
15
+ THINKING_LEVELS,
16
+ type WorkerEscalationSettings,
17
+ } from "../../core/defaults.js";
18
+ import type { GuardrailValues } from "../../core/guardrails.js";
10
19
  import { getAtPath, isRoutingPath } from "../../core/session-routing.js";
11
20
  import { MAX_TIMER_DELAY_MS } from "../../core/timers.js";
12
21
  import { capacityLeaseUsage } from "../../domains/dispatch/capacity-lease.js";
@@ -48,6 +57,7 @@ import { clockLocal } from "../format-time.js";
48
57
  import { buildHint, DEFAULT_SELECT_THEME, showClioOverlayFrame } from "../overlay-frame.js";
49
58
  import { barSep, clioTheme, GLYPH, padAnsi, rule, screenTitle } from "../theme/index.js";
50
59
  import { modelsForTarget } from "./model-selector.js";
60
+ import { SETTINGS_SECTIONS, type SettingsSectionId } from "./settings-sections.js";
51
61
 
52
62
  export const SETTINGS_OVERLAY_WIDTH = "100%";
53
63
  export const SETTINGS_OVERLAY_MAX_HEIGHT = "100%";
@@ -93,6 +103,16 @@ const ULTRA_NARROW_TERMINAL_WIDTH = 60;
93
103
  /** Shown when no runtime is resolvable, so it offers the full vocabulary. */
94
104
  const FALLBACK_THINKING_VALUES: ReadonlyArray<string> = THINKING_LEVELS;
95
105
  const ROW_GAP = " ";
106
+ /**
107
+ * `workers.escalation` and `workers.resilienceCooldownMs` are optional keys, so
108
+ * the row that shows them and the mutation that writes them both need a
109
+ * definite shipped value to fall back to.
110
+ */
111
+ const SHIPPED_ESCALATION: WorkerEscalationSettings = DEFAULT_SETTINGS.workers.escalation ?? {
112
+ timeoutMs: 120_000,
113
+ fallback: "deny",
114
+ };
115
+ const SHIPPED_RESILIENCE_COOLDOWN_MS = DEFAULT_SETTINGS.workers.resilienceCooldownMs ?? 15_000;
96
116
  /**
97
117
  * The product's cut marker, as the help center and every list overlay use it.
98
118
  *
@@ -126,36 +146,27 @@ const RESTART_REQUIRED_IDS = new Set<string>([
126
146
  "runtimePlugins",
127
147
  "terminal.tuiMode",
128
148
  "terminal.fullscreenScrollbar",
149
+ // The mux domain runs its detection ladder once, at boot, from the value this
150
+ // key held then. Changing the rung mid-session would leave the contract on
151
+ // the rung it resolved to, so the row says restart rather than lying.
152
+ "panes.enabled",
129
153
  ]);
130
154
 
131
- export const SETTINGS_SECTIONS = [
132
- { id: "safety", label: "Autonomy & Safety", group: "CORE" },
133
- { id: "orchestrator", label: "Orchestrator", group: "CORE" },
134
- { id: "fleet", label: "Fleet", group: "ROUTING" },
135
- { id: "targets", label: "Targets", group: "ROUTING" },
136
- { id: "models", label: "Models", group: "ROUTING" },
137
- { id: "budget", label: "Budget", group: "RUNTIME" },
138
- { id: "compaction", label: "Compaction", group: "RUNTIME" },
139
- { id: "retry", label: "Retry", group: "RUNTIME" },
140
- { id: "terminal", label: "Terminal", group: "EXPERIENCE" },
141
- { id: "watchdog", label: "Watchdog", group: "EXPERIENCE" },
142
- { id: "advanced", label: "Advanced", group: "EXPERIENCE" },
143
- ] as const;
144
-
145
- export type SettingsSectionId = (typeof SETTINGS_SECTIONS)[number]["id"];
155
+ export { SETTINGS_SECTIONS, type SettingsSectionId };
146
156
 
147
157
  const SETTINGS_SECTION_DESCRIPTIONS = {
148
- safety: "How freely Clio acts, and how delegated agents' tools are governed.",
149
- orchestrator: "Interactive chat routing and the optional proactive-memory model plane.",
150
- fleet: "Defaults, profiles, and agent bindings applied to dispatched workers, and where they run.",
158
+ safety: "How freely Clio acts, how a worker's approval ask resolves, and how delegated agents' tools are governed.",
159
+ orchestrator: "Interactive chat routing, prompt pre-warm, and the optional proactive-memory model plane.",
160
+ fleet: "Defaults, profiles, agent bindings, and route activation for dispatched workers, and where they run.",
151
161
  targets: "Configured inference targets: which one chat and the fleet use, and whether each answers.",
152
162
  models: "The /model picker, favorites, and Alt+J / Alt+K cycling.",
153
- budget: "Cost ceiling, per-turn output budget, and worker concurrency.",
154
- compaction: "When and how the context window is summarized under pressure.",
155
- retry: "Automatic recovery from transient provider and network errors.",
163
+ budget: "Cost ceiling, per-turn output budget, worker concurrency, and the guardrail backstops.",
164
+ compaction: "When and how the context window is evicted and summarized under pressure.",
165
+ retry: "Automatic recovery from transient provider, network, and stalled-stream errors.",
156
166
  terminal: "Terminal integration and the Clio color palette.",
157
167
  watchdog: "The opt-in turn-end verifier run, where it is routed, and whether it also fires mid-turn.",
158
- advanced: "Commit provenance, runtime plugins, delegation timeouts, and links to other surfaces.",
168
+ advanced:
169
+ "Commit provenance, runtime plugins, delegation timeouts, the resource library, and links to other surfaces.",
159
170
  } as const satisfies Record<SettingsSectionId, string>;
160
171
 
161
172
  export const SETTINGS_LABELS_BY_ID = {
@@ -165,6 +176,8 @@ export const SETTINGS_LABELS_BY_ID = {
165
176
  // section headed Fleet whose rows read "Worker profiles" and "Worker
166
177
  // retries" made one setting look like two subsystems.
167
178
  "workers.onPermission": "Fleet approvals routing",
179
+ "workers.escalation.timeoutMs": "Escalation timeout (ms)",
180
+ "workers.escalation.fallback": "Escalation fallback",
168
181
  "delegation.defaults.toolGovernance": "Delegation governance",
169
182
  "skills.trustProjectCompatRoots": "Trust project skill roots",
170
183
  "attribution.gitCommits": "Clio commit provenance",
@@ -180,25 +193,49 @@ export const SETTINGS_LABELS_BY_ID = {
180
193
  "memory.intervention.windowSteps": "Memory trajectory steps",
181
194
  "memory.intervention.maxTokens": "Memory reminder tokens",
182
195
  "memory.intervention.timeoutMs": "Memory timeout (ms)",
196
+ "prewarm.enabled": "Prompt pre-warm",
183
197
  "workers.default.target": "Default target",
184
198
  "workers.default.model": "Default model",
185
199
  "workers.default.thinkingLevel": "Default thinking level",
186
200
  "workers.profiles": "Add profile",
187
201
  "workers.agentBindings": "Add agent route",
188
202
  "workers.maxRetries": "Fleet retries",
203
+ "workers.resilienceCooldownMs": "Resilience cooldown (ms)",
204
+ "routing.activeRoles": "Active routing roles",
205
+ "routing.activePostures": "Active routing postures",
206
+ "routing.agentAutomation.activeAgentRoles": "Active agent routes",
207
+ "panes.enabled": "Panes",
208
+ "panes.notifications": "Pane notifications",
209
+ "panes.journal": "Run event journal",
210
+ "panes.yazi.enabled": "Files pane",
211
+ "panes.yazi.mode": "Files pane mode",
212
+ "panes.yazi.profile": "Yazi profile",
213
+ "panes.yazi.followCwd": "Follow conversation cwd",
189
214
  scope: "Model cycle set",
190
215
  "modelSelector.recentLimit": "Recent models kept",
191
216
  "modelSelector.favorites": "Pinned favorites",
192
217
  "budget.sessionCeilingUsd": "Session ceiling (USD)",
193
218
  "defaults.maxTokens": "Output budget (tokens)",
194
219
  "budget.concurrency": "Fleet concurrency",
220
+ "guardrails.turnToolCallBudget": "Turn tool-call budget",
221
+ "guardrails.workerToolCallCap": "Worker tool-call cap",
222
+ "guardrails.maxDispatchRuns": "Run ledger retention",
223
+ "guardrails.readMaxBytes": "Read byte cap",
224
+ "guardrails.observationTurnBudgetBytes": "Observation byte pool",
225
+ "guardrails.internalDispatchTimeoutMs": "Internal dispatch timeout (ms)",
195
226
  "compaction.auto": "Auto-compact",
196
227
  "compaction.excludeLastTurns": "Protected recent turns",
197
228
  "compaction.threshold": "Compaction threshold",
229
+ "context.workingSet.enabled": "Working-set eviction",
230
+ "context.workingSet.policy": "Eviction policy",
231
+ "context.workingSet.target": "Eviction target pressure",
232
+ "context.workingSet.protectLastTurns": "Turns protected from eviction",
233
+ "context.workingSet.minEvictableTokens": "Minimum evictable tokens",
198
234
  "retry.enabled": "Retry transient errors",
199
235
  "retry.maxRetries": "Max retries",
200
236
  "retry.baseDelayMs": "Base delay (ms)",
201
237
  "retry.maxDelayMs": "Max delay (ms)",
238
+ "retry.streamStallMs": "Stream stall timeout (ms)",
202
239
  "terminal.showTerminalProgress": "Terminal progress badges",
203
240
  "terminal.outputVerbosity": "Output detail",
204
241
  "terminal.tuiMode": "TUI mode",
@@ -218,6 +255,10 @@ export const SETTINGS_LABELS_BY_ID = {
218
255
  targets: "Configured targets",
219
256
  keybindings: "Keybinding overrides",
220
257
  "delegation.agents": "Delegation agents",
258
+ "library.catalog": "Library catalog path",
259
+ "library.remote": "Library remote",
260
+ "library.confirmedRemote": "Confirmed library remote",
261
+ "library.sync": "Library sync",
221
262
  } as const;
222
263
 
223
264
  /**
@@ -231,9 +272,20 @@ type EntrySettingId =
231
272
  | `fleet.nodes.${string}`
232
273
  | `fleet.endpoints.${string}`;
233
274
  export type EditableSettingId = keyof typeof SETTINGS_LABELS_BY_ID | EntrySettingId;
234
- type FleetGroupHeaderId = `fleet.group.${"defaults" | "profiles" | "agent-routes" | "placement"}`;
275
+ type FleetGroupHeaderId =
276
+ `fleet.group.${"defaults" | "profiles" | "agent-routes" | "route-activation" | "placement" | "panes"}`;
277
+ type TerminalGroupHeaderId = "terminal.group.files-pane";
278
+ type BudgetGroupHeaderId = "budget.group.guardrails";
279
+ type CompactionGroupHeaderId = "compaction.group.working-set";
280
+ type AdvancedGroupHeaderId = "advanced.group.library";
281
+ type GroupHeaderId =
282
+ | FleetGroupHeaderId
283
+ | TerminalGroupHeaderId
284
+ | BudgetGroupHeaderId
285
+ | CompactionGroupHeaderId
286
+ | AdvancedGroupHeaderId;
235
287
  type TargetsCtaId = "targets.add-cta";
236
- export type SettingsCenterRowId = EditableSettingId | FleetGroupHeaderId | TargetsCtaId;
288
+ export type SettingsCenterRowId = EditableSettingId | GroupHeaderId | TargetsCtaId;
237
289
  const REMOVE_PROFILE_CHOICE = "(remove profile)";
238
290
  const UNBIND_CHOICE = "(unbind)";
239
291
  const AUTO_PLACEMENT_CHOICE = "(auto placement)";
@@ -244,6 +296,8 @@ export const SETTINGS_SECTION_ROWS = {
244
296
  safety: [
245
297
  "autonomy",
246
298
  "workers.onPermission",
299
+ "workers.escalation.timeoutMs",
300
+ "workers.escalation.fallback",
247
301
  "delegation.defaults.toolGovernance",
248
302
  "skills.trustProjectCompatRoots",
249
303
  "safetyNet",
@@ -260,19 +314,46 @@ export const SETTINGS_SECTION_ROWS = {
260
314
  "memory.intervention.windowSteps",
261
315
  "memory.intervention.maxTokens",
262
316
  "memory.intervention.timeoutMs",
317
+ "prewarm.enabled",
263
318
  ],
264
319
  fleet: [
265
320
  "workers.default.target",
266
321
  "workers.default.model",
267
322
  "workers.default.thinkingLevel",
268
323
  "workers.maxRetries",
324
+ "workers.resilienceCooldownMs",
269
325
  "workers.profiles",
270
326
  "workers.agentBindings",
327
+ "routing.activeRoles",
328
+ "routing.activePostures",
329
+ "routing.agentAutomation.activeAgentRoles",
330
+ "panes.enabled",
331
+ "panes.notifications",
332
+ "panes.journal",
271
333
  ],
272
334
  models: ["scope", "modelSelector.recentLimit", "modelSelector.favorites"],
273
- budget: ["budget.sessionCeilingUsd", "defaults.maxTokens", "budget.concurrency"],
274
- compaction: ["compaction.auto", "compaction.threshold", "compaction.excludeLastTurns"],
275
- retry: ["retry.enabled", "retry.maxRetries", "retry.baseDelayMs", "retry.maxDelayMs"],
335
+ budget: [
336
+ "budget.sessionCeilingUsd",
337
+ "defaults.maxTokens",
338
+ "budget.concurrency",
339
+ "guardrails.turnToolCallBudget",
340
+ "guardrails.workerToolCallCap",
341
+ "guardrails.maxDispatchRuns",
342
+ "guardrails.readMaxBytes",
343
+ "guardrails.observationTurnBudgetBytes",
344
+ "guardrails.internalDispatchTimeoutMs",
345
+ ],
346
+ compaction: [
347
+ "compaction.auto",
348
+ "compaction.threshold",
349
+ "compaction.excludeLastTurns",
350
+ "context.workingSet.enabled",
351
+ "context.workingSet.policy",
352
+ "context.workingSet.target",
353
+ "context.workingSet.protectLastTurns",
354
+ "context.workingSet.minEvictableTokens",
355
+ ],
356
+ retry: ["retry.enabled", "retry.maxRetries", "retry.baseDelayMs", "retry.maxDelayMs", "retry.streamStallMs"],
276
357
  terminal: [
277
358
  "terminal.showTerminalProgress",
278
359
  "terminal.outputVerbosity",
@@ -281,6 +362,10 @@ export const SETTINGS_SECTION_ROWS = {
281
362
  "terminal.smoothStreaming",
282
363
  "terminal.notify",
283
364
  "theme",
365
+ "panes.yazi.enabled",
366
+ "panes.yazi.mode",
367
+ "panes.yazi.profile",
368
+ "panes.yazi.followCwd",
284
369
  ],
285
370
  watchdog: ["watchdog.enabled", "watchdog.target", "watchdog.cadenceToolCalls"],
286
371
  advanced: [
@@ -293,6 +378,10 @@ export const SETTINGS_SECTION_ROWS = {
293
378
  "delegation.defaults.permissionTimeoutMs",
294
379
  "keybindings",
295
380
  "delegation.agents",
381
+ "library.catalog",
382
+ "library.remote",
383
+ "library.confirmedRemote",
384
+ "library.sync",
296
385
  ],
297
386
  targets: ["targets"],
298
387
  } as const satisfies Record<SettingsSectionId, readonly EditableSettingId[]>;
@@ -301,6 +390,8 @@ const SETTINGS_DESCRIPTIONS_BY_ID = {
301
390
  autonomy: "How freely Clio acts; the safety net always applies.",
302
391
  "workers.onPermission":
303
392
  "How a worker resolves an approval ask: deny the call, fail the run, or escalate to this session.",
393
+ "workers.escalation.timeoutMs": "How long an escalated worker approval waits for you before the fallback applies.",
394
+ "workers.escalation.fallback": "What an escalated approval becomes when nobody answers inside the timeout.",
304
395
  "delegation.defaults.toolGovernance": "Tool policy for delegated external agents.",
305
396
  "skills.trustProjectCompatRoots": "Whether third-party project skill roots are loaded.",
306
397
  "attribution.gitCommits":
@@ -317,25 +408,51 @@ const SETTINGS_DESCRIPTIONS_BY_ID = {
317
408
  "memory.intervention.windowSteps": "Recent completed tool steps visible to the memory policy.",
318
409
  "memory.intervention.maxTokens": "Hard cap for one visible memory reminder.",
319
410
  "memory.intervention.timeoutMs": "Hard deadline for one background-model memory call.",
411
+ "prewarm.enabled": "Send the next turn's known prefix ahead of time so a local server has already prefilled it.",
320
412
  "workers.default.target": "Default /run target id.",
321
413
  "workers.default.model": "Default /run wire model id.",
322
414
  "workers.default.thinkingLevel": "Reasoning budget for dispatched workers.",
323
415
  "workers.profiles": "Named target/model/thinking choices that native workers can use. Enter adds one.",
324
416
  "workers.agentBindings": "Pins native Clio agents, including shadow agents, to worker profiles. Enter adds one.",
325
417
  "workers.maxRetries": "Automatic retries for a retryable worker outcome.",
418
+ "workers.resilienceCooldownMs":
419
+ "How long a failing target, runtime, and model route is skipped before it is tried again.",
420
+ "routing.activeRoles": "Execution roles whose joint route selection may act instead of only shadowing.",
421
+ "routing.activePostures": "Route postures whose selection may act instead of only shadowing.",
422
+ "routing.agentAutomation.activeAgentRoles": "Exact agent and execution-role pairs whose agent choice may act.",
423
+ "panes.enabled": "Default panes activation for new sessions; `--with-panes` / `--no-panes` beat it.",
424
+ "panes.notifications": "Which terminal run states raise a pane-host toast.",
425
+ "panes.journal": "Whether every dispatched run's event tail is written to disk for `clio-coder fleet view`.",
426
+ "panes.yazi.enabled": "Whether `/panes open yazi` may open the files pane or one-shot chooser.",
427
+ "panes.yazi.mode": "Keep Yazi beside the conversation, or close it after one selection.",
428
+ "panes.yazi.profile": "Use Clio's managed pick profile or leave the operator's Yazi profile untouched.",
429
+ "panes.yazi.followCwd": "Push the conversation directory into an already-open companion pane.",
326
430
  scope: "Alt+J and Alt+K model cycle set.",
327
431
  "modelSelector.recentLimit": "How many recently used models /model remembers.",
328
432
  "modelSelector.favorites": "Exact target/model refs pinned in /model.",
329
433
  "budget.sessionCeilingUsd": "Per-session cost cap.",
330
434
  "defaults.maxTokens": "Output tokens requested per turn, applied to every target.",
331
435
  "budget.concurrency": "Parallel workers allowed during dispatch.",
436
+ "guardrails.turnToolCallBudget": "Soft per-turn tool-call budget for this chat loop.",
437
+ "guardrails.workerToolCallCap": "Lifetime ceiling on tool calls one dispatched worker may execute.",
438
+ "guardrails.maxDispatchRuns": "How many finished runs the dispatch ledger keeps before the oldest are dropped.",
439
+ "guardrails.readMaxBytes": "Per-call byte cap for the read tool.",
440
+ "guardrails.observationTurnBudgetBytes": "Shared per-turn byte pool across every observation-producing tool.",
441
+ "guardrails.internalDispatchTimeoutMs": "Wall-clock cap for one internal generator dispatch.",
332
442
  "compaction.auto": "Auto-compact before a turn when context crosses the threshold.",
333
443
  "compaction.excludeLastTurns": "Recent user turns protected from observation masking.",
334
444
  "compaction.threshold": "Pressure at which compaction masks stale observations, then summarizes.",
445
+ "context.workingSet.enabled": "Non-destructive eviction of stale tool results before a summary is ever needed.",
446
+ "context.workingSet.policy": "Which candidates the eviction pass selects.",
447
+ "context.workingSet.target": "Context pressure an applied eviction batch brings the session down to.",
448
+ "context.workingSet.protectLastTurns": "Recent user turns whose observations are never evicted.",
449
+ "context.workingSet.minEvictableTokens":
450
+ "Results below this token estimate stay; the marker would cost more than it saves.",
335
451
  "retry.enabled": "Retry transient provider errors on the next submit.",
336
452
  "retry.maxRetries": "Retry attempts after the initial failure.",
337
453
  "retry.baseDelayMs": "Initial retry delay in milliseconds.",
338
454
  "retry.maxDelayMs": "Maximum retry delay in milliseconds.",
455
+ "retry.streamStallMs": "Silence on an in-flight stream past this long is treated as a wedged backend.",
339
456
  "terminal.showTerminalProgress": "Emit OSC 9;4 progress badges during agent turns.",
340
457
  "terminal.outputVerbosity": "How much reasoning, tool input, and live tool output appears in the transcript.",
341
458
  "terminal.tuiMode": "Use regular terminal scrollback or a fullscreen transcript with a sticky composer and footer.",
@@ -356,6 +473,10 @@ const SETTINGS_DESCRIPTIONS_BY_ID = {
356
473
  targets: "Inference targets available for chat and workers. Add one with `clio-coder targets add`.",
357
474
  keybindings: "Custom key overrides layered on the defaults.",
358
475
  "delegation.agents": "External ACP agents available to /delegate.",
476
+ "library.catalog": "Path to the private resource catalog; blank uses the one in your config directory.",
477
+ "library.remote": "Git remote the catalog syncs with; blank keeps the library entirely local.",
478
+ "library.confirmedRemote": "The remote you confirmed. Sync refuses until it matches library.remote.",
479
+ "library.sync": "Whether `clio-coder library sync` and `push` may talk to the remote at all.",
359
480
  } as const satisfies Record<EditableSettingId, string>;
360
481
 
361
482
  /** Longer, optional guidance shown beneath the one-line description when there is room. */
@@ -366,6 +487,38 @@ const SETTINGS_HELP_BY_ID: Partial<Record<EditableSettingId, string>> = {
366
487
  "Clamped down to each model's max-output cap and the remaining context window. Set 0 to use per-model caps only.",
367
488
  "compaction.threshold":
368
489
  "pressure = estimated tokens ÷ context window. Higher keeps more history but risks overflow before a summary runs.",
490
+ "context.workingSet.enabled":
491
+ "Eviction moves stale tool-result bodies and thinking blocks out of the model's working set and records a ledger entry; history is never rewritten. Off skips eviction and goes straight to summary compaction. Legal values: true, false · default: true.",
492
+ "context.workingSet.policy":
493
+ "structural-v1 selects by message structure; age-horizon is the older age-based rule. Legal values: structural-v1, age-horizon · default: structural-v1.",
494
+ "context.workingSet.target":
495
+ "An applied eviction batch keeps evicting until pressure reaches this ratio, so it sits below compaction.threshold. Greater than 0 and less than 1 · default: 0.6.",
496
+ "context.workingSet.protectLastTurns":
497
+ "Counted in user turns, the same unit compaction.excludeLastTurns uses. Whole number of at least 1 · default: 6.",
498
+ "context.workingSet.minEvictableTokens":
499
+ "The floor sweep put marker break-even near 50 tokens; 200 is the churn guard. Whole number, 0 evicts anything · default: 200.",
500
+ "guardrails.turnToolCallBudget":
501
+ "Crossing it blocks further calls in the turn with a stop-and-summarize directive, and the hard interrupt ceiling sits a fixed margin above. A backstop against a model spraying unproductive calls, not a routine ceiling: a repo-wide audit legitimately runs dozens. Whole number of at least 1 · default: 60. Env override CLIO_CODER_TURN_TOOL_CALL_BUDGET beats this value.",
502
+ "guardrails.workerToolCallCap":
503
+ "Bounds admitted calls, not attempts: a call the harness refuses never ran and never spends the cap. Dispatch takes the smaller of this and the agent recipe's own budget, so the recipe normally binds. Whole number of at least 1 · default: 150. Env override CLIO_CODER_WORKER_TOOL_CALL_CAP beats this value.",
504
+ "guardrails.maxDispatchRuns":
505
+ "Runs leaving the ring also lose their event journal directory. Whole number of at least 1 · default: 1000. Env override CLIO_CODER_MAX_DISPATCH_RUNS beats this value.",
506
+ "guardrails.readMaxBytes":
507
+ "Clamped up to a 1KB floor at use. Whole number of bytes, at least 1 · default: 51200 (50KB). Env override CLIO_CODER_READ_MAX_BYTES beats this value.",
508
+ "guardrails.observationTurnBudgetBytes":
509
+ "One pool shared by every observation-producing tool in a turn, so a single verbose tool cannot starve the rest. Whole number of bytes, at least 1 · default: 196608 (192KB). Env override CLIO_CODER_OBSERVATION_TURN_BUDGET_BYTES beats this value.",
510
+ "guardrails.internalDispatchTimeoutMs":
511
+ "Covers the wiki documenter and the bootstrap scout. Continuous output satisfies the heartbeat watchdog and a run mid-generation spends no tool calls, so this is the only guard that ends a degenerate generator. Healthy runs finish in minutes. Whole milliseconds of at least 1 · default: 900000 (15 minutes). Env override CLIO_CODER_INTERNAL_DISPATCH_TIMEOUT_MS beats this value.",
512
+ "retry.streamStallMs":
513
+ "Measured from the last token received, not from the request, so a slow-but-alive stream is never aborted. The retry then follows the same enabled/maxRetries/delay settings above. Whole milliseconds · default: 180000 (three minutes).",
514
+ "library.catalog":
515
+ "Absolute path, or blank for the catalog in your config directory. The catalog is the index `clio-coder library` reads; installed resources land in the usual skill and resource roots either way. Default: blank.",
516
+ "library.remote":
517
+ "A Git remote URL, or blank to keep the library local. Setting it is not enough to sync: the remote must also be confirmed, and library.sync must be true. Default: blank.",
518
+ "library.confirmedRemote":
519
+ "Written by the confirm flow, not by hand, because confirming a remote here would be the record confirming itself. Sync refuses with library_remote_unconfirmed until this equals library.remote. Default: blank.",
520
+ "library.sync":
521
+ "Off means `clio-coder library sync` and `push` refuse before touching the network, whatever the remote says. Legal values: true, false · default: false.",
369
522
  "budget.concurrency": "auto sizes to your machine. A fixed number caps how many workers run at once.",
370
523
  "skills.trustProjectCompatRoots":
371
524
  "Project roots like .claude/skills and .codex/skills are untrusted by default; enabling exposes them to the model.",
@@ -373,6 +526,20 @@ const SETTINGS_HELP_BY_ID: Partial<Record<EditableSettingId, string>> = {
373
526
  "Role trailers are added only when Clio has trusted evidence for that role. Disabling leaves subsequent commit messages entirely unchanged.",
374
527
  "workers.onPermission":
375
528
  "deny turns the ask into a tool denial and the run continues; fail stops the run as permission_required; escalate forwards the ask to you and falls back per workers.escalation on timeout.",
529
+ "workers.escalation.timeoutMs":
530
+ "Only the escalate posture reads it, and it is what keeps that posture non-stall: a headless session has no operator to answer, so the fallback always governs there. Whole milliseconds of at least 1; default: 120000 (two minutes).",
531
+ "workers.escalation.fallback":
532
+ "deny turns the unanswered ask into a tool denial and the run continues; fail ends the run as permission_required. Legal values: deny, fail · default: deny.",
533
+ "workers.resilienceCooldownMs":
534
+ "Applied per target, runtime, and wire model after a failure class that trips the breaker; a clean run clears it immediately. Whole milliseconds, 0 disables the cooldown; default: 15000.",
535
+ "routing.activeRoles":
536
+ "Joint route selection stays shadow-only, recording what it would have picked, unless both the execution role and the requested posture are named as active. Legal values: researcher, verifier, reviewer, judge · default: none active.",
537
+ "routing.activePostures":
538
+ "Manual pins are exact rather than adaptive, so manual is never an activated posture. Legal values: quality, balanced, latency, economy · default: none active.",
539
+ "routing.agentAutomation.activeAgentRoles":
540
+ "Exact agentId and executionRole pairs, because independent agent and role lists would authorize their whole cross-product. Execution roles: builder, researcher, verifier, reviewer, judge; the agentId `auto` is reserved. Edit the pairs in settings.yaml; default: none active.",
541
+ "prewarm.enabled":
542
+ "Fires at session start, after a resume rebuilds the message array, and after a compaction settles, never while a turn or dispatch is running. Local-native targets and interactive sessions only, whatever this says. Legal values: true, false · default: true.",
376
543
  "workers.agentBindings":
377
544
  "Bind base, custom, and shadow native agents such as scout, researcher, and provenance to profiles. ACP delegation agents cannot be bound.",
378
545
  "delegation.defaults.toolGovernance":
@@ -408,6 +575,26 @@ const SETTINGS_VALUE_HELP_BY_ID: Partial<Record<EditableSettingId, Record<string
408
575
  escalate:
409
576
  "the ask is forwarded to this session's operator; on timeout it falls back to deny or fail per workers.escalation",
410
577
  },
578
+ "workers.escalation.fallback": {
579
+ deny: "an unanswered escalation becomes a tool denial and the run continues",
580
+ fail: "an unanswered escalation ends the run as permission_required",
581
+ },
582
+ "prewarm.enabled": {
583
+ true: "prefill the next turn's known prefix on local-native targets",
584
+ false: "never send a pre-warm request; the first turn pays the whole prefill",
585
+ },
586
+ "context.workingSet.enabled": {
587
+ true: "evict stale observations non-destructively before summarizing",
588
+ false: "skip eviction and go straight to summary compaction",
589
+ },
590
+ "context.workingSet.policy": {
591
+ "structural-v1": "select eviction candidates by message structure",
592
+ "age-horizon": "the older rule: select by age alone",
593
+ },
594
+ "library.sync": {
595
+ true: "allow `clio-coder library sync` and `push` to reach the confirmed remote",
596
+ false: "refuse every library network operation",
597
+ },
411
598
  "delegation.defaults.toolGovernance": {
412
599
  "clio-policy": "Clio's safety policy gates the delegated agent's tools",
413
600
  "agent-managed": "the external agent governs its own tools",
@@ -733,6 +920,16 @@ const NUMBER_SETTING_RULES = {
733
920
  "delegation.defaults.connectTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
734
921
  "delegation.defaults.turnTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
735
922
  "delegation.defaults.permissionTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
923
+ // The escalation deadline is armed as a timer, so it shares the delegation
924
+ // bounds; the rest mirror the config validator's own integer bounds.
925
+ "workers.escalation.timeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
926
+ "workers.resilienceCooldownMs": { min: 0, integer: true },
927
+ "guardrails.turnToolCallBudget": { min: 1, integer: true },
928
+ "guardrails.workerToolCallCap": { min: 1, integer: true },
929
+ "guardrails.maxDispatchRuns": { min: 1, integer: true },
930
+ "guardrails.readMaxBytes": { min: 1, integer: true },
931
+ "guardrails.observationTurnBudgetBytes": { min: 1, integer: true },
932
+ "guardrails.internalDispatchTimeoutMs": { min: 1, integer: true },
736
933
  } as const satisfies Partial<Record<EditableSettingId, NumberSettingRule>>;
737
934
 
738
935
  export type NumberSettingId = keyof typeof NUMBER_SETTING_RULES;
@@ -818,6 +1015,51 @@ function editNumberSubmenu(title: string, id: NumberSettingId): SettingSubmenuBu
818
1015
  };
819
1016
  }
820
1017
 
1018
+ /**
1019
+ * The comma-separated set an activation list holds, refused in place when an
1020
+ * entry is not one of the legal values. Silently dropping the unknown entry
1021
+ * would leave the operator looking at a list they thought they had activated,
1022
+ * so the editor stays open and names both the entry and the vocabulary.
1023
+ */
1024
+ function parseEnumListSetting(value: string, legal: readonly string[]): { values: string[] } | { refusal: string } {
1025
+ const entries = value
1026
+ .split(",")
1027
+ .map((entry) => entry.trim())
1028
+ .filter((entry) => entry.length > 0);
1029
+ const unknown = entries.find((entry) => !legal.includes(entry));
1030
+ if (unknown !== undefined) {
1031
+ return { refusal: `Not applied: '${unknown}' is not one of ${legal.join(", ")}.` };
1032
+ }
1033
+ const duplicate = entries.find((entry, index) => entries.indexOf(entry) !== index);
1034
+ if (duplicate !== undefined) return { refusal: `Not applied: '${duplicate}' is listed twice.` };
1035
+ return { values: entries };
1036
+ }
1037
+
1038
+ function editEnumListSubmenu(title: string, legal: readonly string[]): SettingSubmenuBuilder {
1039
+ return (currentValue: string, done: (val?: string) => void) => {
1040
+ const input = new Input();
1041
+ input.setValue(currentValue);
1042
+ input.focused = true;
1043
+ const wrapper = new SubmenuWrapper(
1044
+ title,
1045
+ input,
1046
+ buildHint([{ key: "Enter", verb: "confirm" }], "back"),
1047
+ `Comma-separated, from ${legal.join(", ")}; blank activates none.`,
1048
+ );
1049
+ input.onSubmit = (val) => {
1050
+ const outcome = parseEnumListSetting(val, legal);
1051
+ if ("refusal" in outcome) {
1052
+ wrapper.setProblem(outcome.refusal);
1053
+ return;
1054
+ }
1055
+ wrapper.setProblem(null);
1056
+ done(outcome.values.join(", "));
1057
+ };
1058
+ input.onEscape = () => done();
1059
+ return wrapper;
1060
+ };
1061
+ }
1062
+
821
1063
  function selectListSubmenu(
822
1064
  title: string,
823
1065
  items: ReadonlyArray<{
@@ -1288,13 +1530,23 @@ function settingItem(
1288
1530
  return item;
1289
1531
  }
1290
1532
 
1291
- function fleetGroupHeader(id: FleetGroupHeaderId, label: string): SettingsCenterItem {
1533
+ /**
1534
+ * A heading row that names the block of settings under it. The id carries the
1535
+ * section it belongs to, so one builder serves every section that groups its
1536
+ * rows rather than a near-duplicate per section.
1537
+ */
1538
+ function groupHeader(
1539
+ id: GroupHeaderId,
1540
+ section: SettingsSectionId,
1541
+ label: string,
1542
+ description: string,
1543
+ ): SettingsCenterItem {
1292
1544
  return {
1293
1545
  id,
1294
1546
  label,
1295
1547
  currentValue: "",
1296
- description: `${label} in the Fleet workbench.`,
1297
- section: "fleet",
1548
+ description,
1549
+ section,
1298
1550
  configPath: id,
1299
1551
  affordance: "group heading",
1300
1552
  scope: "live",
@@ -1304,6 +1556,14 @@ function fleetGroupHeader(id: FleetGroupHeaderId, label: string): SettingsCenter
1304
1556
  };
1305
1557
  }
1306
1558
 
1559
+ function fleetGroupHeader(id: FleetGroupHeaderId, label: string): SettingsCenterItem {
1560
+ return groupHeader(id, "fleet", label, `${label} in the Fleet workbench.`);
1561
+ }
1562
+
1563
+ function terminalGroupHeader(id: TerminalGroupHeaderId, label: string): SettingsCenterItem {
1564
+ return groupHeader(id, "terminal", label, `${label} behavior in the terminal.`);
1565
+ }
1566
+
1307
1567
  function targetAddCta(): SettingsCenterItem {
1308
1568
  return {
1309
1569
  id: "targets.add-cta",
@@ -1352,6 +1612,7 @@ export function buildSettingItems(
1352
1612
  const retry = settings.retry;
1353
1613
  const terminal = settings.terminal;
1354
1614
  const watchdog = settings.watchdog;
1615
+ const panes = settings.panes;
1355
1616
  const orchestratorThinking = thinkingChoices(
1356
1617
  options?.providers,
1357
1618
  settings.orchestrator.target,
@@ -1394,6 +1655,15 @@ export function buildSettingItems(
1394
1655
  const backgroundModelSubmenu = options?.providers
1395
1656
  ? selectModelSubmenu(options.providers, () => live().background.target ?? undefined)
1396
1657
  : editTextSubmenu("Type memory model name");
1658
+ // Both are optional in the settings type, so the row falls back to the
1659
+ // shipped value rather than rendering a blank for a key that is in force.
1660
+ const escalation = settings.workers.escalation ?? SHIPPED_ESCALATION;
1661
+ const resilienceCooldownMs = settings.workers.resilienceCooldownMs ?? SHIPPED_RESILIENCE_COOLDOWN_MS;
1662
+ const workingSet = settings.context.workingSet;
1663
+ const guardrails = settings.guardrails;
1664
+ const routing = settings.routing;
1665
+ const library = settings.library;
1666
+ const activeAgentRoles = routing.agentAutomation.activeAgentRoles;
1397
1667
  const favorites = settings.modelSelector?.favorites ?? [];
1398
1668
  const agents = settings.delegation?.agents ?? [];
1399
1669
  const keybindingCount = Object.keys(settings.keybindings ?? {}).length;
@@ -1404,6 +1674,13 @@ export function buildSettingItems(
1404
1674
  settingItem("workers.onPermission", settings.workers.onPermission ?? "deny", {
1405
1675
  values: ["deny", "fail", "escalate"],
1406
1676
  }),
1677
+ settingItem("workers.escalation.timeoutMs", String(escalation.timeoutMs), {
1678
+ submenu: editNumberSubmenu("Edit escalation timeout (ms)", "workers.escalation.timeoutMs"),
1679
+ affordance: "free text",
1680
+ }),
1681
+ settingItem("workers.escalation.fallback", escalation.fallback, {
1682
+ values: ["deny", "fail"],
1683
+ }),
1407
1684
  settingItem("delegation.defaults.toolGovernance", settings.delegation.defaults.toolGovernance, {
1408
1685
  values: ["clio-policy", "agent-managed", "deny-all"],
1409
1686
  }),
@@ -1451,6 +1728,9 @@ export function buildSettingItems(
1451
1728
  settingItem("memory.intervention.timeoutMs", String(settings.memory.intervention.timeoutMs), {
1452
1729
  values: ["5000", "10000", "20000", "30000", "60000"],
1453
1730
  }),
1731
+ settingItem("prewarm.enabled", String(settings.prewarm.enabled), {
1732
+ values: ["true", "false"],
1733
+ }),
1454
1734
  fleetGroupHeader("fleet.group.defaults", "Defaults"),
1455
1735
  settingItem("workers.default.target", settings.workers.default.target ?? "(unset)", {
1456
1736
  submenu: targetSubmenu,
@@ -1466,6 +1746,10 @@ export function buildSettingItems(
1466
1746
  settingItem("workers.maxRetries", String(settings.workers.maxRetries), {
1467
1747
  values: ["0", "1", "2", "3", "5", "8"],
1468
1748
  }),
1749
+ settingItem("workers.resilienceCooldownMs", String(resilienceCooldownMs), {
1750
+ submenu: editNumberSubmenu("Edit resilience cooldown (ms)", "workers.resilienceCooldownMs"),
1751
+ affordance: "free text",
1752
+ }),
1469
1753
  fleetGroupHeader("fleet.group.profiles", "Profiles"),
1470
1754
  ...fleetProfileRows(settings, live, options),
1471
1755
  settingItem("workers.profiles", "", {
@@ -1484,9 +1768,35 @@ export function buildSettingItems(
1484
1768
  presentationKind: profileCount > 0 ? "action" : "read-only-fact",
1485
1769
  valueSegments: [],
1486
1770
  }),
1771
+ fleetGroupHeader("fleet.group.route-activation", "Route activation"),
1772
+ settingItem("routing.activeRoles", routing.activeRoles.length > 0 ? routing.activeRoles.join(", ") : "(none)", {
1773
+ submenu: editEnumListSubmenu("Edit active routing roles", ACTIVE_ROUTING_ROLES),
1774
+ affordance: `free text from ${ACTIVE_ROUTING_ROLES.join(", ")}`,
1775
+ editValue: routing.activeRoles.join(", "),
1776
+ }),
1777
+ settingItem(
1778
+ "routing.activePostures",
1779
+ routing.activePostures.length > 0 ? routing.activePostures.join(", ") : "(none)",
1780
+ {
1781
+ submenu: editEnumListSubmenu("Edit active routing postures", ACTIVE_ROUTING_POSTURES),
1782
+ affordance: `free text from ${ACTIVE_ROUTING_POSTURES.join(", ")}`,
1783
+ editValue: routing.activePostures.join(", "),
1784
+ },
1785
+ ),
1786
+ settingItem(
1787
+ "routing.agentAutomation.activeAgentRoles",
1788
+ activeAgentRoles.length > 0
1789
+ ? activeAgentRoles.map((pair) => `${pair.agentId}/${pair.executionRole}`).join(", ")
1790
+ : "(none)",
1791
+ { affordance: "edit settings.yaml", readOnly: true },
1792
+ ),
1487
1793
  fleetGroupHeader("fleet.group.placement", "Placement"),
1488
1794
  ...fleetNodeRows(options?.getFleetNodes?.() ?? []),
1489
1795
  ...fleetEndpointRows(options?.providers),
1796
+ fleetGroupHeader("fleet.group.panes", "Panes"),
1797
+ settingItem("panes.enabled", panes.enabled, { values: ["auto", "embedded", "off"] }),
1798
+ settingItem("panes.notifications", panes.notifications, { values: ["failures", "all", "off"] }),
1799
+ settingItem("panes.journal", String(panes.journal), { values: ["true", "false"] }),
1490
1800
  settingItem("targets", "", {
1491
1801
  description: "Live inference target inventory and routing roles.",
1492
1802
  affordance: "column heading",
@@ -1517,6 +1827,36 @@ export function buildSettingItems(
1517
1827
  settingItem("budget.concurrency", String(settings.budget.concurrency), {
1518
1828
  values: ["auto", "1", "2", "4", "8"],
1519
1829
  }),
1830
+ groupHeader(
1831
+ "budget.group.guardrails",
1832
+ "budget",
1833
+ "Guardrails",
1834
+ "Numeric backstops that bound runaway agent behavior.",
1835
+ ),
1836
+ settingItem("guardrails.turnToolCallBudget", String(guardrails.turnToolCallBudget), {
1837
+ submenu: editNumberSubmenu("Edit turn tool-call budget", "guardrails.turnToolCallBudget"),
1838
+ affordance: "free text",
1839
+ }),
1840
+ settingItem("guardrails.workerToolCallCap", String(guardrails.workerToolCallCap), {
1841
+ submenu: editNumberSubmenu("Edit worker tool-call cap", "guardrails.workerToolCallCap"),
1842
+ affordance: "free text",
1843
+ }),
1844
+ settingItem("guardrails.maxDispatchRuns", String(guardrails.maxDispatchRuns), {
1845
+ submenu: editNumberSubmenu("Edit run ledger retention", "guardrails.maxDispatchRuns"),
1846
+ affordance: "free text",
1847
+ }),
1848
+ settingItem("guardrails.readMaxBytes", String(guardrails.readMaxBytes), {
1849
+ submenu: editNumberSubmenu("Edit read byte cap", "guardrails.readMaxBytes"),
1850
+ affordance: "free text",
1851
+ }),
1852
+ settingItem("guardrails.observationTurnBudgetBytes", String(guardrails.observationTurnBudgetBytes), {
1853
+ submenu: editNumberSubmenu("Edit observation byte pool", "guardrails.observationTurnBudgetBytes"),
1854
+ affordance: "free text",
1855
+ }),
1856
+ settingItem("guardrails.internalDispatchTimeoutMs", String(guardrails.internalDispatchTimeoutMs), {
1857
+ submenu: editNumberSubmenu("Edit internal dispatch timeout (ms)", "guardrails.internalDispatchTimeoutMs"),
1858
+ affordance: "free text",
1859
+ }),
1520
1860
  settingItem("compaction.auto", String(compaction.auto), {
1521
1861
  values: ["true", "false"],
1522
1862
  }),
@@ -1526,6 +1866,27 @@ export function buildSettingItems(
1526
1866
  settingItem("compaction.excludeLastTurns", String(compaction.excludeLastTurns), {
1527
1867
  values: ["3", "6", "10", "15"],
1528
1868
  }),
1869
+ groupHeader(
1870
+ "compaction.group.working-set",
1871
+ "compaction",
1872
+ "Working set",
1873
+ "The non-destructive eviction layer that runs before a summary is needed.",
1874
+ ),
1875
+ settingItem("context.workingSet.enabled", String(workingSet.enabled), {
1876
+ values: ["true", "false"],
1877
+ }),
1878
+ settingItem("context.workingSet.policy", workingSet.policy, {
1879
+ values: ["structural-v1", "age-horizon"],
1880
+ }),
1881
+ settingItem("context.workingSet.target", formatThreshold(workingSet.target, "0.6"), {
1882
+ values: ["0.4", "0.5", "0.6", "0.7"],
1883
+ }),
1884
+ settingItem("context.workingSet.protectLastTurns", String(workingSet.protectLastTurns), {
1885
+ values: ["3", "6", "10", "15"],
1886
+ }),
1887
+ settingItem("context.workingSet.minEvictableTokens", String(workingSet.minEvictableTokens), {
1888
+ values: ["0", "100", "200", "500", "1000"],
1889
+ }),
1529
1890
  settingItem("retry.enabled", String(retry.enabled), {
1530
1891
  values: ["true", "false"],
1531
1892
  }),
@@ -1538,6 +1899,9 @@ export function buildSettingItems(
1538
1899
  settingItem("retry.maxDelayMs", String(retry.maxDelayMs), {
1539
1900
  values: ["10000", "30000", "60000", "120000", "300000"],
1540
1901
  }),
1902
+ settingItem("retry.streamStallMs", String(retry.streamStallMs), {
1903
+ values: ["60000", "120000", "180000", "300000", "600000"],
1904
+ }),
1541
1905
  settingItem("terminal.showTerminalProgress", String(terminal.showTerminalProgress), {
1542
1906
  values: ["false", "true"],
1543
1907
  }),
@@ -1560,6 +1924,11 @@ export function buildSettingItems(
1560
1924
  affordance: "single clio-coder palette",
1561
1925
  readOnly: true,
1562
1926
  }),
1927
+ terminalGroupHeader("terminal.group.files-pane", "Files pane"),
1928
+ settingItem("panes.yazi.enabled", String(panes.yazi.enabled), { values: ["true", "false"] }),
1929
+ settingItem("panes.yazi.mode", panes.yazi.mode, { values: ["companion", "chooser"] }),
1930
+ settingItem("panes.yazi.profile", panes.yazi.profile, { values: ["managed", "user"] }),
1931
+ settingItem("panes.yazi.followCwd", String(panes.yazi.followCwd), { values: ["true", "false"] }),
1563
1932
  settingItem("watchdog.enabled", String(watchdog.enabled), {
1564
1933
  values: ["false", "true"],
1565
1934
  }),
@@ -1617,6 +1986,31 @@ export function buildSettingItems(
1617
1986
  settingItem("delegation.agents", agents.length > 0 ? `${agents.length} agent(s)` : "(none)", {
1618
1987
  ...delegationAgentsAffordance(agents, options?.getInteropProposals?.() ?? []),
1619
1988
  }),
1989
+ groupHeader(
1990
+ "advanced.group.library",
1991
+ "advanced",
1992
+ "Library",
1993
+ "The private resource catalog and the remote it may sync with.",
1994
+ ),
1995
+ settingItem("library.catalog", library.catalog ?? "(config directory)", {
1996
+ submenu: editTextSubmenu("Edit library catalog path; blank uses the config directory"),
1997
+ affordance: "free text",
1998
+ editValue: library.catalog ?? "",
1999
+ }),
2000
+ settingItem("library.remote", library.remote ?? "(local only)", {
2001
+ submenu: editTextSubmenu("Edit library remote URL; blank keeps the library local"),
2002
+ affordance: "free text",
2003
+ editValue: library.remote ?? "",
2004
+ }),
2005
+ // Confirming a remote from the settings row would be the trust record
2006
+ // confirming itself, so this row reports what the confirm flow wrote.
2007
+ settingItem("library.confirmedRemote", library.confirmedRemote ?? "(unconfirmed)", {
2008
+ affordance: "set by `clio-coder library` on confirmation",
2009
+ readOnly: true,
2010
+ }),
2011
+ settingItem("library.sync", String(library.sync), {
2012
+ values: ["true", "false"],
2013
+ }),
1620
2014
  ];
1621
2015
  }
1622
2016
 
@@ -1935,8 +2329,8 @@ function refreshSettingItemsInPlace(items: SettingsCenterItem[], next: readonly
1935
2329
  }
1936
2330
  }
1937
2331
 
1938
- function formatThreshold(value: number): string {
1939
- return Number.isFinite(value) ? String(value) : "0.8";
2332
+ function formatThreshold(value: number, fallback = "0.8"): string {
2333
+ return Number.isFinite(value) ? String(value) : fallback;
1940
2334
  }
1941
2335
 
1942
2336
  function applyNonNegativeInteger(value: string, set: (next: number) => void): void {
@@ -2024,6 +2418,27 @@ export function applySettingChange(settings: ClioSettings, id: string, value: st
2024
2418
  settings.workers.maxRetries = next;
2025
2419
  });
2026
2420
  return;
2421
+ case "panes.enabled":
2422
+ if (value === "auto" || value === "embedded" || value === "off") settings.panes.enabled = value;
2423
+ return;
2424
+ case "panes.notifications":
2425
+ if (value === "failures" || value === "all" || value === "off") settings.panes.notifications = value;
2426
+ return;
2427
+ case "panes.journal":
2428
+ if (value === "true" || value === "false") settings.panes.journal = value === "true";
2429
+ return;
2430
+ case "panes.yazi.enabled":
2431
+ if (value === "true" || value === "false") settings.panes.yazi.enabled = value === "true";
2432
+ return;
2433
+ case "panes.yazi.mode":
2434
+ if (value === "companion" || value === "chooser") settings.panes.yazi.mode = value;
2435
+ return;
2436
+ case "panes.yazi.profile":
2437
+ if (value === "managed" || value === "user") settings.panes.yazi.profile = value;
2438
+ return;
2439
+ case "panes.yazi.followCwd":
2440
+ if (value === "true" || value === "false") settings.panes.yazi.followCwd = value === "true";
2441
+ return;
2027
2442
  case "modelSelector.recentLimit":
2028
2443
  applyNonNegativeInteger(value, (next) => {
2029
2444
  if (next >= 1) settings.modelSelector.recentLimit = next;
@@ -2200,6 +2615,83 @@ export function applySettingChange(settings: ClioSettings, id: string, value: st
2200
2615
  if (next !== null) settings.budget.sessionCeilingUsd = next;
2201
2616
  });
2202
2617
  return;
2618
+ case "workers.escalation.timeoutMs":
2619
+ applyNumberSetting("workers.escalation.timeoutMs", value, (next) => {
2620
+ if (next === null) return;
2621
+ settings.workers.escalation = { ...(settings.workers.escalation ?? SHIPPED_ESCALATION), timeoutMs: next };
2622
+ });
2623
+ return;
2624
+ case "workers.escalation.fallback": {
2625
+ if (value !== "deny" && value !== "fail") return;
2626
+ settings.workers.escalation = { ...(settings.workers.escalation ?? SHIPPED_ESCALATION), fallback: value };
2627
+ return;
2628
+ }
2629
+ case "workers.resilienceCooldownMs":
2630
+ applyNumberSetting("workers.resilienceCooldownMs", value, (next) => {
2631
+ if (next !== null) settings.workers.resilienceCooldownMs = next;
2632
+ });
2633
+ return;
2634
+ case "routing.activeRoles": {
2635
+ const outcome = parseEnumListSetting(value, ACTIVE_ROUTING_ROLES);
2636
+ if ("values" in outcome) settings.routing.activeRoles = outcome.values as ActiveRoutingRole[];
2637
+ return;
2638
+ }
2639
+ case "routing.activePostures": {
2640
+ const outcome = parseEnumListSetting(value, ACTIVE_ROUTING_POSTURES);
2641
+ if ("values" in outcome) settings.routing.activePostures = outcome.values as ActiveRoutingPosture[];
2642
+ return;
2643
+ }
2644
+ case "prewarm.enabled":
2645
+ if (value === "true" || value === "false") settings.prewarm.enabled = value === "true";
2646
+ return;
2647
+ case "guardrails.turnToolCallBudget":
2648
+ case "guardrails.workerToolCallCap":
2649
+ case "guardrails.maxDispatchRuns":
2650
+ case "guardrails.readMaxBytes":
2651
+ case "guardrails.observationTurnBudgetBytes":
2652
+ case "guardrails.internalDispatchTimeoutMs":
2653
+ applyNumberSetting(id, value, (next) => {
2654
+ if (next !== null) settings.guardrails[id.slice("guardrails.".length) as keyof GuardrailValues] = next;
2655
+ });
2656
+ return;
2657
+ case "context.workingSet.enabled":
2658
+ if (value === "true" || value === "false") settings.context.workingSet.enabled = value === "true";
2659
+ return;
2660
+ case "context.workingSet.policy":
2661
+ if (value === "structural-v1" || value === "age-horizon") settings.context.workingSet.policy = value;
2662
+ return;
2663
+ case "context.workingSet.target": {
2664
+ // The validator's bound is exclusive at both ends, so an eviction target
2665
+ // of 0 or 1 is refused here rather than written and rejected at boot.
2666
+ const parsed = Number(value);
2667
+ if (Number.isFinite(parsed) && parsed > 0 && parsed < 1) settings.context.workingSet.target = parsed;
2668
+ return;
2669
+ }
2670
+ case "context.workingSet.protectLastTurns":
2671
+ applyNonNegativeInteger(value, (next) => {
2672
+ if (next >= 1) settings.context.workingSet.protectLastTurns = next;
2673
+ });
2674
+ return;
2675
+ case "context.workingSet.minEvictableTokens":
2676
+ applyNonNegativeInteger(value, (next) => {
2677
+ settings.context.workingSet.minEvictableTokens = next;
2678
+ });
2679
+ return;
2680
+ case "retry.streamStallMs":
2681
+ applyNonNegativeInteger(value, (next) => {
2682
+ settings.retry.streamStallMs = next;
2683
+ });
2684
+ return;
2685
+ case "library.catalog":
2686
+ case "library.remote": {
2687
+ const key = id.slice("library.".length) as "catalog" | "remote";
2688
+ const trimmed = value.trim();
2689
+ settings.library[key] = trimmed.length > 0 ? trimmed : null;
2690
+ return;
2691
+ }
2692
+ case "library.sync":
2693
+ if (value === "true" || value === "false") settings.library.sync = value === "true";
2694
+ return;
2203
2695
  }
2204
2696
  }
2205
2697
 
@@ -3280,7 +3772,7 @@ export class SettingsCenter implements Component {
3280
3772
  if (this.sections().length === 0) return [...head, ...this.emptyFilterLines(width, available)];
3281
3773
  // A detail page owns the work area, and the footer describes the row the
3282
3774
  // operator has already left, so it is suppressed while a submenu is open.
3283
- const footer = this.submenuComponent ? [] : this.renderFooter(width, this.footerBudget(available));
3775
+ const footer = this.submenuComponent ? [] : this.renderFooter(width, this.footerBudget(available, width));
3284
3776
  const contentHeight = Math.max(1, available - footer.length);
3285
3777
  const leftWidth = Math.min(SECTION_LANE_WIDTH, Math.max(16, Math.floor(width * 0.28)));
3286
3778
  const separator = barSep(clioTheme());
@@ -3300,9 +3792,16 @@ export class SettingsCenter implements Component {
3300
3792
  * The footer is help, and the list is the work. A fixed six-line ceiling spent
3301
3793
  * a third of a 20-row body on prose, so the budget is what the body can spare
3302
3794
  * once the list keeps six rows.
3795
+ *
3796
+ * The ceiling follows the scope note, which wraps rather than cuts: at 90
3797
+ * columns that note needs two rows, and the flat four-line ceiling then paid
3798
+ * for the second row out of the explanation above it. The note buys its own
3799
+ * rows instead. A note that fits on one line leaves the ceiling at four, so
3800
+ * every width above the wrap point renders exactly as it did.
3303
3801
  */
3304
- private footerBudget(bodyHeight: number): number {
3305
- return Math.min(4, Math.max(0, bodyHeight - 6));
3802
+ private footerBudget(bodyHeight: number, width: number): number {
3803
+ const noteLines = wrapTextWithAnsi(this.footerNoteText(), Math.max(1, width)).length;
3804
+ return Math.min(2 + noteLines + 1, Math.max(0, bodyHeight - 6));
3306
3805
  }
3307
3806
 
3308
3807
  private renderSectionLane(width: number, height: number): string[] {
@@ -3468,15 +3967,27 @@ export class SettingsCenter implements Component {
3468
3967
  const query = this.filterQuery.trim().length > 0 ? ` ${theme.fg("accent", `/${this.filterQuery}`)}` : "";
3469
3968
  const positionText = `${theme.fg("dim", `section ${position}/${sections.length}`)}${query}`;
3470
3969
 
3970
+ // The note is prose the operator acts on ("choose session, global, or
3971
+ // cancel"), so it wraps under the same rule as the description above it. A
3972
+ // truncated instruction is the one line in this footer that cannot afford
3973
+ // to be a fragment.
3974
+ const noteLines = (text: string, tone: "dim" | "muted"): string[] =>
3975
+ wrapTextWithAnsi(theme.fg(tone, text), safeWidth);
3976
+
3471
3977
  if (this.level === "sections") {
3472
3978
  const breadcrumb = `${screenTitle(theme, section.label)} ${theme.fg("dim", "·")} ${positionText}`;
3473
3979
  const body = wrapTextWithAnsi(theme.fg("muted", SETTINGS_SECTION_DESCRIPTIONS[section.id]), safeWidth);
3474
- const note = theme.fg("dim", "Tab or → to edit its settings");
3475
- return this.assembleFooter([separator, breadcrumb], body, note, maxFooterLines, safeWidth);
3980
+ return this.assembleFooter(
3981
+ [separator, breadcrumb],
3982
+ body,
3983
+ noteLines(this.footerNoteText(), "dim"),
3984
+ maxFooterLines,
3985
+ safeWidth,
3986
+ );
3476
3987
  }
3477
3988
 
3478
3989
  if (!item) {
3479
- return this.assembleFooter([separator], [], theme.fg("muted", "No setting selected."), maxFooterLines, safeWidth);
3990
+ return this.assembleFooter([separator], [], noteLines(this.footerNoteText(), "muted"), maxFooterLines, safeWidth);
3480
3991
  }
3481
3992
 
3482
3993
  const breadcrumb = `${screenTitle(theme, section.label)} ${theme.fg("dim", "›")} ${theme.style("accent", item.label, { bold: true })} ${theme.fg("dim", "·")} ${positionText}`;
@@ -3485,8 +3996,27 @@ export class SettingsCenter implements Component {
3485
3996
  if (item.help) contentLines.push(...wrapTextWithAnsi(theme.fg("dim", item.help), safeWidth));
3486
3997
  const detail = this.footerDetail(item, theme);
3487
3998
  if (detail) contentLines.push(...wrapTextWithAnsi(detail, safeWidth));
3488
- const note = theme.fg("dim", truncateToWidth(this.footerScopeNote(item), safeWidth, ELLIPSIS, true));
3489
- return this.assembleFooter([separator, breadcrumb], contentLines, note, maxFooterLines, safeWidth);
3999
+ return this.assembleFooter(
4000
+ [separator, breadcrumb],
4001
+ contentLines,
4002
+ noteLines(this.footerScopeNote(item), "dim"),
4003
+ maxFooterLines,
4004
+ safeWidth,
4005
+ );
4006
+ }
4007
+
4008
+ /**
4009
+ * The note text renderFooter will show, without theming. `footerBudget` needs
4010
+ * its wrapped height before the footer is rendered, so both read it here and
4011
+ * the ceiling can never disagree with what lands.
4012
+ */
4013
+ private footerNoteText(): string {
4014
+ const section = this.currentSection();
4015
+ if (!section) return "";
4016
+ if (this.level === "sections") return "Tab or → to edit its settings";
4017
+ const item = this.selectedItem();
4018
+ if (!item) return "No setting selected.";
4019
+ return this.footerScopeNote(item);
3490
4020
  }
3491
4021
 
3492
4022
  private footerDetail(item: SettingsCenterItem, theme: ReturnType<typeof clioTheme>): string {
@@ -3523,7 +4053,7 @@ export class SettingsCenter implements Component {
3523
4053
  private assembleFooter(
3524
4054
  top: readonly string[],
3525
4055
  middle: readonly string[],
3526
- note: string,
4056
+ note: readonly string[],
3527
4057
  maxFooterLines: number,
3528
4058
  width: number,
3529
4059
  ): string[] {
@@ -3532,7 +4062,11 @@ export class SettingsCenter implements Component {
3532
4062
  if (maxFooterLines <= top.length) {
3533
4063
  out = top.slice(0, maxFooterLines).map(fit);
3534
4064
  } else {
3535
- const middleBudget = Math.max(0, maxFooterLines - top.length - 1);
4065
+ // The note owns the rows it wrapped to, up to whatever is left under the
4066
+ // breadcrumb; the explanation fills the rest. Dropping a wrapped note
4067
+ // line loses less than cutting the sentence mid-word did.
4068
+ const noteKept = note.slice(0, Math.max(1, maxFooterLines - top.length));
4069
+ const middleBudget = Math.max(0, maxFooterLines - top.length - noteKept.length);
3536
4070
  // The explanation is wrapped, so a short terminal drops whole lines off
3537
4071
  // its end rather than cutting one. At 40 columns the autonomy help
3538
4072
  // stopped at "read-only observes; suggest" and read as the whole
@@ -3541,7 +4075,7 @@ export class SettingsCenter implements Component {
3541
4075
  const last = kept.at(-1);
3542
4076
  const marked =
3543
4077
  middle.length > kept.length && last !== undefined ? [...kept.slice(0, -1), `${last}${ELLIPSIS}`] : kept;
3544
- out = [...top.map(fit), ...marked.map(fit), fit(note)];
4078
+ out = [...top.map(fit), ...marked.map(fit), ...noteKept.map(fit)];
3545
4079
  }
3546
4080
  while (out.length < maxFooterLines) out.push("");
3547
4081
  return out.slice(0, maxFooterLines);
@@ -3651,6 +4185,7 @@ export function openSettingsOverlay(tui: TUI, deps: OpenSettingsOverlayDeps): Se
3651
4185
  margin.right = side;
3652
4186
  return true;
3653
4187
  },
4188
+ markerId: "settings",
3654
4189
  title: "Settings",
3655
4190
  footerHint: (innerWidth) =>
3656
4191
  innerWidth < WIDE_LAYOUT_MIN_WIDTH