@iowarp/clio-coder 0.3.4 → 0.3.7

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 (376) hide show
  1. package/CHANGELOG.md +65 -2
  2. package/CONTRIBUTING.md +6 -6
  3. package/README.md +16 -5
  4. package/dist/{acp-S5R4RR5B.js → acp-SK4MD6MM.js} +11 -11
  5. package/dist/{agents-P6DMMVZY.js → agents-2FN2K6ME.js} +33 -26
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-2XCZLPKS.js → auth-QIYZWM5I.js} +15 -15
  8. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  9. package/dist/{chunk-VAWWTKDP.js → chunk-3HAPLH5M.js} +11 -11
  10. package/dist/{chunk-YCWGATWI.js → chunk-465YSENW.js} +3 -3
  11. package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
  12. package/dist/{chunk-UZHIZC5S.js → chunk-4DWFMQDR.js} +61 -76
  13. package/dist/{chunk-ZWMF7253.js → chunk-5C3AQNDW.js} +328 -9
  14. package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
  15. package/dist/{chunk-WPQLXFOZ.js → chunk-5FR74PWO.js} +3 -2
  16. package/dist/{chunk-35MKKU5R.js → chunk-5UJ6ECTS.js} +18 -10
  17. package/dist/{chunk-BRXQQJFP.js → chunk-6M7VS3J3.js} +571 -50
  18. package/dist/{chunk-QQK64KLB.js → chunk-6TUKSZVF.js} +141 -23
  19. package/dist/{chunk-N4CZJQRK.js → chunk-AB4XIIVB.js} +8 -6
  20. package/dist/{chunk-KRPY7NTG.js → chunk-BMWK7ZIZ.js} +14 -20
  21. package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
  22. package/dist/{chunk-ZYKPLLNQ.js → chunk-CEYBNUGC.js} +821 -83
  23. package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
  24. package/dist/chunk-DJNLUABN.js +843 -0
  25. package/dist/{chunk-BP4OYD6A.js → chunk-DMD2AGVS.js} +21 -2
  26. package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
  27. package/dist/chunk-DQA7QLMD.js +123 -0
  28. package/dist/chunk-DR52UMZW.js +21 -0
  29. package/dist/{chunk-3HZ5RWN2.js → chunk-EBEFWSGL.js} +9 -7
  30. package/dist/{chunk-EDRHSCIE.js → chunk-EELBMBT6.js} +128 -13
  31. package/dist/{chunk-HV5X7OR2.js → chunk-EOOQZZDE.js} +16 -14
  32. package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
  33. package/dist/{chunk-BPGS2WCQ.js → chunk-GEYXPTRF.js} +2 -1
  34. package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
  35. package/dist/{chunk-BEY543CS.js → chunk-GOXNB3AO.js} +5 -2
  36. package/dist/chunk-GWS3VEIW.js +195 -0
  37. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  38. package/dist/chunk-HWUFFB6L.js +83 -0
  39. package/dist/{chunk-X6COSD2O.js → chunk-J7PIKKWC.js} +8 -436
  40. package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
  41. package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
  42. package/dist/{chunk-K6WL7QZT.js → chunk-JTSEDYVQ.js} +7 -7
  43. package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
  44. package/dist/chunk-KZ2H5X4G.js +1026 -0
  45. package/dist/{chunk-A2GZF7DC.js → chunk-LADCF22A.js} +13 -13
  46. package/dist/chunk-LCGCVYZ4.js +57 -0
  47. package/dist/chunk-M4AKACEO.js +382 -0
  48. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  49. package/dist/{chunk-4JUF2NNX.js → chunk-MXI6J5JF.js} +7 -7
  50. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  51. package/dist/{chunk-TTNYS3EA.js → chunk-OB5HIGJY.js} +1 -1
  52. package/dist/{chunk-7RXG6QRZ.js → chunk-OBMAI2DP.js} +61 -840
  53. package/dist/{chunk-5M54SPOL.js → chunk-ODFEOB4F.js} +161 -5
  54. package/dist/chunk-PD3MESLB.js +242 -0
  55. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  56. package/dist/{chunk-VMNQ6OZA.js → chunk-QCTRSGHQ.js} +963 -786
  57. package/dist/chunk-RVG5JXAL.js +41 -0
  58. package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
  59. package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
  60. package/dist/{chunk-34475P3I.js → chunk-TSHXZTOQ.js} +5 -4
  61. package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
  62. package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
  63. package/dist/chunk-UND3GU2L.js +103 -0
  64. package/dist/{chunk-QQL5RT5M.js → chunk-UUANF5CR.js} +2323 -2114
  65. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  66. package/dist/chunk-UVDSQ6LW.js +472 -0
  67. package/dist/{chunk-QWU7ZBO7.js → chunk-VQNODYQ4.js} +215 -56
  68. package/dist/chunk-VREKEFLL.js +37 -0
  69. package/dist/{chunk-2TZWSW76.js → chunk-WHGPSPT5.js} +2 -2
  70. package/dist/{chunk-TW3WDMVS.js → chunk-WHJYKASB.js} +2 -2
  71. package/dist/{chunk-MEQ45TQ4.js → chunk-WJHBC77E.js} +21 -7
  72. package/dist/{chunk-HXG4IURW.js → chunk-X2KV5FXT.js} +2 -2
  73. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  74. package/dist/{chunk-2LZI5CAG.js → chunk-XEGB6BCN.js} +228 -36
  75. package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
  76. package/dist/{verifiers-4UUM6TEE.js → chunk-YTYFXUI3.js} +121 -372
  77. package/dist/{chunk-3JLKSKD7.js → chunk-ZGH7FGS5.js} +17 -7
  78. package/dist/{chunk-VSNATDE6.js → chunk-ZZMN5OM4.js} +2 -2
  79. package/dist/cli/index.js +34 -32
  80. package/dist/{clio-J5JIOIDS.js → clio-WBVQEBKO.js} +7 -7
  81. package/dist/{code-nav-AXCXSBHX.js → code-nav-FGGFIE7L.js} +7 -7
  82. package/dist/codewiki/build-worker.js +4 -4
  83. package/dist/{components-KELWS457.js → components-F7OEATSO.js} +5 -5
  84. package/dist/{config-OEBMIN2U.js → config-TRBL3RCF.js} +48 -41
  85. package/dist/{configure-PUQOSIXQ.js → configure-OLCVPHNM.js} +17 -17
  86. package/dist/{context-URSXPBCK.js → context-MJIJ6GOX.js} +12 -12
  87. package/dist/{context-EKDCKUUZ.js → context-WFPKQSM6.js} +26 -9
  88. package/dist/{context-MGSE4Z2T.js → context-XEWE3MOJ.js} +44 -37
  89. package/dist/{context-clear-KDAJRNUK.js → context-clear-KNOS2JPB.js} +44 -37
  90. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  91. package/dist/{context-working-set-SBKMPPI2.js → context-working-set-EUXAZI6N.js} +14 -13
  92. package/dist/{dispatch-runner-MSWN72NK.js → dispatch-runner-B7MTOVKL.js} +321 -60
  93. package/dist/{docs-2C2LTVT2.js → docs-FLJTIDSE.js} +5 -5
  94. package/dist/{doctor-7BSE27PJ.js → doctor-RN4YKO2X.js} +15 -15
  95. package/dist/{eval-IZGDOO4H.js → eval-RUBJVSNQ.js} +52 -236
  96. package/dist/{evidence-SR7WXB5B.js → evidence-JZNBUOQZ.js} +39 -33
  97. package/dist/{evolve-K7VE2CBX.js → evolve-FJVC4KKI.js} +39 -33
  98. package/dist/{extensions-QVDOHDGJ.js → extensions-IQL36S7K.js} +5 -5
  99. package/dist/{fleet-7XMJNQNF.js → fleet-BDKYJFCP.js} +243 -370
  100. package/dist/fleet-commands-ZFIWZSB3.js +70 -0
  101. package/dist/fleet-graph-Y6HPXIVF.js +125 -0
  102. package/dist/fleet-new-RDVJLHHH.js +48 -0
  103. package/dist/{fleet-preflight-AQNAH644.js → fleet-preflight-BHSNPBMH.js} +2 -2
  104. package/dist/fleet-validate-BIYREGIK.js +79 -0
  105. package/dist/{init-JGNPAYXT.js → init-LQUB5COQ.js} +57 -48
  106. package/dist/library-NJAHIGG4.js +217 -0
  107. package/dist/memory-OG6HOYKM.js +472 -0
  108. package/dist/{models-ZMMLFJNN.js → models-5ZG5XY7J.js} +23 -22
  109. package/dist/{monitor-2F3T5KHP.js → monitor-TJ7AMTGB.js} +69 -35
  110. package/dist/{orchestrator-ORHT43JB.js → orchestrator-WZYB54DM.js} +4868 -1189
  111. package/dist/{paths-UXLN5YYZ.js → paths-XUC7GS6E.js} +5 -5
  112. package/dist/{reset-NXGTYNUO.js → reset-PXQT45IY.js} +8 -8
  113. package/dist/{run-RF4WJGMT.js → run-FQ74YF62.js} +82 -62
  114. package/dist/{share-UT3W6E4M.js → share-FW7SVCL3.js} +34 -10
  115. package/dist/{skills-PSACKC5Q.js → skills-7E7IRB3R.js} +25 -9
  116. package/dist/{skills-eval-WJSI55RZ.js → skills-eval-LI75W6OK.js} +43 -35
  117. package/dist/{targets-PIIRAOYS.js → targets-4CIFKCTW.js} +27 -24
  118. package/dist/{terminal-lease-ULWXWNVY.js → terminal-lease-WUZY7ZV5.js} +5 -4
  119. package/dist/{uninstall-FZCQCDKC.js → uninstall-7FV7IP4E.js} +5 -5
  120. package/dist/{upgrade-346TZ6AV.js → upgrade-K2HVIVMQ.js} +21 -20
  121. package/dist/{usage-6KKXR32N.js → usage-GTZELZQX.js} +159 -59
  122. package/dist/verifiers-RLAHT27O.js +336 -0
  123. package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
  124. package/dist/{wiki-generate-7STOCIFZ.js → wiki-generate-ASIFASCN.js} +58 -48
  125. package/dist/worker/entry.js +98 -84
  126. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  127. package/docs/README.md +4 -3
  128. package/docs/acp.md +1 -1
  129. package/docs/alcf-provider.md +1 -1
  130. package/docs/architecture.md +2 -2
  131. package/docs/artifact-placement.md +1 -2
  132. package/docs/artifact-versions.md +10 -6
  133. package/docs/built-in-agents.md +26 -2
  134. package/docs/capacity-and-scheduling.md +1 -1
  135. package/docs/commands-and-modes.md +90 -8
  136. package/docs/configuration-and-targets.md +90 -2
  137. package/docs/context-engine.md +4 -2
  138. package/docs/context-working-set.md +4 -4
  139. package/docs/development-pipeline.md +1 -1
  140. package/docs/dispatch-architecture-rationale.md +1 -1
  141. package/docs/documentation-coverage.md +4 -4
  142. package/docs/documentation-guide.md +4 -4
  143. package/docs/eval-runner.md +1 -1
  144. package/docs/evals-internal.md +4 -45
  145. package/docs/evidence-and-memory.md +70 -10
  146. package/docs/evolution.md +1 -1
  147. package/docs/exit-codes-and-output.md +4 -1
  148. package/docs/extensions-and-sharing.md +6 -2
  149. package/docs/fleet-demo-runbook.md +2 -2
  150. package/docs/fleet-dispatch.md +224 -11
  151. package/docs/git-commit-provenance.md +2 -2
  152. package/docs/glossary.md +1 -1
  153. package/docs/installation-and-lifecycle.md +2 -2
  154. package/docs/middleware-and-components.md +20 -2
  155. package/docs/model-catalog.md +1 -1
  156. package/docs/observability.md +55 -8
  157. package/docs/proactive-memory.md +26 -16
  158. package/docs/prompt-envelope-and-tools.md +4 -2
  159. package/docs/provider-adapter-cookbook.md +1 -1
  160. package/docs/release-cut-checklist.md +83 -65
  161. package/docs/resource-library.md +59 -0
  162. package/docs/safety-model.md +29 -7
  163. package/docs/scientific-validation.md +3 -3
  164. package/docs/session-lifecycle.md +37 -1
  165. package/docs/skills-marketplace.md +16 -3
  166. package/docs/tool-usage.md +14 -7
  167. package/docs/trace-store.md +1 -1
  168. package/docs/troubleshooting.md +1 -1
  169. package/docs/tui-design.md +38 -4
  170. package/docs/worker-dispatch-mechanics.md +3 -3
  171. package/package.json +7 -4
  172. package/src/cli/agents.ts +2 -3
  173. package/src/cli/argv.ts +14 -1
  174. package/src/cli/fleet-commands.ts +37 -0
  175. package/src/cli/fleet-graph.ts +102 -0
  176. package/src/cli/fleet-new.ts +36 -0
  177. package/src/cli/fleet-preflight.ts +121 -0
  178. package/src/cli/fleet-validate.ts +30 -0
  179. package/src/cli/fleet.ts +188 -335
  180. package/src/cli/index.ts +4 -2
  181. package/src/cli/library.ts +190 -0
  182. package/src/cli/memory.ts +272 -10
  183. package/src/cli/modes/json-stream.ts +2 -2
  184. package/src/cli/modes/print.ts +12 -1
  185. package/src/cli/run.ts +22 -2
  186. package/src/cli/share.ts +13 -1
  187. package/src/cli/targets.ts +12 -3
  188. package/src/cli/usage.ts +160 -20
  189. package/src/core/bus-events.ts +7 -0
  190. package/src/core/commit-attribution.ts +4 -4
  191. package/src/core/config.ts +130 -0
  192. package/src/core/defaults.ts +81 -0
  193. package/src/core/response-model-id.ts +134 -0
  194. package/src/core/toml.ts +62 -0
  195. package/src/core/workspace-files.ts +0 -1
  196. package/src/domains/agents/builtins/architect.md +2 -1
  197. package/src/domains/agents/builtins/oracle.md +33 -0
  198. package/src/domains/agents/catalog.ts +18 -5
  199. package/src/domains/agents/fleet-contract.ts +278 -16
  200. package/src/domains/agents/index.ts +14 -0
  201. package/src/domains/agents/recipe.ts +54 -14
  202. package/src/domains/agents/result-contract.ts +242 -5
  203. package/src/domains/config/classify.ts +4 -0
  204. package/src/domains/context/bootstrap.ts +36 -27
  205. package/src/domains/context/project-metadata.ts +19 -63
  206. package/src/domains/context/prompt-context.ts +8 -0
  207. package/src/domains/context/working-set/policies/index.ts +3 -4
  208. package/src/domains/dispatch/active-route-planner.ts +14 -0
  209. package/src/domains/dispatch/backoff.ts +2 -1
  210. package/src/domains/dispatch/budget-envelope.ts +396 -0
  211. package/src/domains/dispatch/capability-match.ts +1 -0
  212. package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
  213. package/src/domains/dispatch/contract.ts +36 -0
  214. package/src/domains/dispatch/delegation-plan.ts +167 -0
  215. package/src/domains/dispatch/execution-plan.ts +76 -5
  216. package/src/domains/dispatch/execution-role.ts +3 -1
  217. package/src/domains/dispatch/execution-scheduler.ts +183 -67
  218. package/src/domains/dispatch/extension.ts +339 -36
  219. package/src/domains/dispatch/fleet-gate.ts +14 -0
  220. package/src/domains/dispatch/fleet-plan.ts +63 -3
  221. package/src/domains/dispatch/fleet-run.ts +737 -0
  222. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  223. package/src/domains/dispatch/host-verification.ts +178 -0
  224. package/src/domains/dispatch/index.ts +38 -0
  225. package/src/domains/dispatch/intent.ts +159 -0
  226. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  227. package/src/domains/dispatch/receipt-integrity.ts +12 -4
  228. package/src/domains/dispatch/state.ts +37 -3
  229. package/src/domains/dispatch/types.ts +61 -9
  230. package/src/domains/dispatch/validation.ts +80 -6
  231. package/src/domains/dispatch/worker-spawn.ts +14 -3
  232. package/src/domains/eval/metrics/evidence.ts +0 -116
  233. package/src/domains/eval/metrics/invariants.ts +1 -1
  234. package/src/domains/eval/runners/clio-run.ts +1 -10
  235. package/src/domains/eval/runners/external-command.ts +2 -29
  236. package/src/domains/eval/schema/suite.ts +0 -7
  237. package/src/domains/eval/suites/run.ts +1 -7
  238. package/src/domains/evidence/trust-status.ts +10 -1
  239. package/src/domains/memory/index.ts +22 -0
  240. package/src/domains/memory/operations.ts +58 -1
  241. package/src/domains/memory/promotion.ts +281 -0
  242. package/src/domains/memory/prompt-section.ts +25 -5
  243. package/src/domains/memory/proposal.ts +51 -7
  244. package/src/domains/memory/task-bank.ts +3 -2
  245. package/src/domains/memory/task-memory-handoff.ts +181 -24
  246. package/src/domains/memory/task-memory-policy.ts +3 -1
  247. package/src/domains/memory/types.ts +37 -0
  248. package/src/domains/memory/validate.ts +178 -0
  249. package/src/domains/middleware/index.ts +15 -0
  250. package/src/domains/middleware/memory-intervention.ts +35 -25
  251. package/src/domains/middleware/runtime.ts +6 -0
  252. package/src/domains/middleware/skills-reminder.ts +19 -4
  253. package/src/domains/middleware/stalled-turn.ts +43 -1
  254. package/src/domains/middleware/types.ts +10 -0
  255. package/src/domains/middleware/watchdog.ts +281 -0
  256. package/src/domains/observability/contract.ts +9 -2
  257. package/src/domains/observability/cost.ts +31 -4
  258. package/src/domains/observability/extension.ts +2 -2
  259. package/src/domains/observability/index.ts +10 -0
  260. package/src/domains/observability/out-of-turn-usage.ts +223 -0
  261. package/src/domains/providers/index.ts +3 -0
  262. package/src/domains/providers/model-discovery.ts +9 -0
  263. package/src/domains/providers/runtime-resolution.ts +38 -1
  264. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  265. package/src/domains/providers/types/context-window-slots.ts +18 -0
  266. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  267. package/src/domains/resources/index.ts +20 -0
  268. package/src/domains/resources/library.ts +326 -0
  269. package/src/domains/resources/skills/marketplace.ts +37 -12
  270. package/src/domains/safety/call-target.ts +211 -14
  271. package/src/domains/safety/decision-presentation.ts +268 -0
  272. package/src/domains/safety/redaction.ts +73 -0
  273. package/src/domains/session/context-ledger.ts +10 -1
  274. package/src/domains/session/decision-board.ts +4 -0
  275. package/src/domains/session/entries.ts +3 -0
  276. package/src/domains/session/handoff.ts +629 -0
  277. package/src/domains/session/history.ts +68 -19
  278. package/src/domains/session/usage.ts +24 -7
  279. package/src/domains/share/archive.ts +67 -2
  280. package/src/engine/acp/event-mapper.ts +7 -0
  281. package/src/engine/acp/server.ts +29 -2
  282. package/src/engine/apis/lmstudio.ts +25 -4
  283. package/src/engine/apis/openai-completions.ts +147 -22
  284. package/src/engine/claude/sdk-runtime.ts +8 -2
  285. package/src/engine/claude/tool-safety.ts +13 -0
  286. package/src/engine/loop-guard.ts +27 -3
  287. package/src/engine/worker-events.ts +4 -3
  288. package/src/engine/worker-runtime.ts +59 -54
  289. package/src/entry/orchestrator.ts +55 -1
  290. package/src/interactive/bus-notices.ts +26 -0
  291. package/src/interactive/chat-loop-messages.ts +22 -0
  292. package/src/interactive/chat-loop.ts +248 -1
  293. package/src/interactive/chat-renderer.ts +41 -3
  294. package/src/interactive/clio-editor.ts +44 -7
  295. package/src/interactive/context-overlay.ts +43 -5
  296. package/src/interactive/cost-overlay.ts +70 -11
  297. package/src/interactive/council-dispatch.ts +30 -0
  298. package/src/interactive/council-grid.ts +213 -0
  299. package/src/interactive/council.ts +99 -0
  300. package/src/interactive/dispatch-board.ts +471 -50
  301. package/src/interactive/fleet-run-preview.ts +307 -0
  302. package/src/interactive/footer/notifications.ts +219 -0
  303. package/src/interactive/footer/widgets.ts +13 -0
  304. package/src/interactive/handoff-round.ts +56 -0
  305. package/src/interactive/interactive-application.ts +49 -2
  306. package/src/interactive/interactive-event-projection.ts +9 -1
  307. package/src/interactive/interactive-input-runtime.ts +11 -1
  308. package/src/interactive/interactive-presentation.ts +11 -1
  309. package/src/interactive/interactive-slash-runtime.ts +52 -2
  310. package/src/interactive/interactive-subscriptions.ts +14 -2
  311. package/src/interactive/memory-overlay.ts +89 -4
  312. package/src/interactive/oracle.ts +179 -0
  313. package/src/interactive/overlay-ask-user-lifecycle.ts +7 -1
  314. package/src/interactive/overlay-frame.ts +5 -2
  315. package/src/interactive/overlay-general-openers.ts +230 -2
  316. package/src/interactive/overlay-key-routing.ts +58 -2
  317. package/src/interactive/overlay-lifecycle.ts +52 -5
  318. package/src/interactive/overlay-permission-lifecycle.ts +33 -8
  319. package/src/interactive/overlay-resource-openers.ts +11 -3
  320. package/src/interactive/overlay-session-lifecycle.ts +234 -2
  321. package/src/interactive/overlay-transitions.ts +11 -0
  322. package/src/interactive/overlays/ask-user.ts +74 -30
  323. package/src/interactive/overlays/decisions.ts +3 -1
  324. package/src/interactive/overlays/fleet-run-approval.ts +208 -0
  325. package/src/interactive/overlays/handoff-review.ts +185 -0
  326. package/src/interactive/overlays/library-install-confirm.ts +151 -0
  327. package/src/interactive/overlays/list-overlay.ts +168 -2
  328. package/src/interactive/overlays/settings.ts +101 -4
  329. package/src/interactive/overlays/side-question.ts +139 -0
  330. package/src/interactive/overlays/skills-hub.ts +401 -15
  331. package/src/interactive/permission-hint.ts +35 -0
  332. package/src/interactive/permission-overlay.ts +95 -45
  333. package/src/interactive/renderers/tool-execution.ts +19 -49
  334. package/src/interactive/session-last-turn.ts +8 -1
  335. package/src/interactive/session-usage-reseed.ts +36 -10
  336. package/src/interactive/side-question.ts +171 -0
  337. package/src/interactive/slash-commands.ts +434 -7
  338. package/src/interactive/slash-spec.ts +19 -6
  339. package/src/interactive/status/summary.ts +5 -0
  340. package/src/interactive/status/types.ts +5 -0
  341. package/src/interactive/terminal-lease.ts +1 -0
  342. package/src/interactive/theme/tokens.ts +30 -0
  343. package/src/interactive/turn-context.ts +96 -23
  344. package/src/interactive/turn-middleware.ts +16 -1
  345. package/src/interactive/turn-runtime.ts +37 -8
  346. package/src/interactive/turn-state.ts +3 -0
  347. package/src/interactive/watchdog-run.ts +75 -0
  348. package/src/interactive/worker-progress.ts +440 -0
  349. package/src/interactive/worker-share.ts +56 -1
  350. package/src/interactive/worker-stream.ts +58 -110
  351. package/src/tools/agent-tools.ts +28 -3
  352. package/src/tools/ask-user.ts +21 -1
  353. package/src/tools/bootstrap.ts +3 -0
  354. package/src/tools/compete-worktrees.ts +13 -79
  355. package/src/tools/context/index.ts +2 -2
  356. package/src/tools/dispatch-admission.ts +242 -8
  357. package/src/tools/dispatch-arguments.ts +65 -1
  358. package/src/tools/dispatch-event-text.ts +19 -0
  359. package/src/tools/dispatch-plan.ts +136 -6
  360. package/src/tools/dispatch-runner.ts +319 -13
  361. package/src/tools/dispatch-types.ts +20 -1
  362. package/src/tools/dispatch.ts +96 -3
  363. package/src/tools/monitor.ts +31 -0
  364. package/src/tools/profiles.ts +18 -4
  365. package/src/tools/registry.ts +15 -5
  366. package/src/tools/result-disposition.ts +156 -0
  367. package/src/tools/result-shaping.ts +59 -1
  368. package/src/tools/task-worktree.ts +238 -0
  369. package/src/tools/verify/authoring.ts +116 -55
  370. package/src/tools/verify/scripts.ts +62 -0
  371. package/src/tools/worker-evidence.ts +21 -1
  372. package/src/worker/spec-contract.ts +44 -3
  373. package/dist/chunk-EFADSJET.js +0 -18
  374. package/dist/chunk-HC4CLZ2Y.js +0 -68
  375. package/dist/memory-4ALKDJ4Q.js +0 -246
  376. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
