@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
@@ -119,3 +119,33 @@ export function createClioTheme(options: { truecolor?: boolean; color?: boolean
119
119
  fgSequence: (token) => (color ? `\u001b[${fgCode(TOKENS[token], truecolor)}m` : ""),
120
120
  };
121
121
  }
122
+
123
+ /** True when `value` names one of the theme's own tokens, so it can be painted as one. */
124
+ export function isClioToken(value: string): value is ClioToken {
125
+ return Object.hasOwn(TOKENS, value);
126
+ }
127
+
128
+ const HEX_COLOR = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/u;
129
+
130
+ /**
131
+ * Paint text in a configured `#rrggbb` color.
132
+ *
133
+ * A council roster member may carry one. A roster color is the operator's own
134
+ * choice rather than a token from the palette, which is why a literal color
135
+ * reaches the screen here and nowhere else. Returns the text unchanged when
136
+ * color is disabled or the value is not a six-digit hex color, so a caller can
137
+ * fall back to a token without inspecting the string twice. A terminal without
138
+ * truecolor gets the nearest color in the 6x6x6 xterm cube.
139
+ */
140
+ export function paintHex(text: string, hex: string, options: { truecolor?: boolean; color?: boolean } = {}): string {
141
+ const match = HEX_COLOR.exec(hex);
142
+ if (match === null) return text;
143
+ if (!(options.color ?? !colorDisabled())) return text;
144
+ const truecolor = options.truecolor ?? detectTruecolor();
145
+ const red = Number.parseInt(match[1] ?? "0", 16);
146
+ const green = Number.parseInt(match[2] ?? "0", 16);
147
+ const blue = Number.parseInt(match[3] ?? "0", 16);
148
+ if (truecolor) return `\u001b[38;2;${red};${green};${blue}m${text}${SGR_RESET}`;
149
+ const cube = (channel: number): number => Math.round((channel / 255) * 5);
150
+ return `\u001b[38;5;${16 + 36 * cube(red) + 6 * cube(green) + cube(blue)}m${text}${SGR_RESET}`;
151
+ }
@@ -23,7 +23,12 @@ import { selectVisibleEntries } from "../domains/context/working-set/visible.js"
23
23
  import type { ObservabilityContract } from "../domains/observability/contract.js";
24
24
  import type { CompiledSessionPrompt, SessionPromptInputs } from "../domains/prompts/compiler.js";
25
25
  import type { PromptsContract } from "../domains/prompts/contract.js";
26
- import type { ProvidersContract } from "../domains/providers/index.js";
26
+ import {
27
+ type ContextWindowDetails,
28
+ type ContextWindowSource,
29
+ type ProvidersContract,
30
+ resolveRuntimeTarget,
31
+ } from "../domains/providers/index.js";
27
32
  import type { LocalModelQuirks } from "../domains/providers/types/local-model-quirks.js";
28
33
  import {
29
34
  AutoCompactionTrigger,
@@ -309,6 +314,75 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
309
314
  return ceilChars(snapshot.pendingUserInput.length);
310
315
  };
311
316
 
