@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
@@ -6,12 +6,15 @@
6
6
  * are pure data: no class methods, no engine refs.
7
7
  */
8
8
 
9
+ import type { ResponseModelIdObservation } from "../../core/response-model-id.js";
9
10
  import type { SkillActivation } from "../../core/skill-activation.js";
10
11
  import type { ToolProfileName } from "../../tools/profiles.js";
11
12
  import type { AgentAudience } from "../agents/spec.js";
12
13
  import type { EvidenceTag } from "../evidence/index.js";
13
14
  import type { CostProvenance, RuntimeTargetSnapshot } from "../providers/index.js";
15
+ import type { RunToolBudgetEnvelope } from "./budget-envelope.js";
14
16
  import type { ExecutionRole, GateTopologyRole } from "./execution-role.js";
17
+ import type { DispatchIntent } from "./intent.js";
15
18
  import type { RouteDecisionV1 } from "./route-decision.js";
16
19
  import type { RoutingIntent } from "./routing-intent.js";
17
20
 
@@ -39,7 +42,8 @@ export type RunOutcomeCode =
39
42
  | "worker_tool_call_cap_exhausted"
40
43
  | "loop_guard_tools_disabled_exhausted"
41
44
  | "result_contract_exhausted"
42
- | "worker_final_output_missing";
45
+ | "worker_final_output_missing"
46
+ | "host_verification_rejected";
43
47
 
