@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
@@ -2,6 +2,12 @@ import { readFileSync } from "node:fs";
2
2
  import { sleep } from "../core/timers.js";
3
3
  import { renderAgentLedgerBoard } from "../domains/dispatch/agent-ledger-store.js";
4
4
  import type { DurableAssignmentRecord } from "../domains/dispatch/assignment-store.js";
5
+ import {
6
+ formatBudgetPolicy,
7
+ formatBudgetReasons,
8
+ formatBudgetRequest,
9
+ formatEffectiveBudget,
10
+ } from "../domains/dispatch/budget-envelope.js";
5
11
  import type { DispatchContract } from "../domains/dispatch/contract.js";
6
12
  import { UNVERIFIABLE_RECEIPT_VERIFICATION } from "../domains/dispatch/receipt-findings.js";
7
13
  import type { ReceiptIntegrityResult } from "../domains/dispatch/receipt-integrity.js";
@@ -117,6 +123,19 @@ function runStatus(deps: MonitorToolDeps, runId: string): ToolResult {
117
123
  `started=${run.startedAt} ended=${run.endedAt ?? "n/a"} exit=${run.exitCode ?? "n/a"}`,
118
124
  `tokens=${run.tokenCount} cost=${formatCostAggregate(costAggregateForAmount(run.costUsd, run.costProvenance)) ?? COST_NOT_MEASURED} receipt=${run.receiptPath ?? "n/a"}`,
119
125
  ];