317
+ /**
318
+ * The window the next turn will resolve to, read the way ensureRuntime
319
+ * reads it but without building an agent. Before the first turn of a
320
+ * process, /resume included, state.runtime is null, and the ledger and the
321
+ * footer meter said `context window unknown · 0 tokens` until a turn ran
322
+ * (issue #189). Null when no target is configured or it does not resolve,
323
+ * and the overlay's "unknown" is then true.
324
+ */
325
+ const resolveWindowWithoutRuntime = (): ContextWindowDetails | null => {
326
+ const settings = deps.getSettings();
327
+ const targetId = settings.orchestrator?.target?.trim();
328
+ const wireModelId = settings.orchestrator?.model?.trim();
329
+ if (!targetId || !wireModelId) return null;
330
+ const resolved = resolveRuntimeTarget(deps.providers, {
331
+ targetId,
332
+ wireModelId,
333
+ requestedThinkingLevel: settings.orchestrator?.thinkingLevel ?? "off",
334
+ use: "orchestrator",
335
+ requireTools: false,
336
+ requireOutputBudget: true,
337
+ });
338
+ return resolved.ok ? resolved.target.contextWindowDetails : null;
339
+ };
340
+
341
+ const CONTEXT_WINDOW_SOURCES: ReadonlySet<string> = new Set<ContextWindowSource>([
342
+ "catalog",
343
+ "probe",
344
+ "loaded",
345
+ "target-override",
346
+ "model-hint",
347
+ "descriptor-default",
348
+ "unknown",
349
+ ]);
350
+
351
+ /** The snapshot stores its source as a plain string; only a known label is worth repeating. */
352
+ const snapshotWindowSource = (snapshot: ContextSnapshot): ContextWindowSource | null =>
353
+ CONTEXT_WINDOW_SOURCES.has(snapshot.contextWindowSource)
354
+ ? (snapshot.contextWindowSource as ContextWindowSource)
355
+ : null;
356
+
357
+ /**
358
+ * Window facts while no runtime exists: the live resolution first, then the
359
+ * resumed snapshot's recorded window, which is what the previous process
360
+ * measured the same messages against.
361
+ */
362
+ const windowWithoutRuntime = (): {
363
+ contextWindow: number;
364
+ contextWindowSource: ContextWindowSource | null;
365
+ contextWindowSlots: ContextWindowDetails["contextWindowSlots"];
366
+ } => {
367
+ const details = resolveWindowWithoutRuntime();
368
+ if (details) {
369
+ return {
370
+ contextWindow: details.effectiveContextWindow,
371
+ contextWindowSource: details.contextWindowSource,
372
+ contextWindowSlots: details.contextWindowSlots,
373
+ };
374
+ }
375
+ const snapshot = currentContextSnapshot;
376
+ if (snapshot && snapshot.effectiveContextWindow > 0) {
377
+ return {
378
+ contextWindow: snapshot.effectiveContextWindow,
379
+ contextWindowSource: snapshotWindowSource(snapshot),
380
+ contextWindowSlots: null,
381
+ };
382
+ }
383
+ return { contextWindow: 0, contextWindowSource: null, contextWindowSlots: null };
384
+ };
385
+
312
386
  const liveContextEstimate = (agentRuntime: AgentRuntime, pendingUserText?: string): LiveContextEstimate => {
313
387
  const contextWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
314
388
  const estimateInput = {
@@ -846,8 +920,9 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
846
920
  },
847
921
 
848
922
  contextUsage(): ContextUsageSnapshot {
849
- if (!state.runtime) return contextUsageSnapshot(null, 0);
850
- const effectiveWindow = state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
923
+ const effectiveWindow = state.runtime
924
+ ? state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow
925
+ : windowWithoutRuntime().contextWindow;
851
926
  if (!currentContextSnapshot) {
852
927
  return contextUsageSnapshot(null, effectiveWindow);
853
928
  }
@@ -867,28 +942,27 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
867
942
  const settings = deps.getSettings();
868
943
  const compactionThreshold = settings.compaction?.threshold ?? null;
869
944
  const compactionAuto = settings.compaction?.auto !== false;
870
- if (!state.runtime) {
871
- return buildContextLedger({
872
- provider: settings.orchestrator?.target ?? null,
873
- model: settings.orchestrator?.model ?? null,
874
- contextWindow: 0,
875
- compactionThreshold,
876
- compactionAuto,
877
- });
878
- }
879
- const windowDetails = state.runtime.runtimeResolution.contextWindowDetails;
880
- const effectiveWindow = windowDetails.effectiveContextWindow;
881
-
882
- const provider = state.runtime.targetId ?? settings.orchestrator?.target ?? null;
883
- const model = state.runtime.wireModelId ?? settings.orchestrator?.model ?? null;
945
+ // Without a runtime (before the first turn of this process, /resume
946
+ // included) the window comes from the live resolution or the resumed
947
+ // snapshot, and the token facts from the snapshot: the resumed
948
+ // messages are the ones it measured.
949
+ const window = state.runtime
950
+ ? {
951
+ contextWindow: state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow,
952
+ contextWindowSource: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSource,
953
+ contextWindowSlots: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSlots,
954
+ }
955
+ : windowWithoutRuntime();
956
+ const provider = state.runtime?.targetId ?? settings.orchestrator?.target ?? null;
957
+ const model = state.runtime?.wireModelId ?? settings.orchestrator?.model ?? null;
958
+ const liveToolCount = state.runtime?.agent.state.tools.length ?? 0;
884
959
 
885
960
  if (!currentContextSnapshot) {
886
961
  return buildContextLedger({
887
962
  provider,
888
963
  model,
889
- contextWindow: effectiveWindow,
890
- contextWindowSource: windowDetails.contextWindowSource,
891
- toolCount: state.runtime.agent.state.tools.length,
964
+ ...window,
965
+ toolCount: liveToolCount,
892
966
  compactionThreshold,
893
967
  compactionAuto,
894
968
  promptCache: lastPromptCache,
@@ -903,15 +977,14 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
903
977
  return buildContextLedger({
904
978
  provider,
905
979
  model,
906
- contextWindow: effectiveWindow,
907
- contextWindowSource: windowDetails.contextWindowSource,
980
+ ...window,
908
981
  compactionThreshold,
909
982
  compactionAuto,
910
983
  systemPromptTokens: currentContextSnapshot.categories.system,
911
984
  toolSchemaTokens: currentContextSnapshot.categories.tools,
912
985
  // Persisted snapshots strip the captured schemas; fall back to
913
986
  // the live agent state after a session resume.
914
- toolCount: currentContextSnapshot.activeToolSchemas?.length ?? state.runtime.agent.state.tools.length,
987
+ toolCount: currentContextSnapshot.activeToolSchemas?.length ?? liveToolCount,
915
988
  messageTokens: currentContextSnapshot.categories.messages,
916
989
  agentsTokens: currentContextSnapshot.categories.agents,
917
990
  skillsTokens: currentContextSnapshot.categories.skills,
@@ -25,7 +25,7 @@ export interface TurnMiddlewareDeps {
25
25
  middleware?: MiddlewareContract | undefined;
26
26
  session?: SessionContract | undefined;
27
27
  middlewareToolChoice: MiddlewareToolChoiceControl;
28
- emitNotice: (text: string) => void;
28
+ emitNotice: (text: string, level?: "info" | "warning" | "error") => void;
29
29
  emitFooterNotice: (level: "info" | "success" | "warning" | "error", text: string, key: string) => void;
30
30
  }
31
31
 
@@ -55,6 +55,14 @@ export interface TurnMiddleware {
55
55
  * turn_end reminder takes.
56
56
  */
57
57
  injectDeferredReminder(message: string, severity?: MiddlewareReminderSeverity): void;
58
+ /**
59
+ * Deliver an operator-facing finding produced after its turn boundary closed.
60
+ * The watchdog seam: its run settles well after the turn it reviewed, and
61
+ * what it found is for the person, not the model. Unlike a deferred
62
+ * reminder, this never joins the pending-reminder buffer and never appends a
63
+ * `middlewareReminder` entry, so nothing it says can enter the next request.
64
+ */
65
+ emitDeferredNotice(text: string, level?: "info" | "warning"): void;
58
66
  }
59
67
 
60
68
  export function createTurnMiddleware(deps: TurnMiddlewareDeps): TurnMiddleware {
@@ -205,6 +213,7 @@ export function createTurnMiddleware(deps: TurnMiddlewareDeps): TurnMiddleware {
205
213
  runtimeTier: agentRuntime.runtimeResolution.runtimeTier ?? "",
206
214
  activeToolNames: toolNamesFromAgentState(agentRuntime.agent.state.tools).join(","),
207
215
  turnToolCalls: state.turnToolCalls,
216
+ turnToolNames: state.turnToolNames.join(","),
208
217
  sharedWorkerNote: state.turnSharedWorkerNote,
209
218
  };
210
219
  if (terminalToolResult !== undefined) {
@@ -279,5 +288,11 @@ export function createTurnMiddleware(deps: TurnMiddlewareDeps): TurnMiddleware {
279
288
  appendMiddlewareReminderEntry(text, level);
280
289
  deps.emitNotice(text);
281
290
  },
291
+
292
+ emitDeferredNotice(text, level = "warning"): void {
293
+ const message = text.trim();
294
+ if (message.length === 0) return;
295
+ deps.emitNotice(message, level);
296
+ },
282
297
  };
283
298
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { performance } from "node:perf_hooks";
9
9
  import type { ClioSettings } from "../core/config.js";
10
+ import { attributedModelId } from "../core/response-model-id.js";
10
11
  import type { MiddlewareToolChoiceControl } from "../domains/middleware/index.js";
11
12
  import type { ObservabilityContract } from "../domains/observability/contract.js";
12
13
  import {
@@ -15,7 +16,7 @@ import {
15
16
  type ProvidersContract,
16
17
  refineRuntimeTargetWithModelHints,
17
18
  resolveRuntimeTarget,
18
- runtimeResolutionWarnings,
19
+ runtimeResolutionWarningsBesideThinkingNotice,
19
20
  type TargetStatus,
20
21
  targetRequiresAuth,
21
22
  } from "../domains/providers/index.js";
@@ -199,7 +200,12 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
199
200
  failure?.code ?? "admission-failed",
200
201
  );
201
202
  }
202
- for (const message of runtimeResolutionWarnings(resolved.diagnostics)) {
203
+ // emitThinkingClampNotice prints the one combined thinking line when the
204
+ // dial takes effect; the thinking diagnostics are its two halves.
205
+ for (const message of runtimeResolutionWarningsBesideThinkingNotice(
206
+ resolved.diagnostics,
207
+ resolved.target.modelRuntime.thinking.notice,
208
+ )) {
203
209
  const key = `${targetId}|${wireModelId}|${message}`;
204
210
  if (announcedResolutionWarnings.has(key)) continue;
205
211
  announcedResolutionWarnings.add(key);
@@ -229,6 +235,7 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
229
235
  */
230
236
  const TARGET_PROBE_TTL_MS = 5 * 60 * 1000;
231
237
  let lastTargetProbe: { key: string; at: number } | null = null;
238
+ const targetProbesInFlight = new Map<string, Promise<void>>();
232
239
  const ensureLiveCapabilitiesForSelectedModel = async (): Promise<void> => {
233
240
  const settings = deps.getSettings();
234
241
  const targetId = settings.orchestrator.target?.trim();
@@ -239,16 +246,29 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
239
246
  const runtimeDesc = deps.providers.getRuntime(target.runtime);
240
247
  if (!runtimeDesc || runtimeDesc.tier === "cloud") return;
241
248
  const key = `${targetId}|${wireModelId}`;
249
+ const inFlight = targetProbesInFlight.get(key);
250
+ if (inFlight) {
251
+ await inFlight;
252
+ return;
253
+ }
242
254
  const now = Date.now();
243
255
  if (lastTargetProbe?.key === key && now - lastTargetProbe.at < TARGET_PROBE_TTL_MS) return;
244
256
  lastTargetProbe = { key, at: now };
245
- let status: Awaited<ReturnType<ProvidersContract["probeTarget"]>> = null;
257
+ const probe = (async (): Promise<void> => {
258
+ let status: Awaited<ReturnType<ProvidersContract["probeTarget"]>> = null;
259
+ try {
260
+ status = await deps.providers.probeTarget(targetId);
261
+ } catch {
262
+ // Fall back to the last known target state.
263
+ }
264
+ announceColdModel(status, targetId, wireModelId);
265
+ })();
266
+ targetProbesInFlight.set(key, probe);
246
267
  try {
247
- status = await deps.providers.probeTarget(targetId);
248
- } catch {
249
- // Fall back to the last known target state.
268
+ await probe;
269
+ } finally {
270
+ if (targetProbesInFlight.get(key) === probe) targetProbesInFlight.delete(key);
250
271
  }
251
- announceColdModel(status, targetId, wireModelId);
252
272
  };
253
273
 
254
274
  /** One notice per target+model+state, so a repeated probe stays quiet. */
@@ -589,6 +609,7 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
589
609
  middlewareToolChoice.toolStarted(event.toolName);
590
610
  deps.toolStartTimes.set(event.toolCallId, eventClock);
591
611
  state.turnToolCalls += 1;
612
+ state.turnToolNames.push(event.toolName);
592
613
  } else if (event.type === "tool_execution_end") {
593
614
  toolsInFlight = Math.max(0, toolsInFlight - 1);
594
615
  const startedAt = deps.toolStartTimes.get(event.toolCallId);
@@ -713,7 +734,11 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
713
734
  if (summary.hadUsage && (summary.tokens > 0 || summary.costUsd > 0)) {
714
735
  deps.observability.recordTokens(
715
736
  localRuntime.targetId,
716
- localRuntime.wireModelId,
737
+ attributedModelId(
738
+ summary.lastResponseModelIdObservation,
739
+ localRuntime.wireModelId,
740
+ summary.lastDifferingResponseModelId,
741
+ ),
717
742
  summary.tokens,
718
743
  summary.costUsd,
719
744
  {
@@ -726,6 +751,10 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
726
751
  apiCalls: summary.apiCalls,
727
752
  },
728
753
  localRuntime.runtimeResolution.costProvenance,
754
+ {
755
+ requestedModelIds: [localRuntime.wireModelId],
756
+ responseModelIdObservationCounts: summary.responseModelIdObservationCounts,
757
+ },
729
758
  );
730
759
  }
731
760
  if (summary.output > 0 && firstAssistantDeltaAt !== null) {
@@ -97,6 +97,8 @@ export interface ChatTurnState {
97
97
  toolProseAssessedChars: number;
98
98
  /** Tool calls observed in the current turn; feeds turn_end metadata. */
99
99
  turnToolCalls: number;
100
+ /** Names of those calls, in order, so turn_end can tell a listing-only turn from a working one. */
101
+ turnToolNames: string[];
100
102
  /** A `[worker result]` note the operator shared entered this turn, as the prompt or as a steer; feeds turn_end metadata. */
101
103
  turnSharedWorkerNote: boolean;
102
104
  /** One stalled-turn nudge per user prompt; reset when a real prompt arrives. */
@@ -123,6 +125,7 @@ export function createTurnState(initialThinkingLevel: ThinkingLevel): ChatTurnSt
123
125
  streamStallReason: null,
124
126
  toolProseAssessedChars: 0,
125
127
  turnToolCalls: 0,
128
+ turnToolNames: [],
126
129
  turnSharedWorkerNote: false,
127
130
  stalledTurnNudgeSpent: false,
128
131
  pendingRequestContinuation: false,
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The watchdog's run: one read-only verifier dispatch, one transcript notice.
3
+ *
4
+ * The middleware registration decides when to fire and what the turn changed;
5
+ * this decides nothing. It dispatches through the ordinary path so admission,
6
+ * the receipt, and the Fleet Runs island treat a watchdog run exactly as they
7
+ * treat any other, reads the failed checks out of the `verifier-report`
8
+ * contract, and hands the operator one line. A passing report produces nothing
9
+ * at all.
10
+ */
11
+
12
+ import { BusChannels } from "../core/bus-events.js";
13
+ import type { SafeEventBus } from "../core/event-bus.js";
14
+ import { parseVerifierResult } from "../domains/agents/index.js";
15
+ import type { DispatchContract, DispatchRequest } from "../domains/dispatch/contract.js";
16
+ import { type AgentRoleFactsResolver, requestExecutionRole } from "../domains/dispatch/execution-role.js";
17
+ import { WATCHDOG_TASK, type WatchdogTrigger, watchdogBriefing } from "../domains/middleware/index.js";
18
+ import { watchdogBlockersNotice } from "./bus-notices.js";
19
+
20
+ /** The builtin recipe the watchdog reviews with. */
21
+ export const WATCHDOG_AGENT_ID = "verifier";
22
+
23
+ export interface WatchdogRunDeps {
24
+ dispatch: DispatchContract;
25
+ bus?: SafeEventBus;
26
+ getAgentRoleFacts?: AgentRoleFactsResolver;
27
+ /** `watchdog.target` when the operator set one; the session's active target otherwise. */
28
+ target?: string | undefined;
29
+ /** One transcript line for the operator. Absent means the finding has nowhere to go and the run is skipped. */
30
+ emitNotice?: (text: string) => void;
31
+ }
32
+
33
+ /**
34
+ * Dispatch one watchdog review and report what it found.
35
+ *
36
+ * Resolves when the run has settled, whatever the outcome. A watchdog that
37
+ * failed is not a turn that failed: the review is advisory, so a broken run
38
+ * stays silent rather than raising an alarm about itself in the middle of the
39
+ * operator's work.
40
+ */
41
+ export async function runWatchdogReview(trigger: WatchdogTrigger, deps: WatchdogRunDeps): Promise<void> {
42
+ if (!deps.emitNotice) return;
43
+ const request: DispatchRequest = {
44
+ agentId: WATCHDOG_AGENT_ID,
45
+ task: WATCHDOG_TASK,
46
+ briefing: watchdogBriefing(trigger),
47
+ executionRole: requestExecutionRole({
48
+ agentId: WATCHDOG_AGENT_ID,
49
+ ...(deps.getAgentRoleFacts ? { resolveFacts: deps.getAgentRoleFacts } : {}),
50
+ }),
51
+ requestOrigin: "internal",
52
+ // Narrowed below whatever the session holds. A reviewer that could write
53
+ // would be a second builder nobody admitted.
54
+ autonomy: "read-only",
55
+ ...(deps.target ? { target: deps.target } : {}),
56
+ };
57
+ const progressBus = deps.dispatch.ownsProgressBus?.(deps.bus) === true ? undefined : deps.bus;
58
+ try {
59
+ const handle = await deps.dispatch.dispatch(request);
60
+ for await (const event of handle.events) {
61
+ const typed = event as { type?: string };
62
+ if (!typed.type || typed.type === "heartbeat") continue;
63
+ progressBus?.emit(BusChannels.DispatchProgress, { runId: handle.runId, agentId: WATCHDOG_AGENT_ID, event });
64
+ }
65
+ const receipt = await handle.finalPromise;
66
+ const report = parseVerifierResult(receipt.output?.text ?? null);
67
+ if (report === null) return;
68
+ const notice = watchdogBlockersNotice(report.checks);
69
+ if (notice === null) return;
70
+ deps.emitNotice(notice.text);
71
+ } catch {
72
+ // An advisory review that could not run says nothing. The receipt, if one
73
+ // was written at all, is in the dispatch board like every other run.
74
+ }
75
+ }