44
48
  export function isRunOutcomeCode(value: unknown): value is RunOutcomeCode {
45
49
  return (
@@ -47,7 +51,8 @@ export function isRunOutcomeCode(value: unknown): value is RunOutcomeCode {
47
51
  value === "worker_tool_call_cap_exhausted" ||
48
52
  value === "loop_guard_tools_disabled_exhausted" ||
49
53
  value === "result_contract_exhausted" ||
50
- value === "worker_final_output_missing"
54
+ value === "worker_final_output_missing" ||
55
+ value === "host_verification_rejected"
51
56
  );
52
57
  }
53
58
 
@@ -236,6 +241,13 @@ export interface RunGateProvenance {
236
241
  verdict?: "pass" | "fail" | "revise";
237
242
  }
238
243
 
244
+ export interface RunCouncilProvenance {
245
+ group: string;
246
+ label: string;
247
+ color?: string;
248
+ round: number;
249
+ }
250
+
239
251
  /**
240
252
  * Plan-approval provenance for multi-task, compete, or remote dispatch.
241
253
  * `approval: "operator"` records that a supervised autonomy level parked the
@@ -246,7 +258,7 @@ export interface RunGateProvenance {
246
258
  */
247
259
  export interface RunPlanProvenance {
248
260
  hash: string;
249
- topology: "parallel" | "sequential" | "pipeline" | "review" | "compete" | "detached" | "fleet";
261
+ topology: "parallel" | "sequential" | "pipeline" | "review" | "compete" | "council" | "detached" | "fleet";
250
262
  taskCount: number;
251
263
  approval: "operator" | "full-auto";
252
264
  source: null | {
@@ -309,7 +321,7 @@ export interface RunPhaseDurations {
309
321
  * bumping one without the other is a compile error.
310
322
  */
311
323
  export interface RunReceiptIntegrity {
312
- version: 15;
324
+ version: 19;
313
325
  algorithm: "sha256";
314
326
  digest: string;
315
327
  }
@@ -418,6 +430,8 @@ export interface RunEnvelope {
418
430
  agentAudience?: AgentAudience;
419
431
  requestOrigin?: DispatchRequestOrigin;
420
432
  task: string;
433
+ /** Immutable recipe policy, invocation request, effective phase, and admission reasons. */
434
+ budget?: RunToolBudgetEnvelope;
421
435
  /** Present only when a bounded parent briefing was sent as dynamic task data. */
422
436
  briefing?: RunBriefingProvenance;
423
437
  /** Sent steering provenance in stable per-run sequence order; prose is never persisted. */
@@ -445,6 +459,7 @@ export interface RunEnvelope {
445
459
  pipeline?: RunPipelineProvenance;
446
460
  /** Review/compete gate provenance; present only on runs of a gated dispatch. */
447
461
  gate?: RunGateProvenance;
462
+ council?: RunCouncilProvenance;
448
463
  /** Plan-approval provenance; present only on runs of an approval-gated plan. */
449
464
  plan?: RunPlanProvenance;
450
465
  /** Ad-hoc specialist provenance; present only when a persona override composed the stable prompt. */
@@ -615,9 +630,10 @@ export interface RunReceiptReproducibility {
615
630
  }
616
631
 
617
632
  export interface RunReceiptUpstreamResponse {
618
- model: string | null;
619
- responseModel: string | null;
620
- responseId: string | null;
633
+ requestedModelId: string | null;
634
+ responseModelIdObservation: ResponseModelIdObservation;
635
+ differingResponseModelId: string | null;
636
+ providerResponseId: string | null;
621
637
  }
622
638
 
623
639
  /**
@@ -669,6 +685,25 @@ export interface RunReceiptVerification {
669
685
  | "receipt-unavailable";
670
686
  }
671
687
 
688
+ export interface RunHostVerificationCheck {
689
+ check: string;
690
+ argv: string[];
691
+ cwd: string;
692
+ exitCode: number;
693
+ durationMs: number;
694
+ memo: boolean;
695
+ outputTail: string;
696
+ artifactPath?: string;
697
+ /** Original evidence owner on a memo hit. */
698
+ evidenceRunId?: string;
699
+ }
700
+
701
+ export interface RunHostVerification {
702
+ status: "verified" | "rejected" | "skipped";
703
+ reason?: string;
704
+ checks: RunHostVerificationCheck[];
705
+ }
706
+
672
707
  export interface RunReceipt {
673
708
  runId: string;
674
709
  agentId: string;
@@ -677,6 +712,10 @@ export interface RunReceipt {
677
712
  agentAudience?: AgentAudience;
678
713
  requestOrigin?: DispatchRequestOrigin;
679
714
  task: string;
715
+ /** Normalized dispatch intent admitted before worker execution. */
716
+ intent?: DispatchIntent;
717
+ /** Integrity-sealed recipe policy, invocation request, effective phase, and admission reasons. */
718
+ budget?: RunToolBudgetEnvelope;
680
719
  /** Proof of briefing content without copying its prose into the receipt. */
681
720
  briefing?: RunBriefingProvenance;
682
721
  /** Sent steering provenance in stable per-run sequence order; prose is never persisted. */
@@ -707,8 +746,11 @@ export interface RunReceipt {
707
746
  pipeline?: RunPipelineProvenance;
708
747
  /** Review/compete gate provenance; present only on runs of a gated dispatch. */
709
748
  gate?: RunGateProvenance;
749
+ council?: RunCouncilProvenance;
710
750
  /** Plan-approval provenance; present only on runs of an approval-gated plan. */
711
751
  plan?: RunPlanProvenance;
752
+ /** Version 5 fleet gate artifact authored by this run. */
753
+ fleetGate?: { path: string; pathHash: string };
712
754
  /** Ad-hoc specialist provenance; present only when a persona override composed the stable prompt. */
713
755
  personaOverride?: RunPersonaOverride;
714
756
  /** Effective project-context tier for this run; absent on receipts written before this field landed. */
@@ -757,6 +799,17 @@ export interface RunReceipt {
757
799
  toolActivity?: ToolActivitySummary;
758
800
  /** Integrity-sealed evidence confidence. Sealed on every receipt. */
759
801
  verification: RunReceiptVerification;
802
+ /** Orchestrator-executed declared checks. Worker self-report never populates this field. */
803
+ hostVerification?: RunHostVerification;
804
+ /** Isolated writer checkout and its collect-time application result. */
805
+ worktree?: {
806
+ path: string;
807
+ branch: string;
808
+ diffHash: string;
809
+ apply: "merge" | "preserve";
810
+ applied: boolean;
811
+ reason?: string;
812
+ };
760
813
  /** Required normalized routing request, sealed without task or prompt data. */
761
814
  routingIntent: RoutingIntent;
762
815
  /** Required routing-quality facts known at receipt finalization. */
@@ -779,8 +832,7 @@ export interface RunReceipt {
779
832
  * What this run contributed to its dispatch's agent ledger. Optional and
780
833
  * absent unless the run had a ledger, following validationGrounding and
781
834
  * capabilityMismatch: receiptDigestFields skips undefined, so a receipt
782
- * without one digests exactly as it did before this landed and
783
- * RUN_RECEIPT_INTEGRITY_VERSION stays where it is.
835
+ * without one omits the field from canonical serialization.
784
836
  */
785
837
  ledgerContribution?: RunLedgerContribution;
786
838
  /**
@@ -11,6 +11,7 @@ import { cloneValidatedResponseSchema } from "../../core/response-schema.js";
11
11
  import { isToolProfileName, type ToolProfileName } from "../../tools/profiles.js";
12
12
  import type { AgentProduct } from "../agents/spec.js";
13
13
  import { type AutonomyLevel, isAutonomyLevel } from "../safety/autonomy.js";
14
+ import { cloneDispatchBudgetRequest, type DispatchBudgetRequest } from "./budget-envelope.js";
14
15
  import {
15
16
  EXECUTION_HANDOFF_MAX_ITEMS,
16
17
  EXECUTION_HANDOFF_MAX_TEXT_BYTES,
@@ -18,6 +19,7 @@ import {
18
19
  } from "./execution-handoff.js";
19
20
  import { isExecutionRole } from "./execution-role.js";
20
21
  import { COMPETE_STANCES, type CompeteStance } from "./gate-role-prompts.js";
22
+ import { type DispatchIntent, isDispatchIntent } from "./intent.js";
21
23
  import { isRoutingIntent, type RoutingIntent } from "./routing-intent.js";
22
24
  import type {
23
25
  DispatchRequestOrigin,
@@ -76,6 +78,8 @@ export interface JobSpec {
76
78
  target?: string;
77
79
  model?: string;
78
80
  thinkingLevel?: JobThinkingLevel;
81
+ /** Invocation phase and optional preauthorized retry or revision ceiling. */
82
+ budget?: DispatchBudgetRequest;
79
83
  /**
80
84
  * What this run delivers, which decides what its reserve window admits.
81
85
  * "orientation" adds `code_nav` to the delivery tools kept live inside the
@@ -118,6 +122,10 @@ export interface JobSpec {
118
122
  */
119
123
  denyTools?: ReadonlyArray<string>;
120
124
  cwd?: string;
125
+ /** Run this writer in an isolated git worktree. */
126
+ worktree?: true;
127
+ /** How a successful isolated writer is applied to its parent checkout. */
128
+ apply?: "merge" | "preserve";
121
129
  memorySection?: string;
122
130
  noSkills?: boolean;
123
131
  skillPaths?: ReadonlyArray<string>;
@@ -131,6 +139,8 @@ export interface JobSpec {
131
139
  * per-tool calls (subprocess).
132
140
  */
133
141
  writeRoots?: ReadonlyArray<string>;
142
+ /** Normalized model-declared path, output, and host verification intent. */
143
+ intent?: DispatchIntent;
134
144
  requestOrigin?: DispatchRequestOrigin;
135
145
  /**
136
146
  * Threaded output from the previous pipeline step. Set only by the dispatch
@@ -156,6 +166,8 @@ export interface JobSpec {
156
166
  autonomy?: AutonomyLevel;
157
167
  /** Review/compete gate provenance sealed into the run's receipt. */
158
168
  gate?: RunGateProvenance;
169
+ /** Council grouping projected to receipts and fleet surfaces. */
170
+ council?: { group: string; label: string; color?: string; round: number };
159
171
  /** Plan-approval provenance sealed into the run's receipt. */
160
172
  plan?: RunPlanProvenance;
161
173
  /**
@@ -180,6 +192,7 @@ const KNOWN_KEYS = new Set([
180
192
  "target",
181
193
  "model",
182
194
  "thinkingLevel",
195
+ "budget",
183
196
  "node",
184
197
  "routingIntent",
185
198
  "failover",
@@ -191,18 +204,22 @@ const KNOWN_KEYS = new Set([
191
204
  "toolProfile",
192
205
  "denyTools",
193
206
  "cwd",
207
+ "worktree",
208
+ "apply",
194
209
  "memorySection",
195
210
  "noSkills",
196
211
  "skillPaths",
197
212
  "trustProjectCompatRoots",
198
213
  "responseSchema",
199
214
  "writeRoots",
215
+ "intent",
200
216
  "requestOrigin",
201
217
  "pipelineInput",
202
218
  "predecessorHandoffs",
203
219
  "lineage",
204
220
  "autonomy",
205
221
  "gate",
222
+ "council",
206
223
  "plan",
207
224
  "competeStance",
208
225
  ]);
@@ -378,6 +395,15 @@ export function validateJobSpec(spec: unknown): Validated {
378
395
  }
379
396
  }
380
397
 
398
+ let budget: DispatchBudgetRequest | undefined;
399
+ if ("budget" in spec && spec.budget !== undefined) {
400
+ try {
401
+ budget = cloneDispatchBudgetRequest(spec.budget);
402
+ } catch (error) {
403
+ errors.push(error instanceof Error ? error.message : String(error));
404
+ }
405
+ }
406
+
381
407
  if ("requiredCapabilities" in spec && spec.requiredCapabilities !== undefined) {
382
408
  if (!Array.isArray(spec.requiredCapabilities) || spec.requiredCapabilities.some((c) => typeof c !== "string")) {
383
409
  errors.push("requiredCapabilities must be a string[]");
@@ -386,7 +412,7 @@ export function validateJobSpec(spec: unknown): Validated {
386
412
 
387
413
  if ("toolProfile" in spec && spec.toolProfile !== undefined) {
388
414
  if (typeof spec.toolProfile !== "string" || !isToolProfileName(spec.toolProfile)) {
389
- errors.push("toolProfile must be one of: minimal-local|science-local|full-agent");
415
+ errors.push("toolProfile must be one of: minimal-local|science-local|full-agent|council-read-only");
390
416
  }
391
417
  }
392
418
 
@@ -401,6 +427,13 @@ export function validateJobSpec(spec: unknown): Validated {
401
427
  errors.push("cwd must be a non-empty string");
402
428
  }
403
429
  }
430
+ if ("worktree" in spec && spec.worktree !== undefined && spec.worktree !== true) {
431
+ errors.push("worktree must be true when present");
432
+ }
433
+ if ("apply" in spec && spec.apply !== undefined && spec.apply !== "merge" && spec.apply !== "preserve") {
434
+ errors.push("apply must be merge or preserve");
435
+ }
436
+ if (spec.apply !== undefined && spec.worktree !== true) errors.push("apply requires worktree: true");
404
437
 
405
438
  if ("memorySection" in spec && spec.memorySection !== undefined) {
406
439
  if (typeof spec.memorySection !== "string") {
@@ -444,6 +477,15 @@ export function validateJobSpec(spec: unknown): Validated {
444
477
  errors.push("writeRoots must be a non-empty array of non-empty strings");
445
478
  }
446
479
  }
480
+ if ("intent" in spec && spec.intent !== undefined && !isDispatchIntent(spec.intent)) {
481
+ errors.push("intent must be a normalized dispatch intent");
482
+ }
483
+ if (isDispatchIntent(spec.intent) && spec.intent.writeRoots.length > 0 && Array.isArray(spec.writeRoots)) {
484
+ const jobCwd = typeof spec.cwd === "string" && spec.cwd.length > 0 ? spec.cwd : process.cwd();
485
+ const legacy = [...new Set(spec.writeRoots.map((root) => path.resolve(jobCwd, String(root))))].sort();
486
+ const declared = [...new Set(spec.intent.writeRoots.map((root) => path.resolve(jobCwd, root)))].sort();
487
+ if (JSON.stringify(legacy) !== JSON.stringify(declared)) errors.push("intent_write_roots_contradiction");
488
+ }
447
489
 
448
490
  if ("requestOrigin" in spec && spec.requestOrigin !== undefined) {
449
491
  if (typeof spec.requestOrigin !== "string" || !VALID_REQUEST_ORIGINS.has(spec.requestOrigin)) {
@@ -530,24 +572,32 @@ export function validateJobSpec(spec: unknown): Validated {
530
572
  out.reroutes = spec.reroutes.map((hop) => ({ ...hop }));
531
573
  }
532
574
  if (typeof spec.thinkingLevel === "string") out.thinkingLevel = spec.thinkingLevel as JobThinkingLevel;
575
+ if (budget !== undefined) out.budget = budget;
533
576
  if (Array.isArray(spec.requiredCapabilities)) {
534
577
  out.requiredCapabilities = spec.requiredCapabilities.map((c) => String(c));
535
578
  }
536
579
  if (typeof spec.toolProfile === "string" && isToolProfileName(spec.toolProfile)) out.toolProfile = spec.toolProfile;
537
580
  if (Array.isArray(spec.denyTools)) out.denyTools = spec.denyTools.map((tool) => String(tool));
538
581
  if (typeof spec.cwd === "string") out.cwd = spec.cwd;
582
+ if (spec.worktree === true) out.worktree = true;
583
+ if (spec.apply === "merge" || spec.apply === "preserve") out.apply = spec.apply;
539
584
  if (typeof spec.memorySection === "string") out.memorySection = spec.memorySection;
540
585
  if (typeof spec.noSkills === "boolean") out.noSkills = spec.noSkills;
541
586
  if (Array.isArray(spec.skillPaths)) out.skillPaths = spec.skillPaths.map((p) => String(p));
542
587
  if (typeof spec.trustProjectCompatRoots === "boolean") out.trustProjectCompatRoots = spec.trustProjectCompatRoots;
543
588
  if (responseSchema) out.responseSchema = responseSchema;
544
- if (
589
+ if (isDispatchIntent(spec.intent)) out.intent = structuredClone(spec.intent);
590
+ const effectiveWriteRoots =
545
591
  Array.isArray(spec.writeRoots) &&
546
592
  spec.writeRoots.length > 0 &&
547
593
  spec.writeRoots.every((root) => typeof root === "string" && root.length > 0)
548
- ) {
594
+ ? spec.writeRoots
595
+ : isDispatchIntent(spec.intent) && spec.intent.writeRoots.length > 0
596
+ ? spec.intent.writeRoots
597
+ : undefined;
598
+ if (effectiveWriteRoots !== undefined) {
549
599
  const jobCwd = typeof spec.cwd === "string" && spec.cwd.length > 0 ? spec.cwd : process.cwd();
550
- out.writeRoots = spec.writeRoots.map((root) => path.resolve(jobCwd, String(root)));
600
+ out.writeRoots = effectiveWriteRoots.map((root) => path.resolve(jobCwd, String(root)));
551
601
  }
552
602
  if (typeof spec.requestOrigin === "string" && VALID_REQUEST_ORIGINS.has(spec.requestOrigin)) {
553
603
  out.requestOrigin = spec.requestOrigin as DispatchRequestOrigin;
@@ -558,6 +608,7 @@ export function validateJobSpec(spec: unknown): Validated {
558
608
  if (isValidLineage(spec.lineage)) out.lineage = spec.lineage;
559
609
  if (isAutonomyLevel(spec.autonomy)) out.autonomy = spec.autonomy;
560
610
  if (isValidGate(spec.gate)) out.gate = cloneGate(spec.gate);
611
+ if (isValidCouncil(spec.council)) out.council = { ...spec.council };
561
612
  if (typeof spec.competeStance === "string" && VALID_COMPETE_STANCES.has(spec.competeStance)) {
562
613
  out.competeStance = spec.competeStance as CompeteStance;
563
614
  }
@@ -640,9 +691,18 @@ function isValidProtectedArtifactRemap(value: unknown): value is ProtectedArtifa
640
691
  );
641
692
  }
642
693
 
643
- const VALID_GATE_ROLES = new Set(["builder", "reviewer", "candidate", "judge"]);
694
+ const VALID_GATE_ROLES = new Set(["builder", "reviewer", "candidate", "judge", "member", "synthesis"]);
644
695
  const VALID_GATE_VERDICTS = new Set(["pass", "fail", "revise"]);
645
- const VALID_PLAN_TOPOLOGIES = new Set(["parallel", "sequential", "pipeline", "review", "compete", "detached", "fleet"]);
696
+ const VALID_PLAN_TOPOLOGIES = new Set([
697
+ "parallel",
698
+ "sequential",
699
+ "pipeline",
700
+ "review",
701
+ "compete",
702
+ "council",
703
+ "detached",
704
+ "fleet",
705
+ ]);
646
706
  const VALID_PLAN_APPROVALS = new Set(["operator", "full-auto"]);
647
707
 
648
708
  function isValidGate(value: unknown): value is RunGateProvenance {
@@ -674,6 +734,20 @@ function cloneGate(gate: RunGateProvenance): RunGateProvenance {
674
734
  };
675
735
  }
676
736
 
737
+ function isValidCouncil(value: unknown): value is NonNullable<JobSpec["council"]> {
738
+ return (
739
+ isPlainObject(value) &&
740
+ typeof value.group === "string" &&
741
+ value.group.length > 0 &&
742
+ typeof value.label === "string" &&
743
+ value.label.length > 0 &&
744
+ (value.color === undefined || typeof value.color === "string") &&
745
+ typeof value.round === "number" &&
746
+ Number.isInteger(value.round) &&
747
+ value.round >= 1
748
+ );
749
+ }
750
+
677
751
  function isValidPlan(value: unknown): value is RunPlanProvenance {
678
752
  if (!isPlainObject(value)) return false;
679
753
  if (typeof value.hash !== "string" || value.hash.length === 0) return false;
@@ -133,6 +133,16 @@ export interface WorkerProcessOptions {
133
133
  approvedIdentity?: ApprovedWorkerIdentity;
134
134
  /** How long bulk output may precede the announce before the peer is refused. */
135
135
  attestationGraceMs?: number;
136
+ /**
137
+ * Clock behind the heartbeat stamp, defaulting to `Date.now`. The stamp stays
138
+ * a wall-clock instant in production because the ledger, the receipt, and the
139
+ * evidence record all serialize it as ISO-8601 for an operator to read. That
140
+ * leaves a test with no honest way to assert the stamp advanced: comparing
141
+ * two wall-clock reads taken either side of an interval orders them backward
142
+ * on any host that resyncs its clock in between. A test injects the steppable
143
+ * clock from tests/harness/clock.ts here and asserts on that instead.
144
+ */
145
+ now?: () => number;
136
146
  }
137
147
 
138
148
  /**
@@ -181,6 +191,7 @@ export function spawnWorkerProcess(
181
191
  ): SpawnedWorker {
182
192
  const shutdownGraceMs = opts?.shutdownGraceMs ?? DEFAULT_SHUTDOWN_GRACE_MS;
183
193
  const attestationGraceMs = opts?.attestationGraceMs ?? DEFAULT_ATTESTATION_GRACE_MS;
194
+ const now = opts?.now ?? Date.now;
184
195
  const approved = opts?.approvedIdentity ?? approvedIdentityForSpec(spec);
185
196
 
186
197
  const child: ChildProcess = spawn(command, [...args], {
@@ -193,7 +204,7 @@ export function spawnWorkerProcess(
193
204
  });
194
205
  const pid = child.pid ?? null;
195
206
 
196
- const heartbeatAt = { current: Date.now() };
207
+ const heartbeatAt = { current: now() };
197
208
 
198
209
  const queue = createBoundedEventQueue();
199
210
  const waiters: Array<(r: IteratorResult<unknown>) => void> = [];
@@ -222,7 +233,7 @@ export function spawnWorkerProcess(
222
233
  }
223
234
 
224
235
  function push(value: unknown): void {
225
- heartbeatAt.current = Date.now();
236
+ heartbeatAt.current = now();
226
237
  const w = waiters.shift();
227
238
  if (w) {
228
239
  w({ value, done: false });
@@ -367,7 +378,7 @@ export function spawnWorkerProcess(
367
378
  if (!announceAccepted) failAttestation(`Invalid worker attestation: ${frame.reason}`);
368
379
  return;
369
380
  }
370
- heartbeatAt.current = Date.now();
381
+ heartbeatAt.current = now();
371
382
  if (frame.value.kind === "announce") {
372
383
  if (announceAccepted || announceFailed) return;
373
384
  const verdict = verifyWorkerAttestation(frame.value.attestation, approved);
@@ -64,119 +64,3 @@ export function evidenceMetricsFromReceipt(receipt: RunReceipt): Record<string,
64
64
  ...(typeof receipt.costUsd === "number" && Number.isFinite(receipt.costUsd) ? { "cost.usd": receipt.costUsd } : {}),
65
65
  };
66
66
  }
67
-
68
- /**
69
- * Count terminal dispatch tool calls in a `clio-coder run --json` stream: the
70
- * decomposition checkpoint. Mirrors the dedup rules of the tool-call metric
71
- * fold (canonical clio finishes win over pi execution ends when both exist).
72
- * An absent or eventless stream counts zero.
73
- */
74
- export function dispatchCountFromJsonl(stdout: string): number {
75
- let executionEnds = 0;
76
- let canonicalFinishes = 0;
77
- const seenExecutionEnds = new Set<string>();
78
- const seenCanonicalFinishes = new Set<string>();
79
- let sawCanonicalFinishEvent = false;
80
- for (const event of jsonlEvents(stdout)) {
81
- if (event.type === "tool_execution_end") {
82
- if (stringField(event, "toolName") !== "dispatch") continue;
83
- const callId = stringField(event, "toolCallId");
84
- if (callId !== undefined) {
85
- if (seenExecutionEnds.has(callId)) continue;
86
- seenExecutionEnds.add(callId);
87
- }
88
- executionEnds += 1;
89
- continue;
90
- }
91
- if (event.type !== "clio_tool_finish" || !isRecord(event.payload)) continue;
92
- sawCanonicalFinishEvent = true;
93
- if (stringField(event.payload, "tool") !== "dispatch") continue;
94
- const callId = stringField(event.payload, "toolCallId") ?? stringField(event, "toolCallId");
95
- if (callId !== undefined) {
96
- if (seenCanonicalFinishes.has(callId)) continue;
97
- seenCanonicalFinishes.add(callId);
98
- }
99
- canonicalFinishes += 1;
100
- }
101
- return sawCanonicalFinishEvent ? canonicalFinishes : executionEnds;
102
- }
103
-
104
- /** Count model-authored dispatch calls whose normalized task set includes Scout. */
105
- export function scoutDispatchCountFromJsonl(stdout: string): number {
106
- const seen = new Set<string>();
107
- let count = 0;
108
- for (const event of jsonlEvents(stdout)) {
109
- if (event.type !== "tool_execution_start" || stringField(event, "toolName") !== "dispatch") continue;
110
- if (!isRecord(event.args) || !dispatchArgsIncludeAgent(event.args, "scout")) continue;
111
- const callId = stringField(event, "toolCallId");
112
- if (callId !== undefined) {
113
- if (seen.has(callId)) continue;
114
- seen.add(callId);
115
- }
116
- count += 1;
117
- }
118
- return count;
119
- }
120
-
121
- function dispatchArgsIncludeAgent(args: Record<string, unknown>, expectedAgent: string): boolean {
122
- const sharedAgent = stringField(args, "agent") ?? stringField(args, "agent_id") ?? stringField(args, "agentId");
123
- let tasks: unknown = args.tasks;
124
- if (typeof tasks === "string") {
125
- const trimmed = tasks.trim();
126
- if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
127
- try {
128
- tasks = JSON.parse(trimmed) as unknown;
129
- } catch {
130
- // A plain task string keeps using the shared agent below.
131
- }
132
- }
133
- }
134
- const taskList: unknown[] = Array.isArray(tasks) ? tasks : tasks === undefined ? [{ task: args.task }] : [tasks];
135
- return taskList.some((task: unknown) => {
136
- if (typeof task === "string") return sharedAgent?.toLowerCase() === expectedAgent;
137
- if (!isRecord(task)) return false;
138
- const agent =
139
- stringField(task, "agent") ?? stringField(task, "agent_id") ?? stringField(task, "agentId") ?? sharedAgent;
140
- return agent?.toLowerCase() === expectedAgent;
141
- });
142
- }
143
-
144
- /**
145
- * Stale-wiki behavioral checkpoint: true when the stream shows a live source
146
- * read (read/grep start) AFTER a `code_nav mode=wiki` start, i.e. the model
147
- * did not answer from the wiki alone. Absent either half → false.
148
- */
149
- export function wikiStaleAcknowledgedFromJsonl(stdout: string): boolean {
150
- let sawWikiLookup = false;
151
- for (const event of jsonlEvents(stdout)) {
152
- if (event.type !== "tool_execution_start") continue;
153
- const toolName = stringField(event, "toolName");
154
- if (toolName === "code_nav" && isRecord(event.args) && event.args.mode === "wiki") {
155
- sawWikiLookup = true;
156
- continue;
157
- }
158
- if (sawWikiLookup && (toolName === "read" || toolName === "grep")) return true;
159
- }
160
- return false;
161
- }
162
-
163
- function* jsonlEvents(stdout: string): Generator<Record<string, unknown>> {
164
- for (const line of stdout.split(/\r?\n/)) {
165
- if (line.trim().length === 0) continue;
166
- try {
167
- const parsed: unknown = JSON.parse(line);
168
- if (isRecord(parsed)) yield parsed;
169
- } catch {
170
- // Non-JSON noise (including the pretty receipt tail) is not an event.
171
- }
172
- }
173
- }
174
-
175
- function stringField(record: Record<string, unknown>, field: string): string | undefined {
176
- const value = record[field];
177
- return typeof value === "string" && value.length > 0 ? value : undefined;
178
- }
179
-
180
- function isRecord(value: unknown): value is Record<string, unknown> {
181
- return typeof value === "object" && value !== null && !Array.isArray(value);
182
- }
@@ -2,7 +2,7 @@
2
2
  * Invariant metrics: the promises Clio makes about its own machinery, read
3
3
  * from the journal one eval item left behind.
4
4
  *
5
- * These invert what a benchmark measures. A weak model that never solved the
5
+ * These invert what a task outcome measures. A weak model that never solved the
6
6
  * task leaves every one of them intact; a strong model that solved it leaves
7
7
  * them broken the moment Clio failed to seal, to agree with itself, or to
8
8
  * write a receipt its own ledger can authenticate. The task outcome and the
@@ -1,11 +1,5 @@
1
1
  import { shellQuote } from "../../../core/shell-quote.js";
2
- import {
3
- dispatchCountFromJsonl,
4
- evidenceMetricsFromReceipt,
5
- receiptFromRunJsonStdout,
6
- scoutDispatchCountFromJsonl,
7
- wikiStaleAcknowledgedFromJsonl,
8
- } from "../metrics/evidence.js";
2
+ import { evidenceMetricsFromReceipt, receiptFromRunJsonStdout } from "../metrics/evidence.js";
9
3
  import { streamInvariantMetrics } from "../metrics/invariants.js";
10
4
  import { tokenMetricEntries } from "../metrics/token-stream.js";
11
5
  import type { EvalRunnerV2, EvalSuiteTargetV2 } from "../schema/suite.js";
@@ -58,9 +52,6 @@ export async function runClioRunRunner(
58
52
  "tools.failed": tools.failed,
59
53
  "tools.blocked": tools.blocked,
60
54
  "verifier.exitCode": result.exitCode,
61
- "dispatch.count": dispatchCountFromJsonl(toolMetricStream),
62
- "dispatch.scoutCount": scoutDispatchCountFromJsonl(toolMetricStream),
63
- "wiki.staleAcknowledged": wikiStaleAcknowledgedFromJsonl(toolMetricStream),
64
55
  ...(receipt === null ? {} : evidenceMetricsFromReceipt(receipt)),
65
56
  ...(receipt === null
66
57
  ? {}