126
+ if (run.council !== undefined || run.gate?.role === "synthesis") {
127
+ lines.push(
128
+ `council: role=${run.gate?.role === "synthesis" ? "synthesis" : "member"} group=${run.council?.group ?? run.gate?.group ?? "unknown"}${run.council?.label ? ` label=${run.council.label}` : ""}`,
129
+ );
130
+ }
131
+ if (run.budget !== undefined) {
132
+ lines.push(
133
+ `recipe policy: ${formatBudgetPolicy(run.budget)}`,
134
+ `requested envelope: ${formatBudgetRequest(run.budget)}`,
135
+ `effective envelope: ${formatEffectiveBudget(run.budget)}`,
136
+ `clamp or escalation reason: ${formatBudgetReasons(run.budget)}`,
137
+ );
138
+ }
120
139
  if (live) {
121
140
  lines.push(
122
141
  `live: phase=${live.outcomePhase} heartbeat=${live.heartbeat} elapsed=${Math.round(live.elapsedMs / 1000)}s tokens=${live.tokens.total}`,
@@ -143,6 +162,16 @@ function runStatus(deps: MonitorToolDeps, runId: string): ToolResult {
143
162
  tokenCount: run.tokenCount,
144
163
  costUsd: run.costUsd,
145
164
  costProvenance: run.costProvenance ?? "unknown",
165
+ budget: run.budget ?? null,
166
+ ...(run.council !== undefined || run.gate?.role === "synthesis"
167
+ ? {
168
+ council: {
169
+ role: run.gate?.role === "synthesis" ? "synthesis" : "member",
170
+ group: run.council?.group ?? run.gate?.group ?? null,
171
+ ...(run.council !== undefined ? { label: run.council.label, round: run.council.round } : {}),
172
+ },
173
+ }
174
+ : {}),
146
175
  receiptPath: run.receiptPath,
147
176
  running: live !== null,
148
177
  },
@@ -363,6 +392,7 @@ function runReceipt(deps: MonitorToolDeps, runId: string): ToolResult {
363
392
  ...(receipt !== null && receiptIntegrity.ok
364
393
  ? {
365
394
  evidenceVerification: receipt.verification,
395
+ hostVerification: receipt.hostVerification ?? null,
366
396
  briefing: receipt.briefing ?? null,
367
397
  projectContext: receipt.projectContext ?? null,
368
398
  }
@@ -702,6 +732,7 @@ async function runCollect(
702
732
  receiptIntegrity: row.evidence.integrity,
703
733
  trustStatus: row.evidence.trustStatus,
704
734
  evidenceVerification: row.evidence.verification,
735
+ hostVerification: row.evidence.receipt?.hostVerification ?? null,
705
736
  briefing: row.evidence.receipt?.briefing ?? null,
706
737
  projectContext: row.evidence.receipt?.projectContext ?? null,
707
738
  ...(output ? { output: { state: output.state, bytes: output.bytes, truncated: output.truncated } } : {}),
@@ -1,8 +1,13 @@
1
1
  import { type BuiltinToolName, isBuiltinToolName, type ToolName, ToolNames } from "../core/tool-names.js";
2
2
 
3
- export type ToolProfileName = "minimal-local" | "science-local" | "full-agent";
3
+ export type ToolProfileName = "minimal-local" | "science-local" | "full-agent" | "council-read-only";
4
4
 
5
- export const TOOL_PROFILE_NAMES: ReadonlyArray<ToolProfileName> = ["minimal-local", "science-local", "full-agent"];
5
+ export const TOOL_PROFILE_NAMES: ReadonlyArray<Exclude<ToolProfileName, "council-read-only">> = [
6
+ "minimal-local",
7
+ "science-local",
8
+ "full-agent",
9
+ ];
10
+ const ALL_TOOL_PROFILE_NAMES: ReadonlyArray<ToolProfileName> = [...TOOL_PROFILE_NAMES, "council-read-only"];
6
11
  const CODEWIKI_TOOL_NAMES: ReadonlyArray<BuiltinToolName> = [ToolNames.CodeNav];
7
12
 
8
13
  export interface ToolProfileContext {
@@ -24,14 +29,23 @@ const MINIMAL_LOCAL_TOOLS: ReadonlyArray<BuiltinToolName> = [
24
29
  ];
25
30
 
26
31
  const SCIENCE_LOCAL_TOOLS: ReadonlyArray<BuiltinToolName> = [...MINIMAL_LOCAL_TOOLS, ToolNames.Verify];
32
+ const COUNCIL_READ_ONLY_TOOLS: ReadonlyArray<BuiltinToolName> = [
33
+ ToolNames.Read,
34
+ ToolNames.Grep,
35
+ ToolNames.Find,
36
+ ToolNames.Ls,
37
+ ToolNames.CodeNav,
38
+ ToolNames.Context,
39
+ ];
27
40
 
28
41
  const NARROW_TOOL_PROFILES: Readonly<Record<Exclude<ToolProfileName, "full-agent">, ReadonlySet<BuiltinToolName>>> = {
29
42
  "minimal-local": new Set(MINIMAL_LOCAL_TOOLS),
30
43
  "science-local": new Set(SCIENCE_LOCAL_TOOLS),
44
+ "council-read-only": new Set(COUNCIL_READ_ONLY_TOOLS),
31
45
  };
32
46
 
33
47
  export function isToolProfileName(value: string): value is ToolProfileName {
34
- return (TOOL_PROFILE_NAMES as ReadonlyArray<string>).includes(value);
48
+ return (ALL_TOOL_PROFILE_NAMES as ReadonlyArray<string>).includes(value);
35
49
  }
36
50
 
37
51
  /**
@@ -72,7 +86,7 @@ export function applyToolProfile(
72
86
  const allowed = NARROW_TOOL_PROFILES[profile];
73
87
  profiled = unique.filter((tool): tool is BuiltinToolName => isBuiltinToolName(tool) && allowed.has(tool));
74
88
  }
75
- return applyCodewikiWorkerPolicy(profiled, context);
89
+ return profile === "council-read-only" ? profiled : applyCodewikiWorkerPolicy(profiled, context);
76
90
  }
77
91
 
78
92
  function uniquePreservingOrder(tools: ReadonlyArray<ToolName>): ToolName[] {
@@ -22,13 +22,14 @@ import {
22
22
  mapAutonomy,
23
23
  } from "../domains/safety/autonomy.js";
24
24
  import type { SafetyContract, SafetyDecision } from "../domains/safety/contract.js";
25
+ import type { DecisionPresentation } from "../domains/safety/decision-presentation.js";
25
26
  import { hashToolCall } from "../domains/safety/loop-detector.js";
26
27
  import { detectValidationCommand } from "../domains/safety/protected-artifacts.js";
27
28
  import { askUserExposure } from "./ask-user.js";
28
29
  import { type DispatchPlanView, describeDispatchPlan } from "./dispatch-plan.js";
29
30
  import type { ToolPresentationPolicy } from "./presentation.js";
30
- import type { ToolResultDisposition } from "./result-disposition.js";
31
- import { DEFAULT_TOOL_RESULT_MAX_BYTES, shapeToolResult } from "./result-shaping.js";
31
+ import type { ToolResultDigest, ToolResultDisposition } from "./result-disposition.js";
32
+ import { DEFAULT_TOOL_RESULT_MAX_BYTES, shapeToolResult, toolResultDigestFor } from "./result-shaping.js";
32
33
 
33
34
  /**
34
35
  * Tool registry. Admission point for every tool call. Delegates classification
@@ -200,6 +201,8 @@ export interface ToolInvokeOptions {
200
201
  correlationId?: string;
201
202
  pendingSkillPolicy?: PendingSkillToolPolicy;
202
203
  askUserPolicy?: AskUserToolPolicy;
204
+ /** Host-derived display copy for an ask_user round. It has no admission authority. */
205
+ decisionPresentation?: DecisionPresentation;
203
206
  /** Registry-authenticated one-shot operator approval for this execution. */
204
207
  approval?: { requestId: string; requestedBy: string; actionClass: ActionClass };
205
208
  /**
@@ -259,6 +262,8 @@ export interface AskUserToolPolicy {
259
262
  sessionId?: string;
260
263
  turnId?: string;
261
264
  transcriptPath?: string;
265
+ /** Monotonic exposure fact for live presentation and durable replay. */
266
+ exposure?: AutonomyExposure;
262
267
  summary?: string;
263
268
  rounds: AskUserTranscriptRound[];
264
269
  decisions: AskUserTranscriptDecision[];
@@ -421,13 +426,15 @@ export function createRegistry(deps: RegistryDeps): ToolRegistry {
421
426
  const preparedArgs = prepareToolArgs(spec, call.args ?? {});
422
427
  resultDisposition = resolveToolResultDisposition(spec, preparedArgs);
423
428
  const result = await spec.run(preparedArgs, options);
424
- const afterEffects = runToolHook("after_tool", spec, call, decision, options, result);
429
+ const digest = toolResultDigestFor(spec, result, resultDisposition);
430
+ const afterEffects = runToolHook("after_tool", spec, call, decision, options, result, digest);
425
431
  const finalResult = shapeToolResult(spec, applyToolResultEffects(result, afterEffects), options, resultDisposition);
426
432
  return { kind: "ok", result: finalResult, decision };
427
433
  } catch (err) {
428
434
  const message = err instanceof Error ? err.message : String(err);
429
435
  const result: ToolResult = { kind: "error", message };
430
- const afterEffects = runToolHook("after_tool", spec, call, decision, options, result);
436
+ const digest = toolResultDigestFor(spec, result, resultDisposition);
437
+ const afterEffects = runToolHook("after_tool", spec, call, decision, options, result, digest);
431
438
  return {
432
439
  kind: "ok",
433
440
  result: shapeToolResult(spec, applyToolResultEffects(result, afterEffects), options, resultDisposition),
@@ -446,9 +453,10 @@ export function createRegistry(deps: RegistryDeps): ToolRegistry {
446
453
  decision: SafetyDecision,
447
454
  options: ToolInvokeOptions | undefined,
448
455
  result?: ToolResult,
456
+ resultDigest?: ToolResultDigest,
449
457
  ): ReadonlyArray<MiddlewareEffect> => {
450
458
  if (!deps.middleware) return [];
451
- const input = buildToolHookInput(hook, spec, call, decision, "operating", options, result);
459
+ const input = buildToolHookInput(hook, spec, call, decision, "operating", options, result, resultDigest);
452
460
  const effects = deps.middleware.runHook(input).effects;
453
461
  try {
454
462
  deps.onMiddlewareEffects?.(effects, input);
@@ -1135,6 +1143,7 @@ function buildToolHookInput(
1135
1143
  posture: string,
1136
1144
  options: ToolInvokeOptions | undefined,
1137
1145
  result: ToolResult | undefined,
1146
+ resultDigest: ToolResultDigest | undefined,
1138
1147
  ): MiddlewareHookInput {
1139
1148
  const metadata: Record<string, MiddlewareMetadataValue> = {
1140
1149
  posture,
@@ -1171,6 +1180,7 @@ function buildToolHookInput(
1171
1180
  };
1172
1181
  if (call.args !== undefined) input.toolArgs = call.args;
1173
1182
  if (result?.details !== undefined) input.toolResultDetails = result.details;
1183
+ if (resultDigest !== undefined) input.toolResultDigest = resultDigest;
1174
1184
  if (options?.runId !== undefined) input.runId = options.runId;
1175
1185
  if (options?.sessionId !== undefined) input.sessionId = options.sessionId;
1176
1186
  if (options?.turnId !== undefined) input.turnId = options.turnId;
@@ -52,6 +52,23 @@ export interface ToolResultSummaryProvenance {
52
52
  redactions?: number;
53
53
  }
54
54
 
55
+ export const TOOL_RESULT_DIGEST_MAX_BYTES = 240;
56
+
57
+ export interface ToolResultDigestProvenance {
58
+ producer: "code";
59
+ source: "canonical-result-disposition" | "legacy-fallback";
60
+ algorithm: "redacted-context-digest-v1" | "redacted-legacy-digest-v1";
61
+ contextMode?: AppliedToolResultContextMode;
62
+ summaryAlgorithm?: ToolResultSummaryProvenance["algorithm"];
63
+ redactions?: number;
64
+ }
65
+
66
+ /** A bounded diagnostic that is safe to pass to task memory. */
67
+ export interface ToolResultDigest {
68
+ text: string;
69
+ provenance: ToolResultDigestProvenance;
70
+ }
71
+
55
72
  export interface ToolResultDispositionMetadata {
56
73
  version: 1;
57
74
  applications: 1;
@@ -223,6 +240,14 @@ function capUtf8(text: string, maxBytes: number): string {
223
240
  return byteLength(text) <= maxBytes ? text : utf8Prefix(text, maxBytes);
224
241
  }
225
242
 
243
+ function capDigestUtf8(text: string, maxBytes: number): string {
244
+ if (byteLength(text) <= maxBytes) return text;
245
+ const marker = "…";
246
+ const markerBytes = byteLength(marker);
247
+ if (markerBytes >= maxBytes) return utf8Prefix(text, maxBytes);
248
+ return `${utf8Prefix(text, maxBytes - markerBytes).trimEnd()}${marker}`;
249
+ }
250
+
226
251
  /** A deterministic, UTF-8-safe excerpt whose total bytes never exceed maxBytes. */
227
252
  function boundedToolResultExcerpt(text: string, maxBytes: number, bias: ToolResultExcerptBias = "head-tail"): string {
228
253
  if (maxBytes <= 0) return "";
@@ -504,6 +529,137 @@ export function projectToolResultContext(input: ProjectToolResultContextInput):
504
529
  };
505
530
  }
506
531
 
532
+ const DIGEST_FACT_KEYS = [
533
+ "outcome",
534
+ "exitCode",
535
+ "timedOut",
536
+ "aborted",
537
+ "outputCapped",
538
+ "signal",
539
+ "status",
540
+ "error",
541
+ "decision",
542
+ "next",
543
+ ] as const;
544
+
545
+ function digestFactText(details: ToolResultDetails | undefined): string {
546
+ if (details === undefined) return "";
547
+ const facts: string[] = [];
548
+ for (const key of DIGEST_FACT_KEYS) {
549
+ if (details[key] !== undefined) facts.push(`${key}=${stableJson(details[key])}`);
550
+ }
551
+ return facts.join(" ");
552
+ }
553
+
554
+ function projectionBody(input: ProjectToolResultContextInput, projection: ToolResultContextProjection): string {
555
+ if (projection.appliedMode === "metadata-only") return "";
556
+ if (projection.appliedMode === "full") {
557
+ const trailer = fullTrailer(input);
558
+ return trailer.length > 0 && projection.text.endsWith(`\n\n${trailer}`)
559
+ ? projection.text.slice(0, -(trailer.length + 2))
560
+ : projection.text;
561
+ }
562
+ const header = contextHeader(input, projection.appliedMode, projection.truncated, projection.summaryProvenance);
563
+ const prefix = `${header}\n`;
564
+ return projection.text.startsWith(prefix) ? projection.text.slice(prefix.length) : "";
565
+ }
566
+
567
+ function digestText(
568
+ status: string,
569
+ facts: string,
570
+ body: string,
571
+ redactions: number,
572
+ maxBytes: number,
573
+ ): { text: string; redactions: number } {
574
+ const tally = createRedactionTally();
575
+ const safeStatus = redactSecretsText(status, tally);
576
+ const safeFacts = redactSecretsText(facts, tally);
577
+ const statusAndFacts = [safeStatus, safeFacts].filter((value) => value.length > 0).join(" ");
578
+ const bodyBudget = Math.max(0, maxBytes - byteLength(statusAndFacts) - 2);
579
+ const selected = deterministicDiagnosticSummary(body, bodyBudget, true);
580
+ const candidate = [statusAndFacts, selected.text.replace(/\s+/gu, " ").trim()]
581
+ .filter((value) => value.length > 0)
582
+ .join("; ");
583
+ return {
584
+ text: capDigestUtf8(candidate, maxBytes),
585
+ redactions: redactions + tally.count + selected.redactions,
586
+ };
587
+ }
588
+
589
+ /**
590
+ * Reuse the applied model-context projection as task memory's diagnostic
591
+ * source. Metadata-only never contributes captured content, and bounded or
592
+ * summarized modes contribute only the body admitted by that projection.
593
+ */
594
+ export function deterministicToolResultDigest(
595
+ input: ProjectToolResultContextInput,
596
+ maxBytes = TOOL_RESULT_DIGEST_MAX_BYTES,
597
+ ): ToolResultDigest {
598
+ const projection = projectToolResultContext(input);
599
+ const status = [
600
+ `kind=${input.kind}`,
601
+ `mode=${projection.appliedMode}`,
602
+ `truncated=${String(projection.truncated)}`,
603
+ ...(projection.appliedMode === "metadata-only" || projection.truncated
604
+ ? [`capturedBytes=${input.capturedBytes}`]
605
+ : []),
606
+ ].join(" ");
607
+ const digest = digestText(
608
+ status,
609
+ digestFactText(input.details),
610
+ projectionBody(input, projection),
611
+ projection.summaryProvenance?.redactions ?? 0,
612
+ Math.max(1, Math.floor(maxBytes)),
613
+ );
614
+ return {
615
+ text: digest.text,
616
+ provenance: {
617
+ producer: "code",
618
+ source: "canonical-result-disposition",
619
+ algorithm: "redacted-context-digest-v1",
620
+ contextMode: projection.appliedMode,
621
+ ...(projection.summaryProvenance === undefined ? {} : { summaryAlgorithm: projection.summaryProvenance.algorithm }),
622
+ ...(digest.redactions > 0 ? { redactions: digest.redactions } : {}),
623
+ },
624
+ };
625
+ }
626
+
627
+ /** Deterministic compatibility path for results without a canonical disposition. */
628
+ export function legacyToolResultDigest(
629
+ text: string,
630
+ options: { outcome: "ok" | "error"; maxBytes?: number },
631
+ ): ToolResultDigest {
632
+ const maxBytes = Math.max(1, Math.floor(options.maxBytes ?? TOOL_RESULT_DIGEST_MAX_BYTES));
633
+ const fallback = options.outcome === "error" && text.trim().length === 0 ? "an unknown tool error" : text;
634
+ const digest = digestText("", "", fallback, 0, maxBytes);
635
+ return {
636
+ text: digest.text,
637
+ provenance: {
638
+ producer: "code",
639
+ source: "legacy-fallback",
640
+ algorithm: "redacted-legacy-digest-v1",
641
+ ...(digest.redactions > 0 ? { redactions: digest.redactions } : {}),
642
+ },
643
+ };
644
+ }
645
+
646
+ /** Reapply the memory boundary's redaction and byte cap to a supplied digest. */
647
+ export function sanitizeToolResultDigest(
648
+ digest: ToolResultDigest,
649
+ maxBytes = TOOL_RESULT_DIGEST_MAX_BYTES,
650
+ ): ToolResultDigest {
651
+ const tally = createRedactionTally();
652
+ const safe = redactSecretsText(digest.text, tally).replace(/\s+/gu, " ").trim();
653
+ const redactions = (digest.provenance.redactions ?? 0) + tally.count;
654
+ return {
655
+ text: capDigestUtf8(safe, Math.max(1, Math.floor(maxBytes))),
656
+ provenance: {
657
+ ...digest.provenance,
658
+ ...(redactions > 0 ? { redactions } : {}),
659
+ },
660
+ };
661
+ }
662
+
507
663
  /** The text inserted into the provider conversation for a registry result. */
508
664
  export function toolResultContextText(result: ToolResult): string {
509
665
  if (result.modelContext !== undefined) return result.modelContext;
@@ -1,11 +1,14 @@
1
1
  import { createHash } from "node:crypto";
2
- import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { mkdirSync, readdirSync, rmdirSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { isAbsolute, join, relative, resolve } from "node:path";
4
4
  import { clioStateDir } from "../core/xdg.js";
5
5
  import type { ToolInvokeOptions, ToolResult, ToolResultDetails, ToolSpec } from "./registry.js";
6
6
  import {
7
+ deterministicToolResultDigest,
8
+ legacyToolResultDigest,
7
9
  normalizeToolResultDisposition,
8
10
  projectToolResultContext,
11
+ type ToolResultDigest,
9
12
  type ToolResultDisposition,
10
13
  type ToolResultDispositionFallback,
11
14
  type ToolResultDispositionMetadata,
@@ -21,6 +24,7 @@ export const DEFAULT_TOOL_RESULT_MAX_BYTES = DEFAULT_MAX_BYTES + 2 * 1024;
21
24
  const RESULT_TRUNCATION_MARKER = "\n[tool result truncated]";
22
25
  const RESULT_OFFLOAD_MAX_BYTES = 10 * 1024 * 1024;
23
26
  const TAIL_NOTICE_RESERVE_BYTES = 512;
27
+ export const TOOL_OFFLOAD_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1000;
24
28
 
25
29
  type ToolResultShapeContext = Pick<ToolInvokeOptions, "sessionId" | "toolCallId">;
26
30
 
@@ -49,6 +53,34 @@ function offloadMaxBytesFor(spec: ToolSpec): number {
49
53
  : RESULT_OFFLOAD_MAX_BYTES;
50
54
  }
51
55
 
56
+ /**
57
+ * Build the task-memory diagnostic from the same normalized disposition that
58
+ * will shape model context. Legacy tools use the explicit compatibility path.
59
+ */
60
+ export function toolResultDigestFor(
61
+ spec: ToolSpec,
62
+ result: ToolResult,
63
+ requestedDisposition?: ToolResultDisposition,
64
+ ): ToolResultDigest {
65
+ const text = resultText(result);
66
+ const disposition = normalizeToolResultDisposition(spec, maxBytesFor(spec), requestedDisposition);
67
+ if (disposition === null) {
68
+ const projected = shapeLegacyToolResult(spec, result);
69
+ return legacyToolResultDigest(resultText(projected), { outcome: result.kind });
70
+ }
71
+ const capturedBytes = capturedBytesFor(result, text);
72
+ return deterministicToolResultDigest({
73
+ text,
74
+ kind: result.kind,
75
+ details: result.details,
76
+ disposition,
77
+ capturedBytes,
78
+ displayedBytes: Math.min(capturedBytes, disposition.presentation.maxBytes),
79
+ offloadPath: existingOffloadPath(result.details),
80
+ followUpHint: followUpHint(spec),
81
+ });
82
+ }
83
+
52
84
  function detailsRecord(details: ToolResultDetails | undefined, key: string): Record<string, unknown> | null {
53
85
  const candidate = details?.[key];
54
86
  return candidate !== null && typeof candidate === "object" && !Array.isArray(candidate)
@@ -91,6 +123,32 @@ function offloadBody(text: string, bytes: number, maxBytes: number): string {
91
123
  return `${truncateUtf8(text, Math.max(0, prefixBudget), "")}${notice}`;
92
124
  }
93
125
 
126
+ /** Remove regular offload files older than the boot retention cap. */
127
+ export function sweepExpiredToolOffloads(now = Date.now()): number {
128
+ const root = join(clioStateDir(), "scratch");
129
+ const cutoff = now - TOOL_OFFLOAD_MAX_AGE_MS;
130
+ let removed = 0;
131
+ try {
132
+ for (const session of readdirSync(root, { withFileTypes: true })) {
133
+ if (!session.isDirectory()) continue;
134
+ const sessionDir = join(root, session.name);
135
+ for (const entry of readdirSync(sessionDir, { withFileTypes: true })) {
136
+ if (!entry.isFile()) continue;
137
+ const path = join(sessionDir, entry.name);
138
+ try {
139
+ if (statSync(path).mtimeMs >= cutoff) continue;
140
+ rmSync(path, { force: true });
141
+ removed += 1;
142
+ } catch {}
143
+ }
144
+ try {
145
+ if (readdirSync(sessionDir).length === 0) rmdirSync(sessionDir);
146
+ } catch {}
147
+ }
148
+ } catch {}
149
+ return removed;
150
+ }
151
+
94
152
  /**
95
153
  * Persist the full text of a tool result to a per-session scratch file and
96
154
  * return its path (or null if the write fails). Self-shaping callers use this