package/src/cli/run.ts CHANGED
@@ -28,7 +28,7 @@ import { SafetyDomainModule } from "../domains/safety/index.js";
28
28
  import { SchedulingDomainModule } from "../domains/scheduling/index.js";
29
29
  import { SessionDomainModule } from "../domains/session/index.js";
30
30
  import type { ImageContent } from "../engine/types.js";
31
- import { assistantTextFromEvent } from "../tools/dispatch-event-text.js";
31
+ import { assistantTextFromEvent, receiptResponseModelIdObservationLabel } from "../tools/dispatch-event-text.js";
32
32
  import { isToolProfileName } from "../tools/profiles.js";
33
33
  import { parseRunCliArgs, type RunCliArgs } from "./args.js";
34
34
  import { runClioCommand } from "./clio.js";
@@ -393,8 +393,27 @@ async function runDispatch(
393
393
  let memorySection = "";
394
394
  try {
395
395
  const records = loadMemoryRecordsSync(clioDataDir());
396
+ const boundProfileName = parsed.agentProfile ?? effectiveSettings.workers.agentBindings[parsed.agentId];
397
+ const boundProfile = boundProfileName ? effectiveSettings.workers.profiles[boundProfileName] : undefined;
398
+ const configuredRuntime = (targetId: string | null | undefined): string | undefined =>
399
+ effectiveSettings.targets.find((target) => target.id === targetId)?.runtime;
400
+ const profileRuntimeId = configuredRuntime(boundProfile?.target);
401
+ // The memory section is compiled before fleet routing settles. Admit a
402
+ // runtime-scoped record only when every permitted initial and fallback
403
+ // route is constrained to the same runtime.
404
+ const memoryRuntimeId =
405
+ parsed.target !== undefined
406
+ ? configuredRuntime(parsed.target)
407
+ : boundProfileName !== undefined
408
+ ? parsed.agentRuntime === profileRuntimeId
409
+ ? profileRuntimeId
410
+ : undefined
411
+ : parsed.agentRuntime;
396
412
  memorySection = buildMemoryPromptSection(records, {
413
+ scopes: ["global", "repo", "runtime", "agent"],
397
414
  activeRepository: canonicalMemoryRepositoryIdentity(process.cwd()),
415
+ activeRuntime: memoryRuntimeId === undefined ? null : { kind: "runtime", key: memoryRuntimeId },
416
+ activeAgent: { kind: "agent", key: parsed.agentId },
398
417
  }).section;
399
418
  } catch (err) {
400
419
  process.stderr.write(
@@ -488,7 +507,8 @@ function formatReceipt(r: RunReceipt): string {
488
507
  const reasoning =
489
508
  typeof r.reasoningTokenCount === "number" && r.reasoningTokenCount > 0 ? ` reasoning=${r.reasoningTokenCount}` : "";
490
509
  const failure = r.failureMessage ? ` error=${r.failureMessage}` : "";
491
- return `receipt: ${r.runId} agent=${r.agentId} exit=${r.exitCode} target=${r.targetId} model=${r.wireModelId} tokens=${r.tokenCount}${reasoning}${failure} start=${r.startedAt} end=${r.endedAt}`;
510
+ const responseModelIdObservation = receiptResponseModelIdObservationLabel(r);
511
+ return `receipt: ${r.runId} agent=${r.agentId} exit=${r.exitCode} target=${r.targetId} requested_model_id=${r.wireModelId}${responseModelIdObservation ? ` ${responseModelIdObservation}` : ""} tokens=${r.tokenCount}${reasoning}${failure} start=${r.startedAt} end=${r.endedAt}`;
492
512
  }
493
513
 
494
514
  function mapExitCode(r: RunReceipt): number {
package/src/cli/share.ts CHANGED
@@ -15,7 +15,7 @@ const HELP = `clio-coder share <command>
15
15
  Export and import portable Clio project/resource archives.
16
16
 
17
17
  Commands:
18
- clio-coder share export --out <path> [--project|--user|--both] [--context] [--prompts] [--skills] [--settings] [--extensions]
18
+ clio-coder share export --out <path> [--project|--user|--both] [--context] [--prompts] [--skills] [--agents] [--fleets] [--settings] [--extensions]
19
19
  clio-coder share import <path> [--dry-run] [--force] [--project|--user] [--json]
20
20
  clio-coder share inspect <path> [--json]
21
21
 
@@ -36,6 +36,8 @@ interface Parsed {
36
36
  includeContext?: boolean;
37
37
  includePrompts?: boolean;
38
38
  includeSkills?: boolean;
39
+ includeAgents?: boolean;
40
+ includeFleets?: boolean;
39
41
  includeSettings?: boolean;
40
42
  includeExtensions?: boolean;
41
43
  }
@@ -93,6 +95,12 @@ function parse(argv: ReadonlyArray<string>): Parsed | null {
93
95
  case "--skills":
94
96
  out.includeSkills = true;
95
97
  break;
98
+ case "--agents":
99
+ out.includeAgents = true;
100
+ break;
101
+ case "--fleets":
102
+ out.includeFleets = true;
103
+ break;
96
104
  case "--settings":
97
105
  out.includeSettings = true;
98
106
  break;
@@ -103,6 +111,8 @@ function parse(argv: ReadonlyArray<string>): Parsed | null {
103
111
  out.includeContext = true;
104
112
  out.includePrompts = true;
105
113
  out.includeSkills = true;
114
+ out.includeAgents = true;
115
+ out.includeFleets = true;
106
116
  out.includeSettings = true;
107
117
  out.includeExtensions = true;
108
118
  break;
@@ -152,6 +162,8 @@ function exportOptions(parsed: Parsed): ShareExportOptions {
152
162
  ...(parsed.includeContext !== undefined ? { includeContext: parsed.includeContext } : {}),
153
163
  ...(parsed.includePrompts !== undefined ? { includePrompts: parsed.includePrompts } : {}),
154
164
  ...(parsed.includeSkills !== undefined ? { includeSkills: parsed.includeSkills } : {}),
165
+ ...(parsed.includeAgents !== undefined ? { includeAgents: parsed.includeAgents } : {}),
166
+ ...(parsed.includeFleets !== undefined ? { includeFleets: parsed.includeFleets } : {}),
155
167
  ...(parsed.includeSettings !== undefined ? { includeSettings: parsed.includeSettings } : {}),
156
168
  ...(parsed.includeExtensions !== undefined ? { includeExtensions: parsed.includeExtensions } : {}),
157
169
  };
@@ -1028,10 +1028,19 @@ export function residentModelsSummary(states: TargetStatus["discoveredModelState
1028
1028
  * capability the target reported. Saying so is the difference between a number
1029
1029
  * a user can plan against and one they cannot.
1030
1030
  */
1031
- export function formatContextWindow(status: Pick<TargetStatus, "capabilities" | "contextWindowProvenance">): string {
1031
+ export function formatContextWindow(
1032
+ status: Pick<TargetStatus, "capabilities" | "contextWindowProvenance"> &
1033
+ Partial<Pick<TargetStatus, "target" | "discoveredModelStates">>,
1034
+ ): string {
1032
1035
  const window = status.capabilities.contextWindow;
1033
- return status.contextWindowProvenance === "runtime-default"
1034
- ? `ctx ${window} (unverified runtime default)`
1036
+ if (status.contextWindowProvenance === "runtime-default") return `ctx ${window} (unverified runtime default)`;
1037
+ // A llama.cpp window that is one slot's share of `--ctx-size` names the
1038
+ // split, so `ctx 196608` is not mistaken for the whole server (issue #187).
1039
+ const slots = status.target?.defaultModel
1040
+ ? status.discoveredModelStates?.[status.target.defaultModel]?.contextSlots
1041
+ : undefined;
1042
+ return slots && Math.floor(slots.totalContextSize / slots.slots) === window
1043
+ ? `ctx ${window} (${slots.totalContextSize} / ${slots.slots} slots)`
1035
1044
  : `ctx ${window}`;
1036
1045
  }
1037
1046
 
package/src/cli/usage.ts CHANGED
@@ -1,8 +1,15 @@
1
1
  import { readdir, readFile, stat } from "node:fs/promises";
2
2
  import { join, resolve } from "node:path";
3
+ import {
4
+ addResponseModelIdObservationCount,
5
+ emptyResponseModelIdObservationCounts,
6
+ type ResponseModelIdObservationCounts,
7
+ responseModelIdObservationCountsLabel,
8
+ } from "../core/response-model-id.js";
3
9
  import { clioDataDir, clioStateDir } from "../core/xdg.js";
4
10
  import { loadMemoryRecordsSync, type MemoryRecord } from "../domains/memory/index.js";
5
11
  import { readEvidenceIndex } from "../domains/observability/evidence-index.js";
12
+ import { type OutOfTurnUsageRow, readOutOfTurnUsageRows } from "../domains/observability/out-of-turn-usage.js";
6
13
  import { loadSkills } from "../domains/resources/index.js";
7
14
  import {
8
15
  type LedgerUsageCall,
@@ -17,9 +24,10 @@ import { formatColumns, printError } from "./shared.js";
17
24
  const HELP = `clio-coder usage report [--repo <path>] [--days <n>] [--json]
18
25
 
19
26
  Cross-session usage analyzer (experimental, read-only). Reads the local usage
20
- archive (receipts, session ledgers, audit rows, evidence index, memory store)
21
- and reports facts plus improvement opportunities, every line citing ids and
22
- counts. Nothing is written or stored; suggestions are printed only.
27
+ archive (receipts, session ledgers, the out-of-turn usage store, audit rows,
28
+ evidence index, memory store) and reports facts plus improvement opportunities,
29
+ every line citing ids and counts. Nothing is written or stored; suggestions are
30
+ printed only.
23
31
 
24
32
  Flags:
25
33
  --repo <path> restrict sessions (and runs via the run ledger) to one repo
@@ -88,6 +96,58 @@ function emptyUsageTotals(): UsageTotals {
88
96
  };
89
97
  }
90
98
 
99
+ function addResponseModelIdObservation(counts: ResponseModelIdObservationCounts, call: LedgerUsageCall): void {
100
+ addResponseModelIdObservationCount(counts, call.responseModelIdObservation, call.apiCalls ?? 1);
101
+ }
102
+
103
+ /**
104
+ * How the folded calls split between the session's own turns and the rounds
105
+ * that were billed beside it. A `/btw` side question and a `/handoff` round are
106
+ * real spend and belong in the token and cost totals, but neither is a turn:
107
+ * they never entered the session. `turns` therefore subtracts them from the
108
+ * folded row count, which is exactly what the `/cost` overlay does.
109
+ */
110
+ interface CallOrigins {
111
+ rows: number;
112
+ sideQuestions: number;
113
+ handoffs: number;
114
+ }
115
+
116
+ function emptyCallOrigins(): CallOrigins {
117
+ return { rows: 0, sideQuestions: 0, handoffs: 0 };
118
+ }
119
+
120
+ function turnsOf(origins: CallOrigins): number {
121
+ return origins.rows - origins.sideQuestions - origins.handoffs;
122
+ }
123
+
124
+ function hasLabelledCall(origins: CallOrigins): boolean {
125
+ return origins.sideQuestions > 0 || origins.handoffs > 0;
126
+ }
127
+
128
+ function addOutOfTurnRow(origins: CallOrigins, row: OutOfTurnUsageRow): void {
129
+ origins.rows += 1;
130
+ if (row.label === "side-question") origins.sideQuestions += 1;
131
+ else origins.handoffs += 1;
132
+ }
133
+
134
+ /** The out-of-turn store keeps its own usage shape; fold it as one completed call. */
135
+ function outOfTurnUsageCall(row: OutOfTurnUsageRow): LedgerUsageCall {
136
+ return {
137
+ providerId: row.target,
138
+ attributedModelId: row.attributedModelId,
139
+ requestedModelId: row.attributedModelId,
140
+ responseModelIdObservation: { state: "not-observed" },
141
+ input: row.usage.input,
142
+ output: row.usage.output,
143
+ cacheRead: row.usage.cacheRead,
144
+ cacheWrite: row.usage.cacheWrite,
145
+ reasoningTokens: row.usage.reasoning,
146
+ totalTokens: row.usage.totalTokens,
147
+ costUsd: row.usage.costUsd,
148
+ };
149
+ }
150
+
91
151
  function addUsageCall(totals: UsageTotals, call: LedgerUsageCall): void {
92
152
  totals.apiCalls += call.apiCalls ?? 1;
93
153
  totals.input += call.input;
@@ -240,6 +300,13 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
240
300
  (receipt) => repoRunIds === null || repoRunIds.has(receipt.runId),
241
301
  );
242
302
  const sessions = await readSessions(stateDir, windowStart, now, repoHash, diagnostics);
303
+ // Side questions and handoff rounds append nothing to the session ledger by
304
+ // design, so their spend lives in its own store and is folded in here.
305
+ const outOfTurn = readOutOfTurnUsageRows(stateDir);
306
+ for (const error of outOfTurn.errors) diagnostics.notes.push(error);
307
+ const outOfTurnRows = outOfTurn.rows.filter(
308
+ (row) => inWindow(row.timestamp, windowStart, now) && (repoHash === undefined || row.repoIdentity === repoHash),
309
+ );
243
310
  const auditRows = await readAuditRows(stateDir);
244
311
  diagnostics.malformedAuditRows = auditRows.errors.length;
245
312
  const auditInWindow = auditRows.rows.filter((row) => row.ts !== null && inWindow(row.ts, windowStart, now));
@@ -321,21 +388,50 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
321
388
  // Token and cost facts fold the same per-call usage the `/cost` overlay
322
389
  // reseeds from, through the same session-domain function, so the report and
323
390
  // the overlay cannot disagree about what a session spent.
324
- const usageByModel = new Map<string, { providerId: string; modelId: string; totals: UsageTotals }>();
391
+ // Keyed by the model id accounting attributes the call to. A reported LM
392
+ // Link peer id gets its own row, while an observed omission becomes unknown.
393
+ // Requested ids and observation-state counts remain alongside that row.
394
+ const usageByModel = new Map<
395
+ string,
396
+ {
397
+ providerId: string;
398
+ attributedModelId: string;
399
+ requestedModelIds: Set<string>;
400
+ responseModelIdObservationCounts: ResponseModelIdObservationCounts;
401
+ totals: UsageTotals;
402
+ }
403
+ >();
325
404
  const usageTotals = emptyUsageTotals();
405
+ const callOrigins = emptyCallOrigins();
406
+ const foldCall = (call: LedgerUsageCall): void => {
407
+ addUsageCall(usageTotals, call);
408
+ const key = `${call.providerId}::${call.attributedModelId}`;
409
+ const entry = usageByModel.get(key) ?? {
410
+ providerId: call.providerId,
411
+ attributedModelId: call.attributedModelId,
412
+ requestedModelIds: new Set<string>(),
413
+ responseModelIdObservationCounts: emptyResponseModelIdObservationCounts(),
414
+ totals: emptyUsageTotals(),
415
+ };
416
+ entry.requestedModelIds.add(call.requestedModelId);
417
+ addResponseModelIdObservation(entry.responseModelIdObservationCounts, call);
418
+ addUsageCall(entry.totals, call);
419
+ usageByModel.set(key, entry);
420
+ };
326
421
  for (const session of sessions) {
327
422
  for (const call of session.usageCalls) {
328
- addUsageCall(usageTotals, call);
329
- const key = `${call.providerId}::${call.modelId}`;
330
- const entry = usageByModel.get(key) ?? {
331
- providerId: call.providerId,
332
- modelId: call.modelId,
333
- totals: emptyUsageTotals(),
334
- };
335
- addUsageCall(entry.totals, call);
336
- usageByModel.set(key, entry);
423
+ foldCall(call);
424
+ callOrigins.rows += 1;
337
425
  }
338
426
  }
427
+ for (const row of outOfTurnRows) {
428
+ foldCall(outOfTurnUsageCall(row));
429
+ addOutOfTurnRow(callOrigins, row);
430
+ }
431
+ // Token and cost facts need one of their two inputs on disk. A machine whose
432
+ // session store is gone can still have recorded out-of-turn spend, and
433
+ // dropping those rows would report money that was spent as nothing at all.
434
+ const usageMeasurable = presence.sessionsPresent || outOfTurnRows.length > 0;
339
435
  const usageRows = [...usageByModel.values()].sort(
340
436
  (a, b) => b.totals.totalTokens - a.totals.totalTokens || a.providerId.localeCompare(b.providerId),
341
437
  );
@@ -417,10 +513,32 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
417
513
  if (presence.receiptsPresent) emit({ kind: "fact", fact: "dispatch-runs", value: receipts.length });
418
514
  else emit({ kind: "fact", fact: "receipt-store-missing", path: presence.receiptsPath });
419
515
  emit({ kind: "fact", fact: "audit-tool-calls", value: auditToolCalls.length, blocked: auditBlocked.length });
420
- if (presence.sessionsPresent) {
421
- emit({ kind: "fact", fact: "tokens", ...usageTotals });
516
+ if (usageMeasurable) {
517
+ // The origin split is emitted only when something out of turn was
518
+ // recorded, so a report over an archive with no `/btw` or `/handoff`
519
+ // round in it stays byte-identical to what it printed before.
520
+ emit({
521
+ kind: "fact",
522
+ fact: "tokens",
523
+ ...usageTotals,
524
+ ...(hasLabelledCall(callOrigins)
525
+ ? {
526
+ turns: turnsOf(callOrigins),
527
+ sideQuestions: callOrigins.sideQuestions,
528
+ handoffs: callOrigins.handoffs,
529
+ }
530
+ : {}),
531
+ });
422
532
  for (const row of usageRows) {
423
- emit({ kind: "fact", fact: "model-usage", providerId: row.providerId, modelId: row.modelId, ...row.totals });
533
+ emit({
534
+ kind: "fact",
535
+ fact: "model-usage",
536
+ providerId: row.providerId,
537
+ attributedModelId: row.attributedModelId,
538
+ requestedModelIds: [...row.requestedModelIds].sort(),
539
+ responseModelIdObservationCounts: row.responseModelIdObservationCounts,
540
+ ...row.totals,
541
+ });
424
542
  }
425
543
  }
426
544
  for (const [tool, totals] of topTools) emit({ kind: "fact", fact: "top-tool", tool, ...totals });
@@ -471,22 +589,44 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
471
589
  out(` receipt store missing at ${presence.receiptsPath}`);
472
590
  }
473
591
  out(` audited tool calls in window: ${auditToolCalls.length} (${auditBlocked.length} blocked/denied)`);
474
- if (presence.sessionsPresent) {
592
+ if (usageMeasurable) {
475
593
  out(
476
594
  ` tokens in window: ${usageTotals.totalTokens} over ${usageTotals.apiCalls} model calls (input ${usageTotals.input}, output ${usageTotals.output}, cache read ${usageTotals.cacheRead}, cache write ${usageTotals.cacheWrite}, reasoning ${usageTotals.reasoningTokens})`,
477
595
  );
596
+ if (hasLabelledCall(callOrigins)) {
597
+ // Only printed when a labelled call is in the window. Over an archive
598
+ // with none, these three lines would say nothing the line above does
599
+ // not already say, and their absence keeps the older output intact.
600
+ out(` turns in window: ${turnsOf(callOrigins)}`);
601
+ if (callOrigins.sideQuestions > 0) out(` side questions in window: ${callOrigins.sideQuestions}`);
602
+ if (callOrigins.handoffs > 0) out(` handoffs in window: ${callOrigins.handoffs}`);
603
+ }
478
604
  out(` provider-reported cost in window: $${usageTotals.costUsd.toFixed(4)}`);
479
605
  }
480
606
  if (usageRows.length > 0) {
481
607
  out("");
482
- out(" tokens by model (from session ledgers, provider-reported)");
608
+ out(" tokens by attributed model (from session ledgers and provider-reported usage)");
483
609
  process.stdout.write(
484
610
  indent(
485
611
  formatColumns([
486
- ["provider", "model", "calls", "input", "output", "cache read", "reasoning", "tokens", "cost"],
612
+ [
613
+ "provider",
614
+ "attributed model",
615
+ "requested model ids",
616
+ "response model id observation",
617
+ "calls",
618
+ "input",
619
+ "output",
620
+ "cache read",
621
+ "reasoning",
622
+ "tokens",
623
+ "cost",
624
+ ],
487
625
  ...usageRows.map((row) => [
488
626
  row.providerId,
489
- row.modelId,
627
+ row.attributedModelId,
628
+ [...row.requestedModelIds].sort().join(","),
629
+ responseModelIdObservationCountsLabel(row.responseModelIdObservationCounts),
490
630
  String(row.totals.apiCalls),
491
631
  String(row.totals.input),
492
632
  String(row.totals.output),
@@ -14,6 +14,7 @@
14
14
 
15
15
  import type { AgentAudience } from "../domains/agents/spec.js";
16
16
  import type { ConfigDiff } from "../domains/config/classify.js";
17
+ import type { RunToolBudgetEnvelope } from "../domains/dispatch/budget-envelope.js";
17
18
  import type {
18
19
  DispatchRequestOrigin,
19
20
  RunKind,
@@ -480,10 +481,14 @@ export interface DispatchRunIdentity {
480
481
  wireModelId: string;
481
482
  runtimeId: string;
482
483
  runtimeKind: RunKind;
484
+ /** Admitted invocation budget provenance for native workers. */
485
+ budget?: RunToolBudgetEnvelope | undefined;
483
486
  /** Fleet node id the run was placed on; absent renders as the local node. */
484
487
  node?: string | undefined;
485
488
  /** Review/compete gate role and cycle, for fleet board badges. */
486
489
  gate?: { role: string; cycle: number } | undefined;
490
+ /** Council group presentation data for the Fleet Runs board. */
491
+ council?: { group: string; label: string; color?: string; round: number } | undefined;
487
492
  /** Dead-node failover hops recorded on this run's chain so far. */
488
493
  rerouteCount?: number | undefined;
489
494
  /** Model context window in tokens, for the per-worker context meter. */
@@ -569,6 +574,8 @@ export interface DispatchTerminalStats {
569
574
  exitCode: number;
570
575
  /** Honest activity record aggregated from the run's tool telemetry; null when the receipt predates it. */
571
576
  toolActivity: ToolActivitySummary | null;
577
+ /** Host-run declared verification status when the request included checks. */
578
+ hostVerification?: "verified" | "rejected" | "skipped";
572
579
  }
573
580
 
574
581
  /** Published on {@link BusChannels.DispatchCompleted} when a run finalizes as succeeded. */
@@ -16,7 +16,7 @@ export const CLIO_COMMIT_TRAILERS = {
16
16
  } as const;
17
17
 
18
18
  export interface CommitReceiptEvidence {
19
- version: 15;
19
+ version: 19;
20
20
  algorithm: "sha256";
21
21
  digest: string;
22
22
  /** The receipt was checked against its run-ledger envelope. */
@@ -58,7 +58,7 @@ const KNOWN_CLIO_TRAILERS = new Set(
58
58
  );
59
59
 
60
60
  function isClioTrailer(key: string): boolean {
61
- return KNOWN_CLIO_TRAILERS.has(key) || key.startsWith("clio-evidence:receipt-v15/sha256:");
61
+ return KNOWN_CLIO_TRAILERS.has(key) || key.startsWith("clio-evidence:receipt-v19/sha256:");
62
62
  }
63
63
 
64
64
  /**
@@ -87,7 +87,7 @@ function trailerBlockStart(lines: ReadonlyArray<string>): number | null {
87
87
 
88
88
  function receiptTrailer(receipt: CommitReceiptEvidence | undefined): string | null {
89
89
  if (
90
- receipt?.version !== 15 ||
90
+ receipt?.version !== 19 ||
91
91
  receipt.algorithm !== "sha256" ||
92
92
  receipt.integrityValid !== true ||
93
93
  receipt.directlyRelevant !== true ||
@@ -95,7 +95,7 @@ function receiptTrailer(receipt: CommitReceiptEvidence | undefined): string | nu
95
95
  ) {
96
96
  return null;
97
97
  }
98
- return `Clio-Evidence: receipt-v15/sha256:${receipt.digest}`;
98
+ return `Clio-Evidence: receipt-v19/sha256:${receipt.digest}`;
99
99
  }
100
100
 
101
101
  /**
@@ -19,7 +19,9 @@ import {
19
19
  ACTIVE_AGENT_AUTOMATION_ROLES,
20
20
  ACTIVE_ROUTING_POSTURES,
21
21
  ACTIVE_ROUTING_ROLES,
22
+ COUNCIL_MEMBER_LABEL_PATTERN,
22
23
  DEFAULT_SETTINGS,
24
+ THEME_NAMED_COLORS,
23
25
  THINKING_LEVELS,
24
26
  type ThinkingLevel,
25
27
  } from "./defaults.js";
@@ -915,6 +917,37 @@ function validateMemorySettings(issues: Issues, value: unknown): ClioSettings["m
915
917
  return out;
916
918
  }
917
919
 
920
+ /**
921
+ * The watchdog block. `target` and `cadenceToolCalls` stay absent rather than
922
+ * taking sentinel values: an absent target means the session's active target,
923
+ * and an absent cadence means the watchdog fires only at turn end. A written
924
+ * default for either would turn "not configured" into a configuration.
925
+ */
926
+ function validateWatchdogSettings(issues: Issues, value: unknown): ClioSettings["watchdog"] {
927
+ const out = cloneValue(DEFAULT_SETTINGS.watchdog);
928
+ if (!isPlainObject(value)) {
929
+ issues.add("watchdog", `expected a map, got ${describe(value)}`);
930
+ return out;
931
+ }
932
+ issues.unknownKeys("watchdog", value, ["enabled", "target", "cadenceToolCalls"]);
933
+ if ("enabled" in value) {
934
+ const enabled = expectBoolean(issues, "watchdog.enabled", value.enabled);
935
+ if (enabled !== undefined) out.enabled = enabled;
936
+ }
937
+ if ("target" in value && value.target !== null) {
938
+ const target = expectString(issues, "watchdog.target", value.target);
939
+ if (target !== undefined) {
940
+ if (target.trim().length === 0) issues.add("watchdog.target", "expected a non-empty target id");
941
+ else out.target = target.trim();
942
+ }
943
+ }
944
+ if ("cadenceToolCalls" in value && value.cadenceToolCalls !== null) {
945
+ const cadence = expectInteger(issues, "watchdog.cadenceToolCalls", value.cadenceToolCalls, { min: 1 });
946
+ if (cadence !== undefined) out.cadenceToolCalls = cadence;
947
+ }
948
+ return out;
949
+ }
950
+
918
951
  function validateKeybindings(issues: Issues, value: unknown): ClioSettings["keybindings"] {
919
952
  if (!isPlainObject(value)) {
920
953
  issues.add("keybindings", `expected a map, got ${describe(value)}`);
@@ -954,6 +987,7 @@ const TOP_LEVEL_KEYS = [
954
987
  "orchestrator",
955
988
  "background",
956
989
  "memory",
990
+ "watchdog",
957
991
  "workers",
958
992
  "fleet",
959
993
  "routing",
@@ -964,6 +998,7 @@ const TOP_LEVEL_KEYS = [
964
998
  "theme",
965
999
  "terminal",
966
1000
  "skills",
1001
+ "library",
967
1002
  "attribution",
968
1003
  "delegation",
969
1004
  "keybindings",
@@ -1030,6 +1065,25 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1030
1065
  const v = expectStringArray(issues, "runtimePlugins", raw.runtimePlugins);
1031
1066
  if (v !== undefined) settings.runtimePlugins = v;
1032
1067
  }
1068
+ if ("library" in raw) {
1069
+ if (!isPlainObject(raw.library)) {
1070
+ issues.add("library", `expected a map, got ${describe(raw.library)}`);
1071
+ } else {
1072
+ issues.unknownKeys("library", raw.library, ["catalog", "remote", "confirmedRemote", "sync"]);
1073
+ for (const key of ["catalog", "remote", "confirmedRemote"] as const) {
1074
+ const value = raw.library[key];
1075
+ if (value === undefined) continue;
1076
+ if (value !== null && typeof value !== "string")
1077
+ issues.add(`library.${key}`, `expected a string or null, got ${describe(value)}`);
1078
+ else settings.library[key] = value as string | null;
1079
+ }
1080
+ if (raw.library.sync !== undefined) {
1081
+ if (typeof raw.library.sync !== "boolean")
1082
+ issues.add("library.sync", `expected a boolean, got ${describe(raw.library.sync)}`);
1083
+ else settings.library.sync = raw.library.sync;
1084
+ }
1085
+ }
1086
+ }
1033
1087
 
1034
1088
  if ("orchestrator" in raw) {
1035
1089
  settings.orchestrator = validateWorkerTarget(
@@ -1050,6 +1104,7 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1050
1104
  );
1051
1105
  }
1052
1106
  if ("memory" in raw) settings.memory = validateMemorySettings(issues, raw.memory);
1107
+ if ("watchdog" in raw) settings.watchdog = validateWatchdogSettings(issues, raw.watchdog);
1053
1108
 
1054
1109
  // Fleet nodes validate before workers so profile node pins can be checked
1055
1110
  // against the configured node ids.
@@ -1146,6 +1201,7 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1146
1201
  issues.unknownKeys("workers", raw.workers, [
1147
1202
  "default",
1148
1203
  "profiles",
1204
+ "rosters",
1149
1205
  "agentBindings",
1150
1206
  "maxRetries",
1151
1207
  "onPermission",
@@ -1187,6 +1243,75 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1187
1243
  settings.workers.profiles = profiles;
1188
1244
  }
1189
1245
  }
1246
+ if ("rosters" in raw.workers) {
1247
+ if (!isPlainObject(raw.workers.rosters)) {
1248
+ issues.add("workers.rosters", `expected a map, got ${describe(raw.workers.rosters)}`);
1249
+ } else {
1250
+ const rosters: ClioSettings["workers"]["rosters"] = {};
1251
+ for (const [rawName, rawRoster] of Object.entries(raw.workers.rosters)) {
1252
+ const name = rawName.trim();
1253
+ const path = `workers.rosters.${name}`;
1254
+ if (!name) {
1255
+ issues.add("workers.rosters", "empty roster name");
1256
+ continue;
1257
+ }
1258
+ if (!isPlainObject(rawRoster)) {
1259
+ issues.add(path, `expected a map, got ${describe(rawRoster)}`);
1260
+ continue;
1261
+ }
1262
+ issues.unknownKeys(path, rawRoster, ["members"]);
1263
+ if (!Array.isArray(rawRoster.members)) {
1264
+ issues.add(`${path}.members`, "expected a list");
1265
+ continue;
1266
+ }
1267
+ if (rawRoster.members.length < 2 || rawRoster.members.length > 5) {
1268
+ issues.add(`${path}.members`, "expected 2 to 5 members");
1269
+ }
1270
+ const members: ClioSettings["workers"]["rosters"][string]["members"] = [];
1271
+ const labels = new Set<string>();
1272
+ for (const [index, rawMember] of rawRoster.members.entries()) {
1273
+ const memberPath = `${path}.members[${index}]`;
1274
+ if (!isPlainObject(rawMember)) {
1275
+ issues.add(memberPath, `expected a map, got ${describe(rawMember)}`);
1276
+ continue;
1277
+ }
1278
+ issues.unknownKeys(memberPath, rawMember, ["label", "target", "model", "thinking", "color"]);
1279
+ const label = expectString(issues, `${memberPath}.label`, rawMember.label);
1280
+ const target = expectString(issues, `${memberPath}.target`, rawMember.target);
1281
+ if (label !== undefined && !COUNCIL_MEMBER_LABEL_PATTERN.test(label)) {
1282
+ issues.add(`${memberPath}.label`, "expected [a-z][a-z0-9_-]{0,31}");
1283
+ }
1284
+ if (label !== undefined && labels.has(label)) issues.add(`${memberPath}.label`, "duplicate label");
1285
+ if (label !== undefined) labels.add(label);
1286
+ if (target !== undefined && !settings.targets.some((entry) => entry.id === target)) {
1287
+ issues.add(`${memberPath}.target`, `unknown target '${target}'`);
1288
+ }
1289
+ const model =
1290
+ rawMember.model === undefined ? undefined : expectString(issues, `${memberPath}.model`, rawMember.model);
1291
+ const thinking =
1292
+ rawMember.thinking === undefined
1293
+ ? undefined
1294
+ : expectEnum(issues, `${memberPath}.thinking`, rawMember.thinking, THINKING_LEVELS);
1295
+ const color =
1296
+ rawMember.color === undefined ? undefined : expectString(issues, `${memberPath}.color`, rawMember.color);
1297
+ if (color !== undefined && !THEME_NAMED_COLORS.includes(color as never) && !/^#[0-9a-fA-F]{6}$/u.test(color)) {
1298
+ issues.add(`${memberPath}.color`, "expected a theme named color or 6-digit hex color");
1299
+ }
1300
+ if (label === undefined || target === undefined) continue;
1301
+ members.push({
1302
+ label,
1303
+ target,
1304
+ ...(model ? { model } : {}),
1305
+ ...(thinking ? { thinking } : {}),
1306
+ ...(color ? { color } : {}),
1307
+ });
1308
+ }
1309
+ if (rawRoster.members.length >= 2 && rawRoster.members.length <= 5 && members.length === rawRoster.members.length)
1310
+ rosters[name] = { members };
1311
+ }
1312
+ settings.workers.rosters = rosters;
1313
+ }
1314
+ }
1190
1315
  if ("agentBindings" in raw.workers) {
1191
1316
  if (!isPlainObject(raw.workers.agentBindings)) {
1192
1317
  issues.add("workers.agentBindings", `expected a map, got ${describe(raw.workers.agentBindings)}`);
@@ -1318,6 +1443,7 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1318
1443
  "tuiMode",
1319
1444
  "fullscreenScrollbar",
1320
1445
  "smoothStreaming",
1446
+ "notify",
1321
1447
  ]);
1322
1448
  if ("showTerminalProgress" in raw.terminal) {
1323
1449
  const v = expectBoolean(issues, "terminal.showTerminalProgress", raw.terminal.showTerminalProgress);
@@ -1343,6 +1469,10 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1343
1469
  if (v === "off" || v === "auto" || v === "on") settings.terminal.smoothStreaming = v;
1344
1470
  else if (v !== undefined) issues.add("terminal.smoothStreaming", "expected off, auto, or on");
1345
1471
  }
1472
+ if ("notify" in raw.terminal) {
1473
+ const v = expectBoolean(issues, "terminal.notify", raw.terminal.notify);
1474
+ if (v !== undefined) settings.terminal.notify = v;
1475
+ }
1346
1476
  }
1347
1477
  }
1348
1478