@iowarp/clio-coder 0.3.7 → 0.3.9

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 (400) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +13 -4
  3. package/dist/{acp-SK4MD6MM.js → acp-7LOELQFP.js} +13 -13
  4. package/dist/{agents-2FN2K6ME.js → agents-FIBG2SHA.js} +41 -37
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-QIYZWM5I.js → auth-OI4LIH2I.js} +31 -24
  7. package/dist/builtins-AD25UL3C.js +17 -0
  8. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  9. package/dist/chunk-3DPEIQKN.js +113 -0
  10. package/dist/{chunk-EOOQZZDE.js → chunk-3DUR4WUA.js} +19 -19
  11. package/dist/{chunk-WHJYKASB.js → chunk-3MRC2YSQ.js} +2 -2
  12. package/dist/{chunk-EBEFWSGL.js → chunk-3UUY7R3Z.js} +14 -10
  13. package/dist/{chunk-LADCF22A.js → chunk-3V5AYSEQ.js} +113 -54
  14. package/dist/{chunk-BMWK7ZIZ.js → chunk-465CC7FK.js} +16 -13
  15. package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
  16. package/dist/{chunk-CEYBNUGC.js → chunk-4H6ULJ3H.js} +378 -36
  17. package/dist/{chunk-YTYFXUI3.js → chunk-4LJX2PUC.js} +9 -9
  18. package/dist/{chunk-DOOEX22V.js → chunk-56KB5IJP.js} +5 -5
  19. package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
  20. package/dist/{chunk-TSHXZTOQ.js → chunk-5HFBWUMU.js} +23 -11
  21. package/dist/{chunk-5UJ6ECTS.js → chunk-5PVQ4SRS.js} +80 -8
  22. package/dist/{chunk-ZWLZP4ZT.js → chunk-5QKCQQ3E.js} +359 -17
  23. package/dist/{chunk-6M7VS3J3.js → chunk-5T7RBWN2.js} +111 -5
  24. package/dist/chunk-774ILSRL.js +172 -0
  25. package/dist/chunk-7C6RYZGQ.js +391 -0
  26. package/dist/{chunk-GH5622CP.js → chunk-A2NJGIB3.js} +2 -2
  27. package/dist/{chunk-C4JBQ5SR.js → chunk-AD7Y7STJ.js} +6 -6
  28. package/dist/{chunk-GEYXPTRF.js → chunk-AEYBF3TB.js} +33 -12
  29. package/dist/{chunk-2SFS6XQE.js → chunk-AMKHQW3C.js} +3 -2
  30. package/dist/{chunk-D4MDIG46.js → chunk-B5CSFE7B.js} +7 -7
  31. package/dist/{chunk-MXI6J5JF.js → chunk-B5XRQOLB.js} +10 -10
  32. package/dist/{chunk-X2KV5FXT.js → chunk-BVDVID7E.js} +2 -2
  33. package/dist/{chunk-JNXPYBB4.js → chunk-CA42X6KT.js} +3 -3
  34. package/dist/{chunk-VREKEFLL.js → chunk-D73KXYPF.js} +3 -3
  35. package/dist/{chunk-JTSEDYVQ.js → chunk-DG4M6ZUE.js} +7 -7
  36. package/dist/{chunk-DQA7QLMD.js → chunk-EBOC7MT3.js} +10 -25
  37. package/dist/{chunk-KZ2H5X4G.js → chunk-ECUO3KDP.js} +129 -14
  38. package/dist/{chunk-JRIO5UD2.js → chunk-EQ63NRB7.js} +5 -5
  39. package/dist/{chunk-YD734TPH.js → chunk-FALJGAWU.js} +2 -2
  40. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  41. package/dist/{chunk-XEGB6BCN.js → chunk-GAYUJ7LE.js} +68 -14
  42. package/dist/{chunk-UND3GU2L.js → chunk-H7IXIC72.js} +2 -2
  43. package/dist/{chunk-IR4CFBFN.js → chunk-HAY4ZE2P.js} +12 -12
  44. package/dist/{chunk-UVDSQ6LW.js → chunk-HCBCAYZU.js} +74 -147
  45. package/dist/{chunk-4DWFMQDR.js → chunk-HJB5IUKP.js} +89 -145
  46. package/dist/{chunk-M4AKACEO.js → chunk-HKO36JWF.js} +33 -5
  47. package/dist/{chunk-KCMKRQX4.js → chunk-HPCTNZM2.js} +45 -82
  48. package/dist/{chunk-465YSENW.js → chunk-IFBNV6H6.js} +3 -3
  49. package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
  50. package/dist/chunk-JEQQR47K.js +3025 -0
  51. package/dist/{chunk-FO5ZOVUY.js → chunk-KV2AOLDF.js} +27 -7
  52. package/dist/chunk-LU7P4LHA.js +33 -0
  53. package/dist/{chunk-6TUKSZVF.js → chunk-LXPJXFM5.js} +11 -11
  54. package/dist/{chunk-VQNODYQ4.js → chunk-MIX5N5AC.js} +488 -3668
  55. package/dist/chunk-MLOK6ZOS.js +2888 -0
  56. package/dist/{chunk-ZZMN5OM4.js → chunk-MV2VUEJC.js} +2 -2
  57. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  58. package/dist/{chunk-OBMAI2DP.js → chunk-N3PBVRTZ.js} +12 -388
  59. package/dist/{chunk-WJHBC77E.js → chunk-N5XKWMDW.js} +17 -7
  60. package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
  61. package/dist/{chunk-UFQ3F4FW.js → chunk-NQ6UCCOD.js} +4 -4
  62. package/dist/chunk-NUGM5KR6.js +165 -0
  63. package/dist/{chunk-DMD2AGVS.js → chunk-NZU6YDNV.js} +20 -18
  64. package/dist/{chunk-WHGPSPT5.js → chunk-O6I4CIEU.js} +151 -13
  65. package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
  66. package/dist/{chunk-PD3MESLB.js → chunk-P3JGPQFL.js} +4 -4
  67. package/dist/{chunk-UHXRNZ2J.js → chunk-PNY46YEY.js} +23 -6
  68. package/dist/{chunk-THKY7CD7.js → chunk-PZ4I4JE2.js} +134 -29
  69. package/dist/{chunk-SROCI7ZU.js → chunk-QQ7EKM72.js} +5 -5
  70. package/dist/{chunk-QCTRSGHQ.js → chunk-R7LNVMCS.js} +91 -53
  71. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  72. package/dist/chunk-RKKLTLYB.js +45 -0
  73. package/dist/{chunk-OB5HIGJY.js → chunk-RKRLDWD3.js} +4 -1
  74. package/dist/{chunk-DJNLUABN.js → chunk-S4COXYBG.js} +588 -32
  75. package/dist/{chunk-3HAPLH5M.js → chunk-T3Z6VAAF.js} +172 -11
  76. package/dist/{chunk-FOT2FX5J.js → chunk-TD7UE2L5.js} +12 -10
  77. package/dist/{chunk-UUANF5CR.js → chunk-TEO2TLVN.js} +856 -967
  78. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  79. package/dist/{chunk-EELBMBT6.js → chunk-VKBMFOYV.js} +74 -15
  80. package/dist/chunk-VO2LKSTM.js +165 -0
  81. package/dist/{chunk-5C77SEEY.js → chunk-VPTUJU4P.js} +3 -3
  82. package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
  83. package/dist/{chunk-J7PIKKWC.js → chunk-WXCJ7VME.js} +8 -8
  84. package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
  85. package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
  86. package/dist/{chunk-AB4XIIVB.js → chunk-YKOFT37S.js} +6 -6
  87. package/dist/chunk-YSEHGPCT.js +127 -0
  88. package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
  89. package/dist/cli/index.js +32 -32
  90. package/dist/{clio-WBVQEBKO.js → clio-LT5V7SSZ.js} +9 -9
  91. package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +5 -5
  92. package/dist/codewiki/build-worker.js +4 -4
  93. package/dist/{components-F7OEATSO.js → components-ZFA3SAER.js} +8 -8
  94. package/dist/{config-TRBL3RCF.js → config-RXS5T3JT.js} +98 -65
  95. package/dist/{configure-OLCVPHNM.js → configure-2WYWSCSD.js} +26 -22
  96. package/dist/{context-MJIJ6GOX.js → context-I3BTOTCS.js} +12 -12
  97. package/dist/{context-XEWE3MOJ.js → context-MVOORGMF.js} +54 -47
  98. package/dist/{context-WFPKQSM6.js → context-PALKKQYL.js} +28 -28
  99. package/dist/{context-clear-KNOS2JPB.js → context-clear-N2WOYZ2K.js} +53 -46
  100. package/dist/{context-index-SSR5ECNE.js → context-index-HNG3MOME.js} +6 -6
  101. package/dist/{context-working-set-EUXAZI6N.js → context-working-set-MIEVECVZ.js} +17 -18
  102. package/dist/{dispatch-runner-B7MTOVKL.js → dispatch-runner-VVA4SRRH.js} +90 -61
  103. package/dist/{docs-FLJTIDSE.js → docs-7LQ23DLM.js} +8 -8
  104. package/dist/doctor-TWBWFK5V.js +165 -0
  105. package/dist/eval-IJ5VEZDJ.js +4483 -0
  106. package/dist/{evidence-JZNBUOQZ.js → evidence-L5APPXNV.js} +68 -61
  107. package/dist/{evolve-FJVC4KKI.js → evolve-RGNKFJ52.js} +47 -40
  108. package/dist/{extensions-IQL36S7K.js → extensions-7WYWUX5A.js} +13 -7
  109. package/dist/{fleet-BDKYJFCP.js → fleet-6CNVBZZP.js} +113 -76
  110. package/dist/{fleet-commands-ZFIWZSB3.js → fleet-commands-L2SXSYEI.js} +10 -10
  111. package/dist/{fleet-graph-Y6HPXIVF.js → fleet-graph-2J3OOIPO.js} +17 -15
  112. package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-CZRJ4JP5.js} +5 -6
  113. package/dist/{fleet-validate-BIYREGIK.js → fleet-validate-C5RI6DP7.js} +20 -19
  114. package/dist/{init-LQUB5COQ.js → init-VBN2ACVA.js} +70 -63
  115. package/dist/{library-NJAHIGG4.js → library-JHGUMLY2.js} +22 -20
  116. package/dist/{memory-OG6HOYKM.js → memory-K4OQIYWG.js} +49 -42
  117. package/dist/{models-5ZG5XY7J.js → models-2NCZUWDD.js} +35 -29
  118. package/dist/{monitor-TJ7AMTGB.js → monitor-MMVTJABD.js} +64 -45
  119. package/dist/{orchestrator-WZYB54DM.js → orchestrator-ZKBPCHW6.js} +1971 -520
  120. package/dist/{paths-XUC7GS6E.js → paths-DBXMZMDU.js} +5 -5
  121. package/dist/registry-LG64LTF4.js +11 -0
  122. package/dist/{reset-PXQT45IY.js → reset-DD5JGOY3.js} +11 -11
  123. package/dist/{run-FQ74YF62.js → run-QEGNX7FL.js} +89 -83
  124. package/dist/{share-FW7SVCL3.js → share-JKD3BQMW.js} +20 -18
  125. package/dist/{skills-7E7IRB3R.js → skills-LMQIKDOZ.js} +23 -21
  126. package/dist/{skills-eval-LI75W6OK.js → skills-eval-I7X2774U.js} +59 -52
  127. package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
  128. package/dist/support-I7LOJLIF.js +38 -0
  129. package/dist/{targets-4CIFKCTW.js → targets-RUSR6B5Z.js} +77 -42
  130. package/dist/{terminal-lease-WUZY7ZV5.js → terminal-lease-QYVORFR4.js} +6 -4
  131. package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
  132. package/dist/{uninstall-7FV7IP4E.js → uninstall-ZJF5H5ZN.js} +8 -8
  133. package/dist/{upgrade-K2HVIVMQ.js → upgrade-XANW3FXB.js} +29 -26
  134. package/dist/{usage-GTZELZQX.js → usage-4H7ZRXQT.js} +110 -61
  135. package/dist/{verifiers-RLAHT27O.js → verifiers-UZXNBZEB.js} +13 -13
  136. package/dist/{verify-BX3BRKH5.js → verify-BVKWTNDL.js} +9 -9
  137. package/dist/{wiki-generate-ASIFASCN.js → wiki-generate-MY7WV2QI.js} +76 -69
  138. package/dist/worker/entry.js +69 -66
  139. package/docs/alcf-provider.md +1 -1
  140. package/docs/architecture.md +1 -1
  141. package/docs/artifact-versions.md +11 -5
  142. package/docs/built-in-agents.md +1 -1
  143. package/docs/capacity-and-scheduling.md +23 -2
  144. package/docs/commands-and-modes.md +2 -2
  145. package/docs/configuration-and-targets.md +37 -5
  146. package/docs/context-engine.md +63 -4
  147. package/docs/documentation-coverage.md +3 -3
  148. package/docs/documentation-guide.md +1 -1
  149. package/docs/environment-variables.md +2 -0
  150. package/docs/eval-runner.md +262 -11
  151. package/docs/evals-internal.md +72 -2
  152. package/docs/evidence-and-memory.md +77 -12
  153. package/docs/evolution.md +1 -1
  154. package/docs/extensions-and-sharing.md +3 -1
  155. package/docs/fleet-dispatch.md +34 -9
  156. package/docs/glossary.md +21 -1
  157. package/docs/installation-and-lifecycle.md +1 -1
  158. package/docs/middleware-and-components.md +1 -1
  159. package/docs/model-catalog.md +1 -1
  160. package/docs/observability.md +54 -3
  161. package/docs/proactive-memory.md +127 -14
  162. package/docs/prompt-envelope-and-tools.md +22 -2
  163. package/docs/provider-adapter-cookbook.md +1 -1
  164. package/docs/release-cut-checklist.md +60 -41
  165. package/docs/safety-model.md +1 -1
  166. package/docs/scientific-validation.md +1 -1
  167. package/docs/skills-marketplace.md +1 -1
  168. package/docs/tool-usage.md +1 -1
  169. package/docs/trace-store.md +1 -1
  170. package/docs/troubleshooting.md +87 -0
  171. package/docs/tui-design.md +1 -1
  172. package/docs/worker-dispatch-mechanics.md +1 -1
  173. package/package.json +2 -2
  174. package/src/cli/agents.ts +1 -1
  175. package/src/cli/argv.ts +5 -0
  176. package/src/cli/config-inspect.ts +33 -6
  177. package/src/cli/config.ts +1 -1
  178. package/src/cli/configure.ts +107 -23
  179. package/src/cli/doctor-state-size.ts +82 -0
  180. package/src/cli/doctor.ts +7 -1
  181. package/src/cli/eval.ts +80 -16
  182. package/src/cli/evidence.ts +30 -25
  183. package/src/cli/extensions.ts +5 -1
  184. package/src/cli/fleet-preflight.ts +2 -12
  185. package/src/cli/fleet.ts +32 -3
  186. package/src/cli/shared.ts +1 -0
  187. package/src/cli/targets.ts +45 -11
  188. package/src/cli/trace.ts +63 -4
  189. package/src/cli/usage.ts +63 -14
  190. package/src/cli/validate-model.ts +60 -5
  191. package/src/core/bus-events.ts +54 -1
  192. package/src/core/cache-telemetry.ts +42 -0
  193. package/src/core/commit-attribution.ts +4 -4
  194. package/src/core/config.ts +18 -0
  195. package/src/core/defaults.ts +36 -6
  196. package/src/core/endpoint-key.ts +27 -0
  197. package/src/core/path-boundary.ts +100 -0
  198. package/src/core/residency-target-key.ts +25 -0
  199. package/src/core/response-schema.ts +36 -2
  200. package/src/domains/agents/extension.ts +2 -11
  201. package/src/domains/agents/fleet-contract.ts +30 -12
  202. package/src/domains/agents/recipe.ts +7 -1
  203. package/src/domains/agents/registry.ts +73 -5
  204. package/src/domains/agents/result-contract.ts +128 -17
  205. package/src/domains/agents/write-boundary.ts +15 -50
  206. package/src/domains/config/classify.ts +3 -0
  207. package/src/domains/context/codewiki/coordinator.ts +12 -4
  208. package/src/domains/context/project-rules.ts +51 -1
  209. package/src/domains/dispatch/admission.ts +40 -3
  210. package/src/domains/dispatch/assignment-reconcile.ts +22 -5
  211. package/src/domains/dispatch/assignment-store.ts +151 -14
  212. package/src/domains/dispatch/capacity-lease.ts +98 -9
  213. package/src/domains/dispatch/contract.ts +26 -1
  214. package/src/domains/dispatch/delegation-plan.ts +2 -5
  215. package/src/domains/dispatch/execution-plan.ts +44 -4
  216. package/src/domains/dispatch/execution-role.ts +9 -1
  217. package/src/domains/dispatch/extension.ts +309 -96
  218. package/src/domains/dispatch/fleet-run.ts +78 -4
  219. package/src/domains/dispatch/gate-role-prompts.ts +38 -0
  220. package/src/domains/dispatch/heartbeat.ts +32 -8
  221. package/src/domains/dispatch/index.ts +6 -1
  222. package/src/domains/dispatch/intent-requirements.ts +40 -0
  223. package/src/domains/dispatch/intent.ts +84 -8
  224. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  225. package/src/domains/dispatch/path-scope.ts +370 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +2 -1
  227. package/src/domains/dispatch/reservation-store.ts +116 -8
  228. package/src/domains/dispatch/state.ts +4 -0
  229. package/src/domains/dispatch/types.ts +14 -7
  230. package/src/domains/dispatch/validation.ts +6 -3
  231. package/src/domains/dispatch/worker-spawn.ts +25 -11
  232. package/src/domains/dispatch/write-boundary-enforcer.ts +62 -0
  233. package/src/domains/dispatch/write-boundary.ts +262 -22
  234. package/src/domains/eval/artifacts/store.ts +62 -0
  235. package/src/domains/eval/compare/behavioral.ts +224 -0
  236. package/src/domains/eval/compare/compare.ts +355 -2
  237. package/src/domains/eval/compare/envelope.ts +128 -0
  238. package/src/domains/eval/compare/gates.ts +24 -6
  239. package/src/domains/eval/compare/thresholds.ts +30 -3
  240. package/src/domains/eval/execution-provenance.ts +240 -0
  241. package/src/domains/eval/metrics/aggregate.ts +136 -0
  242. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  243. package/src/domains/eval/metrics/evidence.ts +79 -2
  244. package/src/domains/eval/metrics/tracked.ts +413 -0
  245. package/src/domains/eval/provenance.ts +117 -0
  246. package/src/domains/eval/reports/comparison.ts +128 -0
  247. package/src/domains/eval/reports/junit.ts +17 -3
  248. package/src/domains/eval/reports/markdown.ts +3 -3
  249. package/src/domains/eval/reports/text.ts +14 -0
  250. package/src/domains/eval/run-compare.ts +20 -0
  251. package/src/domains/eval/runners/clio-run.ts +139 -2
  252. package/src/domains/eval/runners/external-command.ts +28 -3
  253. package/src/domains/eval/schema/adapter.ts +111 -0
  254. package/src/domains/eval/schema/artifact.ts +20 -0
  255. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  256. package/src/domains/eval/schema/behavioral.ts +520 -0
  257. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  258. package/src/domains/eval/schema/serving.ts +74 -0
  259. package/src/domains/eval/schema/suite.ts +38 -8
  260. package/src/domains/eval/schema/validate.ts +58 -3
  261. package/src/domains/eval/schema/verdict.ts +237 -0
  262. package/src/domains/eval/suites/resolve.ts +2 -0
  263. package/src/domains/eval/suites/run.ts +264 -33
  264. package/src/domains/eval/verifiers/command.ts +2 -1
  265. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  266. package/src/domains/evidence/build.ts +68 -21
  267. package/src/domains/evidence/eval.ts +2 -12
  268. package/src/domains/evidence/findings-markdown.ts +33 -0
  269. package/src/domains/evidence/index.ts +21 -0
  270. package/src/domains/evidence/provenance.ts +46 -11
  271. package/src/domains/evidence/run-trust.ts +7 -113
  272. package/src/domains/evidence/trust-projection.ts +274 -0
  273. package/src/domains/evidence/trust-status.ts +145 -17
  274. package/src/domains/evidence/types.ts +4 -0
  275. package/src/domains/extensions/compatibility.ts +285 -0
  276. package/src/domains/extensions/discovery.ts +126 -4
  277. package/src/domains/extensions/resources.ts +21 -9
  278. package/src/domains/extensions/state.ts +18 -5
  279. package/src/domains/extensions/types.ts +6 -1
  280. package/src/domains/lifecycle/doctor.ts +209 -2
  281. package/src/domains/memory/index.ts +14 -0
  282. package/src/domains/memory/task-bank-promotion.ts +64 -0
  283. package/src/domains/memory/task-memory-policy.ts +77 -8
  284. package/src/domains/memory/task-memory-spend.ts +131 -0
  285. package/src/domains/memory/task-memory-status.ts +7 -0
  286. package/src/domains/memory/task-memory-telemetry.ts +2 -0
  287. package/src/domains/middleware/index.ts +1 -0
  288. package/src/domains/middleware/memory-intervention.ts +69 -5
  289. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  290. package/src/domains/observability/background-memory-usage.ts +140 -0
  291. package/src/domains/observability/cost.ts +1 -1
  292. package/src/domains/observability/index.ts +7 -0
  293. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  294. package/src/domains/observability/trace-store.ts +192 -2
  295. package/src/domains/prompts/compiler.ts +100 -13
  296. package/src/domains/prompts/contract.ts +3 -5
  297. package/src/domains/providers/endpoint-capacity.ts +96 -0
  298. package/src/domains/providers/extension.ts +30 -2
  299. package/src/domains/providers/index.ts +10 -0
  300. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  301. package/src/domains/providers/runtime-resolution.ts +8 -1
  302. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  303. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  304. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  305. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  306. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  307. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  308. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  309. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  310. package/src/domains/providers/types/capability-flags.ts +2 -0
  311. package/src/domains/providers/types/target-descriptor.ts +2 -0
  312. package/src/domains/resources/common-loader.ts +3 -0
  313. package/src/domains/resources/prompts/loader.ts +184 -17
  314. package/src/domains/safety/call-target.ts +52 -0
  315. package/src/domains/safety/policy-engine.ts +5 -5
  316. package/src/domains/safety/run-effects.ts +96 -2
  317. package/src/domains/safety/scope.ts +7 -12
  318. package/src/domains/session/context-accounting.ts +52 -1
  319. package/src/domains/session/context-ledger.ts +37 -13
  320. package/src/domains/session/index.ts +6 -0
  321. package/src/domains/session/prompt-cache.ts +140 -0
  322. package/src/domains/session/prompt-manifest.ts +42 -0
  323. package/src/engine/acp/adapter.ts +18 -3
  324. package/src/engine/acp/server.ts +4 -1
  325. package/src/engine/ai.ts +35 -0
  326. package/src/engine/apis/llamacpp-residency.ts +55 -3
  327. package/src/engine/apis/lmstudio.ts +25 -5
  328. package/src/engine/apis/ollama-native.ts +2 -1
  329. package/src/engine/apis/openai-completions.ts +80 -17
  330. package/src/engine/apis/residency-lock.ts +3 -1
  331. package/src/engine/apis/residency.ts +34 -1
  332. package/src/engine/prompt-templates.ts +18 -1
  333. package/src/engine/provider-payload.ts +29 -1
  334. package/src/engine/worker-runtime.ts +6 -3
  335. package/src/entry/orchestrator.ts +176 -30
  336. package/src/interactive/chat-loop-messages.ts +26 -7
  337. package/src/interactive/chat-loop.ts +318 -41
  338. package/src/interactive/chat-panel.ts +62 -8
  339. package/src/interactive/clio-editor.ts +45 -8
  340. package/src/interactive/context-activity.ts +5 -1
  341. package/src/interactive/context-meter.ts +1 -1
  342. package/src/interactive/context-overlay.ts +40 -10
  343. package/src/interactive/cost-overlay.ts +64 -6
  344. package/src/interactive/dispatch-board.ts +127 -5
  345. package/src/interactive/fleet-run-preview.ts +41 -15
  346. package/src/interactive/handoff-round.ts +41 -2
  347. package/src/interactive/interactive-application.ts +24 -1
  348. package/src/interactive/interactive-event-projection.ts +14 -0
  349. package/src/interactive/interactive-input-runtime.ts +8 -0
  350. package/src/interactive/interactive-presentation.ts +4 -0
  351. package/src/interactive/interactive-shell.ts +20 -17
  352. package/src/interactive/interactive-slash-runtime.ts +27 -4
  353. package/src/interactive/memory-overlay.ts +8 -0
  354. package/src/interactive/mutation-preview.ts +295 -0
  355. package/src/interactive/overlay-general-openers.ts +16 -0
  356. package/src/interactive/overlay-key-routing.ts +38 -0
  357. package/src/interactive/overlay-lifecycle.ts +38 -5
  358. package/src/interactive/overlay-permission-lifecycle.ts +22 -2
  359. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  360. package/src/interactive/overlays/ask-user.ts +91 -19
  361. package/src/interactive/overlays/help-reference.ts +4 -0
  362. package/src/interactive/overlays/prompts.ts +11 -1
  363. package/src/interactive/overlays/settings.ts +176 -48
  364. package/src/interactive/permission-hint.ts +34 -2
  365. package/src/interactive/permission-overlay.ts +159 -9
  366. package/src/interactive/prewarm.ts +197 -0
  367. package/src/interactive/render-trace.ts +162 -15
  368. package/src/interactive/renderers/tool-execution.ts +4 -0
  369. package/src/interactive/side-question.ts +58 -1
  370. package/src/interactive/slash-commands.ts +7 -2
  371. package/src/interactive/status/controller.ts +11 -0
  372. package/src/interactive/status/state-machine.ts +54 -2
  373. package/src/interactive/status/types.ts +7 -0
  374. package/src/interactive/terminal-lease.ts +2 -0
  375. package/src/interactive/turn-context.ts +299 -31
  376. package/src/interactive/turn-persistence.ts +14 -4
  377. package/src/interactive/turn-prewarm.ts +364 -0
  378. package/src/interactive/turn-queues.ts +7 -4
  379. package/src/interactive/turn-runtime.ts +8 -1
  380. package/src/interactive/turn-state.ts +23 -0
  381. package/src/interactive/view/artifacts.ts +42 -9
  382. package/src/interactive/view/view-overlay.ts +43 -6
  383. package/src/interactive/worker-receipts.ts +14 -2
  384. package/src/interactive/worker-stream.ts +8 -0
  385. package/src/tools/ask-user.ts +43 -2
  386. package/src/tools/dispatch-admission.ts +12 -13
  387. package/src/tools/dispatch-arguments.ts +27 -0
  388. package/src/tools/dispatch-plan.ts +46 -9
  389. package/src/tools/dispatch-runner.ts +48 -13
  390. package/src/tools/dispatch-scout.ts +1 -1
  391. package/src/tools/monitor.ts +13 -0
  392. package/src/tools/registry.ts +16 -0
  393. package/src/tools/worker-evidence.ts +19 -13
  394. package/src/worker/spec-contract.ts +2 -1
  395. package/dist/chunk-AOCYTWAV.js +0 -449
  396. package/dist/chunk-HWUFFB6L.js +0 -83
  397. package/dist/chunk-R346GLFC.js +0 -31
  398. package/dist/chunk-ZGH7FGS5.js +0 -1079
  399. package/dist/doctor-RN4YKO2X.js +0 -87
  400. package/dist/eval-RUBJVSNQ.js +0 -2557
@@ -1,4 +1,13 @@
1
1
  import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
2
+ import {
3
+ ShareDomainModule
4
+ } from "./chunk-TD7UE2L5.js";
5
+ import {
6
+ bootstrapInputFromInitOptions,
7
+ modelBootstrapGenerate,
8
+ resolveBootstrapRoute
9
+ } from "./chunk-3DUR4WUA.js";
10
+ import "./chunk-J5Q24KAG.js";
2
11
  import {
3
12
  DEFAULT_KEEP_RECENT_TOKENS,
4
13
  DEFAULT_RESERVE_TOKENS,
@@ -12,7 +21,7 @@ import {
12
21
  projectWorkingSet,
13
22
  resolveWorkingSetPolicy,
14
23
  selectVisibleEntries
15
- } from "./chunk-WHJYKASB.js";
24
+ } from "./chunk-3MRC2YSQ.js";
16
25
  import {
17
26
  assistantSessionPayload,
18
27
  backendCacheVerdict,
@@ -45,86 +54,199 @@ import {
45
54
  toolNamesFromAgentState,
46
55
  toolResultSummary,
47
56
  toolSignatureFromState
48
- } from "./chunk-WJHBC77E.js";
49
- import {
50
- ShareDomainModule
51
- } from "./chunk-FOT2FX5J.js";
52
- import {
53
- bootstrapInputFromInitOptions,
54
- modelBootstrapGenerate,
55
- resolveBootstrapRoute
56
- } from "./chunk-EOOQZZDE.js";
57
- import "./chunk-J5Q24KAG.js";
57
+ } from "./chunk-N5XKWMDW.js";
58
58
  import {
59
59
  SchedulingDomainModule,
60
60
  createPromptsDomainModule,
61
61
  renderAgentCatalogSectionsFromSpecs
62
- } from "./chunk-EBEFWSGL.js";
62
+ } from "./chunk-3UUY7R3Z.js";
63
+ import {
64
+ flushRawStdout,
65
+ writeRawStdout
66
+ } from "./chunk-2VTFPG5O.js";
63
67
  import {
64
68
  SafetyDomainModule
65
- } from "./chunk-J7PIKKWC.js";
69
+ } from "./chunk-WXCJ7VME.js";
66
70
  import {
67
71
  LifecycleDomainModule,
68
72
  describeUpgradeNotice
69
- } from "./chunk-JTSEDYVQ.js";
73
+ } from "./chunk-DG4M6ZUE.js";
70
74
  import {
71
75
  ensureClioState,
72
76
  takeUpgradeNotice
73
- } from "./chunk-3HAPLH5M.js";
77
+ } from "./chunk-T3Z6VAAF.js";
74
78
  import {
75
79
  ConfigDomainModule,
76
80
  createConfigDomainModule,
77
81
  loadDomains
78
- } from "./chunk-BMWK7ZIZ.js";
82
+ } from "./chunk-465CC7FK.js";
83
+ import {
84
+ discoverDeclaredChecks
85
+ } from "./chunk-P3JGPQFL.js";
86
+ import {
87
+ buildRecallFields,
88
+ recallErrorMessage,
89
+ recallParentTurnId,
90
+ recallableRefListing,
91
+ resolveRecall
92
+ } from "./chunk-MV2VUEJC.js";
93
+ import {
94
+ foldWorkingSet
95
+ } from "./chunk-TZSKNMZG.js";
96
+ import {
97
+ classifyLibraryRequirements,
98
+ createResourcesDomainModule,
99
+ discoverLibrary,
100
+ installLibraryPlan,
101
+ libraryEntryInstalled,
102
+ libraryEntryPin,
103
+ libraryEntryRef,
104
+ libraryInstallPath,
105
+ planLibraryInstall
106
+ } from "./chunk-PZ4I4JE2.js";
107
+ import {
108
+ AgentsDomainModule
109
+ } from "./chunk-YSEHGPCT.js";
110
+ import "./chunk-HCBCAYZU.js";
111
+ import "./chunk-DR52UMZW.js";
112
+ import {
113
+ MARKETPLACE_UNCONFIGURED,
114
+ discoverMarketplaceSkills,
115
+ getMarketplaceSkills,
116
+ installSkill,
117
+ modelVisibleSkills,
118
+ parseSkillCommand
119
+ } from "./chunk-AD7Y7STJ.js";
120
+ import "./chunk-AMKHQW3C.js";
79
121
  import {
80
122
  compileScoutTransition,
81
123
  createDispatchRunEventRegistry
82
- } from "./chunk-AB4XIIVB.js";
124
+ } from "./chunk-YKOFT37S.js";
83
125
  import {
84
126
  monitorToolSurface
85
- } from "./chunk-FJ3H4MN5.js";
127
+ } from "./chunk-IHKBWSXF.js";
86
128
  import {
87
129
  COST_NOT_MEASURED,
88
130
  ObservabilityDomainModule,
89
131
  aggregateCostAmounts,
90
132
  costAggregateForAmount,
91
133
  formatCostAggregate,
92
- readAccountabilitySummary
93
- } from "./chunk-5UJ6ECTS.js";
134
+ readAccountabilitySummary,
135
+ recordBackgroundMemoryStep
136
+ } from "./chunk-5PVQ4SRS.js";
94
137
  import {
95
138
  appendOutOfTurnUsageRow
96
- } from "./chunk-GWS3VEIW.js";
97
- import "./chunk-HFSBBKSQ.js";
98
- import "./chunk-VREKEFLL.js";
139
+ } from "./chunk-FWDFM5ZU.js";
140
+ import "./chunk-YW7UVM5V.js";
141
+ import "./chunk-D73KXYPF.js";
99
142
  import {
100
143
  steerToolSurface
101
- } from "./chunk-WEH5XRJQ.js";
144
+ } from "./chunk-WIE7ZOSW.js";
145
+ import "./chunk-FALJGAWU.js";
102
146
  import {
103
- flushRawStdout,
104
- writeRawStdout
105
- } from "./chunk-2VTFPG5O.js";
106
- import "./chunk-YD734TPH.js";
147
+ ClioEditor,
148
+ CombinedAutocompleteProvider,
149
+ Container,
150
+ DEFAULT_SELECT_THEME,
151
+ FILTER_HINT,
152
+ FocusBox,
153
+ GLYPH,
154
+ Input,
155
+ MUTATION_PREVIEW_KEY,
156
+ Markdown,
157
+ Marked,
158
+ SGR_DIM,
159
+ SGR_RESET,
160
+ ScrollView,
161
+ SelectList,
162
+ Text,
163
+ VStack,
164
+ abbreviateModelId,
165
+ barSep,
166
+ brandMark,
167
+ buildHint,
168
+ buildResponsiveHint,
169
+ clioError,
170
+ clioTheme,
171
+ collapseHomePath,
172
+ createAgentProgress,
173
+ createKeybindingManager,
174
+ createProcessInteractiveShell,
175
+ detectPlatformKeybindingWarnings,
176
+ detectTerminalKeySupport,
177
+ dotSep,
178
+ fgSequence,
179
+ fitHintEntries,
180
+ fitUnits,
181
+ formatCompactMs,
182
+ formatContextPercent,
183
+ formatInvalidKeybindingNotice,
184
+ formatPlatformKeybindingNotice,
185
+ formatRuntimeResolutionDiagnostic,
186
+ formatTargetLabel,
187
+ frame,
188
+ fuzzyFilter,
189
+ getActiveRenderTrace,
190
+ getKeybindings,
191
+ innerDivider,
192
+ isClioToken,
193
+ isKeyRelease,
194
+ joinChips,
195
+ joinSections,
196
+ listGroupHeader,
197
+ markdownTheme,
198
+ matchesKey,
199
+ padAnsi,
200
+ paintHex,
201
+ permissionHintEntries,
202
+ rule,
203
+ runtimeResolutionDiagnosticLine,
204
+ screenTitle,
205
+ sectionTag,
206
+ selectListTheme,
207
+ showClioOverlayFrame,
208
+ spinnerFrame,
209
+ stripTerminalSequences,
210
+ truncateToWidth,
211
+ validateKeybindings,
212
+ visibleWidth,
213
+ wrapTextWithAnsi,
214
+ writeInputWedgeDump
215
+ } from "./chunk-NNNWO6F2.js";
216
+ import {
217
+ getTerminationCoordinator
218
+ } from "./chunk-BVDVID7E.js";
107
219
  import {
108
220
  createContextDomainModule,
109
221
  loadProjectClioMd
110
- } from "./chunk-4DWFMQDR.js";
222
+ } from "./chunk-HJB5IUKP.js";
111
223
  import "./chunk-LCGCVYZ4.js";
112
224
  import {
113
225
  renderCodewikiDigest
114
- } from "./chunk-5WIGXA4T.js";
226
+ } from "./chunk-47CMYGET.js";
115
227
  import {
116
228
  buildMemoryPromptSection,
117
229
  canonicalMemoryRepositoryIdentity,
118
230
  createTaskMemoryTrace,
119
231
  describeTaskMemoryActivity,
232
+ formatTaskMemorySpend,
120
233
  loadMemoryRecordsSync,
234
+ proposeInjectedTaskMemory,
121
235
  proposeMemoryPromotion,
236
+ readTaskMemorySpendSummary,
122
237
  renderTaskMemoryHandoffSource,
123
238
  seedTaskMemoryFromNewestHandoff,
124
239
  taskMemoryBankSize,
125
240
  taskMemoryHandoffSeedOffer,
126
241
  taskMemoryTracePath
127
- } from "./chunk-6M7VS3J3.js";
242
+ } from "./chunk-5T7RBWN2.js";
243
+ import {
244
+ listWikiPages,
245
+ wikiCompleteness,
246
+ wikiStaleness,
247
+ wikiStalenessAsync
248
+ } from "./chunk-NDINPTJ4.js";
249
+ import "./chunk-MXHC5QYU.js";
128
250
  import {
129
251
  ACP_MAX_CHUNK_BYTES,
130
252
  ACP_MAX_RAW_RECORD_BYTES,
@@ -137,6 +259,7 @@ import {
137
259
  AcpTimeoutError,
138
260
  WORKER_OUTPUT_MAX_BYTES,
139
261
  acpErrorMessage,
262
+ capacityLeaseUsage,
140
263
  createDispatchDomainModule,
141
264
  createRunReceiptQuality,
142
265
  createStdioServerTransport,
@@ -148,8 +271,18 @@ import {
148
271
  openLedger,
149
272
  protectedResidencyModels,
150
273
  readGateDecisionArtifacts,
151
- readPendingGateDecisions
152
- } from "./chunk-UUANF5CR.js";
274
+ readPendingGateDecisions,
275
+ renderDispatchReviewerTask
276
+ } from "./chunk-TEO2TLVN.js";
277
+ import {
278
+ formatTrustSummaryLine,
279
+ inspectRunReceiptTrustStatus,
280
+ isReceiptIntegrity,
281
+ retiredReceiptIntegrity,
282
+ retiredReceiptIntegrityReason,
283
+ summarizeTrustStatus,
284
+ verifyReceiptIntegrity
285
+ } from "./chunk-MLOK6ZOS.js";
153
286
  import {
154
287
  SessionDomainModule,
155
288
  addResponseModelIdObservationCount,
@@ -163,81 +296,28 @@ import {
163
296
  readAuditRows,
164
297
  responseModelIdObservationCountsLabel,
165
298
  responseModelIdObservationFromRecord
166
- } from "./chunk-6TUKSZVF.js";
299
+ } from "./chunk-LXPJXFM5.js";
167
300
  import {
301
+ describeWriteBoundaryAttributionDowngrade,
168
302
  gitCheckoutRoot,
169
303
  isGitRepository,
170
304
  preflightWriteBoundaries,
171
305
  recoverCleanupReadyCompeteGroups
172
- } from "./chunk-KZ2H5X4G.js";
306
+ } from "./chunk-ECUO3KDP.js";
173
307
  import {
308
+ bindExecutionPlanEndpoints,
174
309
  compileFleetExecutionPlan,
175
310
  requireAgentSteps
176
- } from "./chunk-M4AKACEO.js";
311
+ } from "./chunk-HKO36JWF.js";
177
312
  import {
178
313
  parseRigorOverride,
179
314
  resolveRigor
180
315
  } from "./chunk-RVG5JXAL.js";
181
316
  import {
182
- isReceiptIntegrity,
183
- verifyReceiptIntegrity
184
- } from "./chunk-ZGH7FGS5.js";
185
- import "./chunk-TSHXZTOQ.js";
186
- import {
187
- shellQuote
188
- } from "./chunk-TXOTCRLG.js";
189
- import {
190
- emptyWorkspaceSnapshot,
191
- probeGitStatusAsync,
192
- probeWorkspaceAsync
193
- } from "./chunk-HVDIIIQW.js";
194
- import {
195
- discoverDeclaredChecks
196
- } from "./chunk-PD3MESLB.js";
197
- import {
198
- listWikiPages,
199
- wikiCompleteness,
200
- wikiStaleness,
201
- wikiStalenessAsync
202
- } from "./chunk-NDINPTJ4.js";
203
- import "./chunk-MVVUPGPW.js";
204
- import {
205
- buildRecallFields,
206
- recallErrorMessage,
207
- recallParentTurnId,
208
- recallableRefListing,
209
- resolveRecall
210
- } from "./chunk-ZZMN5OM4.js";
211
- import {
212
- foldWorkingSet
213
- } from "./chunk-TZSKNMZG.js";
214
- import {
215
- classifyLibraryRequirements,
216
- createResourcesDomainModule,
217
- discoverLibrary,
218
- installLibraryPlan,
219
- libraryEntryInstalled,
220
- libraryEntryPin,
221
- libraryEntryRef,
222
- libraryInstallPath,
223
- planLibraryInstall
224
- } from "./chunk-THKY7CD7.js";
225
- import {
226
- AgentsDomainModule
227
- } from "./chunk-UVDSQ6LW.js";
228
- import "./chunk-DR52UMZW.js";
229
- import {
230
- MARKETPLACE_UNCONFIGURED,
231
- discoverMarketplaceSkills,
232
- getMarketplaceSkills,
233
- installSkill,
234
- modelVisibleSkills,
235
- parseSkillCommand
236
- } from "./chunk-C4JBQ5SR.js";
237
- import "./chunk-2SFS6XQE.js";
238
- import {
239
- ExtensionsDomainModule
240
- } from "./chunk-ZWLZP4ZT.js";
317
+ foldPromptCacheTelemetry,
318
+ hasPromptCacheTelemetry,
319
+ uncachedPrefillTokens
320
+ } from "./chunk-3DPEIQKN.js";
241
321
  import {
242
322
  filterEntriesToActivePath
243
323
  } from "./chunk-W6GROXXM.js";
@@ -250,7 +330,21 @@ import {
250
330
  renderFleetPrompt,
251
331
  validateFleetCommands,
252
332
  validateFleetGraph
253
- } from "./chunk-KCMKRQX4.js";
333
+ } from "./chunk-HPCTNZM2.js";
334
+ import "./chunk-RKKLTLYB.js";
335
+ import {
336
+ ExtensionsDomainModule
337
+ } from "./chunk-5QKCQQ3E.js";
338
+ import "./chunk-JVCV3ICN.js";
339
+ import "./chunk-5HFBWUMU.js";
340
+ import {
341
+ shellQuote
342
+ } from "./chunk-TXOTCRLG.js";
343
+ import {
344
+ emptyWorkspaceSnapshot,
345
+ probeGitStatusAsync,
346
+ probeWorkspaceAsync
347
+ } from "./chunk-HVDIIIQW.js";
254
348
  import {
255
349
  formatBootTrace,
256
350
  traceBoot
@@ -258,6 +352,7 @@ import {
258
352
  import {
259
353
  ASK_USER_OTHER_LABEL,
260
354
  INTERACTIVE_LOOP_BLOCK_BUDGET,
355
+ applyEditsToNormalizedContent,
261
356
  askAxis,
262
357
  askUserExposure,
263
358
  assertRegisteredBuiltinTools,
@@ -272,16 +367,20 @@ import {
272
367
  decisionFactsForPermission,
273
368
  diffWords,
274
369
  finalizeAskUserInterviewForHost,
370
+ generateDiffString,
275
371
  lazyTool,
372
+ normalizeToLF,
276
373
  patchProviderThinkingPayload,
374
+ patchResponseSchemaPayloadForDialect,
277
375
  patchToolChoiceNamedPayload,
278
376
  patchToolChoiceNonePayload,
279
377
  readOrchTurnToolCallBudget,
280
378
  registerCoreTools,
281
379
  resolveFdBinary,
282
380
  resolveSessionTools,
283
- sanitizeLockedSynthesisMessage
284
- } from "./chunk-QCTRSGHQ.js";
381
+ sanitizeLockedSynthesisMessage,
382
+ stripBom
383
+ } from "./chunk-R7LNVMCS.js";
285
384
  import {
286
385
  HEADLESS_PERMISSION_DENIED_REASON
287
386
  } from "./chunk-K7VKOLQQ.js";
@@ -289,6 +388,7 @@ import {
289
388
  MIDDLEWARE_HOOK_TEXT_MAX_CHARS,
290
389
  MiddlewareDomainModule,
291
390
  WATCHDOG_TASK,
391
+ announceMemoryStepEndpoint,
292
392
  createDetachedDispatchNudgeRegistration,
293
393
  createHookReceiptLog,
294
394
  createMemoryInterventionRegistration,
@@ -303,9 +403,12 @@ import {
303
403
  openDetachedBatchViews,
304
404
  watchdogBriefing,
305
405
  writeMiddlewareDiagnosticToStderr
306
- } from "./chunk-XEGB6BCN.js";
307
- import "./chunk-IR4CFBFN.js";
406
+ } from "./chunk-GAYUJ7LE.js";
407
+ import "./chunk-HAY4ZE2P.js";
308
408
  import "./chunk-UOV2BYIW.js";
409
+ import "./chunk-CA42X6KT.js";
410
+ import "./chunk-OEDBCISO.js";
411
+ import "./chunk-5DQRIYDZ.js";
309
412
  import {
310
413
  DISPATCH_PLAN_PREPARATION_ERROR_ARGUMENT,
311
414
  RESOLVED_DISPATCH_PLAN_ARGUMENT,
@@ -317,11 +420,14 @@ import {
317
420
  stringArg,
318
421
  timeoutMsArg,
319
422
  withResolvedDispatchPlan
320
- } from "./chunk-EELBMBT6.js";
423
+ } from "./chunk-VKBMFOYV.js";
321
424
  import {
322
425
  TaskMemoryBank,
323
426
  createTaskMemoryTelemetrySink
324
- } from "./chunk-WHGPSPT5.js";
427
+ } from "./chunk-O6I4CIEU.js";
428
+ import {
429
+ escapeRegExp
430
+ } from "./chunk-VG7TBQIY.js";
325
431
  import {
326
432
  COUNCIL_JUDGE_PROMPT,
327
433
  DISPATCH_BRIEFING_MAX_BYTES,
@@ -338,66 +444,61 @@ import {
338
444
  formatBudgetReasons,
339
445
  formatBudgetRequest,
340
446
  formatEffectiveBudget,
447
+ isResponseSchemaRejection,
341
448
  isToolProfileName,
342
449
  normalizeDispatchIntent,
343
450
  redactSecretString,
344
451
  redactToolArgs,
452
+ renderCouncilVoteMemberTask,
453
+ responseSchemaDialectFor,
345
454
  runBashCommand,
346
455
  runKindSupportsLiveSteering,
347
456
  sanitizeCallTargetText,
457
+ sanitizeMultilineDisplayText,
348
458
  toolPresentationPolicy
349
- } from "./chunk-CEYBNUGC.js";
459
+ } from "./chunk-4H6ULJ3H.js";
460
+ import {
461
+ defaultRoutingIntent,
462
+ sameRouteIdentity
463
+ } from "./chunk-VPTUJU4P.js";
350
464
  import {
351
465
  createTaskBoardStore,
352
466
  foldSessionTaskHistory,
353
467
  foldTaskBoard,
354
468
  taskBoardCounts
355
- } from "./chunk-5FR74PWO.js";
356
- import {
357
- DEFAULT_RECENT_ENTRY_LIMIT,
358
- assessFinishContract
359
- } from "./chunk-OBMAI2DP.js";
360
- import {
361
- defaultRoutingIntent,
362
- sameRouteIdentity
363
- } from "./chunk-5C77SEEY.js";
469
+ } from "./chunk-2JDWVJND.js";
364
470
  import {
365
471
  agentRoleFactsResolver,
366
472
  gateDeciderAgentId,
367
473
  requestExecutionRole,
368
474
  withAttemptRole
369
- } from "./chunk-UND3GU2L.js";
370
- import "./chunk-CMZWFGD2.js";
371
- import "./chunk-I4HZDVNP.js";
372
- import "./chunk-ZI647VB5.js";
373
- import "./chunk-JNXPYBB4.js";
374
- import "./chunk-GH5622CP.js";
375
- import "./chunk-XN3L4EYL.js";
475
+ } from "./chunk-H7IXIC72.js";
376
476
  import {
377
- escapeRegExp
378
- } from "./chunk-VG7TBQIY.js";
379
- import "./chunk-OQE5J4C6.js";
380
- import "./chunk-SPULKLCF.js";
381
- import {
382
- SKILL_SUGGESTION_PREFIX,
383
- isSkillActivation,
384
- skillActivationFromToolDetails
385
- } from "./chunk-GOXNB3AO.js";
477
+ DEFAULT_RECENT_ENTRY_LIMIT,
478
+ assessFinishContract
479
+ } from "./chunk-7C6RYZGQ.js";
480
+ import "./chunk-N3PBVRTZ.js";
481
+ import "./chunk-A2NJGIB3.js";
386
482
  import {
387
- DEFAULT_AUTONOMY_LEVEL
388
- } from "./chunk-HWUFFB6L.js";
483
+ resolveToCwd
484
+ } from "./chunk-OQE5J4C6.js";
389
485
  import {
390
486
  parseCouncilReport,
391
487
  parseOracleResult,
392
488
  parseScoutResult,
393
489
  parseVerifierResult,
394
490
  resultContractSourceId
395
- } from "./chunk-DJNLUABN.js";
396
- import "./chunk-AOCYTWAV.js";
491
+ } from "./chunk-S4COXYBG.js";
397
492
  import {
398
493
  CLIO_PROJECT_DIR,
399
494
  toolMutationPaths
400
495
  } from "./chunk-MV3K5QF2.js";
496
+ import {
497
+ DEFAULT_AUTONOMY_LEVEL,
498
+ SKILL_SUGGESTION_PREFIX,
499
+ isSkillActivation,
500
+ skillActivationFromToolDetails
501
+ } from "./chunk-RAPCMZL4.js";
401
502
  import {
402
503
  VERIFICATION_SCRIPT_FAMILY_HINT
403
504
  } from "./chunk-UL3WSD3F.js";
@@ -411,6 +512,9 @@ import {
411
512
  } from "./chunk-OZNBF4L3.js";
412
513
  import "./chunk-4BJ5BYCE.js";
413
514
  import "./chunk-ECH6PKUQ.js";
515
+ import "./chunk-CMZWFGD2.js";
516
+ import "./chunk-I4HZDVNP.js";
517
+ import "./chunk-ZI647VB5.js";
414
518
  import {
415
519
  truncateUtf8
416
520
  } from "./chunk-6XLNIQDB.js";
@@ -424,13 +528,14 @@ import {
424
528
  incompleteInstallationAdvice
425
529
  } from "./chunk-65DEGPJ6.js";
426
530
  import "./chunk-M6L6IDJG.js";
427
- import "./chunk-XAKHZX5N.js";
428
531
  import "./chunk-UUVG37B4.js";
429
532
  import {
430
533
  readCodewiki,
431
534
  readCodewikiAsync
432
535
  } from "./chunk-LBMZMYH2.js";
536
+ import "./chunk-XAKHZX5N.js";
433
537
  import "./chunk-33YXPOE3.js";
538
+ import "./chunk-7CR24IG7.js";
434
539
  import {
435
540
  getVersionInfo
436
541
  } from "./chunk-XPLRXC72.js";
@@ -439,19 +544,20 @@ import {
439
544
  InteropDomainModule,
440
545
  delegationEntryForKind,
441
546
  renderProposalEntry
442
- } from "./chunk-SROCI7ZU.js";
443
- import "./chunk-DOOEX22V.js";
547
+ } from "./chunk-QQ7EKM72.js";
548
+ import "./chunk-56KB5IJP.js";
444
549
  import {
445
550
  source_default
446
551
  } from "./chunk-5TSRNF4G.js";
447
552
  import {
448
- AGENT_ROLE_TOOLS_REQUIRED_REASON,
449
553
  ProvidersDomainModule,
450
554
  VALID_THINKING_LEVELS,
451
555
  applyModelCapabilityPatch,
556
+ canonicalEndpointKey,
557
+ endpointCapacitiesForStatuses,
558
+ endpointCapacityForStatus,
452
559
  firstRuntimeResolutionError,
453
- formatContextWindowSlots,
454
- getRuntimeRegistry,
560
+ foregroundStreamUsage,
455
561
  isDispatchEligibleRuntime,
456
562
  isOrchestratorEligibleRuntime,
457
563
  modelCandidatesForStatus,
@@ -459,28 +565,22 @@ import {
459
565
  modelResidencyForStatus,
460
566
  normalizeCostProvenance,
461
567
  refineRuntimeTargetWithModelHints,
462
- registerBuiltinRuntimes,
568
+ registerForegroundStream,
569
+ residencyTargetKey,
463
570
  resolveModelCapabilities,
464
571
  resolveModelReference,
465
572
  resolveModelRuntimeCapabilitiesForProviders,
466
- resolveProviderReference,
467
573
  resolveReservedOutputTokens,
468
574
  resolveRuntimeTarget,
469
575
  runtimeResolutionWarningsBesideThinkingNotice,
470
576
  runtimeTargetSnapshot,
471
577
  setProtectedModelsProvider,
472
- supportsAgentRoleTools,
473
578
  thinkingLevelChoiceLabel,
474
579
  thinkingLevelFromChoiceLabel,
475
580
  withRunOverrides
476
- } from "./chunk-VQNODYQ4.js";
581
+ } from "./chunk-MIX5N5AC.js";
477
582
  import "./chunk-CFGTUFWB.js";
478
- import {
479
- targetRequiresAuth
480
- } from "./chunk-JRIO5UD2.js";
481
- import {
482
- interopAgentKind
483
- } from "./chunk-IHXBNWMM.js";
583
+ import "./chunk-LU7P4LHA.js";
484
584
  import {
485
585
  AutoCompactionTrigger,
486
586
  DEFAULT_COMPACTION_THRESHOLD,
@@ -492,13 +592,21 @@ import {
492
592
  contextUsageSnapshot,
493
593
  estimateAgentContextBreakdown,
494
594
  estimateAgentContextTokens,
595
+ estimateAgentMessageTokens,
495
596
  estimateReasoningTextTokens,
496
597
  extractReasoningTokens,
497
598
  getLatestContextSnapshot,
599
+ lastLoadedContextWindow,
498
600
  reconcileSnapshot,
499
601
  shouldCompact,
500
602
  snapshotInputTokens
501
- } from "./chunk-GEYXPTRF.js";
603
+ } from "./chunk-AEYBF3TB.js";
604
+ import {
605
+ interopAgentKind
606
+ } from "./chunk-IHXBNWMM.js";
607
+ import {
608
+ setGitCommitAttributionEnabled
609
+ } from "./chunk-B5CSFE7B.js";
502
610
  import {
503
611
  bindAgentProfileInSettings,
504
612
  readSettings,
@@ -507,14 +615,18 @@ import {
507
615
  setFleetProfileInSettings,
508
616
  updateSettings,
509
617
  useTargetInSettings
510
- } from "./chunk-UHXRNZ2J.js";
618
+ } from "./chunk-PNY46YEY.js";
511
619
  import {
512
- DEFAULT_DELEGATION_PERMISSION_TIMEOUT_MS,
513
- DEFAULT_SETTINGS,
514
- THINKING_LEVELS
515
- } from "./chunk-4DGYLA73.js";
516
- import "./chunk-LL4KHSZI.js";
517
- import "./chunk-SST6Z5JA.js";
620
+ MAX_TIMER_DELAY_MS,
621
+ rawDurationMs
622
+ } from "./chunk-FQ4SKYE4.js";
623
+ import {
624
+ getSharedBus
625
+ } from "./chunk-ZGVHUX3M.js";
626
+ import {
627
+ BusChannels,
628
+ isRunAbortedPayload
629
+ } from "./chunk-RKRLDWD3.js";
518
630
  import {
519
631
  atomicWrite,
520
632
  cwdHash,
@@ -522,123 +634,60 @@ import {
522
634
  readSessionTailTurns,
523
635
  sessionCurrentPath,
524
636
  sessionPaths
525
- } from "./chunk-FO5ZOVUY.js";
526
- import "./chunk-R346GLFC.js";
637
+ } from "./chunk-KV2AOLDF.js";
638
+ import "./chunk-6EJMN2Y3.js";
527
639
  import {
528
- setGitCommitAttributionEnabled
529
- } from "./chunk-D4MDIG46.js";
640
+ readClioVersion,
641
+ readPiMonoVersion
642
+ } from "./chunk-IWHMRKLL.js";
530
643
  import {
531
- MAX_TIMER_DELAY_MS,
532
- rawDurationMs
533
- } from "./chunk-FQ4SKYE4.js";
644
+ formatContextWindowSlots,
645
+ registerBuiltinRuntimes
646
+ } from "./chunk-JEQQR47K.js";
647
+ import {
648
+ DEFAULT_DELEGATION_PERMISSION_TIMEOUT_MS,
649
+ DEFAULT_SETTINGS,
650
+ THINKING_LEVELS
651
+ } from "./chunk-XDOQXGFO.js";
652
+ import "./chunk-LL4KHSZI.js";
534
653
  import {
535
654
  configureGuardrails
536
655
  } from "./chunk-4ZG3XFUR.js";
656
+ import {
657
+ resolveProviderReference
658
+ } from "./chunk-774ILSRL.js";
659
+ import {
660
+ targetRequiresAuth
661
+ } from "./chunk-EQ63NRB7.js";
662
+ import "./chunk-SST6Z5JA.js";
537
663
  import "./chunk-IKCO5N3L.js";
538
664
  import "./chunk-3I7MS7N2.js";
539
- import {
540
- StringEnum,
541
- cleanupEngineSessionResources,
542
- completeEngineText,
543
- isEngineRetryableAssistantError,
544
- stream
545
- } from "./chunk-FCSXB6T2.js";
546
665
  import "./chunk-APJ265NV.js";
547
- import "./chunk-YXLYO42X.js";
548
666
  import {
549
667
  clioConfigDir,
550
668
  clioDataDir,
551
669
  clioStateDir,
552
670
  stateRootRemoved
553
671
  } from "./chunk-BNAZZHFG.js";
554
- import "./chunk-6EJMN2Y3.js";
555
672
  import {
556
673
  safeResourceWrite
557
674
  } from "./chunk-WEPFGWHJ.js";
558
675
  import {
559
- ClioEditor,
560
- CombinedAutocompleteProvider,
561
- Container,
562
- DEFAULT_SELECT_THEME,
563
- FILTER_HINT,
564
- FocusBox,
565
- GLYPH,
566
- Input,
567
- Markdown,
568
- Marked,
569
- SGR_DIM,
570
- SGR_RESET,
571
- ScrollView,
572
- SelectList,
573
- Text,
574
- VStack,
575
- abbreviateModelId,
576
- barSep,
577
- brandMark,
578
- buildHint,
579
- buildResponsiveHint,
580
- clioError,
581
- clioTheme,
582
- collapseHomePath,
583
- createAgentProgress,
584
- createKeybindingManager,
585
- createProcessInteractiveShell,
586
- detectPlatformKeybindingWarnings,
587
- detectTerminalKeySupport,
588
- dotSep,
589
- fgSequence,
590
- fitHintEntries,
591
- fitUnits,
592
- formatCompactMs,
593
- formatContextPercent,
594
- formatInvalidKeybindingNotice,
595
- formatPlatformKeybindingNotice,
596
- formatRuntimeResolutionDiagnostic,
597
- formatTargetLabel,
598
- frame,
599
- fuzzyFilter,
600
- getActiveRenderTrace,
601
- getKeybindings,
602
- innerDivider,
603
- isClioToken,
604
- isKeyRelease,
605
- joinChips,
606
- joinSections,
607
- listGroupHeader,
608
- markdownTheme,
609
- matchesKey,
610
- padAnsi,
611
- paintHex,
612
- permissionHintEntries,
613
- rule,
614
- runtimeResolutionDiagnosticLine,
615
- screenTitle,
616
- sectionTag,
617
- selectListTheme,
618
- showClioOverlayFrame,
619
- spinnerFrame,
620
- stripTerminalSequences,
621
- truncateToWidth,
622
- validateKeybindings,
623
- visibleWidth,
624
- wrapTextWithAnsi
625
- } from "./chunk-5C3AQNDW.js";
626
- import {
627
- getTerminationCoordinator
628
- } from "./chunk-X2KV5FXT.js";
676
+ getRuntimeRegistry
677
+ } from "./chunk-NUGM5KR6.js";
629
678
  import {
630
- getSharedBus
631
- } from "./chunk-ZGVHUX3M.js";
632
- import {
633
- BusChannels,
634
- isRunAbortedPayload
635
- } from "./chunk-OB5HIGJY.js";
636
- import "./chunk-JVCV3ICN.js";
637
- import "./chunk-7CR24IG7.js";
679
+ AGENT_ROLE_TOOLS_REQUIRED_REASON,
680
+ supportsAgentRoleTools
681
+ } from "./chunk-VO2LKSTM.js";
638
682
  import {
639
- readClioVersion,
640
- readPiMonoVersion
641
- } from "./chunk-IWHMRKLL.js";
683
+ StringEnum,
684
+ cleanupEngineSessionResources,
685
+ completeEngineText,
686
+ isEngineRetryableAssistantError,
687
+ stream,
688
+ streamSimple
689
+ } from "./chunk-UOSL25KY.js";
690
+ import "./chunk-YXLYO42X.js";
642
691
  import {
643
692
  init_esm_shims
644
693
  } from "./chunk-3R73A4XB.js";
@@ -3242,7 +3291,8 @@ function safeProbeReason(providers, status) {
3242
3291
  } catch {
3243
3292
  return "not-configured";
3244
3293
  }
3245
- return status.available && status.health.status === "healthy" ? null : "unreachable";
3294
+ const reachable = status.health.status === "healthy" || status.health.status === "degraded";
3295
+ return status.available && reachable ? null : "unreachable";
3246
3296
  }
3247
3297
  function installPermissionBridge(input) {
3248
3298
  if (!input.toolRegistry) return { unregister: () => {
@@ -4594,10 +4644,29 @@ async function runSideQuestion(input) {
4594
4644
  const { question, ...rest } = input;
4595
4645
  return runOutOfTurnRound({ ...rest, systemPrompt: SIDE_QUESTION_SYSTEM_PROMPT, userText: question });
4596
4646
  }
4647
+ function schemaBindingFor(input) {
4648
+ if (input.responseSchema === void 0 || input.runtimeId === void 0) return null;
4649
+ const dialect = responseSchemaDialectFor(input.runtimeId);
4650
+ return dialect === null ? null : { dialect, ...input.responseSchema };
4651
+ }
4597
4652
  async function runOutOfTurnRound(input) {
4653
+ const binding = schemaBindingFor(input);
4654
+ if (binding === null) return runRound(input, null);
4655
+ try {
4656
+ return await runRound(input, binding);
4657
+ } catch (error) {
4658
+ if (input.signal?.aborted === true) throw error;
4659
+ if (!isResponseSchemaRejection(error instanceof Error ? error.message : String(error))) throw error;
4660
+ return runRound(input, null);
4661
+ }
4662
+ }
4663
+ async function runRound(input, binding) {
4598
4664
  const options = { maxTokens: input.maxTokens ?? SIDE_QUESTION_MAX_TOKENS };
4599
4665
  if (input.apiKey !== void 0) options.apiKey = input.apiKey;
4600
4666
  if (input.signal !== void 0) options.signal = input.signal;
4667
+ if (binding !== null) {
4668
+ options.onPayload = (payload) => patchResponseSchemaPayloadForDialect(payload, binding.dialect, binding.schema, binding.name);
4669
+ }
4601
4670
  const context = {
4602
4671
  systemPrompt: input.systemPrompt,
4603
4672
  messages: [
@@ -4647,13 +4716,31 @@ var HANDOFF_SYSTEM_PROMPT = [
4647
4716
  `The object must match this JSON schema exactly: ${JSON.stringify(HANDOFF_RESPONSE_SCHEMA)}`
4648
4717
  ].join(" ");
4649
4718
  var HANDOFF_MAX_TOKENS = 4096;
4719
+ var HANDOFF_SCHEMA_NAME = "handoff_record";
4720
+ var HANDOFF_REPAIR_QUOTE_CHARS = 600;
4721
+ function repairText(goal, repair) {
4722
+ const quoted = repair.previous.slice(0, HANDOFF_REPAIR_QUOTE_CHARS);
4723
+ return [
4724
+ `The next session's goal is: ${goal}`,
4725
+ "",
4726
+ "Your previous answer could not be read as a handoff record.",
4727
+ `The parser said: ${repair.complaint}`,
4728
+ "This is what you returned, verbatim:",
4729
+ "---",
4730
+ quoted.length > 0 ? quoted : "(nothing)",
4731
+ "---",
4732
+ "Answer again with one JSON object matching the schema and nothing else.",
4733
+ "No prose before it, no prose after it, no code fence."
4734
+ ].join("\n");
4735
+ }
4650
4736
  async function runHandoffRound(input) {
4651
- const { goal, ...rest } = input;
4737
+ const { goal, repair, ...rest } = input;
4652
4738
  return runOutOfTurnRound({
4653
4739
  ...rest,
4654
4740
  maxTokens: input.maxTokens ?? HANDOFF_MAX_TOKENS,
4655
4741
  systemPrompt: HANDOFF_SYSTEM_PROMPT,
4656
- userText: `The next session's goal is: ${goal}
4742
+ responseSchema: { name: HANDOFF_SCHEMA_NAME, schema: HANDOFF_RESPONSE_SCHEMA },
4743
+ userText: repair ? repairText(goal, repair) : `The next session's goal is: ${goal}
4657
4744
 
4658
4745
  Extract the handoff record for that goal now.`
4659
4746
  });
@@ -4860,6 +4947,7 @@ function maskStaleObservations(entries, excludeLastTurns) {
4860
4947
  init_esm_shims();
4861
4948
  import { appendFileSync, existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
4862
4949
  import { dirname, join as join4 } from "node:path";
4950
+ var PROMPT_MANIFEST_VERSION = 2;
4863
4951
  var SHA256_HEX = /^[a-f0-9]{64}$/;
4864
4952
  function isCanonicalUtcTimestamp(value) {
4865
4953
  if (typeof value !== "string") return false;
@@ -4885,9 +4973,18 @@ function isProjectPreloadClass(value) {
4885
4973
  if (!isRecord6(value)) return false;
4886
4974
  return (value.mode === "full" || value.mode === "synopsis" || value.mode === "none") && isNonNegativeInteger(value.chars) && isNonNegativeInteger(value.lines) && (value.reason === null || value.reason === "size" || value.reason === "lines" || value.reason === "no-clio-md") && typeof value.nearLimit === "boolean" && typeof value.label === "string";
4887
4975
  }
4976
+ function isOptional(value, guard) {
4977
+ return value === void 0 || guard(value);
4978
+ }
4888
4979
  function isSessionPromptCompileRecord(value) {
4889
4980
  if (!isRecord6(value)) return false;
4890
- return isCanonicalUtcTimestamp(value.at) && (value.previousHash === null || isSha256(value.previousHash)) && isSha256(value.systemPromptHash) && isNonNegativeInteger(value.tokenEstimate) && (value.thinkingLevel === null || typeof value.thinkingLevel === "string") && (value.projectPreload === null || isProjectPreloadClass(value.projectPreload)) && Array.isArray(value.sections) && value.sections.every(isPromptManifestSection) && Array.isArray(value.fragments) && value.fragments.every(isPromptManifestFragment);
4981
+ return isOptional(value.version, isNonNegativeInteger) && isOptional(
4982
+ value.contextWindow,
4983
+ (candidate) => candidate === null ? true : isNonNegativeInteger(candidate)
4984
+ ) && isOptional(
4985
+ value.contextWindowSource,
4986
+ (candidate) => candidate === null ? true : typeof candidate === "string"
4987
+ ) && isCanonicalUtcTimestamp(value.at) && (value.previousHash === null || isSha256(value.previousHash)) && isSha256(value.systemPromptHash) && isNonNegativeInteger(value.tokenEstimate) && (value.thinkingLevel === null || typeof value.thinkingLevel === "string") && (value.projectPreload === null || isProjectPreloadClass(value.projectPreload)) && Array.isArray(value.sections) && value.sections.every(isPromptManifestSection) && Array.isArray(value.fragments) && value.fragments.every(isPromptManifestFragment);
4891
4988
  }
4892
4989
  function getPromptManifestFilePath(meta, stateDir) {
4893
4990
  const safeMeta = {
@@ -4935,6 +5032,9 @@ function readPromptCompileManifest(meta, stateDir) {
4935
5032
  };
4936
5033
  }
4937
5034
  }
5035
+ function readPromptCompileRecords(meta) {
5036
+ return readPromptCompileManifest(meta).records;
5037
+ }
4938
5038
 
4939
5039
  // src/interactive/model-session-replay.ts
4940
5040
  init_esm_shims();
@@ -5055,6 +5155,160 @@ function formatRetryStatus(status) {
5055
5155
  // src/interactive/renderers/tool-execution.ts
5056
5156
  init_esm_shims();
5057
5157
 
5158
+ // src/interactive/mutation-preview.ts
5159
+ init_esm_shims();
5160
+ import { createHash as createHash2 } from "node:crypto";
5161
+ import { readFileSync as readFileSync5 } from "node:fs";
5162
+ var MUTATION_PREVIEW_VISIBLE_ROWS = 16;
5163
+ var MUTATION_PREVIEW_MAX_CHARS = 262144;
5164
+ function canonicalJson(value) {
5165
+ if (value === null || value === void 0) return "null";
5166
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
5167
+ if (typeof value === "object") {
5168
+ const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
5169
+ return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
5170
+ }
5171
+ if (typeof value === "string") return JSON.stringify(value);
5172
+ if (typeof value === "number") return Number.isFinite(value) ? JSON.stringify(value) : "null";
5173
+ if (typeof value === "boolean") return value ? "true" : "false";
5174
+ return "null";
5175
+ }
5176
+ function callArgumentsDigest(args) {
5177
+ return createHash2("sha256").update(canonicalJson(args ?? {}), "utf8").digest("hex").slice(0, 16);
5178
+ }
5179
+ function readEdits(value) {
5180
+ if (!Array.isArray(value)) return null;
5181
+ const edits = [];
5182
+ for (const entry of value) {
5183
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
5184
+ const record2 = entry;
5185
+ if (typeof record2.oldText !== "string" || typeof record2.newText !== "string") return null;
5186
+ edits.push({ oldText: record2.oldText, newText: record2.newText });
5187
+ }
5188
+ return edits;
5189
+ }
5190
+ function mutationFacts(tool, args) {
5191
+ if (!args || typeof args.path !== "string" || args.path.length === 0) return null;
5192
+ if (tool === ToolNames.Write) {
5193
+ if (typeof args.content !== "string") return null;
5194
+ return {
5195
+ kind: "write",
5196
+ bytes: Buffer.byteLength(args.content, "utf8"),
5197
+ replacements: 1,
5198
+ digest: callArgumentsDigest(args)
5199
+ };
5200
+ }
5201
+ if (tool === ToolNames.Edit) {
5202
+ const edits = readEdits(args.edits);
5203
+ if (edits === null || edits.length === 0) return null;
5204
+ const bytes = edits.reduce((total, edit) => total + Buffer.byteLength(edit.newText, "utf8"), 0);
5205
+ return { kind: "edit", bytes, replacements: edits.length, digest: callArgumentsDigest(args) };
5206
+ }
5207
+ return null;
5208
+ }
5209
+ function mutationFactsLine(facts) {
5210
+ const shape = facts.kind === "write" ? `write ${facts.bytes} B` : `edit ${facts.replacements} replacement${facts.replacements === 1 ? "" : "s"} \xB7 ${facts.bytes} B`;
5211
+ return `${shape} \xB7 sha256 ${facts.digest}`;
5212
+ }
5213
+ function numberedLines(text) {
5214
+ const raw = text.split("\n");
5215
+ const width = String(raw.length).length;
5216
+ return raw.map((line, index) => `${String(index + 1).padStart(width, " ")} ${line}`);
5217
+ }
5218
+ function boundedContent(content) {
5219
+ if (content.length <= MUTATION_PREVIEW_MAX_CHARS) return { text: content, withheld: 0 };
5220
+ return {
5221
+ text: content.slice(0, MUTATION_PREVIEW_MAX_CHARS),
5222
+ withheld: content.length - MUTATION_PREVIEW_MAX_CHARS
5223
+ };
5224
+ }
5225
+ function previewFrom(facts, heading, text, options = {}) {
5226
+ const clean = sanitizeMultilineDisplayText(text);
5227
+ const body = options.numbered ? numberedLines(clean.text) : clean.text.split("\n");
5228
+ if (options.trailer !== void 0) body.push(options.trailer);
5229
+ return {
5230
+ facts,
5231
+ heading,
5232
+ body,
5233
+ neutralized: clean.neutralized,
5234
+ tabsExpanded: clean.tabsExpanded
5235
+ };
5236
+ }
5237
+ function refusal(facts, heading, reason) {
5238
+ return { facts, heading, body: [reason], neutralized: false, tabsExpanded: false };
5239
+ }
5240
+ function replacementListing(edits) {
5241
+ const blocks = [];
5242
+ for (const [index, edit] of edits.entries()) {
5243
+ blocks.push(`@@ replacement ${index + 1} of ${edits.length}`);
5244
+ for (const line of normalizeToLF(edit.oldText).split("\n")) blocks.push(`- ${line}`);
5245
+ for (const line of normalizeToLF(edit.newText).split("\n")) blocks.push(`+ ${line}`);
5246
+ }
5247
+ return blocks.join("\n");
5248
+ }
5249
+ function editPreview(facts, path, edits, read) {
5250
+ let current;
5251
+ try {
5252
+ current = read(resolveToCwd(path));
5253
+ } catch (error) {
5254
+ const message = sanitizeCallTargetText(error instanceof Error ? error.message : String(error));
5255
+ return previewFrom(
5256
+ facts,
5257
+ `Requested replacements for ${sanitizeCallTargetText(path)} (the file could not be read: ${message})`,
5258
+ replacementListing(edits)
5259
+ );
5260
+ }
5261
+ try {
5262
+ const { text } = stripBom(current);
5263
+ const applied = applyEditsToNormalizedContent(normalizeToLF(text), edits, path);
5264
+ const diff = generateDiffString(applied.baseContent, applied.newContent);
5265
+ return previewFrom(facts, `Effective diff for ${sanitizeCallTargetText(path)}`, diff.diff);
5266
+ } catch (error) {
5267
+ const message = sanitizeCallTargetText(error instanceof Error ? error.message : String(error));
5268
+ return previewFrom(
5269
+ facts,
5270
+ `Requested replacements for ${sanitizeCallTargetText(path)} (they do not apply: ${message})`,
5271
+ replacementListing(edits)
5272
+ );
5273
+ }
5274
+ }
5275
+ function createMutationInspector(tool, args, facts, options = {}) {
5276
+ const read = options.readFile ?? ((path) => readFileSync5(path, "utf8"));
5277
+ return () => {
5278
+ const current = mutationFacts(tool, args);
5279
+ if (current === null || current.digest !== facts.digest) {
5280
+ return refusal(
5281
+ facts,
5282
+ "Preview unavailable",
5283
+ `These arguments no longer digest to sha256 ${facts.digest}. Deny this call rather than approving bytes that cannot be shown.`
5284
+ );
5285
+ }
5286
+ const path = typeof args?.path === "string" ? args.path : "";
5287
+ if (facts.kind === "write") {
5288
+ const content = typeof args?.content === "string" ? args.content : "";
5289
+ const bounded = boundedContent(content);
5290
+ return previewFrom(facts, `Proposed content for ${sanitizeCallTargetText(path)}`, bounded.text, {
5291
+ numbered: true,
5292
+ ...bounded.withheld > 0 ? { trailer: `\u2026 ${bounded.withheld} more characters not shown (preview capped at ${MUTATION_PREVIEW_MAX_CHARS})` } : {}
5293
+ });
5294
+ }
5295
+ const edits = readEdits(args?.edits) ?? [];
5296
+ return editPreview(facts, path, edits, read);
5297
+ };
5298
+ }
5299
+ function mutationPreviewWindow(lines, scroll, rows = MUTATION_PREVIEW_VISIBLE_ROWS) {
5300
+ const visible = Math.max(1, rows);
5301
+ const maxScroll = Math.max(0, lines.length - visible);
5302
+ const start = Math.max(0, Math.min(scroll, maxScroll));
5303
+ const window = lines.slice(start, start + visible);
5304
+ if (lines.length <= visible) return { window, position: null, maxScroll };
5305
+ return {
5306
+ window,
5307
+ position: `(${start + 1}-${start + window.length} of ${lines.length} lines)`,
5308
+ maxScroll
5309
+ };
5310
+ }
5311
+
5058
5312
  // src/interactive/renderers/diff.ts
5059
5313
  init_esm_shims();
5060
5314
  var ESC = String.fromCharCode(27);
@@ -5529,7 +5783,10 @@ function renderToolAwaitingApproval(call, width, view) {
5529
5783
  const facts = [
5530
5784
  ["action", view.actionClass],
5531
5785
  ["axis", axis],
5532
- ...view.target !== void 0 && view.target.length > 0 ? [["target", view.target]] : []
5786
+ ...view.target !== void 0 && view.target.length > 0 ? [["target", view.target]] : [],
5787
+ // Size and digest, never the mutation text: this row is the transcript,
5788
+ // which is written, replayed, and shared (issue #254).
5789
+ ...view.mutation !== void 0 ? [["mutation", mutationFactsLine(view.mutation)]] : []
5533
5790
  ];
5534
5791
  for (const [label, value] of facts) {
5535
5792
  lines.push(...indentAndWrap(`${dim(`${label} \xB7`)} ${value}`, width, false));
@@ -6565,12 +6822,12 @@ function toggledFold(effective) {
6565
6822
 
6566
6823
  // src/interactive/worker-receipts.ts
6567
6824
  init_esm_shims();
6568
- import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
6825
+ import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
6569
6826
  import { join as join6 } from "node:path";
6570
6827
 
6571
6828
  // src/interactive/view/artifacts.ts
6572
6829
  init_esm_shims();
6573
- import { createReadStream, readFileSync as readFileSync5, statSync } from "node:fs";
6830
+ import { createReadStream, readFileSync as readFileSync6, statSync } from "node:fs";
6574
6831
  import { readFile, realpath, stat } from "node:fs/promises";
6575
6832
  import { basename, isAbsolute as isAbsolute4, join as join5, relative as relative4, resolve as resolve3, sep } from "node:path";
6576
6833
 
@@ -6649,7 +6906,7 @@ var CONTEXT_CATEGORY_TOKEN = {
6649
6906
  project: "muted",
6650
6907
  messages: "accent",
6651
6908
  pending: "accentDeep",
6652
- reserve: "dim",
6909
+ reserve: "frame",
6653
6910
  free: "frame",
6654
6911
  streaming: "accent"
6655
6912
  };
@@ -7513,6 +7770,18 @@ function progressAnswerLines(theme6, progress, runId, contentWidth) {
7513
7770
  }
7514
7771
  return body.map((row2, index) => `${index === 0 ? cardKvKey(theme6, "answer") : " ".repeat(gutter)}${row2}`);
7515
7772
  }
7773
+ function trustCardLines(theme6, row2, contentWidth) {
7774
+ const gutter = CARD_KV_KEY_WIDTH + 1;
7775
+ const valueWidth = Math.max(1, contentWidth - gutter);
7776
+ const trust = row2.trust === void 0 ? theme6.fg("dim", isTerminalStatus(row2.status) ? "receipt not read back" : "not sealed yet") : theme6.fg(
7777
+ trustVerdictToken(row2.trust.verdict),
7778
+ `${trustVerdictGlyph(row2.trust.verdict)} ${row2.trust.verdict}; ${row2.trust.text}`
7779
+ );
7780
+ const host = row2.hostVerification === void 0 ? "" : ` \xB7 ${theme6.fg("muted", `host checks ${row2.hostVerification}`)}`;
7781
+ return wrapTextWithAnsi(`${trust}${host}`, valueWidth).map(
7782
+ (line, index) => `${index === 0 ? cardKvKey(theme6, "trust") : " ".repeat(gutter)}${line}`
7783
+ );
7784
+ }
7516
7785
  function renderDispatchCard(row2, width, evidence, options = {}) {
7517
7786
  const theme6 = clioTheme();
7518
7787
  const contentWidth = Math.max(0, width - 4);
@@ -7544,13 +7813,13 @@ function renderDispatchCard(row2, width, evidence, options = {}) {
7544
7813
  const statusUnits = [
7545
7814
  statusStr,
7546
7815
  theme6.fg("muted", `node ${row2.node ?? "local"}`),
7816
+ ...row2.endpoint !== void 0 ? [theme6.fg("info", `slots ${options.endpointActive ?? 0}/${row2.endpoint.limit} ${row2.endpoint.label}`)] : [],
7547
7817
  ...row2.gate !== void 0 ? [theme6.fg("info", `gate ${row2.gate.role} c${row2.gate.cycle}`)] : [],
7548
7818
  ...row2.rerouteCount !== void 0 && row2.rerouteCount > 0 ? [theme6.fg("warning", `rerouted x${row2.rerouteCount}`)] : [],
7549
7819
  ...row2.failoverHops !== void 0 && row2.failoverHops > 0 ? [theme6.fg("warning", `failed over x${row2.failoverHops}`)] : [],
7550
7820
  `${theme6.fg("dim", "ttft")} ${theme6.fg("muted", ttft)}`,
7551
7821
  `${theme6.fg("dim", "cost")} ${theme6.fg("muted", cost)}`
7552
7822
  ];
7553
- const hostVerification = theme6.fg("info", `host_verification=${row2.hostVerification ?? "not_requested"}`);
7554
7823
  const contextUnit = formatWorkerContextMeter(row2.lastContextTokens ?? 0, row2.contextWindow, theme6);
7555
7824
  const phaseCell = formatDispatchPhaseCell(row2.phase, contentWidth);
7556
7825
  const bodyLines2 = [
@@ -7564,7 +7833,7 @@ function renderDispatchCard(row2, width, evidence, options = {}) {
7564
7833
  targetLine,
7565
7834
  ...row2.taskSummary ? [truncateToWidth(`${cardKvKey(theme6, "task")}${theme6.fg("muted", row2.taskSummary)}`, contentWidth, "\u2026", false)] : [],
7566
7835
  cardUnitsLine(theme6, "status", statusUnits, contentWidth),
7567
- cardUnitsLine(theme6, "evidence", [hostVerification], contentWidth),
7836
+ ...trustCardLines(theme6, row2, contentWidth),
7568
7837
  ...row2.budget !== void 0 ? [
7569
7838
  truncateToWidth(
7570
7839
  `${cardKvKey(theme6, "policy")}${theme6.fg("muted", `${formatBudgetPolicy(row2.budget)}; requested ${formatBudgetRequest(row2.budget)}`)}`,
@@ -7619,6 +7888,16 @@ function renderDispatchCard(row2, width, evidence, options = {}) {
7619
7888
  )
7620
7889
  );
7621
7890
  }
7891
+ if (row2.writeRecordDowngrade) {
7892
+ const warning = describeWriteBoundaryAttributionDowngrade({
7893
+ ...row2.writeRecordDowngrade,
7894
+ runId: row2.runId,
7895
+ stepId: row2.phase?.stepId ?? null
7896
+ });
7897
+ bodyLines2.push(
7898
+ ...wrapTextWithAnsi(`${cardKvKey(theme6, "record")}${theme6.fg("warning", `open: ${warning}`)}`, contentWidth)
7899
+ );
7900
+ }
7622
7901
  if (evidence) {
7623
7902
  const proofLine = evidenceCardLine(theme6, evidence, contentWidth);
7624
7903
  if (proofLine !== null) bodyLines2.push(proofLine);
@@ -7757,10 +8036,17 @@ function formatDispatchBoardLines(rows, width = 76, observability, selectedRunId
7757
8036
  return theme6.fg("dim", " ".repeat(padding) + line);
7758
8037
  });
7759
8038
  }
8039
+ const endpointActive = { ...foregroundStreamUsage() };
8040
+ for (const row2 of rows) {
8041
+ if (row2.endpoint !== void 0 && (row2.status === "running" || row2.status === "stale" || row2.status === "enqueued" || row2.status === "cancelling")) {
8042
+ endpointActive[row2.endpoint.key] = (endpointActive[row2.endpoint.key] ?? 0) + 1;
8043
+ }
8044
+ }
7760
8045
  const cards = dispatchBoardItems(rows, selectedRunId).map(
7761
8046
  (item) => item.kind === "council" ? renderCouncilCard(item.group, width) : renderDispatchCard(item.row, width, deriveRunEvidenceState(observability, item.row.runId), {
7762
8047
  selected: item.row.runId === selectedRunId,
7763
- expanded: detailExpanded && item.row.runId === selectedRunId
8048
+ expanded: detailExpanded && item.row.runId === selectedRunId,
8049
+ ...item.row.endpoint !== void 0 ? { endpointActive: endpointActive[item.row.endpoint.key] ?? 0 } : {}
7764
8050
  })
7765
8051
  );
7766
8052
  const body = [];
@@ -7884,6 +8170,14 @@ function parseGateBadge(value) {
7884
8170
  const cycle = parsePositiveInt(record2.cycle) ?? 1;
7885
8171
  return { role: record2.role, cycle };
7886
8172
  }
8173
+ function parseEndpointCapacity(value) {
8174
+ if (typeof value !== "object" || value === null) return void 0;
8175
+ const record2 = value;
8176
+ const key = parseNonEmptyString(record2.key);
8177
+ const label = parseNonEmptyString(record2.label);
8178
+ const limit = parsePositiveInt(record2.limit);
8179
+ return key === void 0 || label === void 0 || limit === void 0 ? void 0 : { key, label, limit };
8180
+ }
7887
8181
  function parseCouncilBadge(value) {
7888
8182
  if (typeof value !== "object" || value === null) return void 0;
7889
8183
  const record2 = value;
@@ -7906,6 +8200,30 @@ function parseOptionalDetail(value) {
7906
8200
  const detail = value.replace(/\s+/g, " ").trim();
7907
8201
  return detail.length > 0 ? detail : null;
7908
8202
  }
8203
+ function trustVerdictToken(verdict) {
8204
+ switch (verdict) {
8205
+ case "reviewed":
8206
+ return "success";
8207
+ case "grounded":
8208
+ return "info";
8209
+ case "unverified":
8210
+ return "muted";
8211
+ case "compromised":
8212
+ return "error";
8213
+ default:
8214
+ return "dim";
8215
+ }
8216
+ }
8217
+ function trustVerdictGlyph(verdict) {
8218
+ switch (verdict) {
8219
+ case "reviewed":
8220
+ return GLYPH.ok;
8221
+ case "compromised":
8222
+ return GLYPH.error;
8223
+ default:
8224
+ return "\u25C7";
8225
+ }
8226
+ }
7909
8227
  function terminalDetail(row2) {
7910
8228
  if (row2.status !== "failed" && row2.status !== "dead" && row2.status !== "aborted") return null;
7911
8229
  return parseOptionalDetail(row2.outcomeDetail);
@@ -8011,6 +8329,7 @@ function toRow(entry, now) {
8011
8329
  runtimeId: entry.runtimeId,
8012
8330
  targetId: entry.targetId,
8013
8331
  wireModelId: entry.wireModelId,
8332
+ ...entry.endpoint !== void 0 ? { endpoint: { ...entry.endpoint } } : {},
8014
8333
  ...entry.taskSummary !== void 0 ? { taskSummary: entry.taskSummary } : {},
8015
8334
  ...entry.budget !== void 0 ? { budget: entry.budget } : {},
8016
8335
  status: retry ? "retrying" : entry.status,
@@ -8026,6 +8345,7 @@ function toRow(entry, now) {
8026
8345
  ...entry.gate !== void 0 ? { gate: { ...entry.gate } } : {},
8027
8346
  ...entry.council !== void 0 ? { council: { ...entry.council } } : {},
8028
8347
  ...entry.hostVerification !== void 0 ? { hostVerification: entry.hostVerification } : {},
8348
+ ...entry.trust !== void 0 ? { trust: entry.trust } : {},
8029
8349
  ...entry.rerouteCount !== void 0 ? { rerouteCount: entry.rerouteCount } : {},
8030
8350
  ...entry.failoverHops !== void 0 ? { failoverHops: entry.failoverHops } : {},
8031
8351
  ...entry.contextWindow !== void 0 ? { contextWindow: entry.contextWindow } : {},
@@ -8037,7 +8357,8 @@ function toRow(entry, now) {
8037
8357
  currentTool: retry ? null : progress.currentAction?.tool ?? null,
8038
8358
  recentTools: progress.recentActions.map((action) => action.tool),
8039
8359
  ...retry ? { retry: { ...retry } } : {},
8040
- ...entry.steerAcknowledgement ? { steerAcknowledgement: { ...entry.steerAcknowledgement } } : {}
8360
+ ...entry.steerAcknowledgement ? { steerAcknowledgement: { ...entry.steerAcknowledgement } } : {},
8361
+ ...entry.writeRecordDowngrade ? { writeRecordDowngrade: { ...entry.writeRecordDowngrade } } : {}
8041
8362
  };
8042
8363
  }
8043
8364
  function sortEntries(a, b) {
@@ -8066,8 +8387,10 @@ function createDispatchBoardStore(bus, snapshot, readReceipt) {
8066
8387
  let nextSequence = 0;
8067
8388
  let reconciledAtMs = Date.now();
8068
8389
  const settleFromReceipt = (entry) => {
8069
- const text = readReceipt?.(entry.runId)?.text;
8390
+ const facts = readReceipt?.(entry.runId);
8391
+ const text = facts?.text;
8070
8392
  entry.progress.settle(typeof text === "string" && text.trim().length > 0 ? text : void 0);
8393
+ if (facts?.trust !== void 0) entry.trust = summarizeTrustStatus(facts.trust);
8071
8394
  };
8072
8395
  const upsertBase = (raw, status, now) => {
8073
8396
  const runId = parseRunId(raw.runId);
@@ -8076,6 +8399,7 @@ function createDispatchBoardStore(bus, snapshot, readReceipt) {
8076
8399
  const agentAudience = parseAgentAudience(raw.agentAudience, previous?.agentAudience);
8077
8400
  const requestOrigin = parseRequestOrigin(raw.requestOrigin, previous?.requestOrigin);
8078
8401
  const node = parseNonEmptyString(raw.node) ?? previous?.node;
8402
+ const endpoint = parseEndpointCapacity(raw.endpoint) ?? previous?.endpoint;
8079
8403
  const gate = parseGateBadge(raw.gate) ?? previous?.gate;
8080
8404
  const council = parseCouncilBadge(raw.council) ?? previous?.council;
8081
8405
  const rerouteCount = parsePositiveInt(raw.rerouteCount) ?? previous?.rerouteCount;
@@ -8092,6 +8416,7 @@ function createDispatchBoardStore(bus, snapshot, readReceipt) {
8092
8416
  runtimeId: parseText(raw.runtimeId, previous?.runtimeId ?? "-"),
8093
8417
  targetId: parseText(raw.targetId, previous?.targetId ?? "-"),
8094
8418
  wireModelId: parseText(raw.wireModelId, previous?.wireModelId ?? "-"),
8419
+ ...endpoint !== void 0 ? { endpoint } : {},
8095
8420
  ...taskSummary !== void 0 ? { taskSummary } : {},
8096
8421
  ...budget !== void 0 ? { budget } : {},
8097
8422
  status,
@@ -8119,7 +8444,8 @@ function createDispatchBoardStore(bus, snapshot, readReceipt) {
8119
8444
  ...phase !== void 0 ? { phase } : {},
8120
8445
  progress: previous?.progress ?? createWorkerProgressFold(),
8121
8446
  ...previous?.retry ? { retry: { ...previous.retry } } : {},
8122
- ...previous?.steerAcknowledgement ? { steerAcknowledgement: { ...previous.steerAcknowledgement } } : {}
8447
+ ...previous?.steerAcknowledgement ? { steerAcknowledgement: { ...previous.steerAcknowledgement } } : {},
8448
+ ...previous?.writeRecordDowngrade ? { writeRecordDowngrade: { ...previous.writeRecordDowngrade } } : {}
8123
8449
  };
8124
8450
  entries.set(runId, entry);
8125
8451
  pruneEntries(entries, (evicted) => fleetPhases.delete(evicted));
@@ -8246,6 +8572,19 @@ function createDispatchBoardStore(bus, snapshot, readReceipt) {
8246
8572
  entry.ttftMs = Math.round(performance3.now() - entry.startedAtClockMs);
8247
8573
  }
8248
8574
  }
8575
+ if (type === "clio_write_record_downgraded") {
8576
+ const rawPayload = workerEvent.payload;
8577
+ const payload2 = typeof rawPayload === "object" && rawPayload !== null ? rawPayload : null;
8578
+ const tool = payload2 === null ? void 0 : parseNonEmptyString(payload2.tool);
8579
+ const toolCallId = payload2 === null ? void 0 : parseNonEmptyString(payload2.toolCallId);
8580
+ if (payload2?.reason === "opaque_tool_succeeded" && tool !== void 0 && toolCallId !== void 0) {
8581
+ entry.writeRecordDowngrade = {
8582
+ reason: "opaque_tool_succeeded",
8583
+ tool: sanitizeCallTargetText(tool),
8584
+ toolCallId: sanitizeCallTargetText(toolCallId)
8585
+ };
8586
+ }
8587
+ }
8249
8588
  entry.progress.observe(payload.event);
8250
8589
  if (type === "clio_steer_received") {
8251
8590
  const steerPayload = workerEvent.payload;
@@ -8689,8 +9028,41 @@ function retryOverlay(status) {
8689
9028
  }
8690
9029
  function reduceStatus(prev, event, ctx) {
8691
9030
  switch (event.type) {
8692
- case "agent_start":
9031
+ // A consumed prompt occupies `preparing` before any engine event exists,
9032
+ // and the previous turn's summary rides along untouched: a refused
9033
+ // admission puts the footer back on the last turn that actually ran,
9034
+ // which is still the truth about what happened.
9035
+ case "submit_accepted":
8693
9036
  if (isActive(prev.phase)) return prev;
9037
+ return {
9038
+ ...prev,
9039
+ phase: "preparing",
9040
+ since: ctx.now,
9041
+ lastMeaningfulAt: ctx.now,
9042
+ localRuntime: ctx.localRuntime,
9043
+ preparingSubmission: true,
9044
+ watchdogTier: 0,
9045
+ resumePhase: void 0,
9046
+ activePhases: void 0,
9047
+ overlayStack: [],
9048
+ tool: void 0,
9049
+ toolStartedAt: void 0,
9050
+ retry: void 0,
9051
+ dispatch: void 0
9052
+ };
9053
+ case "submit_settled":
9054
+ if (prev.preparingSubmission !== true) return prev;
9055
+ return {
9056
+ ...prev,
9057
+ phase: prev.summary ? "ended" : "idle",
9058
+ since: ctx.now,
9059
+ preparingSubmission: void 0,
9060
+ resumePhase: void 0,
9061
+ activePhases: void 0,
9062
+ overlayStack: []
9063
+ };
9064
+ case "agent_start":
9065
+ if (isActive(prev.phase) && prev.preparingSubmission !== true) return prev;
8694
9066
  return {
8695
9067
  ...INITIAL_STATUS,
8696
9068
  phase: "preparing",
@@ -9010,6 +9382,13 @@ function createStatusController(deps) {
9010
9382
  }
9011
9383
  notify(prev, status, force);
9012
9384
  };
9385
+ if (deps.chat.onTurnPreparation) {
9386
+ unsubscribes.push(
9387
+ deps.chat.onTurnPreparation((phase) => {
9388
+ apply({ type: phase === "idle" ? "submit_settled" : "submit_accepted" }, true);
9389
+ })
9390
+ );
9391
+ }
9013
9392
  unsubscribes.push(
9014
9393
  deps.chat.onEvent((event) => {
9015
9394
  if (event.type === "agent_status") return;
@@ -10104,7 +10483,7 @@ function runLedgerPath(stateDir) {
10104
10483
  }
10105
10484
  function readRunLedger(stateDir) {
10106
10485
  try {
10107
- const raw = readFileSync5(runLedgerPath(stateDir), "utf8").trim();
10486
+ const raw = readFileSync6(runLedgerPath(stateDir), "utf8").trim();
10108
10487
  if (raw.length === 0) return [];
10109
10488
  const parsed = JSON.parse(raw);
10110
10489
  return Array.isArray(parsed) ? parsed.filter(isRecord9) : [];
@@ -10146,6 +10525,15 @@ function validateToolStats(value) {
10146
10525
  }
10147
10526
  return { ok: true };
10148
10527
  }
10528
+ function receiptTrustDetail(stateDir, runId) {
10529
+ try {
10530
+ const receipt = JSON.parse(readFileSync6(receiptFilePath(stateDir, runId), "utf8"));
10531
+ const ledger = readRunEnvelope(stateDir, runId);
10532
+ return formatTrustSummaryLine(inspectRunReceiptTrustStatus(receipt, ledger.ok ? ledger.envelope : null).status);
10533
+ } catch {
10534
+ return "integrity verified; trust status unreadable";
10535
+ }
10536
+ }
10149
10537
  function readRunEnvelope(stateDir, runId) {
10150
10538
  const runs = readRunLedger(stateDir);
10151
10539
  for (const entry of runs) {
@@ -10157,7 +10545,7 @@ function verifyReceiptFile(stateDir, runId) {
10157
10545
  const target = receiptFilePath(stateDir, runId);
10158
10546
  let raw;
10159
10547
  try {
10160
- raw = readFileSync5(target, "utf8");
10548
+ raw = readFileSync6(target, "utf8");
10161
10549
  } catch (err) {
10162
10550
  const e = err;
10163
10551
  if (e.code === "ENOENT") return { ok: false, reason: "receipt file not found" };
@@ -10252,6 +10640,8 @@ function verifyReceiptFile(stateDir, runId) {
10252
10640
  if (!isNullableString(r.sessionId)) {
10253
10641
  return { ok: false, reason: `sessionId invalid: ${String(r.sessionId)}` };
10254
10642
  }
10643
+ const retired = retiredReceiptIntegrity(r.integrity);
10644
+ if (retired !== null) return { ok: false, reason: retiredReceiptIntegrityReason(retired), retired };
10255
10645
  if (!isReceiptIntegrity(r.integrity)) {
10256
10646
  return { ok: false, reason: "integrity invalid" };
10257
10647
  }
@@ -10507,8 +10897,10 @@ var ReceiptArtifactProvider = class {
10507
10897
  load: () => loadJsonFileLines(path),
10508
10898
  verify: async () => {
10509
10899
  const result = verifyReceiptFile(this.deps.stateDir, env.id);
10510
- if (!result.ok) return { ok: false, detail: result.reason };
10511
- return { ok: true, detail: "integrity verified" };
10900
+ if (!result.ok) {
10901
+ return { ok: false, detail: result.reason, ...result.retired !== void 0 ? { retired: true } : {} };
10902
+ }
10903
+ return { ok: true, detail: receiptTrustDetail(this.deps.stateDir, env.id) };
10512
10904
  }
10513
10905
  };
10514
10906
  });
@@ -11278,12 +11670,19 @@ function workerReceiptFacts(receipt) {
11278
11670
  };
11279
11671
  }
11280
11672
  function readReceiptFileFacts(runId, stateDir) {
11673
+ let parsed;
11281
11674
  try {
11282
- const parsed = JSON.parse(readFileSync6(receiptFilePath(stateDir, runId), "utf8"));
11283
- return isRecord10(parsed) ? workerReceiptFacts(parsed) : null;
11675
+ parsed = JSON.parse(readFileSync7(receiptFilePath(stateDir, runId), "utf8"));
11284
11676
  } catch {
11285
11677
  return null;
11286
11678
  }
11679
+ if (!isRecord10(parsed)) return null;
11680
+ const facts = workerReceiptFacts(parsed);
11681
+ if (facts === null) return null;
11682
+ const row2 = findRunRow(runId, stateDir);
11683
+ if (row2 === null) return facts;
11684
+ const trust = inspectRunReceiptTrustStatus(parsed, row2).status;
11685
+ return { ...facts, trust };
11287
11686
  }
11288
11687
  function readWorkerReceiptFacts(runId, stateDir = clioStateDir()) {
11289
11688
  return readReceiptFileFacts(runId, stateDir);
@@ -11292,7 +11691,7 @@ function findRunRow(runId, stateDir) {
11292
11691
  const path = join6(stateDir, "runs.json");
11293
11692
  if (!existsSync5(path)) return null;
11294
11693
  try {
11295
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
11694
+ const parsed = JSON.parse(readFileSync7(path, "utf8"));
11296
11695
  if (!Array.isArray(parsed)) return null;
11297
11696
  for (const entry of parsed) {
11298
11697
  if (isRecord10(entry) && entry.id === runId) return entry;
@@ -12469,18 +12868,27 @@ function createTurnContext(deps) {
12469
12868
  const { state, middleware } = deps;
12470
12869
  const compactionTrigger = new AutoCompactionTrigger();
12471
12870
  let currentContextSnapshot = null;
12871
+ let reconciledAnchor = null;
12472
12872
  let lastCompactionEvent = null;
12473
12873
  let lastPromptCache = null;
12474
12874
  let lastSystemPromptReused = false;
12875
+ let lastPrewarm = null;
12475
12876
  let sessionPrompt = null;
12476
12877
  let sessionPromptKey = null;
12878
+ let sessionPromptHash = null;
12879
+ let resumedPromptHashRead = false;
12880
+ let resumedPromptHash = null;
12477
12881
  const sessionWorkingContextPaths = /* @__PURE__ */ new Set();
12478
12882
  let pendingPromptLogEntry = null;
12479
12883
  let emptyAutoCompactTurnId = null;
12480
12884
  const pendingColdReasons = /* @__PURE__ */ new Set();
12481
12885
  let runExpectedColdReasons = [];
12482
12886
  let nextAssistantColdReasons = [];
12483
- const TIER_INDEPENDENT_COLD_REASONS = /* @__PURE__ */ new Set(["working_set_evict"]);
12887
+ const TIER_INDEPENDENT_COLD_REASONS = /* @__PURE__ */ new Set([
12888
+ "working_set_evict",
12889
+ "tool_surface_change",
12890
+ "prompt_recompiled"
12891
+ ]);
12484
12892
  const stampsOnTier = (reason, runtimeId) => TIER_INDEPENDENT_COLD_REASONS.has(reason) || runtimeId !== void 0 && deps.providers.getRuntime(runtimeId)?.tier === "local-native";
12485
12893
  const noteColdReason = (reason) => {
12486
12894
  if (!state.streaming) {
@@ -12504,6 +12912,21 @@ function createTurnContext(deps) {
12504
12912
  noteColdReason("compaction");
12505
12913
  }) ?? null
12506
12914
  ),
12915
+ deps.bus?.on(BusChannels.ResidencyMutation, (payload) => {
12916
+ const runtime = state.runtime;
12917
+ const model = runtime?.agent.state.model;
12918
+ const baseUrl = typeof model?.baseUrl === "string" ? model.baseUrl : null;
12919
+ if (payload.targetKey !== residencyTargetKey(runtime?.runtimeId ?? "", baseUrl)) return;
12920
+ noteColdReason("residency");
12921
+ }) ?? null,
12922
+ // A memory step on another endpoint disturbs nothing here, so the stamp is
12923
+ // gated on the step having called the very server this session streams to.
12924
+ deps.bus?.on(BusChannels.MemoryStepCompleted, (payload) => {
12925
+ const target = state.runtime?.runtimeResolution.target;
12926
+ if (target === void 0) return;
12927
+ if (canonicalEndpointKey(target) !== payload.endpointKey) return;
12928
+ noteColdReason("background_memory");
12929
+ }) ?? null,
12507
12930
  deps.bus?.on(BusChannels.ContextRecalled, (payload) => {
12508
12931
  middleware.fireCompactionHook("working_set_recall", payload.trigger);
12509
12932
  }) ?? null
@@ -12558,6 +12981,23 @@ function createTurnContext(deps) {
12558
12981
  }
12559
12982
  return ceilChars(snapshot.pendingUserInput.length);
12560
12983
  };
12984
+ const rememberedLoadedContextWindow = (targetId, modelId) => {
12985
+ const session = deps.session?.current();
12986
+ if (!session) return null;
12987
+ return lastLoadedContextWindow(session, targetId, modelId);
12988
+ };
12989
+ const lastRecordedPromptHash = () => {
12990
+ if (resumedPromptHashRead) return resumedPromptHash;
12991
+ resumedPromptHashRead = true;
12992
+ const currentSession = deps.session?.current();
12993
+ if (!currentSession) {
12994
+ resumedPromptHashRead = false;
12995
+ return null;
12996
+ }
12997
+ const records = readPromptCompileRecords(currentSession);
12998
+ resumedPromptHash = records[records.length - 1]?.systemPromptHash ?? null;
12999
+ return resumedPromptHash;
13000
+ };
12561
13001
  const resolveWindowWithoutRuntime = () => {
12562
13002
  const settings = deps.getSettings();
12563
13003
  const targetId = settings.orchestrator?.target?.trim();
@@ -12569,7 +13009,8 @@ function createTurnContext(deps) {
12569
13009
  requestedThinkingLevel: settings.orchestrator?.thinkingLevel ?? "off",
12570
13010
  use: "orchestrator",
12571
13011
  requireTools: false,
12572
- requireOutputBudget: true
13012
+ requireOutputBudget: true,
13013
+ knownLoadedContextWindow: rememberedLoadedContextWindow(targetId, wireModelId)
12573
13014
  });
12574
13015
  return resolved.ok ? resolved.target.contextWindowDetails : null;
12575
13016
  };
@@ -12602,6 +13043,19 @@ function createTurnContext(deps) {
12602
13043
  }
12603
13044
  return { contextWindow: 0, contextWindowSource: null, contextWindowSlots: null };
12604
13045
  };
13046
+ const reconciledAnchoredTokens = (agentRuntime, pendingUserTokens) => {
13047
+ const anchor = reconciledAnchor;
13048
+ if (!anchor) return null;
13049
+ const messages = agentRuntime.agent.state.messages;
13050
+ if (anchor.anchoredMessageCount > messages.length) return null;
13051
+ let tail = 0;
13052
+ for (let i = anchor.anchoredMessageCount; i < messages.length; i += 1) {
13053
+ const message = messages[i];
13054
+ if (message === void 0) continue;
13055
+ tail += estimateAgentMessageTokens(message);
13056
+ }
13057
+ return anchor.tokens + tail + pendingUserTokens;
13058
+ };
12605
13059
  const liveContextEstimate = (agentRuntime, pendingUserText) => {
12606
13060
  const contextWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
12607
13061
  const estimateInput = {
@@ -12610,10 +13064,25 @@ function createTurnContext(deps) {
12610
13064
  tools: agentRuntime.agent.state.tools,
12611
13065
  ...pendingUserText !== void 0 ? { pendingUserText } : {}
12612
13066
  };
13067
+ const breakdown = estimateAgentContextBreakdown(estimateInput);
13068
+ const estimatedTokens = estimateAgentContextTokens(estimateInput);
13069
+ const reconciledTokens = reconciledAnchoredTokens(agentRuntime, breakdown.pendingUserTokens);
12613
13070
  return {
12614
- tokens: estimateAgentContextTokens(estimateInput),
13071
+ // The estimate is a floor, not a competing verdict: it prices material
13072
+ // the attested call never saw, so a provider count below it would be
13073
+ // answering about a smaller conversation.
13074
+ tokens: Math.max(estimatedTokens, reconciledTokens ?? 0),
13075
+ estimatedTokens,
13076
+ reconciledTokens,
12615
13077
  contextWindow,
12616
- breakdown: estimateAgentContextBreakdown(estimateInput)
13078
+ breakdown
13079
+ };
13080
+ };
13081
+ const carryReconciledAnchorThroughProjection = (agentRuntime, tokensRemoved) => {
13082
+ if (!reconciledAnchor) return;
13083
+ reconciledAnchor = {
13084
+ tokens: Math.max(0, reconciledAnchor.tokens - Math.max(0, tokensRemoved)),
13085
+ anchoredMessageCount: agentRuntime.agent.state.messages.length
12617
13086
  };
12618
13087
  };
12619
13088
  const refreshAgentMessagesFromSession = (agentRuntime) => {
@@ -12627,7 +13096,7 @@ function createTurnContext(deps) {
12627
13096
  const emitCompactionActivity = (status, message) => {
12628
13097
  deps.bus?.emit(BusChannels.ContextActivity, {
12629
13098
  kind: "compaction",
12630
- phase: "done",
13099
+ phase: status === "completed" ? "done" : "compact",
12631
13100
  status,
12632
13101
  message,
12633
13102
  at: Date.now()
@@ -12694,6 +13163,7 @@ function createTurnContext(deps) {
12694
13163
  emitCompactionActivity("started", "compacting context (mask stage)");
12695
13164
  deps.session.replaceEntries(masked.entries);
12696
13165
  refreshAgentMessagesFromSession(agentRuntime);
13166
+ reconciledAnchor = null;
12697
13167
  deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
12698
13168
  const postMaskSnapshot = captureRuntimeContextSnapshot(
12699
13169
  agentRuntime,
@@ -12772,6 +13242,7 @@ function createTurnContext(deps) {
12772
13242
  });
12773
13243
  noteColdReason("working_set_evict");
12774
13244
  refreshAgentMessagesFromSession(agentRuntime);
13245
+ carryReconciledAnchorThroughProjection(agentRuntime, planned.tokensBefore - planned.tokensAfter);
12775
13246
  const postEvictionSnapshot = captureRuntimeContextSnapshot(
12776
13247
  agentRuntime,
12777
13248
  state.activeUserTurnId || "compaction",
@@ -12847,6 +13318,7 @@ function createTurnContext(deps) {
12847
13318
  deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
12848
13319
  recordCompactionUsage(agentRuntime, result);
12849
13320
  refreshAgentMessagesFromSession(agentRuntime);
13321
+ reconciledAnchor = null;
12850
13322
  const postCompactSnapshot = captureRuntimeContextSnapshot(
12851
13323
  agentRuntime,
12852
13324
  state.activeUserTurnId || "compaction",
@@ -12899,6 +13371,7 @@ function createTurnContext(deps) {
12899
13371
  captureRuntimeContextSnapshot,
12900
13372
  persistContextSnapshot,
12901
13373
  liveContextEstimate,
13374
+ rememberedLoadedContextWindow,
12902
13375
  refreshAgentMessagesFromSession,
12903
13376
  runAutoCompact,
12904
13377
  setCurrentSnapshot(snapshot) {
@@ -12909,6 +13382,14 @@ function createTurnContext(deps) {
12909
13382
  persistContextSnapshot(currentContextSnapshot);
12910
13383
  },
12911
13384
  reconcileUsage(usage) {
13385
+ const promptTokens = (usage.input || 0) + (usage.cacheRead || 0) + (usage.cacheWrite || 0);
13386
+ const messages = state.runtime?.agent.state.messages;
13387
+ if (promptTokens > 0 && messages) {
13388
+ reconciledAnchor = {
13389
+ tokens: promptTokens + (usage.output || 0),
13390
+ anchoredMessageCount: messages.length
13391
+ };
13392
+ }
12912
13393
  if (!currentContextSnapshot) return;
12913
13394
  currentContextSnapshot = reconcileSnapshot(currentContextSnapshot, usage);
12914
13395
  snapshotPersistPending = true;
@@ -12936,7 +13417,10 @@ function createTurnContext(deps) {
12936
13417
  return sessionPrompt;
12937
13418
  }
12938
13419
  const modelState = agentRuntime.agent.state.model;
12939
- const contextWindow = typeof modelState?.contextWindow === "number" ? modelState.contextWindow : null;
13420
+ const windowDetails = agentRuntime.runtimeResolution.contextWindowDetails;
13421
+ const resolvedWindow = windowDetails.effectiveContextWindow;
13422
+ const contextWindow = typeof resolvedWindow === "number" && resolvedWindow > 0 ? resolvedWindow : null;
13423
+ const contextWindowSource = contextWindow === null ? null : windowDetails.contextWindowSource;
12940
13424
  const guidance = modelState?.clio?.quirks?.thinking?.guidance;
12941
13425
  const toolNames = toolNamesFromAgentState(agentRuntime.agent.state.tools);
12942
13426
  const toolPromptHints = toolNames.flatMap((name) => {
@@ -12969,16 +13453,19 @@ function createTurnContext(deps) {
12969
13453
  cwd: process.cwd(),
12970
13454
  workingContextPaths: [...sessionWorkingContextPaths]
12971
13455
  });
12972
- const previousHash = sessionPrompt?.systemPromptHash ?? null;
13456
+ const previousHash = sessionPromptHash ?? lastRecordedPromptHash();
12973
13457
  const changed = agentRuntime.agent.state.systemPrompt !== result.systemPrompt;
12974
13458
  if (changed) {
12975
13459
  agentRuntime.agent.state.systemPrompt = result.systemPrompt;
12976
13460
  pendingPromptLogEntry = {
13461
+ version: PROMPT_MANIFEST_VERSION,
12977
13462
  at: (/* @__PURE__ */ new Date()).toISOString(),
12978
13463
  previousHash,
12979
13464
  systemPromptHash: result.systemPromptHash,
12980
13465
  tokenEstimate: result.tokenEstimate,
12981
13466
  thinkingLevel: agentRuntime.agent.state.thinkingLevel ?? null,
13467
+ contextWindow,
13468
+ contextWindowSource,
12982
13469
  projectPreload: result.projectPreload ?? null,
12983
13470
  sections: result.sections.map((s) => ({ id: s.id, tokenEstimate: s.tokenEstimate })),
12984
13471
  fragments: result.fragmentManifest.map((f) => ({
@@ -12991,6 +13478,7 @@ function createTurnContext(deps) {
12991
13478
  }
12992
13479
  lastSystemPromptReused = !changed;
12993
13480
  sessionPrompt = result;
13481
+ sessionPromptHash = result.systemPromptHash;
12994
13482
  sessionPromptKey = key;
12995
13483
  return result;
12996
13484
  } catch (err) {
@@ -13022,6 +13510,9 @@ function createTurnContext(deps) {
13022
13510
  tokenEstimate: entry.tokenEstimate
13023
13511
  }
13024
13512
  });
13513
+ if (entry.previousHash !== null && entry.previousHash !== entry.systemPromptHash) {
13514
+ noteColdReason("prompt_recompiled");
13515
+ }
13025
13516
  } catch {
13026
13517
  }
13027
13518
  appendPromptCompileRecord(currentMeta, entry);
@@ -13092,7 +13583,8 @@ function createTurnContext(deps) {
13092
13583
  toolCount: liveToolCount,
13093
13584
  compactionThreshold,
13094
13585
  compactionAuto,
13095
- promptCache: lastPromptCache
13586
+ promptCache: lastPromptCache,
13587
+ prewarm: lastPrewarm
13096
13588
  });
13097
13589
  }
13098
13590
  const streamingOutput = liveStreamingOutputTokens();
@@ -13122,7 +13614,8 @@ function createTurnContext(deps) {
13122
13614
  liveTotalTokens: totalUsed > 0 ? totalUsed : null,
13123
13615
  measured,
13124
13616
  lastCompaction: lastCompactionEvent,
13125
- promptCache: lastPromptCache
13617
+ promptCache: lastPromptCache,
13618
+ prewarm: lastPrewarm
13126
13619
  });
13127
13620
  },
13128
13621
  emitContextWindowWarningTransition(warning) {
@@ -13130,6 +13623,7 @@ function createTurnContext(deps) {
13130
13623
  lastContextWindowWarning = warning;
13131
13624
  deps.bus?.emit(BusChannels.ContextWarning, { warning });
13132
13625
  },
13626
+ noteColdReason,
13133
13627
  consumeExpectedColdReasons(runtimeId) {
13134
13628
  runExpectedColdReasons = [];
13135
13629
  nextAssistantColdReasons = [];
@@ -13143,7 +13637,7 @@ function createTurnContext(deps) {
13143
13637
  }
13144
13638
  }
13145
13639
  },
13146
- promptCachePayloadForAssistant(usage) {
13640
+ promptCachePayloadForAssistant(usage, backend) {
13147
13641
  const input = typeof usage.input === "number" ? usage.input : 0;
13148
13642
  const cacheRead = typeof usage.cacheRead === "number" ? usage.cacheRead : 0;
13149
13643
  const cacheWrite = typeof usage.cacheWrite === "number" ? usage.cacheWrite : 0;
@@ -13151,34 +13645,54 @@ function createTurnContext(deps) {
13151
13645
  input,
13152
13646
  cacheRead,
13153
13647
  cacheWrite,
13154
- backendVerdict: backendCacheVerdict(input, cacheRead)
13648
+ backendVerdict: backendCacheVerdict(input, cacheRead, backend)
13155
13649
  };
13650
+ if (backend !== void 0) promptCache.backend = { ...backend };
13156
13651
  if (nextAssistantColdReasons.length > 0) {
13157
13652
  promptCache.expectedColdReasons = [...nextAssistantColdReasons];
13158
13653
  nextAssistantColdReasons = [];
13159
13654
  }
13160
13655
  return promptCache;
13161
13656
  },
13657
+ notePrewarm(prewarm) {
13658
+ lastPrewarm = prewarm;
13659
+ },
13162
13660
  noteRunCacheSummary(messages, runFirstCallVerdict) {
13661
+ lastPrewarm = null;
13163
13662
  const cacheSummary = sumRunUsage(messages);
13164
13663
  if (cacheSummary.hadUsage) {
13664
+ let lastBackend = null;
13665
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
13666
+ const message = messages[index];
13667
+ if (message?.role !== "assistant") continue;
13668
+ lastBackend = message.backendTimings ?? null;
13669
+ break;
13670
+ }
13165
13671
  lastPromptCache = {
13166
13672
  shellReused: lastSystemPromptReused,
13167
13673
  cacheReadTokens: cacheSummary.cacheRead > 0 || cacheSummary.cacheWrite > 0 ? cacheSummary.cacheRead : null,
13168
13674
  cacheWriteTokens: cacheSummary.cacheRead > 0 || cacheSummary.cacheWrite > 0 ? cacheSummary.cacheWrite : null,
13169
13675
  uncachedInputTokens: cacheSummary.input,
13676
+ backend: lastBackend,
13677
+ uncachedPrefillTokens: uncachedPrefillTokens(lastBackend),
13170
13678
  backendVerdict: runFirstCallVerdict,
13171
13679
  ...runExpectedColdReasons.length > 0 ? { expectedColdReasons: [...runExpectedColdReasons] } : {}
13172
13680
  };
13173
13681
  }
13174
13682
  },
13175
13683
  resetForSession() {
13684
+ if (sessionPromptHash !== null) noteColdReason("prompt_recompiled");
13176
13685
  lastPromptCache = null;
13686
+ lastPrewarm = null;
13177
13687
  lastSystemPromptReused = false;
13688
+ sessionPromptHash = null;
13178
13689
  sessionPromptKey = null;
13690
+ resumedPromptHashRead = false;
13691
+ resumedPromptHash = null;
13179
13692
  sessionWorkingContextPaths.clear();
13180
13693
  pendingPromptLogEntry = null;
13181
13694
  emptyAutoCompactTurnId = null;
13695
+ reconciledAnchor = null;
13182
13696
  const session = deps.session?.current();
13183
13697
  currentContextSnapshot = session ? getLatestContextSnapshot(session) : null;
13184
13698
  },
@@ -13475,7 +13989,8 @@ function createTurnPersistence(deps) {
13475
13989
  if (timing) payload.timing = timing;
13476
13990
  const usage = message.usage;
13477
13991
  if (usage && typeof usage === "object") {
13478
- payload.promptCache = deps.promptCachePayloadForAssistant(usage);
13992
+ const backendTimings = message.backendTimings;
13993
+ payload.promptCache = deps.promptCachePayloadForAssistant(usage, backendTimings);
13479
13994
  }
13480
13995
  const interruptedUsage = estimatedUsageForInterruptedTurn(message, deps.promptSideTokens());
13481
13996
  if (interruptedUsage !== null) payload.usage = interruptedUsage;
@@ -13516,8 +14031,8 @@ function createTurnPersistence(deps) {
13516
14031
  appendAssistantTurn,
13517
14032
  appendQueuedUserTurn(message) {
13518
14033
  if (message?.role !== "user") return;
13519
- const text = extractUserText(message).trim();
13520
- if (text.length === 0) return;
14034
+ const text = extractUserText(message);
14035
+ if (text.trim().length === 0) return;
13521
14036
  if (deps.consumePersistedEcho(text)) return;
13522
14037
  deps.removeQueuedMirrorEntry(text);
13523
14038
  if (!deps.session) return;
@@ -13678,6 +14193,266 @@ function createTurnPersistence(deps) {
13678
14193
  };
13679
14194
  }
13680
14195
 
14196
+ // src/interactive/turn-prewarm.ts
14197
+ init_esm_shims();
14198
+
14199
+ // src/interactive/prewarm.ts
14200
+ init_esm_shims();
14201
+ var PREWARM_USER_TEXT = ".";
14202
+ var PREWARM_MAX_TOKENS = 1;
14203
+ var LLM_MESSAGE_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "toolResult"]);
14204
+ function prewarmPrefix(state) {
14205
+ return {
14206
+ systemPrompt: state.systemPrompt,
14207
+ messages: state.messages.filter((message) => LLM_MESSAGE_ROLES.has(message.role ?? "")),
14208
+ tools: [...state.tools]
14209
+ };
14210
+ }
14211
+ function usageOf(message) {
14212
+ if (message === null || typeof message !== "object") return null;
14213
+ const usage = message.usage;
14214
+ return usage !== null && typeof usage === "object" ? usage : null;
14215
+ }
14216
+ function backendOf(message) {
14217
+ if (message === null || typeof message !== "object") return null;
14218
+ const backend = message.backendTimings;
14219
+ return backend !== null && typeof backend === "object" ? backend : null;
14220
+ }
14221
+ function prewarmPromptTokens(result) {
14222
+ if (result.backend) return result.backend.promptTokens;
14223
+ const usage = result.usage;
14224
+ if (!usage) return null;
14225
+ const total = (usage.input || 0) + (usage.cacheRead || 0) + (usage.cacheWrite || 0);
14226
+ return total > 0 ? total : null;
14227
+ }
14228
+ async function runPrewarmRound(input) {
14229
+ const prefix = prewarmPrefix(input.state);
14230
+ const context = {
14231
+ systemPrompt: prefix.systemPrompt,
14232
+ messages: [
14233
+ ...prefix.messages,
14234
+ { role: "user", content: [{ type: "text", text: PREWARM_USER_TEXT }], timestamp: Date.now() }
14235
+ ],
14236
+ tools: prefix.tools
14237
+ };
14238
+ const options = { maxTokens: PREWARM_MAX_TOKENS };
14239
+ if (input.state.thinkingLevel !== "off") options.reasoning = input.state.thinkingLevel;
14240
+ if (input.apiKey !== void 0) options.apiKey = input.apiKey;
14241
+ if (input.signal !== void 0) options.signal = input.signal;
14242
+ const send = input.streamFn ?? streamSimple;
14243
+ const startedAt = performance.now();
14244
+ let firstDeltaAt = null;
14245
+ const elapsed = () => Math.round(Math.max(0, performance.now() - startedAt));
14246
+ const ttft = () => firstDeltaAt === null ? null : Math.round(Math.max(0, firstDeltaAt - startedAt));
14247
+ try {
14248
+ const events = send(
14249
+ input.model,
14250
+ context,
14251
+ options
14252
+ );
14253
+ for await (const event of events) {
14254
+ if (firstDeltaAt === null && event.type !== "start") firstDeltaAt = performance.now();
14255
+ if (event.type === "done") {
14256
+ return {
14257
+ aborted: false,
14258
+ usage: usageOf(event.message),
14259
+ backend: backendOf(event.message),
14260
+ timing: { ttftMs: ttft(), apiMs: elapsed() },
14261
+ errorMessage: null
14262
+ };
14263
+ }
14264
+ if (event.type === "error") {
14265
+ const failed = event.error;
14266
+ const aborted = event.reason === "aborted" || failed.stopReason === "aborted" || input.signal?.aborted === true;
14267
+ return {
14268
+ aborted,
14269
+ usage: usageOf(event.error),
14270
+ backend: backendOf(event.error),
14271
+ timing: { ttftMs: ttft(), apiMs: elapsed() },
14272
+ errorMessage: aborted ? null : typeof failed.errorMessage === "string" ? failed.errorMessage : "pre-warm failed"
14273
+ };
14274
+ }
14275
+ }
14276
+ } catch (error) {
14277
+ return {
14278
+ aborted: input.signal?.aborted === true,
14279
+ usage: null,
14280
+ backend: null,
14281
+ timing: { ttftMs: ttft(), apiMs: elapsed() },
14282
+ errorMessage: input.signal?.aborted === true ? null : error instanceof Error ? error.message : String(error)
14283
+ };
14284
+ }
14285
+ return {
14286
+ aborted: input.signal?.aborted === true,
14287
+ usage: null,
14288
+ backend: null,
14289
+ timing: { ttftMs: ttft(), apiMs: elapsed() },
14290
+ errorMessage: null
14291
+ };
14292
+ }
14293
+
14294
+ // src/interactive/turn-prewarm.ts
14295
+ var ABORT_ROUND_ON_SUBMIT = false;
14296
+ function createTurnPrewarm(deps) {
14297
+ const round = deps.runPrewarm ?? runPrewarmRound;
14298
+ const abortOnSubmit = deps.abortRoundOnSubmit ?? ABORT_ROUND_ON_SUBMIT;
14299
+ let pendingTrigger = null;
14300
+ let timer = null;
14301
+ let active = null;
14302
+ const detached = /* @__PURE__ */ new WeakSet();
14303
+ let inFlight = Promise.resolve(null);
14304
+ let dispatchesInFlight = 0;
14305
+ const unsubscribeDispatch = [
14306
+ deps.bus?.on(BusChannels.DispatchStarted, () => {
14307
+ dispatchesInFlight += 1;
14308
+ }) ?? null,
14309
+ ...[BusChannels.DispatchCompleted, BusChannels.DispatchFailed].map(
14310
+ (channel) => deps.bus?.on(channel, () => {
14311
+ dispatchesInFlight = Math.max(0, dispatchesInFlight - 1);
14312
+ }) ?? null
14313
+ )
14314
+ ];
14315
+ const dispatchActive = () => dispatchesInFlight > 0 || deps.hasActiveDispatch();
14316
+ const admissionRefusal = () => {
14317
+ if (deps.getSettings().prewarm?.enabled === false) return "disabled";
14318
+ if (!deps.isLatencySurface()) return "surface";
14319
+ if (deps.state.streaming || deps.isTurnActive()) return "turn-active";
14320
+ if (dispatchActive()) return "dispatch-active";
14321
+ const targetId = deps.getSettings().orchestrator?.target?.trim();
14322
+ const runtimeId = targetId ? deps.providers.getTarget(targetId)?.runtime : void 0;
14323
+ if (runtimeId === void 0 || deps.providers.getRuntime(runtimeId)?.tier !== "local-native") return "tier";
14324
+ return null;
14325
+ };
14326
+ const runOnce = async (trigger, controller) => {
14327
+ const refusal2 = admissionRefusal();
14328
+ if (refusal2) return { ran: false, reason: refusal2 };
14329
+ const prepared = await deps.prepareRuntime(controller.signal);
14330
+ if (!prepared.ok) return { ran: false, reason: "unresolved" };
14331
+ const runtime = prepared.runtime;
14332
+ if (deps.providers.getRuntime(runtime.runtimeId)?.tier !== "local-native") {
14333
+ return { ran: false, reason: "tier" };
14334
+ }
14335
+ deps.applySessionTools(runtime);
14336
+ await deps.context.ensureSessionPrompt(runtime);
14337
+ const lateRefusal = admissionRefusal();
14338
+ if (lateRefusal) return { ran: false, reason: lateRefusal };
14339
+ if (detached.has(controller) || controller.signal.aborted) return { ran: false, reason: "superseded" };
14340
+ const releaseEndpointSlot = deps.registerEndpointSlot?.(runtime) ?? null;
14341
+ let result;
14342
+ try {
14343
+ result = await round({
14344
+ model: runtime.agent.state.model,
14345
+ state: {
14346
+ systemPrompt: runtime.agent.state.systemPrompt,
14347
+ messages: runtime.agent.state.messages,
14348
+ tools: runtime.agent.state.tools,
14349
+ thinkingLevel: runtime.agent.state.thinkingLevel ?? "off"
14350
+ },
14351
+ ...prepared.apiKey !== void 0 ? { apiKey: prepared.apiKey } : {},
14352
+ signal: controller.signal
14353
+ });
14354
+ } finally {
14355
+ releaseEndpointSlot?.();
14356
+ }
14357
+ const wasDetached = detached.has(controller) || controller.signal.aborted;
14358
+ const promptTokens = prewarmPromptTokens(result);
14359
+ if (!wasDetached) {
14360
+ deps.context.notePrewarm({
14361
+ tokens: promptTokens,
14362
+ ms: result.timing.apiMs,
14363
+ aborted: result.aborted
14364
+ });
14365
+ }
14366
+ deps.recordUsage(runtime, result.usage);
14367
+ try {
14368
+ deps.session?.appendEntry({
14369
+ kind: "custom",
14370
+ customType: "prewarm",
14371
+ // Never a model message and never a rendered transcript block: a
14372
+ // pre-warm is a fact about the backend, not something the session said.
14373
+ display: false,
14374
+ parentTurnId: deps.state.lastTurnId,
14375
+ data: {
14376
+ trigger,
14377
+ target: runtime.targetId,
14378
+ model: runtime.wireModelId,
14379
+ promptTokens,
14380
+ aborted: result.aborted,
14381
+ detached: wasDetached,
14382
+ timing: result.timing,
14383
+ promptCache: {
14384
+ input: result.usage?.input ?? 0,
14385
+ cacheRead: result.usage?.cacheRead ?? 0,
14386
+ cacheWrite: result.usage?.cacheWrite ?? 0,
14387
+ ...result.backend ? { backend: { ...result.backend } } : {}
14388
+ },
14389
+ ...result.errorMessage ? { error: result.errorMessage } : {}
14390
+ }
14391
+ });
14392
+ } catch {
14393
+ }
14394
+ return { ran: true, trigger };
14395
+ };
14396
+ const releaseActiveRound = () => {
14397
+ const controller = active;
14398
+ if (controller === null) return;
14399
+ detached.add(controller);
14400
+ if (abortOnSubmit) controller.abort();
14401
+ active = null;
14402
+ };
14403
+ const fire = () => {
14404
+ timer = null;
14405
+ const trigger = pendingTrigger;
14406
+ pendingTrigger = null;
14407
+ if (trigger === null) return;
14408
+ const controller = new AbortController();
14409
+ active = controller;
14410
+ const previous = inFlight;
14411
+ inFlight = previous.catch(() => null).then(() => runOnce(trigger, controller)).catch(() => null).finally(() => {
14412
+ if (active === controller) active = null;
14413
+ });
14414
+ };
14415
+ return {
14416
+ schedule(trigger) {
14417
+ releaseActiveRound();
14418
+ pendingTrigger = trigger;
14419
+ if (timer !== null) return;
14420
+ timer = setTimeout(fire, 0);
14421
+ },
14422
+ cancel() {
14423
+ pendingTrigger = null;
14424
+ if (timer !== null) {
14425
+ clearTimeout(timer);
14426
+ timer = null;
14427
+ }
14428
+ releaseActiveRound();
14429
+ },
14430
+ settled() {
14431
+ return new Promise((resolve7) => {
14432
+ setTimeout(() => {
14433
+ resolve7(inFlight.catch(() => null));
14434
+ }, 0);
14435
+ });
14436
+ },
14437
+ dispose() {
14438
+ for (const unsubscribe of unsubscribeDispatch) unsubscribe?.();
14439
+ pendingTrigger = null;
14440
+ if (timer !== null) {
14441
+ clearTimeout(timer);
14442
+ timer = null;
14443
+ }
14444
+ active?.abort();
14445
+ active = null;
14446
+ }
14447
+ };
14448
+ }
14449
+ function subscribePrewarmToCompaction(bus, prewarm) {
14450
+ const unsubscribe = bus?.on(BusChannels.CompactionEnd, () => {
14451
+ prewarm.schedule("compaction");
14452
+ });
14453
+ return () => unsubscribe?.();
14454
+ }
14455
+
13681
14456
  // src/interactive/turn-queues.ts
13682
14457
  init_esm_shims();
13683
14458
  var DEFAULT_STEERING_MODE = "next-slot";
@@ -13689,14 +14464,13 @@ function createTurnQueues(deps) {
13689
14464
  deps.emitQueueUpdateEvent(queuedMirror.map((entry) => ({ ...entry })));
13690
14465
  };
13691
14466
  const enqueue = (text, kind) => {
13692
- const trimmed = text.trim();
13693
- if (trimmed.length === 0 || !state.streaming || !state.runtime) return false;
14467
+ if (text.trim().length === 0 || !state.streaming || !state.runtime) return false;
13694
14468
  const message = {
13695
14469
  role: "user",
13696
- content: trimmed,
14470
+ content: text,
13697
14471
  timestamp: Date.now()
13698
14472
  };
13699
- queuedMirror.push({ text: trimmed, kind });
14473
+ queuedMirror.push({ text, kind });
13700
14474
  if (kind === "steer") {
13701
14475
  state.runtime.agent.steer(message);
13702
14476
  } else {
@@ -14090,7 +14864,11 @@ function createTurnRuntime(deps) {
14090
14864
  requestedThinkingLevel: settings.orchestrator.thinkingLevel ?? "off",
14091
14865
  use: "orchestrator",
14092
14866
  requireTools: false,
14093
- requireOutputBudget: true
14867
+ requireOutputBudget: true,
14868
+ // A resumed session already knows what this backend had open; without
14869
+ // it the first turn budgets against the probed server-wide figure and
14870
+ // corrects only once discovery reports a loaded window (issue #227).
14871
+ knownLoadedContextWindow: context.rememberedLoadedContextWindow(targetId, wireModelId)
14094
14872
  });
14095
14873
  if (!resolved.ok) {
14096
14874
  const failure = resolved.diagnostics.find((entry) => entry.severity === "error") ?? resolved.diagnostics[0];
@@ -14180,7 +14958,8 @@ function createTurnRuntime(deps) {
14180
14958
  requestedThinkingLevel: deps.getSettings().orchestrator.thinkingLevel ?? "off",
14181
14959
  use: "orchestrator",
14182
14960
  requireTools: false,
14183
- requireOutputBudget: true
14961
+ requireOutputBudget: true,
14962
+ knownLoadedContextWindow: context.rememberedLoadedContextWindow(target.target.id, target.wireModelId)
14184
14963
  });
14185
14964
  if (!refreshed.ok) return;
14186
14965
  const liveModel = state.runtime.agent.state.model;
@@ -14541,7 +15320,8 @@ function createTurnRuntime(deps) {
14541
15320
  if (isAssistant && usage && typeof usage === "object" && runFirstCallVerdict === null) {
14542
15321
  const input = typeof usage.input === "number" ? usage.input : 0;
14543
15322
  const cacheRead = typeof usage.cacheRead === "number" ? usage.cacheRead : 0;
14544
- runFirstCallVerdict = backendCacheVerdict(input, cacheRead);
15323
+ const backendTimings = enrichedEvent.message.backendTimings;
15324
+ runFirstCallVerdict = backendCacheVerdict(input, cacheRead, backendTimings);
14545
15325
  }
14546
15326
  if (usage) {
14547
15327
  context.reconcileUsage(usage);
@@ -14585,6 +15365,8 @@ function createTurnState(initialThinkingLevel) {
14585
15365
  runtime: null,
14586
15366
  lastTurnId: null,
14587
15367
  streaming: false,
15368
+ turnPreparation: "idle",
15369
+ turnPreparationSince: 0,
14588
15370
  currentThinkingLevel: initialThinkingLevel,
14589
15371
  replayedContextMessages: [],
14590
15372
  activeUserTurnId: null,
@@ -14702,6 +15484,31 @@ function createChatLoop(deps) {
14702
15484
  const middlewareToolChoice = deps.middlewareToolChoice ?? createMiddlewareToolChoiceControl();
14703
15485
  const state = createTurnState(deps.getSettings().orchestrator.thinkingLevel ?? "off");
14704
15486
  const toolStartTimes = /* @__PURE__ */ new Map();
15487
+ const preparationListeners = /* @__PURE__ */ new Set();
15488
+ const setTurnPreparation = (phase) => {
15489
+ if (state.turnPreparation === phase) return;
15490
+ if (state.turnPreparation === "idle") state.turnPreparationSince = Date.now();
15491
+ if (phase === "idle") state.turnPreparationSince = 0;
15492
+ state.turnPreparation = phase;
15493
+ for (const listener of preparationListeners) {
15494
+ try {
15495
+ listener(phase);
15496
+ } catch {
15497
+ }
15498
+ }
15499
+ };
15500
+ let preparingSubmits = 0;
15501
+ const enterPreparation = () => {
15502
+ preparingSubmits += 1;
15503
+ if (state.turnPreparation === "idle") setTurnPreparation("preparing");
15504
+ };
15505
+ const leavePreparation = () => {
15506
+ preparingSubmits = Math.max(0, preparingSubmits - 1);
15507
+ if (preparingSubmits === 0) setTurnPreparation("idle");
15508
+ };
15509
+ const endPreparationCompaction = () => {
15510
+ setTurnPreparation(preparingSubmits > 0 ? "preparing" : "idle");
15511
+ };
14705
15512
  const emit = (event) => {
14706
15513
  for (const listener of listeners) {
14707
15514
  listener(event);
@@ -14778,7 +15585,7 @@ function createChatLoop(deps) {
14778
15585
  middlewareToolChoice,
14779
15586
  consumePersistedEcho: (text) => queues.consumePersistedEcho(text),
14780
15587
  removeQueuedMirrorEntry: (text) => queues.removeQueuedMirrorEntry(text),
14781
- promptCachePayloadForAssistant: (usage) => context.promptCachePayloadForAssistant(usage),
15588
+ promptCachePayloadForAssistant: (usage, backend) => context.promptCachePayloadForAssistant(usage, backend),
14782
15589
  promptSideTokens: () => context.promptSideTokens(),
14783
15590
  observability: deps.observability
14784
15591
  });
@@ -14849,6 +15656,16 @@ function createChatLoop(deps) {
14849
15656
  return { ok: false, reason: err instanceof Error ? err.message : String(err) };
14850
15657
  }
14851
15658
  };
15659
+ const withEndpointSlot = async (runtime, round) => {
15660
+ const endpointKey = canonicalEndpointKey(runtime.runtimeResolution.target);
15661
+ const release = endpointKey === null ? () => {
15662
+ } : registerForegroundStream(endpointKey);
15663
+ try {
15664
+ return await round();
15665
+ } finally {
15666
+ release();
15667
+ }
15668
+ };
14852
15669
  const writeOutOfTurnUsageRow = deps.recordOutOfTurnUsageRow ?? ((row2) => appendOutOfTurnUsageRow(clioStateDir(), row2));
14853
15670
  const recordOutOfTurnUsage = (runtime, usage, label) => {
14854
15671
  if (!usage) return;
@@ -14893,6 +15710,39 @@ function createChatLoop(deps) {
14893
15710
  }
14894
15711
  });
14895
15712
  };
15713
+ let turnActive = false;
15714
+ const prewarm = createTurnPrewarm({
15715
+ state,
15716
+ getSettings: deps.getSettings,
15717
+ providers: deps.providers,
15718
+ context,
15719
+ bus: deps.bus,
15720
+ ...deps.session ? { session: deps.session } : {},
15721
+ isLatencySurface: () => deps.isLatencySurface?.() !== false,
15722
+ isTurnActive: () => turnActive,
15723
+ hasActiveDispatch: () => (deps.hasActiveDispatch ?? deps.hasAttachedDispatch)?.() === true,
15724
+ prepareRuntime: async (signal) => {
15725
+ await turnRuntime.ensureLiveCapabilitiesForSelectedModel().catch(() => {
15726
+ });
15727
+ return prepareOutOfTurnRound("a turn is in flight", signal);
15728
+ },
15729
+ applySessionTools: (runtime) => {
15730
+ runtime.agent.state.tools = resolveSessionTools(
15731
+ runtime,
15732
+ deps.toolRegistry,
15733
+ currentToolInvokeOptions,
15734
+ turnRuntime.toolTelemetry
15735
+ );
15736
+ },
15737
+ recordUsage: (runtime, usage) => {
15738
+ recordOutOfTurnUsage(runtime, sideQuestionUsage(usage), "prewarm");
15739
+ },
15740
+ ...deps.runPrewarm ? { runPrewarm: deps.runPrewarm } : {},
15741
+ ...deps.abortPrewarmOnSubmit === void 0 ? {} : { abortRoundOnSubmit: deps.abortPrewarmOnSubmit },
15742
+ ...deps.registerPrewarmEndpointSlot ? { registerEndpointSlot: deps.registerPrewarmEndpointSlot } : {}
15743
+ });
15744
+ const unsubscribePrewarmCompaction = subscribePrewarmToCompaction(deps.bus, prewarm);
15745
+ prewarm.schedule("session-start");
14896
15746
  const api = {
14897
15747
  steer: (text) => queues.steer(text),
14898
15748
  queueFollowUp: (text) => queues.queueFollowUp(text),
@@ -14905,9 +15755,9 @@ function createChatLoop(deps) {
14905
15755
  let mode = options.steering ?? DEFAULT_STEERING_MODE;
14906
15756
  const trimmed = text.trim();
14907
15757
  if (mode === "interrupt" && trimmed.length > 0) {
14908
- const refusal = interruptRefusalReason();
14909
- if (refusal !== null) {
14910
- emitNotice(`[Clio Coder] interrupt refused: ${refusal}. Queued for the next slot instead.`, "warning");
15758
+ const refusal2 = interruptRefusalReason();
15759
+ if (refusal2 !== null) {
15760
+ emitNotice(`[Clio Coder] interrupt refused: ${refusal2}. Queued for the next slot instead.`, "warning");
14911
15761
  mode = "next-slot";
14912
15762
  } else {
14913
15763
  const prior = priorSubmit;
@@ -14931,15 +15781,15 @@ function createChatLoop(deps) {
14931
15781
  const hasImages = options.images !== void 0 && options.images.length > 0;
14932
15782
  if (!hasImages && trimmed.length > 0 && state.runtime) {
14933
15783
  if (isWorkerShareNote(trimmed)) state.turnSharedWorkerNote = true;
14934
- if (mode === "end-of-turn") queues.queueFollowUp(trimmed);
14935
- else queues.steer(trimmed);
15784
+ if (mode === "end-of-turn") queues.queueFollowUp(text);
15785
+ else queues.steer(text);
14936
15786
  return;
14937
15787
  }
14938
15788
  emitNotice("[Clio Coder] response already in progress. Press Esc to cancel the active run.");
14939
15789
  return;
14940
15790
  }
14941
15791
  }
14942
- state.lastRunSnapshot = null;
15792
+ const previousRunSnapshot = state.lastRunSnapshot;
14943
15793
  let agentRuntime;
14944
15794
  try {
14945
15795
  await turnRuntime.ensureLiveCapabilitiesForSelectedModel();
@@ -14970,6 +15820,7 @@ function createChatLoop(deps) {
14970
15820
  currentToolInvokeOptions,
14971
15821
  turnRuntime.toolTelemetry
14972
15822
  );
15823
+ const toolSignature = toolSignatureFromState(agentRuntime.agent.state.tools);
14973
15824
  const askUserPolicy = createAskUserToolPolicy(agentRuntime.agent.state.tools);
14974
15825
  middleware.fireTurnStart(agentRuntime, text, pendingSkillRequests.length, options.requestContinuation === true);
14975
15826
  const reminderBlock = middleware.flushPendingReminders();
@@ -14984,9 +15835,12 @@ function createChatLoop(deps) {
14984
15835
  const submittedText = [reminderBlock, skillPreamble, taskMemoryHandoffSource, text].filter((part) => part.length > 0).join("\n\n");
14985
15836
  const forceNow = process.env.CLIO_CODER_FORCE_COMPACT === "1";
14986
15837
  try {
15838
+ setTurnPreparation("compacting");
14987
15839
  await context.runAutoCompact(agentRuntime, forceNow, void 0, void 0, submittedText);
14988
15840
  } catch (err) {
14989
15841
  emitNotice(`[Clio Coder] auto-compaction failed: ${err instanceof Error ? err.message : String(err)}`);
15842
+ } finally {
15843
+ endPreparationCompaction();
14990
15844
  }
14991
15845
  const compiledPrompt = await context.ensureSessionPrompt(agentRuntime);
14992
15846
  const compactionThreshold = deps.getSettings().compaction?.threshold ?? null;
@@ -14995,18 +15849,23 @@ function createChatLoop(deps) {
14995
15849
  pendingUserInput: submittedText,
14996
15850
  images,
14997
15851
  promptHash: compiledPrompt?.systemPromptHash,
14998
- toolSignature: toolSignatureFromState(agentRuntime.agent.state.tools)
15852
+ toolSignature
14999
15853
  });
15000
15854
  const reservedOutput = resolveReservedOutputTokens(agentRuntime.runtimeResolution.capabilityDecisions.maxTokens);
15001
15855
  const effectiveWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
15002
15856
  const pendingInputTokens = ceilChars(submittedText.length);
15003
15857
  let turnSnapshot = captureTurnSnapshot("pending");
15004
- const totalEstimate = snapshotInputTokens(turnSnapshot) + pendingInputTokens + reservedOutput;
15858
+ const budgetedPromptTokens = (snapshot) => Math.max(
15859
+ snapshotInputTokens(snapshot) + pendingInputTokens,
15860
+ context.liveContextEstimate(agentRuntime, submittedText).tokens
15861
+ );
15862
+ const totalEstimate = budgetedPromptTokens(turnSnapshot) + reservedOutput;
15005
15863
  if (effectiveWindow > 0 && totalEstimate > effectiveWindow) {
15006
15864
  emitNotice(
15007
- `[Clio Coder] Estimated request size ${totalEstimate} tokens (input ${snapshotInputTokens(turnSnapshot) + pendingInputTokens} + output budget ${reservedOutput}) exceeds the effective context window of ${effectiveWindow} tokens. Running compaction before sending...`
15865
+ `[Clio Coder] Estimated request size ${totalEstimate} tokens (input ${totalEstimate - reservedOutput} + output budget ${reservedOutput}) exceeds the effective context window of ${effectiveWindow} tokens. Running compaction before sending...`
15008
15866
  );
15009
- const compacted = await context.runAutoCompact(agentRuntime, true, void 0, void 0, submittedText);
15867
+ setTurnPreparation("compacting");
15868
+ const compacted = await context.runAutoCompact(agentRuntime, true, void 0, void 0, submittedText).finally(endPreparationCompaction);
15010
15869
  if (!compacted) {
15011
15870
  emitNotice(
15012
15871
  "[Clio Coder] Compaction could not reclaim enough space. Request blocked; trim the prompt, reduce active tools, or start a fresh session."
@@ -15015,7 +15874,7 @@ function createChatLoop(deps) {
15015
15874
  }
15016
15875
  context.refreshAgentMessagesFromSession(agentRuntime);
15017
15876
  turnSnapshot = captureTurnSnapshot("pending");
15018
- const postTotalEstimate = snapshotInputTokens(turnSnapshot) + pendingInputTokens + reservedOutput;
15877
+ const postTotalEstimate = budgetedPromptTokens(turnSnapshot) + reservedOutput;
15019
15878
  if (postTotalEstimate > effectiveWindow) {
15020
15879
  emitNotice(
15021
15880
  `[Clio Coder] Request still exceeds the effective window after compaction (${postTotalEstimate} > ${effectiveWindow}). Request blocked.`
@@ -15035,6 +15894,13 @@ function createChatLoop(deps) {
15035
15894
  );
15036
15895
  if (interrupted) emit({ type: "queued_user_turn", text, kind: "interrupt" });
15037
15896
  context.logPromptCompileIfPending();
15897
+ const previousThinkingLevel = previousRunSnapshot?.runtimeResolution?.effectiveThinkingLevel;
15898
+ if (previousThinkingLevel !== void 0 && previousThinkingLevel !== agentRuntime.runtimeResolution.effectiveThinkingLevel) {
15899
+ context.noteColdReason("thinking_change");
15900
+ }
15901
+ if (typeof previousRunSnapshot?.toolSignature === "string" && previousRunSnapshot.toolSignature !== toolSignature) {
15902
+ context.noteColdReason("tool_surface_change");
15903
+ }
15038
15904
  turnSnapshot = { ...turnSnapshot, turnId: userTurnId ?? "unknown" };
15039
15905
  context.setCurrentSnapshot(turnSnapshot);
15040
15906
  context.persistContextSnapshot(turnSnapshot);
@@ -15049,7 +15915,7 @@ function createChatLoop(deps) {
15049
15915
  compiledPromptHash: promptHash,
15050
15916
  staticCompositionHash: promptHash,
15051
15917
  promptSignature: promptHash,
15052
- toolSignature: toolSignatureFromState(agentRuntime.agent.state.tools),
15918
+ toolSignature,
15053
15919
  runtimeResolution: runtimeTargetSnapshot(agentRuntime.runtimeResolution),
15054
15920
  sessionId: deps.session?.current()?.id ?? null,
15055
15921
  cwd: process.cwd()
@@ -15062,6 +15928,9 @@ function createChatLoop(deps) {
15062
15928
  state.interruptedUsage = null;
15063
15929
  context.consumeExpectedColdReasons(agentRuntime.runtimeId);
15064
15930
  state.streaming = true;
15931
+ const endpointKey = canonicalEndpointKey(agentRuntime.runtimeResolution.target);
15932
+ const releaseForeground = endpointKey === null ? () => {
15933
+ } : registerForegroundStream(endpointKey);
15065
15934
  try {
15066
15935
  options.onAdmitted?.();
15067
15936
  } catch {
@@ -15111,6 +15980,7 @@ function createChatLoop(deps) {
15111
15980
  }
15112
15981
  await recovery.runCompactAndRetry(agentRuntime, runtimePromptText, overflow, images);
15113
15982
  } finally {
15983
+ releaseForeground();
15114
15984
  if (askUserPolicy) {
15115
15985
  try {
15116
15986
  await finalizeAskUserInterviewForHost(
@@ -15180,9 +16050,19 @@ function createChatLoop(deps) {
15180
16050
  isStreaming() {
15181
16051
  return state.streaming;
15182
16052
  },
16053
+ turnPreparation() {
16054
+ return { phase: state.turnPreparation, since: state.turnPreparationSince };
16055
+ },
16056
+ onTurnPreparation(handler) {
16057
+ preparationListeners.add(handler);
16058
+ return () => {
16059
+ preparationListeners.delete(handler);
16060
+ };
16061
+ },
15183
16062
  contextUsage: () => context.contextUsage(),
15184
16063
  contextLedger: () => context.contextLedger(),
15185
16064
  whenSettled: () => activeSubmit,
16065
+ whenPrewarmSettled: () => prewarm.settled(),
15186
16066
  resetForSession(leafTurnId, replayMessages) {
15187
16067
  if (state.runtime) {
15188
16068
  state.runtime.agent.abort();
@@ -15194,6 +16074,7 @@ function createChatLoop(deps) {
15194
16074
  middleware.clearPendingReminders();
15195
16075
  middlewareToolChoice.reset();
15196
16076
  state.lastTurnId = leafTurnId;
16077
+ state.lastRunSnapshot = null;
15197
16078
  context.resetForSession();
15198
16079
  void turnRuntime.ensureLiveCapabilitiesForSelectedModel().catch(() => {
15199
16080
  });
@@ -15204,10 +16085,13 @@ function createChatLoop(deps) {
15204
16085
  if (deps.protectedArtifacts) {
15205
16086
  reloadProtectedArtifactsForSession(deps.protectedArtifacts, deps.readSessionEntries);
15206
16087
  }
16088
+ prewarm.schedule(replayMessages && replayMessages.length > 0 ? "resume" : "session-start");
15207
16089
  },
15208
16090
  dispose() {
15209
16091
  unsubscribeConfigReload?.();
15210
16092
  unsubscribeSynthesisLock?.();
16093
+ unsubscribePrewarmCompaction();
16094
+ prewarm.dispose();
15211
16095
  context.dispose();
15212
16096
  if (state.runtime) {
15213
16097
  state.runtime.agent.abort();
@@ -15230,16 +16114,19 @@ function createChatLoop(deps) {
15230
16114
  if (!prepared.ok) return { status: "refused", reason: prepared.reason };
15231
16115
  let result;
15232
16116
  try {
15233
- result = await sideQuestionRound({
15234
- model: prepared.runtime.agent.state.model,
15235
- // Read-only: runSideQuestion copies before appending its own
15236
- // message, so the live agent's history is untouched.
15237
- messages: prepared.runtime.agent.state.messages,
15238
- question: text,
15239
- ...prepared.apiKey !== void 0 ? { apiKey: prepared.apiKey } : {},
15240
- ...options.signal ? { signal: options.signal } : {},
15241
- ...options.onDelta ? { onDelta: options.onDelta } : {}
15242
- });
16117
+ result = await withEndpointSlot(
16118
+ prepared.runtime,
16119
+ () => sideQuestionRound({
16120
+ model: prepared.runtime.agent.state.model,
16121
+ // Read-only: runSideQuestion copies before appending its own
16122
+ // message, so the live agent's history is untouched.
16123
+ messages: prepared.runtime.agent.state.messages,
16124
+ question: text,
16125
+ ...prepared.apiKey !== void 0 ? { apiKey: prepared.apiKey } : {},
16126
+ ...options.signal ? { signal: options.signal } : {},
16127
+ ...options.onDelta ? { onDelta: options.onDelta } : {}
16128
+ })
16129
+ );
15243
16130
  } catch (err) {
15244
16131
  return { status: "failed", reason: err instanceof Error ? err.message : String(err) };
15245
16132
  }
@@ -15258,14 +16145,21 @@ function createChatLoop(deps) {
15258
16145
  if (!prepared.ok) return { status: "refused", reason: prepared.reason };
15259
16146
  let result;
15260
16147
  try {
15261
- result = await handoffRound({
15262
- model: prepared.runtime.agent.state.model,
15263
- // Read-only, exactly as the side-question round treats it.
15264
- messages: prepared.runtime.agent.state.messages,
15265
- goal: text,
15266
- ...prepared.apiKey !== void 0 ? { apiKey: prepared.apiKey } : {},
15267
- ...options.signal ? { signal: options.signal } : {}
15268
- });
16148
+ result = await withEndpointSlot(
16149
+ prepared.runtime,
16150
+ () => handoffRound({
16151
+ model: prepared.runtime.agent.state.model,
16152
+ // Read-only, exactly as the side-question round treats it.
16153
+ messages: prepared.runtime.agent.state.messages,
16154
+ goal: text,
16155
+ // The runtime id is what decides whether the schema can be bound
16156
+ // on the wire rather than only stated in the prompt.
16157
+ runtimeId: prepared.runtime.runtimeResolution.runtime.id,
16158
+ ...prepared.apiKey !== void 0 ? { apiKey: prepared.apiKey } : {},
16159
+ ...options.signal ? { signal: options.signal } : {},
16160
+ ...options.repair ? { repair: options.repair } : {}
16161
+ })
16162
+ );
15269
16163
  } catch (err) {
15270
16164
  return { status: "failed", reason: err instanceof Error ? err.message : String(err) };
15271
16165
  }
@@ -15304,13 +16198,17 @@ function createChatLoop(deps) {
15304
16198
  const submitInner = api.submit.bind(api);
15305
16199
  const submitTracked = (text, options) => {
15306
16200
  priorSubmit = activeSubmit;
15307
- const run = submitInner(text, options);
16201
+ turnActive = true;
16202
+ const run = submitInner(text, options).finally(() => {
16203
+ turnActive = false;
16204
+ });
15308
16205
  activeSubmit = run.catch(() => {
15309
16206
  });
15310
16207
  return run;
15311
16208
  };
15312
16209
  let admissionTail = null;
15313
16210
  api.submit = (text, options = {}) => {
16211
+ prewarm.cancel();
15314
16212
  const previous = admissionTail;
15315
16213
  let release = () => {
15316
16214
  };
@@ -15322,14 +16220,30 @@ function createChatLoop(deps) {
15322
16220
  release();
15323
16221
  if (admissionTail === ticket) admissionTail = null;
15324
16222
  };
15325
- const start = () => submitTracked(text, {
15326
- ...options,
15327
- onAdmitted: () => {
15328
- releaseTicket();
15329
- options.onAdmitted?.();
16223
+ enterPreparation();
16224
+ let leftPreparation = false;
16225
+ const leaveOnce = () => {
16226
+ if (leftPreparation) return;
16227
+ leftPreparation = true;
16228
+ leavePreparation();
16229
+ };
16230
+ const start = async () => {
16231
+ const { onPreparationVisible, ...submitOptions } = options;
16232
+ try {
16233
+ await onPreparationVisible?.();
16234
+ } catch {
15330
16235
  }
15331
- }).finally(releaseTicket);
15332
- return previous ? previous.then(start) : start();
16236
+ return submitTracked(text, {
16237
+ ...submitOptions,
16238
+ onAdmitted: () => {
16239
+ releaseTicket();
16240
+ leaveOnce();
16241
+ options.onAdmitted?.();
16242
+ }
16243
+ }).finally(releaseTicket);
16244
+ };
16245
+ const run = previous ? previous.then(start) : start();
16246
+ return run.finally(leaveOnce);
15333
16247
  };
15334
16248
  return api;
15335
16249
  }
@@ -15632,6 +16546,7 @@ function verificationText(state) {
15632
16546
  if (!state || state.status === "idle") return "";
15633
16547
  if (state.status === "running") return `${GLYPH.running} verify running`;
15634
16548
  if (state.status === "ok") return `${GLYPH.ok} verify ok ${state.detail}`;
16549
+ if (state.status === "retired") return `${GLYPH.warn} verify retired ${state.detail}`;
15635
16550
  return `${GLYPH.error} verify fail ${state.detail}`;
15636
16551
  }
15637
16552
  function buildArtifactHeader(artifact, verification, width) {
@@ -15643,11 +16558,22 @@ function buildArtifactHeader(artifact, verification, width) {
15643
16558
  if (size.length > 0) parts.push(theme6.fg("dim", size));
15644
16559
  const verify = verificationText(verification);
15645
16560
  if (verify.length > 0) {
15646
- const token = verification?.status === "ok" ? "success" : verification?.status === "fail" ? "error" : "info";
16561
+ const token = verification?.status === "ok" ? "success" : verification?.status === "fail" ? "error" : verification?.status === "retired" ? "warning" : "info";
15647
16562
  parts.push(theme6.fg(token, verify));
15648
16563
  }
15649
16564
  return padAnsi(parts.join(" "), width, ELLIPSIS);
15650
16565
  }
16566
+ function buildArtifactHeaderLines(artifact, verification, width) {
16567
+ const metadata = buildArtifactHeader(artifact, void 0, width);
16568
+ const verify = verificationText(verification);
16569
+ if (artifact === void 0 || verify.length === 0) return [metadata];
16570
+ const theme6 = clioTheme();
16571
+ const token = verification?.status === "ok" ? "success" : verification?.status === "fail" ? "error" : verification?.status === "retired" ? "warning" : "info";
16572
+ return [
16573
+ metadata,
16574
+ ...wrapTextWithAnsi(theme6.fg(token, verify), Math.max(1, width)).map((line) => padAnsi(line, width, ELLIPSIS))
16575
+ ];
16576
+ }
15651
16577
  function viewFooterHint(focus, canVerify, innerWidth) {
15652
16578
  if (innerWidth !== void 0 && viewUsesSinglePane(innerWidth - 2)) {
15653
16579
  const budget = innerWidth - 3;
@@ -15837,14 +16763,14 @@ var ViewOverlayView = class {
15837
16763
  this.ensureContentLoaded(artifact);
15838
16764
  this.lastContentWidth = width;
15839
16765
  const verification = artifact ? this.verifications.get(artifactKey(artifact)) : void 0;
15840
- const header = buildArtifactHeader(artifact, verification, width);
15841
- const bodyHeight = Math.max(0, height - 1);
16766
+ const header = buildArtifactHeaderLines(artifact, verification, width);
16767
+ const bodyHeight = Math.max(0, height - header.length);
15842
16768
  this.lastContentBodyHeight = Math.max(1, bodyHeight);
15843
16769
  const body = this.renderedContentLines(width);
15844
16770
  const maxOffset = Math.max(0, body.length - Math.max(1, bodyHeight));
15845
16771
  if (this.contentScrollOffset > maxOffset) this.contentScrollOffset = maxOffset;
15846
16772
  const visible = body.slice(this.contentScrollOffset, this.contentScrollOffset + bodyHeight).map((line) => padAnsi(line, width, ELLIPSIS));
15847
- const lines = [header, ...visible];
16773
+ const lines = [...header, ...visible];
15848
16774
  return this.fixedLines(lines, width, height);
15849
16775
  }
15850
16776
  fixedLines(lines, width, height) {
@@ -15957,7 +16883,7 @@ var ViewOverlayView = class {
15957
16883
  void artifact.verify().then((result) => {
15958
16884
  this.verifications.set(
15959
16885
  key,
15960
- result.ok ? { status: "ok", detail: result.detail } : { status: "fail", detail: result.detail }
16886
+ result.ok ? { status: "ok", detail: result.detail } : { status: result.retired === true ? "retired" : "fail", detail: result.detail }
15961
16887
  );
15962
16888
  }).catch((err) => {
15963
16889
  const detail = err instanceof Error ? err.message : String(err);
@@ -16034,7 +16960,8 @@ function createQuestionState(question) {
16034
16960
  selected: /* @__PURE__ */ new Set(),
16035
16961
  customAnswer: "",
16036
16962
  inputValue: "",
16037
- answer: ""
16963
+ answer: "",
16964
+ rawValue: ""
16038
16965
  };
16039
16966
  }
16040
16967
  function isOtherOption(label) {
@@ -16071,12 +16998,16 @@ function optionIndexFromValue(value) {
16071
16998
  const index = Number(value.slice("option:".length));
16072
16999
  return Number.isInteger(index) && index >= 0 ? index : null;
16073
17000
  }
16074
- function answerText(question, selected, customAnswer) {
16075
- const parts = [];
17001
+ function selectedOptionLabels(question, selected) {
17002
+ const labels = [];
16076
17003
  for (const index of [...selected].sort((a, b) => a - b)) {
16077
17004
  const label = question.options?.[index]?.label;
16078
- if (label) parts.push(label);
17005
+ if (label) labels.push(label);
16079
17006
  }
17007
+ return labels;
17008
+ }
17009
+ function answerText(question, selected, customAnswer) {
17010
+ const parts = selectedOptionLabels(question, selected);
16080
17011
  const custom = customAnswer.trim();
16081
17012
  if (custom.length > 0) parts.push(custom);
16082
17013
  return parts.join("; ");
@@ -16193,6 +17124,10 @@ var AskUserOverlayView = class {
16193
17124
  this.commitMultiSelectOrOpenOther(state);
16194
17125
  return;
16195
17126
  }
17127
+ if (this.isAddTextKey(data)) {
17128
+ this.chooseFocusedAndOpenText(question, state);
17129
+ return;
17130
+ }
16196
17131
  this.list?.handleInput(data);
16197
17132
  }
16198
17133
  /**
@@ -16319,20 +17254,16 @@ var AskUserOverlayView = class {
16319
17254
  { key: "Alt+Left/Right", verb: "question" }
16320
17255
  ]) : this.withScrollHint([{ key: "Enter", verb: recordAnswer }]);
16321
17256
  }
17257
+ const addText = { key: "t", verb: "add text", short: "text" };
16322
17258
  if (question.multi_select === true) {
16323
17259
  return this.questions.length > 1 ? this.withScrollHint([
16324
17260
  { key: "Left/Right", verb: "question" },
16325
17261
  { key: "Space", verb: "toggle" },
17262
+ addText,
16326
17263
  { key: "Enter", verb: recordAnswer }
16327
- ]) : this.withScrollHint([
16328
- { key: "Space", verb: "toggle" },
16329
- { key: "Enter", verb: recordAnswer }
16330
- ]);
17264
+ ]) : this.withScrollHint([{ key: "Space", verb: "toggle" }, addText, { key: "Enter", verb: recordAnswer }]);
16331
17265
  }
16332
- return this.questions.length > 1 ? this.withScrollHint([
16333
- { key: "Left/Right", verb: "question" },
16334
- { key: "Enter", verb: recordAnswer }
16335
- ]) : this.withScrollHint([{ key: "Enter", verb: recordAnswer }]);
17266
+ return this.questions.length > 1 ? this.withScrollHint([{ key: "Left/Right", verb: "question" }, addText, { key: "Enter", verb: recordAnswer }]) : this.withScrollHint([addText, { key: "Enter", verb: recordAnswer }]);
16336
17267
  }
16337
17268
  renderDecisionContext(width) {
16338
17269
  const theme6 = clioTheme();
@@ -16433,6 +17364,32 @@ var AskUserOverlayView = class {
16433
17364
  isTextModeNextKey(data) {
16434
17365
  return this.questions.length > 1 && (matchesKey(data, "alt+right") || matchesKey(data, "ctrl+right"));
16435
17366
  }
17367
+ /**
17368
+ * The key that adds typed text to the option under the cursor.
17369
+ *
17370
+ * Choosing an option used to be the whole answer, so a model that offered
17371
+ * "Exact number - I'll type it" gave the operator a label and nowhere to put
17372
+ * the number; the interview then spent two of its four rounds asking for the
17373
+ * figures again (issue #228). The list itself only reads the arrows, Enter,
17374
+ * and Esc, so a letter is free here.
17375
+ */
17376
+ isAddTextKey(data) {
17377
+ return matchesKey(data, "t");
17378
+ }
17379
+ /**
17380
+ * Take the focused option and open the text field for it, without committing.
17381
+ * Submitting the text records the label and the text together.
17382
+ */
17383
+ chooseFocusedAndOpenText(question, state) {
17384
+ const current = this.list?.getSelectedItem();
17385
+ const optionIndex = current && current.value !== "other" ? optionIndexFromValue(current.value) : null;
17386
+ if (optionIndex !== null) {
17387
+ if (question.multi_select === true) state.selected.add(optionIndex);
17388
+ else state.selected = /* @__PURE__ */ new Set([optionIndex]);
17389
+ state.focusedValue = `option:${optionIndex}`;
17390
+ }
17391
+ this.openTextInput(state.selected.size > 0 ? "Add your answer to the chosen option" : "Other answer");
17392
+ }
16436
17393
  /**
16437
17394
  * The row above the question, or nothing.
16438
17395
  *
@@ -16586,14 +17543,15 @@ var AskUserOverlayView = class {
16586
17543
  return;
16587
17544
  }
16588
17545
  state.inputValue = answer;
17546
+ state.rawValue = value;
16589
17547
  if (questionHasOptions(question) && question.multi_select === true) {
16590
17548
  state.customAnswer = answer;
16591
17549
  this.commitCurrentAnswer();
16592
- } else {
16593
- state.customAnswer = questionHasOptions(question) ? answer : "";
16594
- state.answer = answer;
16595
- this.finishIfCompleteOrAdvance();
17550
+ return;
16596
17551
  }
17552
+ state.customAnswer = questionHasOptions(question) ? answer : "";
17553
+ state.answer = questionHasOptions(question) ? answerText(question, state.selected, state.customAnswer) : answer;
17554
+ this.finishIfCompleteOrAdvance();
16597
17555
  };
16598
17556
  activeInput.onEscape = () => this.cancel();
16599
17557
  this.input = activeInput;
@@ -16622,7 +17580,10 @@ var AskUserOverlayView = class {
16622
17580
  return;
16623
17581
  }
16624
17582
  state.selected = /* @__PURE__ */ new Set([optionIndex]);
16625
- state.answer = question.options?.[optionIndex]?.label ?? item.label;
17583
+ state.customAnswer = "";
17584
+ state.rawValue = "";
17585
+ state.inputValue = "";
17586
+ state.answer = answerText(question, state.selected, state.customAnswer) || item.label;
16626
17587
  state.focusedValue = item.value;
16627
17588
  this.status = "";
16628
17589
  this.finishIfCompleteOrAdvance();
@@ -16734,12 +17695,26 @@ var AskUserOverlayView = class {
16734
17695
  allAnswered() {
16735
17696
  return this.states.length > 0 && this.states.every((state) => state.answer.trim().length > 0);
16736
17697
  }
17698
+ /**
17699
+ * What the round captured, as three separable facts per question: the one-line
17700
+ * answer, the labels chosen, and the text typed. A reader tells a label-only
17701
+ * answer from a label-plus-value one by whether `value` is there, which the
17702
+ * joined string alone could never say.
17703
+ */
16737
17704
  answers() {
16738
17705
  const answers = [];
16739
17706
  for (let index = 0; index < this.questions.length; index += 1) {
16740
17707
  const question = this.questions[index];
16741
- const answer = this.states[index]?.answer.trim();
16742
- if (question && answer && answer.length > 0) answers.push({ question: question.question, answer });
17708
+ const state = this.states[index];
17709
+ const answer = state?.answer.trim();
17710
+ if (!question || !state || !answer || answer.length === 0) continue;
17711
+ const options = selectedOptionLabels(question, state.selected);
17712
+ answers.push({
17713
+ question: question.question,
17714
+ answer,
17715
+ ...options.length > 0 ? { options } : {},
17716
+ ...state.rawValue.length > 0 ? { value: state.rawValue } : {}
17717
+ });
16743
17718
  }
16744
17719
  return answers;
16745
17720
  }
@@ -17348,7 +18323,7 @@ function legendRow2(group, contentWidth) {
17348
18323
  const tokens = formatTokens(group.tokens);
17349
18324
  const percent = formatContextPercent(group.percent);
17350
18325
  const right = `${tokens.padStart(9)} ${percent.padStart(6)}`;
17351
- const labelToken = group.category === "free" || group.category === "reserve" ? "dim" : "muted";
18326
+ const labelToken = group.category === "reserve" ? "frame" : group.category === "free" ? "dim" : "muted";
17352
18327
  const leftWidth = Math.max(0, contentWidth - visibleWidth(right) - 2);
17353
18328
  const labelText = group.label.length > leftWidth ? group.label.slice(0, leftWidth) : group.label.padEnd(leftWidth);
17354
18329
  return `${swatch} ${theme6.fg(labelToken, labelText)} ${theme6.fg("muted", right)}`;
@@ -17370,6 +18345,16 @@ function coldReasonLabel(reason) {
17370
18345
  return "compaction";
17371
18346
  case "dispatch":
17372
18347
  return "dispatch traffic";
18348
+ case "residency":
18349
+ return "residency change";
18350
+ case "thinking_change":
18351
+ return "thinking-level change";
18352
+ case "tool_surface_change":
18353
+ return "tool-surface change";
18354
+ case "prompt_recompiled":
18355
+ return "prompt recompile";
18356
+ case "background_memory":
18357
+ return "background memory step";
17373
18358
  default:
17374
18359
  return reason;
17375
18360
  }
@@ -17441,18 +18426,28 @@ function renderContextLedgerLines(ledger, contentWidth, workingSet, workingSetCo
17441
18426
  if (ledger.promptCache) {
17442
18427
  const cache2 = ledger.promptCache;
17443
18428
  const shell = cache2.shellReused ? "shell reused" : "shell recompiled";
17444
- const backend = cache2.backendVerdict === "hot" || cache2.backendVerdict === "partial" ? "backend reused" : cache2.backendVerdict === "cold" ? "backend cold" : cache2.backendVerdict === "small" ? "backend small" : "backend n/a";
18429
+ const backendCacheReadsUnknown = cache2.backend?.cachedTokens === null;
18430
+ const backend = backendCacheReadsUnknown ? "server does not report cache reads" : cache2.backendVerdict === "hot" || cache2.backendVerdict === "partial" ? "backend reused" : cache2.backendVerdict === "cold" ? "backend cold" : cache2.backendVerdict === "small" ? "backend small" : "backend n/a";
17445
18431
  const read = cache2.cacheReadTokens !== null ? `cache read ${formatTokens(cache2.cacheReadTokens)}` : "cache read n/a";
17446
18432
  const uncached = cache2.uncachedInputTokens !== null ? `uncached input ${formatTokens(cache2.uncachedInputTokens)}` : null;
17447
- const line = ["prompt cache:", shell, "\xB7", backend, "\xB7", read, ...uncached ? ["\xB7", uncached] : []].join(" ");
17448
- const coldReasons = cache2.backendVerdict === "cold" ? cache2.expectedColdReasons ?? [] : [];
17449
- const misleading = cache2.shellReused && cache2.backendVerdict === "cold" && coldReasons.length === 0;
18433
+ const line = backendCacheReadsUnknown ? ["prompt cache:", shell, "\xB7", backend].join(" ") : ["prompt cache:", shell, "\xB7", backend, "\xB7", read, ...uncached ? ["\xB7", uncached] : []].join(" ");
18434
+ const coldReasons = cache2.backendVerdict === "cold" && !backendCacheReadsUnknown ? cache2.expectedColdReasons ?? [] : [];
18435
+ const misleading = cache2.shellReused && cache2.backendVerdict === "cold" && !backendCacheReadsUnknown && coldReasons.length === 0;
17450
18436
  lines.push(theme6.fg(misleading ? "warning" : "dim", line));
18437
+ if (cache2.backend) {
18438
+ const prefill = cache2.backend.cachedTokens !== null && cache2.uncachedPrefillTokens !== null ? `prefill: ${formatTokens(cache2.uncachedPrefillTokens)} uncached \xB7 ${formatTokens(cache2.backend.cachedTokens)} cached \xB7 ${formatTokens(cache2.backend.promptMs)} ms` : `prefill: ${formatTokens(cache2.backend.promptTokens)} prompt \xB7 ${formatTokens(cache2.backend.promptMs)} ms`;
18439
+ lines.push(theme6.fg("dim", prefill));
18440
+ }
17451
18441
  if (coldReasons.length > 0) {
17452
18442
  const reasons = coldReasons.map(coldReasonLabel).join(", ");
17453
18443
  lines.push(theme6.fg("dim", `last cold turn: ${reasons} (expected)`));
17454
18444
  }
17455
18445
  }
18446
+ if (ledger.prewarm) {
18447
+ const tokens = ledger.prewarm.tokens !== null ? `${formatTokens(ledger.prewarm.tokens)} tokens` : "prefix";
18448
+ const aborted = ledger.prewarm.aborted ? " (aborted on submit; prefix stays in the slot)" : "";
18449
+ lines.push(theme6.fg("dim", `prewarmed: ${tokens} in ${formatTokens(ledger.prewarm.ms)} ms${aborted}`));
18450
+ }
17456
18451
  if (ledger.lastCompaction) {
17457
18452
  const pruneInfo = `last compaction: reclaimed ${formatTokens(ledger.lastCompaction.tokensBefore)} -> ${formatTokens(ledger.lastCompaction.tokensAfter)} tokens (${ledger.lastCompaction.stage})`;
17458
18453
  lines.push(theme6.fg("dim", pruneInfo));
@@ -17546,6 +18541,8 @@ function aggregateCostEntries(entries) {
17546
18541
  existing.row.apiCalls += entry.apiCalls ?? 1;
17547
18542
  if (entry.label === "side-question") existing.row.sideQuestions += 1;
17548
18543
  if (entry.label === "handoff") existing.row.handoffs += 1;
18544
+ if (entry.label === "prewarm") existing.row.prewarms += 1;
18545
+ if (entry.label === "background-memory") existing.row.backgroundMemory += 1;
17549
18546
  for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
17550
18547
  addResponseModelIdObservationCounts(
17551
18548
  existing.responseModelIdObservationCounts,
@@ -17567,7 +18564,9 @@ function aggregateCostEntries(entries) {
17567
18564
  reasoningTokens: entry.reasoningTokens,
17568
18565
  apiCalls: entry.apiCalls ?? 1,
17569
18566
  sideQuestions: entry.label === "side-question" ? 1 : 0,
17570
- handoffs: entry.label === "handoff" ? 1 : 0
18567
+ handoffs: entry.label === "handoff" ? 1 : 0,
18568
+ prewarms: entry.label === "prewarm" ? 1 : 0,
18569
+ backgroundMemory: entry.label === "background-memory" ? 1 : 0
17571
18570
  },
17572
18571
  requestedModelIds: new Set(entry.requestedModelIds),
17573
18572
  responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
@@ -17599,7 +18598,9 @@ function sumRows(rows) {
17599
18598
  reasoningTokens: acc.reasoningTokens + row2.reasoningTokens,
17600
18599
  apiCalls: acc.apiCalls + row2.apiCalls,
17601
18600
  sideQuestions: acc.sideQuestions + row2.sideQuestions,
17602
- handoffs: acc.handoffs + row2.handoffs
18601
+ handoffs: acc.handoffs + row2.handoffs,
18602
+ prewarms: acc.prewarms + row2.prewarms,
18603
+ backgroundMemory: acc.backgroundMemory + row2.backgroundMemory
17603
18604
  }),
17604
18605
  {
17605
18606
  runs: 0,
@@ -17611,7 +18612,9 @@ function sumRows(rows) {
17611
18612
  reasoningTokens: 0,
17612
18613
  apiCalls: 0,
17613
18614
  sideQuestions: 0,
17614
- handoffs: 0
18615
+ handoffs: 0,
18616
+ prewarms: 0,
18617
+ backgroundMemory: 0
17615
18618
  }
17616
18619
  );
17617
18620
  }
@@ -17633,21 +18636,37 @@ function kvBlock(entries) {
17633
18636
  return annotation ? `${row2} ${theme6.fg("dim", annotation)}` : row2;
17634
18637
  });
17635
18638
  }
17636
- function summaryBlock(totalCost, totalTokens, rows) {
18639
+ function summaryBlock(totalCost, totalTokens, rows, promptCache) {
17637
18640
  const totals = sumRows(rows);
17638
18641
  const resolvedTotal = totalTokens > 0 ? totalTokens : totals.tokens;
17639
18642
  const cost = formatCostAggregate(totalCost);
18643
+ const cacheRows = promptCache !== null && hasPromptCacheTelemetry(promptCache) ? [
18644
+ [
18645
+ "uncached prefill",
18646
+ promptCache.uncachedPrefillTokens === null ? "not reported" : formatTokens2(promptCache.uncachedPrefillTokens)
18647
+ ],
18648
+ [
18649
+ "cache verdicts",
18650
+ `hot ${promptCache.verdictCounts.hot} \xB7 partial ${promptCache.verdictCounts.partial} \xB7 cold ${promptCache.verdictCounts.cold} \xB7 small ${promptCache.verdictCounts.small}`
18651
+ ]
18652
+ ] : [];
17640
18653
  return kvBlock([
17641
- ["turns", formatTokens2(totals.runs - totals.sideQuestions - totals.handoffs)],
18654
+ [
18655
+ "turns",
18656
+ formatTokens2(totals.runs - totals.sideQuestions - totals.handoffs - totals.prewarms - totals.backgroundMemory)
18657
+ ],
17642
18658
  ["model calls", formatTokens2(totals.apiCalls)],
17643
18659
  ...totals.sideQuestions > 0 ? [["side questions", formatTokens2(totals.sideQuestions)]] : [],
17644
18660
  ...totals.handoffs > 0 ? [["handoffs", formatTokens2(totals.handoffs)]] : [],
18661
+ ...totals.prewarms > 0 ? [["pre-warms", formatTokens2(totals.prewarms)]] : [],
18662
+ ...totals.backgroundMemory > 0 ? [["memory steps", formatTokens2(totals.backgroundMemory)]] : [],
17645
18663
  ...cost === null ? [] : [["cost", cost]],
17646
18664
  ["input", formatTokens2(totals.input)],
17647
18665
  ["output", formatTokens2(totals.output)],
17648
18666
  ["reasoning", ...reasoningValue(totals.reasoningTokens)],
17649
18667
  ["cache read", ...cacheReadValue(totals.cacheRead, totals.apiCalls)],
17650
18668
  ["cache write", formatTokens2(totals.cacheWrite)],
18669
+ ...cacheRows,
17651
18670
  ["processed", `${formatTokens2(resolvedTotal)} tokens`]
17652
18671
  ]);
17653
18672
  }
@@ -17656,10 +18675,12 @@ function modelBlock(row2) {
17656
18675
  return kvBlock([
17657
18676
  ["requested model ids", row2.requestedModelIds.join(", ")],
17658
18677
  ["response model id observation", responseModelIdObservationCountsLabel(row2.responseModelIdObservationCounts)],
17659
- ["turns", formatTokens2(row2.runs - row2.sideQuestions - row2.handoffs)],
18678
+ ["turns", formatTokens2(row2.runs - row2.sideQuestions - row2.handoffs - row2.prewarms - row2.backgroundMemory)],
17660
18679
  ["model calls", formatTokens2(row2.apiCalls)],
17661
18680
  ...row2.sideQuestions > 0 ? [["side questions", formatTokens2(row2.sideQuestions)]] : [],
17662
18681
  ...row2.handoffs > 0 ? [["handoffs", formatTokens2(row2.handoffs)]] : [],
18682
+ ...row2.prewarms > 0 ? [["pre-warms", formatTokens2(row2.prewarms)]] : [],
18683
+ ...row2.backgroundMemory > 0 ? [["memory steps", formatTokens2(row2.backgroundMemory)]] : [],
17663
18684
  ...cost === null ? [] : [["cost", cost]],
17664
18685
  ["input", formatTokens2(row2.input)],
17665
18686
  ["output", formatTokens2(row2.output)],
@@ -17669,10 +18690,10 @@ function modelBlock(row2) {
17669
18690
  ["processed", `${formatTokens2(row2.tokens)} tokens`]
17670
18691
  ]);
17671
18692
  }
17672
- function formatCostOverlayBodyLines(totalCost, totalTokens, rows, contentWidth) {
18693
+ function formatCostOverlayBodyLines(totalCost, totalTokens, rows, contentWidth, promptCache = null) {
17673
18694
  const theme6 = clioTheme();
17674
18695
  const lines = [];
17675
- for (const line of summaryBlock(totalCost, totalTokens, rows)) {
18696
+ for (const line of summaryBlock(totalCost, totalTokens, rows, promptCache)) {
17676
18697
  lines.push(line);
17677
18698
  }
17678
18699
  lines.push(rule(theme6, contentWidth));
@@ -17689,7 +18710,7 @@ function formatCostOverlayBodyLines(totalCost, totalTokens, rows, contentWidth)
17689
18710
  }
17690
18711
  return lines;
17691
18712
  }
17692
- function buildCostSnapshot(observability, sessionId, snapshot) {
18713
+ function buildCostSnapshot(observability, sessionId, snapshot, getSessionEntries) {
17693
18714
  const entries = observability.costEntries();
17694
18715
  const rows = aggregateCostEntries(entries);
17695
18716
  const totalTokens = rows.reduce((sum, r) => sum + r.tokens, 0);
@@ -17697,7 +18718,8 @@ function buildCostSnapshot(observability, sessionId, snapshot) {
17697
18718
  sessionId,
17698
18719
  totalCost: snapshot?.session.cost ?? observability.sessionCostSummary(),
17699
18720
  totalTokens,
17700
- rows
18721
+ rows,
18722
+ promptCache: getSessionEntries ? foldPromptCacheTelemetry(getSessionEntries()) : null
17701
18723
  };
17702
18724
  }
17703
18725
  var CostOverlayBody = class {
@@ -17708,7 +18730,13 @@ var CostOverlayBody = class {
17708
18730
  render(width) {
17709
18731
  const contentWidth = Math.max(1, Math.floor(width));
17710
18732
  const snapshot = this.getSnapshot();
17711
- return formatCostOverlayBodyLines(snapshot.totalCost, snapshot.totalTokens, snapshot.rows, contentWidth);
18733
+ return formatCostOverlayBodyLines(
18734
+ snapshot.totalCost,
18735
+ snapshot.totalTokens,
18736
+ snapshot.rows,
18737
+ contentWidth,
18738
+ snapshot.promptCache
18739
+ );
17712
18740
  }
17713
18741
  invalidate() {
17714
18742
  }
@@ -17716,7 +18744,9 @@ var CostOverlayBody = class {
17716
18744
  function openCostOverlay(tui, observability, options) {
17717
18745
  const sessionId = options?.sessionId ?? null;
17718
18746
  let latest = observability.snapshot();
17719
- const body = new CostOverlayBody(() => buildCostSnapshot(observability, sessionId, latest));
18747
+ const body = new CostOverlayBody(
18748
+ () => buildCostSnapshot(observability, sessionId, latest, options?.getSessionEntries)
18749
+ );
17720
18750
  const handle = showClioOverlayFrame(tui, body, {
17721
18751
  anchor: "center",
17722
18752
  width: COST_OVERLAY_WIDTH,
@@ -17803,6 +18833,38 @@ function compileFleetRunPreview(input) {
17803
18833
  diagnostics.push(describeError(error));
17804
18834
  return fail();
17805
18835
  }
18836
+ const routes = /* @__PURE__ */ new Map();
18837
+ if (input.resolveRoute !== void 0) {
18838
+ for (const step of plan.steps) {
18839
+ if (step.kind === "code") continue;
18840
+ try {
18841
+ const route = input.resolveRoute({
18842
+ stepId: step.id,
18843
+ agentId: step.agentId,
18844
+ task: step.task,
18845
+ scope: step.scope,
18846
+ ...step.target !== void 0 ? { target: step.target } : {},
18847
+ ...step.profile !== void 0 ? { profile: step.profile } : {}
18848
+ });
18849
+ if (route !== null) routes.set(step.id, route);
18850
+ } catch (error) {
18851
+ diagnostics.push(`step '${step.id}' route preflight failed: ${describeError(error)}`);
18852
+ }
18853
+ }
18854
+ plan = bindExecutionPlanEndpoints(
18855
+ plan,
18856
+ Object.fromEntries(
18857
+ [...routes].map(([stepId, route]) => [
18858
+ stepId,
18859
+ route.endpoint === void 0 ? void 0 : {
18860
+ key: route.endpoint.key,
18861
+ limit: route.endpoint.limit,
18862
+ ...route.endpoint.foregroundHeld !== void 0 ? { foregroundHeld: route.endpoint.foregroundHeld } : {}
18863
+ }
18864
+ ])
18865
+ )
18866
+ );
18867
+ }
17806
18868
  try {
17807
18869
  preflightWriteBoundaries(plan, input.workspaceRoot);
17808
18870
  } catch (error) {
@@ -17851,19 +18913,7 @@ function compileFleetRunPreview(input) {
17851
18913
  }
17852
18914
  ];
17853
18915
  }
17854
- let route = null;
17855
- try {
17856
- route = input.resolveRoute?.({
17857
- stepId: step.id,
17858
- agentId: step.agentId,
17859
- task: step.task,
17860
- scope: step.scope,
17861
- ...step.target !== void 0 ? { target: step.target } : {},
17862
- ...step.profile !== void 0 ? { profile: step.profile } : {}
17863
- }) ?? null;
17864
- } catch (error) {
17865
- diagnostics.push(`step '${step.id}' route preflight failed: ${describeError(error)}`);
17866
- }
18916
+ const route = routes.get(step.id) ?? null;
17867
18917
  return [
17868
18918
  {
17869
18919
  ...base,
@@ -18481,6 +19531,8 @@ function formatMemoryStatusLine(status, contentWidth) {
18481
19531
  theme6.fg("muted", `last ${status.lastDecision ?? "none"}`)
18482
19532
  ];
18483
19533
  if (status.stepInFlight) units.push(theme6.fg("reason", "step running"));
19534
+ const spend = status.spend === null || status.spend === void 0 ? "" : formatTaskMemorySpend(status.spend);
19535
+ if (spend.length > 0) units.push(theme6.fg("dim", spend));
18484
19536
  return fitUnits(theme6, "", units, width);
18485
19537
  }
18486
19538
  function bankEntries(snapshot) {
@@ -18577,7 +19629,8 @@ function memorySignature(status, records) {
18577
19629
  status.tier,
18578
19630
  String(status.size),
18579
19631
  status.lastDecision ?? "none",
18580
- status.stepInFlight ? "running" : "idle"
19632
+ status.stepInFlight ? "running" : "idle",
19633
+ `${status.spend?.llmSteps ?? 0}:${status.spend?.injections ?? 0}:${status.spend?.totalTokens ?? 0}`
18581
19634
  ];
18582
19635
  for (const record2 of records) parts.push(`r:${record2.id}:${record2.approved}:${record2.rejectedAt ?? ""}`);
18583
19636
  for (const entry of bankEntries(status.bank)) {
@@ -20552,6 +21605,15 @@ var SubmenuWrapper = class {
20552
21605
  child;
20553
21606
  hint;
20554
21607
  note;
21608
+ /**
21609
+ * Why the last submission was refused, or null while nothing is wrong. The
21610
+ * editor sets it instead of closing, so the operator corrects the value with
21611
+ * the reason on screen rather than back at the row list with no reason.
21612
+ */
21613
+ problem = null;
21614
+ setProblem(problem) {
21615
+ this.problem = problem;
21616
+ }
20555
21617
  render(width) {
20556
21618
  const theme6 = clioTheme();
20557
21619
  const lines = [];
@@ -20565,6 +21627,11 @@ var SubmenuWrapper = class {
20565
21627
  }
20566
21628
  lines.push("");
20567
21629
  lines.push(...this.child.render(Math.max(1, width - 2)).map((line) => ` ${line}`));
21630
+ if (this.problem !== null) {
21631
+ for (const line of wrapTextWithAnsi(this.problem, Math.max(1, width - 2))) {
21632
+ lines.push(theme6.fg("error", ` ${line}`));
21633
+ }
21634
+ }
20568
21635
  lines.push("");
20569
21636
  lines.push(theme6.fg("dim", ` ${this.hint}`));
20570
21637
  return lines;
@@ -20628,31 +21695,63 @@ function selectModelSubmenu(providers, getActiveTarget) {
20628
21695
  function editTextSubmenu(title, note) {
20629
21696
  return textInputSubmenu(title, note);
20630
21697
  }
20631
- function editNumberSubmenu(title, options = {}) {
20632
- const min = options.min ?? 0;
21698
+ var NUMBER_SETTING_RULES = {
21699
+ "budget.sessionCeilingUsd": { min: 0, integer: false },
21700
+ "watchdog.cadenceToolCalls": { min: 1, integer: true, allowBlank: true },
21701
+ "delegation.defaults.connectTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
21702
+ "delegation.defaults.turnTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
21703
+ "delegation.defaults.permissionTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true }
21704
+ };
21705
+ var NUMBER_SETTING_IDS = Object.keys(NUMBER_SETTING_RULES);
21706
+ function describeSubmittedText(value) {
21707
+ const trimmed = value.trim();
21708
+ return trimmed.length === 0 ? "an empty string" : JSON.stringify(trimmed);
21709
+ }
21710
+ function parseNumberSetting(value, rule2) {
21711
+ const trimmed = value.trim();
21712
+ const noun = rule2.integer ? "an integer" : "a number";
21713
+ if (trimmed.length === 0 && rule2.allowBlank === true) return { value: null };
21714
+ const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
21715
+ if (!Number.isFinite(parsed) || rule2.integer && !Number.isInteger(parsed)) {
21716
+ const shown = Number.isFinite(parsed) ? String(parsed) : describeSubmittedText(value);
21717
+ return { refusal: `Not applied: expected ${noun}, got ${shown}.` };
21718
+ }
21719
+ if (parsed < rule2.min) return { refusal: `Not applied: expected ${noun} >= ${rule2.min}, got ${parsed}.` };
21720
+ if (rule2.max !== void 0 && parsed > rule2.max) {
21721
+ return { refusal: `Not applied: expected ${noun} <= ${rule2.max}, got ${parsed}.` };
21722
+ }
21723
+ return { value: parsed };
21724
+ }
21725
+ function numberSettingNote(rule2) {
21726
+ const noun = rule2.integer ? "a whole number" : "a number";
21727
+ const clears = rule2.allowBlank === true ? "; blank clears it" : "";
21728
+ if (rule2.min > 0 && rule2.max !== void 0) return `Use ${noun} from ${rule2.min} to ${rule2.max}${clears}.`;
21729
+ if (rule2.min > 0) return `Use ${noun} of at least ${rule2.min}${clears}.`;
21730
+ return `Use a non-negative ${rule2.integer ? "whole number" : "number"}${clears}.`;
21731
+ }
21732
+ function editNumberSubmenu(title, id) {
21733
+ const rule2 = NUMBER_SETTING_RULES[id];
20633
21734
  return (currentValue, done) => {
20634
21735
  const input = new Input();
20635
21736
  input.setValue(currentValue);
20636
21737
  input.focused = true;
21738
+ const wrapper = new SubmenuWrapper(
21739
+ title,
21740
+ input,
21741
+ buildHint([{ key: "Enter", verb: "confirm" }], "back"),
21742
+ numberSettingNote(rule2)
21743
+ );
20637
21744
  input.onSubmit = (val) => {
20638
- if (options.allowBlank === true && val.trim().length === 0) {
20639
- done("");
21745
+ const outcome = parseNumberSetting(val, rule2);
21746
+ if ("refusal" in outcome) {
21747
+ wrapper.setProblem(outcome.refusal);
20640
21748
  return;
20641
21749
  }
20642
- const num = Number(val);
20643
- if (Number.isFinite(num) && num >= min) {
20644
- done(val);
20645
- } else {
20646
- done();
20647
- }
21750
+ wrapper.setProblem(null);
21751
+ done(outcome.value === null ? "" : val.trim());
20648
21752
  };
20649
21753
  input.onEscape = () => done();
20650
- return new SubmenuWrapper(
20651
- title,
20652
- input,
20653
- buildHint([{ key: "Enter", verb: "confirm" }], "back"),
20654
- min > 0 ? `Use a whole number of at least ${min}${options.allowBlank === true ? "; blank clears it" : ""}.` : "Use a non-negative number."
20655
- );
21754
+ return wrapper;
20656
21755
  };
20657
21756
  }
20658
21757
  function selectListSubmenu(title, items, note) {
@@ -21189,6 +22288,7 @@ function buildSettingItems(settings, options) {
21189
22288
  }),
21190
22289
  fleetGroupHeader("fleet.group.placement", "Placement"),
21191
22290
  ...fleetNodeRows(options?.getFleetNodes?.() ?? []),
22291
+ ...fleetEndpointRows(options?.providers),
21192
22292
  settingItem("targets", "", {
21193
22293
  description: "Live inference target inventory and routing roles.",
21194
22294
  affordance: "column heading",
@@ -21210,7 +22310,7 @@ function buildSettingItems(settings, options) {
21210
22310
  readOnly: true
21211
22311
  }),
21212
22312
  settingItem("budget.sessionCeilingUsd", String(settings.budget.sessionCeilingUsd), {
21213
- submenu: editNumberSubmenu("Edit session cost ceiling USD"),
22313
+ submenu: editNumberSubmenu("Edit session cost ceiling USD", "budget.sessionCeilingUsd"),
21214
22314
  affordance: "free text"
21215
22315
  }),
21216
22316
  settingItem("defaults.maxTokens", String(settings.defaults.maxTokens), {
@@ -21277,10 +22377,10 @@ function buildSettingItems(settings, options) {
21277
22377
  "watchdog.cadenceToolCalls",
21278
22378
  watchdog.cadenceToolCalls === void 0 ? "(turn end only)" : String(watchdog.cadenceToolCalls),
21279
22379
  {
21280
- submenu: editNumberSubmenu("Edit watchdog cadence in tool calls; blank fires at turn end only", {
21281
- min: 1,
21282
- allowBlank: true
21283
- }),
22380
+ submenu: editNumberSubmenu(
22381
+ "Edit watchdog cadence in tool calls; blank fires at turn end only",
22382
+ "watchdog.cadenceToolCalls"
22383
+ ),
21284
22384
  affordance: "free text",
21285
22385
  editValue: watchdog.cadenceToolCalls === void 0 ? "" : String(watchdog.cadenceToolCalls)
21286
22386
  }
@@ -21301,15 +22401,15 @@ function buildSettingItems(settings, options) {
21301
22401
  affordance: "free text"
21302
22402
  }),
21303
22403
  settingItem("delegation.defaults.connectTimeoutMs", String(settings.delegation.defaults.connectTimeoutMs), {
21304
- submenu: editNumberSubmenu("Edit delegate connect timeout (ms)"),
22404
+ submenu: editNumberSubmenu("Edit delegate connect timeout (ms)", "delegation.defaults.connectTimeoutMs"),
21305
22405
  affordance: "free text"
21306
22406
  }),
21307
22407
  settingItem("delegation.defaults.turnTimeoutMs", String(settings.delegation.defaults.turnTimeoutMs), {
21308
- submenu: editNumberSubmenu("Edit delegate turn timeout (ms)"),
22408
+ submenu: editNumberSubmenu("Edit delegate turn timeout (ms)", "delegation.defaults.turnTimeoutMs"),
21309
22409
  affordance: "free text"
21310
22410
  }),
21311
22411
  settingItem("delegation.defaults.permissionTimeoutMs", String(settings.delegation.defaults.permissionTimeoutMs), {
21312
- submenu: editNumberSubmenu("Edit delegate permission timeout (ms)"),
22412
+ submenu: editNumberSubmenu("Edit delegate permission timeout (ms)", "delegation.defaults.permissionTimeoutMs"),
21313
22413
  affordance: "free text"
21314
22414
  }),
21315
22415
  settingItem("keybindings", keybindingCount > 0 ? `${keybindingCount} override(s)` : "(defaults)", {
@@ -21527,6 +22627,32 @@ function fleetNodeRows(nodes) {
21527
22627
  });
21528
22628
  });
21529
22629
  }
22630
+ function fleetEndpointRows(providers) {
22631
+ if (providers === void 0) return [];
22632
+ let usage = {};
22633
+ try {
22634
+ usage = capacityLeaseUsage().endpoints;
22635
+ } catch {
22636
+ }
22637
+ const capacities = endpointCapacitiesForStatuses(providers.list());
22638
+ const targetsByEndpoint = /* @__PURE__ */ new Map();
22639
+ for (const status of providers.list()) {
22640
+ const endpoint = endpointCapacityForStatus(status);
22641
+ if (endpoint === null) continue;
22642
+ targetsByEndpoint.set(endpoint.key, [...targetsByEndpoint.get(endpoint.key) ?? [], status.target.id]);
22643
+ }
22644
+ return Object.entries(capacities).map(([key, endpoint]) => {
22645
+ const slots = `slots ${usage[key] ?? 0}/${endpoint.limit}`;
22646
+ return settingItem(`fleet.endpoints.${key}`, slots, {
22647
+ label: `endpoint ${endpoint.label}`,
22648
+ description: `Targets: ${(targetsByEndpoint.get(key) ?? []).join(", ")} \xB7 Limit source: ${endpoint.source}`,
22649
+ affordance: "read-only inference endpoint capacity",
22650
+ readOnly: true,
22651
+ presentationKind: "status",
22652
+ valueSegments: [{ text: slots, tone: "neutral" }]
22653
+ });
22654
+ });
22655
+ }
21530
22656
  function buildSettingsSections(items) {
21531
22657
  return SETTINGS_SECTIONS.map((section2) => ({
21532
22658
  id: section2.id,
@@ -21572,9 +22698,10 @@ function applyNonNegativeInteger(value, set) {
21572
22698
  const parsed = Number(value);
21573
22699
  if (Number.isFinite(parsed) && parsed >= 0) set(Math.floor(parsed));
21574
22700
  }
21575
- function applyPositiveInteger(value, set) {
21576
- const parsed = Number(value);
21577
- if (Number.isInteger(parsed) && parsed >= 1 && parsed <= MAX_TIMER_DELAY_MS) set(parsed);
22701
+ function applyNumberSetting(id, value, set) {
22702
+ const outcome = parseNumberSetting(value, NUMBER_SETTING_RULES[id]);
22703
+ if ("refusal" in outcome) return;
22704
+ set(outcome.value);
21578
22705
  }
21579
22706
  function applyDelegationAgentChange(settings, value) {
21580
22707
  if (value.startsWith(DELEGATION_REMOVE_PREFIX)) {
@@ -21733,15 +22860,12 @@ function applySettingChange(settings, id, value) {
21733
22860
  else delete settings.watchdog.target;
21734
22861
  return;
21735
22862
  }
21736
- case "watchdog.cadenceToolCalls": {
21737
- if (value.trim().length === 0) {
21738
- delete settings.watchdog.cadenceToolCalls;
21739
- return;
21740
- }
21741
- const parsed = Number(value);
21742
- if (Number.isFinite(parsed) && Math.floor(parsed) >= 1) settings.watchdog.cadenceToolCalls = Math.floor(parsed);
22863
+ case "watchdog.cadenceToolCalls":
22864
+ applyNumberSetting("watchdog.cadenceToolCalls", value, (next) => {
22865
+ if (next === null) delete settings.watchdog.cadenceToolCalls;
22866
+ else settings.watchdog.cadenceToolCalls = next;
22867
+ });
21743
22868
  return;
21744
- }
21745
22869
  case "terminal.smoothStreaming":
21746
22870
  if (value === "off" || value === "auto" || value === "on") settings.terminal.smoothStreaming = value;
21747
22871
  return;
@@ -21749,18 +22873,18 @@ function applySettingChange(settings, id, value) {
21749
22873
  settings.runtimePlugins = value.split(",").map((entry) => entry.trim()).filter(Boolean);
21750
22874
  return;
21751
22875
  case "delegation.defaults.connectTimeoutMs":
21752
- applyPositiveInteger(value, (next) => {
21753
- settings.delegation.defaults.connectTimeoutMs = next;
22876
+ applyNumberSetting("delegation.defaults.connectTimeoutMs", value, (next) => {
22877
+ if (next !== null) settings.delegation.defaults.connectTimeoutMs = next;
21754
22878
  });
21755
22879
  return;
21756
22880
  case "delegation.defaults.turnTimeoutMs":
21757
- applyPositiveInteger(value, (next) => {
21758
- settings.delegation.defaults.turnTimeoutMs = next;
22881
+ applyNumberSetting("delegation.defaults.turnTimeoutMs", value, (next) => {
22882
+ if (next !== null) settings.delegation.defaults.turnTimeoutMs = next;
21759
22883
  });
21760
22884
  return;
21761
22885
  case "delegation.defaults.permissionTimeoutMs":
21762
- applyPositiveInteger(value, (next) => {
21763
- settings.delegation.defaults.permissionTimeoutMs = next;
22886
+ applyNumberSetting("delegation.defaults.permissionTimeoutMs", value, (next) => {
22887
+ if (next !== null) settings.delegation.defaults.permissionTimeoutMs = next;
21764
22888
  });
21765
22889
  return;
21766
22890
  case "orchestrator.target": {
@@ -21799,11 +22923,11 @@ function applySettingChange(settings, id, value) {
21799
22923
  case "scope":
21800
22924
  settings.scope = parseScopedModelSelection(value) ?? value.split(",").map((v) => v.trim()).filter(Boolean);
21801
22925
  return;
21802
- case "budget.sessionCeilingUsd": {
21803
- const parsed = Number(value);
21804
- if (Number.isFinite(parsed) && parsed >= 0) settings.budget.sessionCeilingUsd = parsed;
22926
+ case "budget.sessionCeilingUsd":
22927
+ applyNumberSetting("budget.sessionCeilingUsd", value, (next) => {
22928
+ if (next !== null) settings.budget.sessionCeilingUsd = next;
22929
+ });
21805
22930
  return;
21806
- }
21807
22931
  }
21808
22932
  }
21809
22933
  function applyEntrySettingChange(settings, id, value) {
@@ -24718,6 +25842,8 @@ ${usage}` : usage);
24718
25842
  const result = ctx.verifyReceipt(command.runId);
24719
25843
  if (result.ok) {
24720
25844
  ctx.notice("success", `verify ok ${command.runId}`);
25845
+ } else if (result.retired !== void 0) {
25846
+ ctx.notice("warn", `verify retired ${command.runId} ${result.reason}`);
24721
25847
  } else {
24722
25848
  ctx.notice("error", `verify fail ${command.runId} ${result.reason}`);
24723
25849
  }
@@ -24966,8 +26092,8 @@ function dispatchSlashCommand(command, ctx) {
24966
26092
  ctx.submitChat(command.text);
24967
26093
  return "accepted";
24968
26094
  }
24969
- const refusal = expansion?.expanded === false ? expansion.refusal : void 0;
24970
- ctx.notice("error", refusal ? refusal.message : `/${command.token} is not a command. Type /help for the list.`);
26095
+ const refusal2 = expansion?.expanded === false ? expansion.refusal : void 0;
26096
+ ctx.notice("error", refusal2 ? refusal2.message : `/${command.token} is not a command. Type /help for the list.`);
24971
26097
  ctx.render();
24972
26098
  return "rejected";
24973
26099
  }
@@ -25418,7 +26544,10 @@ function createOverlayGeneralOpeners(deps) {
25418
26544
  if (deps.transitions.state !== "closed") return;
25419
26545
  deps.transitions.state = "cost";
25420
26546
  deps.transitions.handle = openCostOverlayFactory(deps.tui, deps.observability, {
25421
- sessionId: deps.getSessionId?.() ?? null
26547
+ sessionId: deps.getSessionId?.() ?? null,
26548
+ ...deps.readSessionEntries ? {
26549
+ getSessionEntries: () => deps.readSessionEntries?.() ?? []
26550
+ } : {}
25422
26551
  });
25423
26552
  deps.requestRender();
25424
26553
  };
@@ -25663,10 +26792,17 @@ function createOverlayGeneralOpeners(deps) {
25663
26792
  };
25664
26793
  const resolution = deps.dispatch.preview?.(request);
25665
26794
  if (!resolution) return null;
26795
+ const foregroundHeld = resolution.endpoint === void 0 ? 0 : foregroundStreamUsage()[resolution.endpoint.key] ?? 0;
25666
26796
  return {
25667
26797
  targetId: resolution.targetId,
25668
26798
  wireModelId: resolution.wireModelId,
25669
- nodeId: resolution.node.id
26799
+ nodeId: resolution.node.id,
26800
+ ...resolution.endpoint !== void 0 ? {
26801
+ endpoint: {
26802
+ ...resolution.endpoint,
26803
+ ...foregroundHeld > 0 ? { foregroundHeld } : {}
26804
+ }
26805
+ } : {}
25670
26806
  };
25671
26807
  }
25672
26808
  });
@@ -25853,12 +26989,41 @@ function permissionOverlayPlacement(tui, editor, footer) {
25853
26989
  };
25854
26990
  }
25855
26991
  var PermissionOverlayBody = class {
25856
- constructor(view) {
26992
+ constructor(view, inspect) {
25857
26993
  this.view = view;
26994
+ this.inspect = inspect;
25858
26995
  }
25859
26996
  view;
26997
+ inspect;
26998
+ preview = null;
26999
+ scroll = 0;
27000
+ lastLineCount = 0;
27001
+ canInspect() {
27002
+ return this.inspect !== void 0;
27003
+ }
27004
+ isInspecting() {
27005
+ return this.preview !== null;
27006
+ }
27007
+ toggleInspect() {
27008
+ if (this.inspect === void 0) return;
27009
+ if (this.preview !== null) {
27010
+ this.preview = null;
27011
+ this.scroll = 0;
27012
+ return;
27013
+ }
27014
+ this.preview = this.inspect();
27015
+ this.scroll = 0;
27016
+ }
27017
+ scrollInspect(delta) {
27018
+ if (this.preview === null) return;
27019
+ const maxScroll = Math.max(0, this.lastLineCount - MUTATION_PREVIEW_VISIBLE_ROWS);
27020
+ this.scroll = Math.max(0, Math.min(this.scroll + delta, maxScroll));
27021
+ }
25860
27022
  render(width) {
25861
- return permissionOverlayLines(this.view, width);
27023
+ if (this.preview === null) return permissionOverlayLines(this.view, width);
27024
+ const rendered = permissionInspectionLines(this.view, this.preview, width, this.scroll);
27025
+ this.lastLineCount = rendered.wrappedLineCount;
27026
+ return rendered.lines;
25862
27027
  }
25863
27028
  invalidate() {
25864
27029
  }
@@ -25919,18 +27084,66 @@ function permissionOverlayTitle(view) {
25919
27084
  function permissionOverlayTone(view) {
25920
27085
  return permissionDecisionPresentation(view).semanticToken;
25921
27086
  }
25922
- function permissionOverlayHint(innerWidth, composerHasDraft = false) {
25923
- return fitHintEntries(permissionHintEntries(composerHasDraft), innerWidth - 3);
27087
+ function permissionOverlayHint(innerWidth, composerHasDraft = false, inspection = "none") {
27088
+ return fitHintEntries(permissionHintEntries(composerHasDraft, inspection), innerWidth - 3);
27089
+ }
27090
+ function isFileMutationTool(tool) {
27091
+ return tool === "write" || tool === "edit";
25924
27092
  }
25925
27093
  function actionConsequence(presentation, id) {
25926
27094
  return presentation.requiredActions.find((action) => action.id === id)?.consequence ?? "";
25927
27095
  }
27096
+ function wrapMutationLine(value, max) {
27097
+ if (max <= 1) return [value];
27098
+ if (value.length <= max) return [value];
27099
+ const lines = [];
27100
+ let remaining = value;
27101
+ while (remaining.length > max) {
27102
+ lines.push(`${remaining.slice(0, max - 1)}\u21A9`);
27103
+ remaining = remaining.slice(max - 1);
27104
+ }
27105
+ lines.push(remaining);
27106
+ return lines;
27107
+ }
27108
+ function permissionInspectionLines(view, preview, width, scroll) {
27109
+ const content = Math.max(8, Math.floor(width));
27110
+ const wrapped = preview.body.flatMap((line) => wrapMutationLine(line, content));
27111
+ const pane = mutationPreviewWindow(wrapped, scroll);
27112
+ const notes = [];
27113
+ if (preview.neutralized) notes.push("control characters shown as \xB7");
27114
+ if (preview.tabsExpanded) notes.push("tabs shown as spaces");
27115
+ const lines = [
27116
+ field("Tool: ", `${view.tool} \xB7 Action: ${view.actionClass}`, content),
27117
+ ...view.target !== void 0 && view.target.length > 0 ? [field("Target: ", view.target, content)] : [],
27118
+ ...wrapSentence(`Mutation: ${mutationFactsLine(preview.facts)}`, content),
27119
+ "",
27120
+ ...wrapSentence(preview.heading, content),
27121
+ ...pane.window,
27122
+ ...pane.position === null ? [] : [pane.position],
27123
+ ...notes.length > 0 ? [`Rendered safely: ${notes.join(", ")}.`] : []
27124
+ ];
27125
+ return { lines, wrappedLineCount: wrapped.length };
27126
+ }
25928
27127
  function permissionOverlayLines(view, width) {
25929
27128
  const content = Math.max(8, Math.floor(width));
25930
27129
  const presentation = permissionDecisionPresentation(view);
25931
27130
  const lines = [
25932
27131
  field("Tool: ", `${view.tool} \xB7 Action: ${view.actionClass}`, content),
25933
27132
  ...view.target !== void 0 && view.target.length > 0 ? [field("Target: ", view.target, content)] : [],
27133
+ // Size and digest stay on the collapsed card whether or not the operator
27134
+ // opens the mutation, so the decision always carries the identity of the
27135
+ // bytes it applies to.
27136
+ // Wrapped, never ellipsized: at 40 columns the digest is the tail of the
27137
+ // line, and ellipsizing it would drop the one fact that ties the decision
27138
+ // to the bytes it applies to.
27139
+ ...view.mutation !== void 0 ? [
27140
+ ...wrapSentence(`Mutation: ${mutationFactsLine(view.mutation)}`, content),
27141
+ ...wrapSentence(`Press ${MUTATION_PREVIEW_KEY} to read it before deciding.`, content)
27142
+ ] : [],
27143
+ ...view.mutation === void 0 && view.origin.kind === "worker" && isFileMutationTool(view.tool) ? wrapSentence(
27144
+ "No local preview: this call's arguments stay inside the worker, so you are approving the target above without inspecting the mutation.",
27145
+ content
27146
+ ) : [],
25934
27147
  ...wrapSentence(`Requested by: ${presentation.requestedByCopy}`, content),
25935
27148
  ...view.artifact !== void 0 ? [
25936
27149
  "",
@@ -25950,8 +27163,8 @@ function permissionOverlayLines(view, width) {
25950
27163
  }
25951
27164
  return lines;
25952
27165
  }
25953
- function createPermissionOverlayBody(view) {
25954
- return new PermissionOverlayBody(view);
27166
+ function createPermissionOverlayBody(view, inspect) {
27167
+ return new PermissionOverlayBody(view, inspect);
25955
27168
  }
25956
27169
 
25957
27170
  // src/interactive/bus-notices.ts
@@ -26172,6 +27385,7 @@ function mainApprovalRequestView(call, decision, meta, autonomy, queueDepth) {
26172
27385
  const axisFromDecision = askAxis(decision);
26173
27386
  const axis = axisFromMeta ?? (axisFromDecision.kind === "net" ? { kind: "net", ruleId: axisFromDecision.ruleId } : { kind: "autonomy", level: autonomy });
26174
27387
  const target = describeCallTarget(call.tool, call.args);
27388
+ const mutation = mutationFacts(call.tool, call.args);
26175
27389
  return {
26176
27390
  requestId: meta?.requestId ?? "permission-pending",
26177
27391
  tool: call.tool,
@@ -26182,9 +27396,14 @@ function mainApprovalRequestView(call, decision, meta, autonomy, queueDepth) {
26182
27396
  ...call.tool === ToolNames.Dispatch && decision.kind === "ask" ? { artifact: { kind: "dispatch-plan", text: decision.rejection.detail } } : {},
26183
27397
  ...call.tool === ToolNames.AskUser ? { exposure: askUserExposure(call.args) } : {},
26184
27398
  ...target.length > 0 ? { target } : {},
27399
+ ...mutation !== null ? { mutation } : {},
26185
27400
  ...queueDepth !== void 0 && queueDepth > 1 ? { queueDepth } : {}
26186
27401
  };
26187
27402
  }
27403
+ function mainMutationInspector(call, view) {
27404
+ if (view.mutation === void 0) return void 0;
27405
+ return createMutationInspector(call.tool, call.args, view.mutation);
27406
+ }
26188
27407
  function workerEscalationEntry(payload, autonomy) {
26189
27408
  if (!isLiveWorkerEscalationRequest(payload) || typeof payload.requestId !== "string") return null;
26190
27409
  const origin = typeof payload.origin === "string" ? payload.origin : void 0;
@@ -26258,7 +27477,7 @@ function createOverlayPermissionLifecycle(deps) {
26258
27477
  announceParked();
26259
27478
  return;
26260
27479
  }
26261
- if (!deps.openPermissionOverlay(view)) {
27480
+ if (!deps.openPermissionOverlay(view, mainMutationInspector(call, view))) {
26262
27481
  announceParked();
26263
27482
  return;
26264
27483
  }
@@ -26646,7 +27865,8 @@ function openHelpOverlay(tui, manager, onClose, initialFilter) {
26646
27865
  "**Tool surface**: which tools exist at all through registration, tool profiles, skill narrowing, and dispatch admission. Violations are terminal denials, never approvable.",
26647
27866
  "**Safety net** (always on, level-independent): damage-control rules, path policy for secrets and system paths, command-substitution confirmation, and `git_destructive` blocks. Blocks are final at every level; confirm rails ask at every level.",
26648
27867
  "**Autonomy level** (`/settings`, persisted as `autonomy`): the operator's standing grant per action class for actions the net passed, enforced by the harness at tool admission. read-only denies non-read, suggest parks every non-read call, auto-edit parks unrecognized commands, and full-auto runs them.",
26649
- "**Approvals**: a parked call waits for a one-shot operator decision; approving resumes only that call. Workers resolve asks per `workers.onPermission` (Approvals Routing); headless runs auto-deny."
27868
+ "**Approvals**: a parked call waits for a one-shot operator decision; approving resumes only that call. Workers resolve asks per `workers.onPermission` (Approvals Routing); headless runs auto-deny.",
27869
+ "**Inspecting a mutation**: a parked `write` or `edit` card carries the target, the byte count, and a `sha256` digest of the exact call arguments. Press `v` to read the complete proposed content, or the complete effective diff against the file on disk, and `v` again to put it away; \u2191/\u2193 and PageUp/PageDown scroll it. Enter still allows, `s` still stops, and Esc still denies while it is open. The mutation text is shown locally and never enters the transcript, a notice, a desktop notification, or the render trace. A worker escalation has no preview because the call's arguments never leave the worker, and its card says so."
26650
27870
  ]
26651
27871
  }
26652
27872
  ];
@@ -26779,13 +27999,16 @@ function openPromptsOverlay(tui, ctx, onClose) {
26779
27999
  lines.push(`**Argument Hint:** \`${template.argumentHint}\``);
26780
28000
  }
26781
28001
  lines.push(`**Source:** ${template.sourceInfo.source ?? template.sourceInfo.scope}`);
28002
+ if (template.unavailable !== void 0) {
28003
+ lines.push(`**Unavailable:** ${template.unavailable}`);
28004
+ }
26782
28005
  if (!template.trusted) {
26783
28006
  lines.push("**Untrusted:** set `skills.trustProjectCompatRoots` before this template will expand.");
26784
28007
  }
26785
28008
  return lines;
26786
28009
  }
26787
28010
  };
26788
- const marker = template.trusted ? void 0 : clioTheme().fg("warning", "untrusted");
28011
+ const marker = template.unavailable !== void 0 ? clioTheme().fg("error", "unavailable") : template.trusted ? void 0 : clioTheme().fg("warning", "untrusted");
26789
28012
  if (marker) item.meta = template.argumentHint ? `${template.argumentHint} \xB7 ${marker}` : marker;
26790
28013
  else if (template.argumentHint) item.meta = template.argumentHint;
26791
28014
  return item;
@@ -26945,7 +28168,7 @@ function runCompactWithNotice(onCompact, notice, instructions) {
26945
28168
  init_esm_shims();
26946
28169
  import { spawnSync } from "node:child_process";
26947
28170
  import { randomUUID as randomUUID2 } from "node:crypto";
26948
- import { readFileSync as readFileSync7, unlinkSync, writeFileSync } from "node:fs";
28171
+ import { readFileSync as readFileSync8, unlinkSync, writeFileSync } from "node:fs";
26949
28172
  import { tmpdir } from "node:os";
26950
28173
  import { join as join7 } from "node:path";
26951
28174
  function defaultProbe(candidates) {
@@ -26985,7 +28208,7 @@ function editTextExternally(initialText, command) {
26985
28208
  const result = runEditor(command, tmpFile);
26986
28209
  if (result.error) return { ok: false, error: result.error.message };
26987
28210
  if (result.status !== 0) return { ok: false, error: `external editor exited with code ${result.status ?? "?"}` };
26988
- return { ok: true, text: readFileSync7(tmpFile, "utf8").replace(/\n$/, "") };
28211
+ return { ok: true, text: readFileSync8(tmpFile, "utf8").replace(/\n$/, "") };
26989
28212
  } finally {
26990
28213
  try {
26991
28214
  unlinkSync(tmpFile);
@@ -28242,19 +29465,54 @@ function createOverlaySessionLifecycle(deps) {
28242
29465
  }
28243
29466
  void runHandoffExtraction(session, fromSessionId, verdict.goal);
28244
29467
  }
29468
+ const HANDOFF_REFUSAL_QUOTE_CHARS = 200;
29469
+ function terminalHandoffRefusal(firstReason, secondReason, secondText) {
29470
+ const answered = secondText.replace(/\s+/g, " ").trim().slice(0, HANDOFF_REFUSAL_QUOTE_CHARS);
29471
+ return [
29472
+ "the extraction round could not produce a handoff record after one repair attempt.",
29473
+ `Asked for: one JSON object with decisions, facts, files, commands, and openQuestions.`,
29474
+ `Round 1: ${firstReason}.`,
29475
+ `Round 2: ${secondReason}.`,
29476
+ `Round 2 returned: ${answered.length > 0 ? answered : "(nothing)"}`
29477
+ ].join(" ");
29478
+ }
29479
+ async function extractWithOneRepair(goal) {
29480
+ const first = await deps.chat.extractHandoff(goal);
29481
+ if (first.status !== "answered") {
29482
+ return {
29483
+ ok: false,
29484
+ level: first.status === "failed" ? "error" : "warn",
29485
+ reason: first.status === "aborted" ? "the extraction round was cancelled" : first.reason
29486
+ };
29487
+ }
29488
+ const parsedFirst = parseHandoffExtraction(first.text);
29489
+ if (parsedFirst.ok) return { ok: true, parsed: parsedFirst };
29490
+ const second = await deps.chat.extractHandoff(goal, {
29491
+ repair: { complaint: parsedFirst.reason, previous: first.text }
29492
+ });
29493
+ if (second.status !== "answered") {
29494
+ return {
29495
+ ok: false,
29496
+ level: second.status === "failed" ? "error" : "warn",
29497
+ reason: second.status === "aborted" ? "the repair round was cancelled" : `round 1 could not be read (${parsedFirst.reason}); the repair round then failed: ${second.reason}`
29498
+ };
29499
+ }
29500
+ const parsedSecond = parseHandoffExtraction(second.text);
29501
+ if (parsedSecond.ok) return { ok: true, parsed: parsedSecond };
29502
+ return {
29503
+ ok: false,
29504
+ level: "error",
29505
+ reason: terminalHandoffRefusal(parsedFirst.reason, parsedSecond.reason, second.text)
29506
+ };
29507
+ }
28245
29508
  async function runHandoffExtraction(session, fromSessionId, goal) {
28246
29509
  const notice = deps.getSlashNotice();
28247
- const outcome = await deps.chat.extractHandoff(goal);
28248
- if (outcome.status !== "answered") {
28249
- const reason = outcome.status === "aborted" ? "the extraction round was cancelled" : outcome.reason;
28250
- emitCommandNotice(notice, outcome.status === "failed" ? "error" : "warn", "handoff", reason);
28251
- return;
28252
- }
28253
- const parsed = parseHandoffExtraction(outcome.text);
28254
- if (!parsed.ok) {
28255
- emitCommandNotice(notice, "error", "handoff", parsed.reason);
29510
+ const extraction = await extractWithOneRepair(goal);
29511
+ if (!extraction.ok) {
29512
+ emitCommandNotice(notice, extraction.level, "handoff", extraction.reason);
28256
29513
  return;
28257
29514
  }
29515
+ const parsed = extraction.parsed;
28258
29516
  const meta = session.current();
28259
29517
  const cwd = typeof meta?.cwd === "string" && meta.cwd.length > 0 ? meta.cwd : null;
28260
29518
  const entries = deps.readStructuredEntries(fromSessionId);
@@ -28433,6 +29691,14 @@ var DRAFT_EDIT_KEYS = ["backspace", "delete", "ctrl+u", "ctrl+w", "alt+backspace
28433
29691
  function isDraftEditKey(data) {
28434
29692
  return !isKeyRelease(data) && DRAFT_EDIT_KEYS.some((key) => matchesKey(data, key));
28435
29693
  }
29694
+ var MUTATION_PAGE_ROWS = 16;
29695
+ function mutationScrollDelta(data) {
29696
+ if (matchesKey(data, "up")) return -1;
29697
+ if (matchesKey(data, "down")) return 1;
29698
+ if (matchesKey(data, "pageUp")) return -MUTATION_PAGE_ROWS;
29699
+ if (matchesKey(data, "pageDown")) return MUTATION_PAGE_ROWS;
29700
+ return 0;
29701
+ }
28436
29702
  function routePermissionOverlayKey(data, deps) {
28437
29703
  if (matchesKey(data, "enter") && !isKeyRelease(data)) {
28438
29704
  if (!(deps.composerHasDraft?.() ?? false)) deps.confirmPermission();
@@ -28442,6 +29708,17 @@ function routePermissionOverlayKey(data, deps) {
28442
29708
  deps.editDraft(data);
28443
29709
  return true;
28444
29710
  }
29711
+ if (matchesKey(data, MUTATION_PREVIEW_KEY) && !isKeyRelease(data) && (deps.canInspectMutation?.() ?? false) && deps.toggleMutationInspection) {
29712
+ deps.toggleMutationInspection();
29713
+ return true;
29714
+ }
29715
+ if ((deps.isInspectingMutation?.() ?? false) && deps.scrollMutationInspection && !isKeyRelease(data)) {
29716
+ const delta = mutationScrollDelta(data);
29717
+ if (delta !== 0) {
29718
+ deps.scrollMutationInspection(delta);
29719
+ return true;
29720
+ }
29721
+ }
28445
29722
  if (isEscapeKey(data)) {
28446
29723
  deps.cancelPermission();
28447
29724
  return true;
@@ -28616,6 +29893,11 @@ function createOverlayLifecycle(deps) {
28616
29893
  } = deps;
28617
29894
  let overlayPermission = null;
28618
29895
  let overlayAskUser = null;
29896
+ let permissionBody = null;
29897
+ const inspectionHint = () => {
29898
+ if (permissionBody === null || !permissionBody.canInspect()) return "none";
29899
+ return permissionBody.isInspecting() ? "open" : "closed";
29900
+ };
28619
29901
  const overlayTransitions = createOverlayTransitions({
28620
29902
  stopDispatchBoardTicker: () => interactiveTickers.stopDispatchBoardTicker(),
28621
29903
  renderContextIsland: () => interactiveTickers.renderContextIsland(),
@@ -28623,7 +29905,10 @@ function createOverlayLifecycle(deps) {
28623
29905
  requestRender: () => tui.requestRender(),
28624
29906
  cancelPendingAskUser: () => overlayAskUser?.cancelPending() ?? false,
28625
29907
  finishAuth: (dismiss) => overlayAuth.finish(dismiss),
28626
- onPermissionOverlayClosed: () => overlayPermission?.onPermissionOverlayClosed(),
29908
+ onPermissionOverlayClosed: () => {
29909
+ permissionBody = null;
29910
+ overlayPermission?.onPermissionOverlayClosed();
29911
+ },
28627
29912
  onOverlayClosed: () => overlayPermission?.retryPending()
28628
29913
  });
28629
29914
  const closeOverlay = overlayTransitions.close;
@@ -28652,17 +29937,20 @@ function createOverlayLifecycle(deps) {
28652
29937
  dispatch: deps.app.dispatch,
28653
29938
  getAutonomy: () => deps.app.getSettings?.().autonomy ?? "auto-edit",
28654
29939
  getOverlayState: () => overlayTransitions.state,
28655
- openPermissionOverlay: (view) => {
29940
+ openPermissionOverlay: (view, inspect) => {
28656
29941
  if (overlayTransitions.state !== "closed") return false;
28657
29942
  overlayTransitions.state = "permission-confirm";
28658
- overlayTransitions.handle = showOverlayFrame(tui, createPermissionOverlayBody(view), {
29943
+ const body = createPermissionOverlayBody(view, inspect);
29944
+ permissionBody = body;
29945
+ overlayTransitions.handle = showOverlayFrame(tui, body, {
28659
29946
  ...permissionOverlayPlacement(tui, editor, footer.view),
28660
29947
  width: PERMISSION_OVERLAY_WIDTH,
28661
29948
  title: permissionOverlayTitle(view),
28662
29949
  tone: permissionOverlayTone(view),
28663
29950
  // Read per frame: the footer names what Enter does right now, and
28664
- // that depends on whether the composer holds a draft.
28665
- footerHint: (innerWidth) => permissionOverlayHint(innerWidth, editor.getText().length > 0)
29951
+ // that depends on whether the composer holds a draft and on whether
29952
+ // the mutation is open.
29953
+ footerHint: (innerWidth) => permissionOverlayHint(innerWidth, editor.getText().length > 0, inspectionHint())
28666
29954
  });
28667
29955
  tui.requestRender();
28668
29956
  return true;
@@ -28860,6 +30148,16 @@ function createOverlayLifecycle(deps) {
28860
30148
  footer.refresh();
28861
30149
  tui.requestRender();
28862
30150
  },
30151
+ canInspectMutation: () => permissionBody?.canInspect() ?? false,
30152
+ isInspectingMutation: () => permissionBody?.isInspecting() ?? false,
30153
+ toggleMutationInspection: () => {
30154
+ permissionBody?.toggleInspect();
30155
+ tui.requestRender();
30156
+ },
30157
+ scrollMutationInspection: (delta) => {
30158
+ permissionBody?.scrollInspect(delta);
30159
+ tui.requestRender();
30160
+ },
28863
30161
  cancelAskUser: overlayAskUser.cancel,
28864
30162
  dispose: () => {
28865
30163
  overlayPermission?.dispose();
@@ -30083,6 +31381,14 @@ function createInteractiveEventProjection(deps) {
30083
31381
  })
30084
31382
  );
30085
31383
  remainingUnsubscribers.push(
31384
+ deps.bus.on(BusChannels.DispatchScopeNotice, (payload) => {
31385
+ const event = payload;
31386
+ if (!event || typeof event !== "object" || !["typed_scope_replaced_inferred_paths", "legacy_scope_inferred", "legacy_scope_empty"].includes(event.code) || typeof event.message !== "string") {
31387
+ return;
31388
+ }
31389
+ deps.appendTranscriptNotice("warn", event.message);
31390
+ deps.requestRender();
31391
+ }),
30086
31392
  deps.bus.on(BusChannels.LoopBlocked, (payload) => {
30087
31393
  const event = payload;
30088
31394
  if (!event || typeof event !== "object" || typeof event.tool !== "string" || typeof event.repeatCount !== "number") {
@@ -30374,6 +31680,10 @@ function createInteractiveInputRuntime(deps) {
30374
31680
  confirmPermission: () => deps.overlay.confirmPermission(),
30375
31681
  stopTurnFromPermission: () => deps.overlay.stopTurnFromPermission(),
30376
31682
  composerHasDraft: () => deps.editor.getText().length > 0,
31683
+ canInspectMutation: () => deps.overlay.canInspectMutation(),
31684
+ isInspectingMutation: () => deps.overlay.isInspectingMutation(),
31685
+ toggleMutationInspection: () => deps.overlay.toggleMutationInspection(),
31686
+ scrollMutationInspection: (delta) => deps.overlay.scrollMutationInspection(delta),
30377
31687
  editDraft: (data2) => {
30378
31688
  deps.editor.handleInput?.(data2);
30379
31689
  deps.requestRender();
@@ -31205,11 +32515,23 @@ function renderErrorSegmentLines(seg, width) {
31205
32515
  var CLIO_PREFIX = `${TEAL}${AGENT_GLYPH}${RESET} `;
31206
32516
  var CLIO_PREFIX_ERROR = `${RED_CRIT}${AGENT_GLYPH}${RESET} `;
31207
32517
  var USER_PREFIX = `${TEAL}${USER_GLYPH}${RESET} `;
32518
+ var USER_PREFIX_PENDING = `${DIM}${USER_GLYPH}${RESET} `;
32519
+ var USER_PENDING_TAIL = " \xB7 preparing";
32520
+ var USER_REFUSED_TAIL = " \xB7 not sent";
31208
32521
  var PROSE_GUTTER = " ";
31209
32522
  var PROSE_GUTTER_WIDTH = 2;
31210
32523
  function hangProseLines(lines, firstPrefix) {
31211
32524
  return lines.map((line, index) => `${index === 0 && firstPrefix !== void 0 ? firstPrefix : PROSE_GUTTER}${line}`);
31212
32525
  }
32526
+ function appendUserRowTail(rendered, tail, width) {
32527
+ const last = rendered.length - 1;
32528
+ const lastLine = rendered[last];
32529
+ if (lastLine !== void 0 && visibleWidth(lastLine) + tail.length <= width) {
32530
+ rendered[last] = `${lastLine}${DIM}${tail}${RESET}`;
32531
+ return;
32532
+ }
32533
+ rendered.push(`${PROSE_GUTTER}${dimLine(tail.trimStart(), Math.max(1, width - PROSE_GUTTER_WIDTH))}`);
32534
+ }
31213
32535
  var THINKING_HIDDEN_LABEL = `Thinking${GLYPH.ellipsis}`;
31214
32536
  var THINKING_LINE_LIMIT = 12;
31215
32537
  function dimLine(text, width) {
@@ -31366,8 +32688,11 @@ function renderEntryLines(entry, width, expandKey, latestHintToolId, latestFolde
31366
32688
  const contentWidth = Math.max(1, width - PROSE_GUTTER_WIDTH);
31367
32689
  const lines2 = [];
31368
32690
  for (const sourceLine of entry.text.split("\n")) lines2.push(...wrapTextWithAnsi(sourceLine, contentWidth));
31369
- const rendered = hangProseLines(lines2, USER_PREFIX);
32691
+ const status = entry.status?.() ?? "committed";
32692
+ const rendered = hangProseLines(lines2, status === "committed" ? USER_PREFIX : USER_PREFIX_PENDING);
31370
32693
  if (rendered[0] !== void 0) rendered[0] = `${OSC133_PROMPT_START}${rendered[0]}`;
32694
+ if (status !== "committed")
32695
+ appendUserRowTail(rendered, status === "pending" ? USER_PENDING_TAIL : USER_REFUSED_TAIL, width);
31371
32696
  return rendered;
31372
32697
  }
31373
32698
  if (entry.role === "retryStatus") {
@@ -31667,8 +32992,8 @@ function createChatPanel(options = {}) {
31667
32992
  (segment) => segment.kind === "tool" && !segment.finished && segment.startedAtMs !== void 0
31668
32993
  // The live reasoning line counts its own elapsed, so a turn that is
31669
32994
  // only thinking still needs the time-keyed render key.
31670
- ) || entry.pending && openThinkingSegment(entry)?.startedAtMs !== void 0) || entry.role === "replayBlock" && entry.isLive?.() === true;
31671
- const entryIsStable = (entry) => entry.role === "user" || entry.role === "replayBlock" && entry.isLive?.() !== true || entry.role === "worker" && !entry.state.pending || entry.role === "assistant" && !entry.pending && !entry.segments.some((segment) => segment.kind === "tool" && !segment.finished);
32995
+ ) || entry.pending && openThinkingSegment(entry)?.startedAtMs !== void 0) || entry.role === "replayBlock" && entry.isLive?.() === true || entry.role === "user" && (entry.status?.() ?? "committed") !== "committed";
32996
+ const entryIsStable = (entry) => entry.role === "user" && (entry.status?.() ?? "committed") === "committed" || entry.role === "replayBlock" && entry.isLive?.() !== true || entry.role === "worker" && !entry.state.pending || entry.role === "assistant" && !entry.pending && !entry.segments.some((segment) => segment.kind === "tool" && !segment.finished);
31672
32997
  const render2 = (width) => {
31673
32998
  const startedAt = performance5.now();
31674
32999
  const expandKey = resolveExpandKey();
@@ -31750,8 +33075,8 @@ function createChatPanel(options = {}) {
31750
33075
  return out;
31751
33076
  };
31752
33077
  return {
31753
- appendUser(text) {
31754
- transcript.push({ role: "user", text });
33078
+ appendUser(text, status) {
33079
+ transcript.push({ role: "user", text, ...status ? { status } : {} });
31755
33080
  markDirty();
31756
33081
  },
31757
33082
  appendReplayBlock(renderBlock, isLive2, fold) {
@@ -32188,6 +33513,7 @@ init_esm_shims();
32188
33513
  var CONTEXT_ISLAND_WIDTH = 52;
32189
33514
  var PHASES = ["scan", "codewiki", "generate", "clio-md", "state", "done"];
32190
33515
  var WIKI_PHASES = ["codewiki", "generate", "state", "done"];
33516
+ var COMPACTION_PHASES = ["compact", "done"];
32191
33517
  var PHASE_LABELS = {
32192
33518
  scan: "scan",
32193
33519
  // "index" rather than "wiki": this phase is the codewiki index build, and
@@ -32196,6 +33522,7 @@ var PHASE_LABELS = {
32196
33522
  generate: "draft",
32197
33523
  "clio-md": "CLIO-CODER.md",
32198
33524
  state: "state",
33525
+ compact: "compact",
32199
33526
  done: "done"
32200
33527
  };
32201
33528
  var WIKI_PHASE_LABELS = {
@@ -32210,8 +33537,9 @@ var KINDS = /* @__PURE__ */ new Set([
32210
33537
  "context-wiki",
32211
33538
  "compaction"
32212
33539
  ]);
32213
- var PHASE_SET = new Set(PHASES);
33540
+ var PHASE_SET = /* @__PURE__ */ new Set([...PHASES, ...COMPACTION_PHASES]);
32214
33541
  function phasesFor(kind) {
33542
+ if (kind === "compaction") return COMPACTION_PHASES;
32215
33543
  return kind === "context-wiki" ? WIKI_PHASES : PHASES;
32216
33544
  }
32217
33545
  function phaseLabel(kind, phase) {
@@ -33516,6 +34844,8 @@ function createInteractivePresentation(deps) {
33516
34844
  },
33517
34845
  isStreaming: () => deps.chat.isStreaming(),
33518
34846
  ...deps.isAwaitingApproval ? { isAwaitingApproval: deps.isAwaitingApproval } : {},
34847
+ ...deps.getPermissionInspection ? { getPermissionInspection: deps.getPermissionInspection } : {},
34848
+ getTurnPreparation: () => deps.chat.turnPreparation().phase,
33519
34849
  willEnterSteer: (text) => willEnterSteerActiveWork(deps, text),
33520
34850
  getSubmitKeyLabel: () => formatKeyLabel(keybindings.getKeys("tui.input.submit")[0], "Enter"),
33521
34851
  getNewlineKeyLabel: () => formatKeyLabel(keybindings.getKeys("tui.input.newLine")[0], "Shift+Enter")
@@ -34028,9 +35358,9 @@ function createInteractiveSlashRuntime(deps) {
34028
35358
  const willQueue = deps.chat.isStreaming();
34029
35359
  deps.recordSubmittedTurn();
34030
35360
  deps.refreshFooter();
34031
- if (!willQueue) deps.chatPanel.appendUser(sub.text);
35361
+ let rowStatus = "pending";
35362
+ if (!willQueue) deps.chatPanel.appendUser(sub.text, () => rowStatus);
34032
35363
  deps.requestRender();
34033
- deps.beforeSemanticSubmit?.();
34034
35364
  let acknowledgeAdmission = () => {
34035
35365
  };
34036
35366
  const admitted = new Promise((resolve7) => {
@@ -34041,13 +35371,26 @@ function createInteractiveSlashRuntime(deps) {
34041
35371
  ...sub.workingContextPaths.length > 0 ? { workingContextPaths: sub.workingContextPaths } : {},
34042
35372
  ...sub.pendingSkillRequests.length > 0 ? { pendingSkillRequests: sub.pendingSkillRequests } : {},
34043
35373
  ...awaitAdmission && willQueue ? { steering: "end-of-turn" } : {},
34044
- ...awaitAdmission ? { onAdmitted: acknowledgeAdmission } : {}
35374
+ ...!willQueue ? {
35375
+ onPreparationVisible: async () => {
35376
+ deps.beforeSemanticSubmit?.();
35377
+ await deps.settleVisibleFrame?.("submit-preparing");
35378
+ }
35379
+ } : {},
35380
+ onAdmitted: () => {
35381
+ rowStatus = "committed";
35382
+ deps.requestRender();
35383
+ if (awaitAdmission) acknowledgeAdmission();
35384
+ }
34045
35385
  });
34046
35386
  const settlement = turn.then(() => deps.settleVisibleFrame?.("submit-return")).catch((err) => {
34047
35387
  const msg = err instanceof Error ? err.message : String(err);
34048
35388
  deps.io.stderr(`[interactive] chat failed: ${msg}
34049
35389
  `);
34050
- }).finally(deps.requestRender);
35390
+ }).finally(() => {
35391
+ if (rowStatus === "pending") rowStatus = willQueue ? "committed" : "refused";
35392
+ deps.requestRender();
35393
+ });
34051
35394
  return awaitAdmission ? Promise.race([admitted, settlement]) : settlement;
34052
35395
  } catch (err) {
34053
35396
  const msg = err instanceof Error ? err.message : String(err);
@@ -34801,6 +36144,13 @@ async function createInteractiveApplication(deps) {
34801
36144
  });
34802
36145
  const { terminal, tui } = shell;
34803
36146
  const renderTrace = getActiveRenderTrace();
36147
+ const dumpInputWedgeOnTerminate = renderTrace ? () => {
36148
+ try {
36149
+ writeInputWedgeDump(clioStateDir(), renderTrace.snapshotInputWedge());
36150
+ } catch {
36151
+ }
36152
+ } : null;
36153
+ if (dumpInputWedgeOnTerminate) process.on("SIGTERM", dumpInputWedgeOnTerminate);
34804
36154
  const visibleEventIngress = /* @__PURE__ */ new WeakMap();
34805
36155
  let visibleEventSequence = 0;
34806
36156
  let visibleEventGeneration = 0;
@@ -34856,6 +36206,11 @@ async function createInteractiveApplication(deps) {
34856
36206
  getLeaderArmed: () => leaderArmed,
34857
36207
  getShutdownArmed: () => shutdownArmed,
34858
36208
  isAwaitingApproval: () => overlayLifecycle?.getState() === "permission-confirm",
36209
+ getPermissionInspection: () => {
36210
+ if (overlayLifecycle === void 0 || overlayLifecycle === null) return "none";
36211
+ if (!overlayLifecycle.canInspectMutation()) return "none";
36212
+ return overlayLifecycle.isInspectingMutation() ? "open" : "closed";
36213
+ },
34859
36214
  resolveVisibleEventSequence: (event) => visibleEventIngress.get(event)?.traceSequence ?? null,
34860
36215
  resolveStreamIngress: (event) => visibleEventIngress.get(event) ?? null,
34861
36216
  commitFrame: (reason) => shell.commitCurrentFrame(reason === "teardown" ? 300 : 3e4),
@@ -34964,7 +36319,7 @@ async function createInteractiveApplication(deps) {
34964
36319
  chat: deps.chat,
34965
36320
  chatPanel: {
34966
36321
  appendReplayBlock: (...args) => chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "slash-output"),
34967
- appendUser: (text) => chatRenderer.mutate(() => chatPanel.appendUser(text), "user-submit"),
36322
+ appendUser: (text, status) => chatRenderer.mutate(() => chatPanel.appendUser(text, status), "user-submit"),
34968
36323
  clearFoldOverrides: () => chatRenderer.mutate(() => chatPanel.clearFoldOverrides(), "output-detail")
34969
36324
  },
34970
36325
  beforeSemanticSubmit: () => chatRenderer.flush(),
@@ -35263,6 +36618,7 @@ async function createInteractiveApplication(deps) {
35263
36618
  cancelParkedCalls: (reason) => deps.toolRegistry?.cancelParkedCalls(reason),
35264
36619
  onShutdown: async () => {
35265
36620
  try {
36621
+ if (dumpInputWedgeOnTerminate) process.off("SIGTERM", dumpInputWedgeOnTerminate);
35266
36622
  await deps.onShutdown();
35267
36623
  } finally {
35268
36624
  if (lease) await lease.close();
@@ -35381,7 +36737,7 @@ import { isAbsolute as isAbsolute6, relative as relative7, resolve as resolve6 }
35381
36737
 
35382
36738
  // src/tools/dispatch-scout-admission.ts
35383
36739
  init_esm_shims();
35384
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
36740
+ import { existsSync as existsSync9, readFileSync as readFileSync9 } from "node:fs";
35385
36741
  import { join as join10 } from "node:path";
35386
36742
  var MAX_SCOUT_PLAN_DEADLINE_MS = 36e5;
35387
36743
  function record(value) {
@@ -35433,7 +36789,7 @@ function loadVerifiedScoutSource(input) {
35433
36789
  if (!existsSync9(receiptPath)) throw new Error(`dispatch: Scout source receipt '${input.ref.runId}' is unavailable`);
35434
36790
  let receipt;
35435
36791
  try {
35436
- receipt = JSON.parse(readFileSync8(receiptPath, "utf8"));
36792
+ receipt = JSON.parse(readFileSync9(receiptPath, "utf8"));
35437
36793
  } catch (error) {
35438
36794
  throw new Error(
35439
36795
  `dispatch: Scout source receipt is unreadable: ${error instanceof Error ? error.message : String(error)}`
@@ -35670,14 +37026,6 @@ function councilSettingsFromArgs(args, deps) {
35670
37026
  function isRecord11(value) {
35671
37027
  return typeof value === "object" && value !== null && !Array.isArray(value);
35672
37028
  }
35673
- function reviewerTask(originalTask, builderRunId, cycle) {
35674
- return [
35675
- `Review the work of builder run ${builderRunId} (review cycle ${cycle}).`,
35676
- "The builder's final answer is provided as input data; verify it against the workspace, do not trust it blindly.",
35677
- "Original task the builder was given:",
35678
- originalTask
35679
- ].join("\n\n");
35680
- }
35681
37029
  function reviewSettingsFromArgs(args) {
35682
37030
  const raw = args.review;
35683
37031
  if (raw === void 0 || raw === false) return { ok: true, review: void 0 };
@@ -36007,9 +37355,6 @@ function createDispatchAdmissionController(deps) {
36007
37355
  if (parsed.requests.length !== 1 || parsed.requests[0] === void 0) {
36008
37356
  return shapeRejection(args, REVIEW_SINGLE_TASK_MESSAGE);
36009
37357
  }
36010
- if (parsed.requests.some((request) => (request.resolvedVerification?.length ?? 0) > 0)) {
36011
- return shapeRejection(args, "verification_unsupported_for_mode: review requests cannot run host verification");
36012
- }
36013
37358
  }
36014
37359
  if (mode === "compete" && (parsed.requests.length !== 1 || parsed.requests[0] === void 0)) {
36015
37360
  return shapeRejection(args, COMPETE_SINGLE_TASK_MESSAGE);
@@ -36060,7 +37405,7 @@ function createDispatchAdmissionController(deps) {
36060
37405
  {
36061
37406
  agentId: gateDeciderAgentId(reviewResult.review.reviewer),
36062
37407
  executionRole: "reviewer",
36063
- task: reviewerTask(base.task, subject.runId, cycle),
37408
+ task: renderDispatchReviewerTask(base.task, subject.runId, cycle, base.intent),
36064
37409
  systemPrompt: REVIEWER_GATE_PROMPT,
36065
37410
  autonomy: "read-only",
36066
37411
  gate: { role: "reviewer", group: "plan-preview", cycle, subjects: [subject] },
@@ -36121,6 +37466,13 @@ function createDispatchAdmissionController(deps) {
36121
37466
  executionRole: "researcher",
36122
37467
  autonomy: "read-only",
36123
37468
  toolProfile: "council-read-only",
37469
+ // The runner reuses this composed task from the resolved plan, so
37470
+ // the approval artifact the plan hash binds shows the operator the
37471
+ // exact ballot the member is asked to cast.
37472
+ ...council.synthesis === "vote" ? {
37473
+ task: renderCouncilVoteMemberTask(base.task),
37474
+ resultContractOverride: { kind: "council-ballot" }
37475
+ } : {},
36124
37476
  target: member.target,
36125
37477
  ...member.model ? { model: member.model } : {},
36126
37478
  ...member.thinking ? { thinkingLevel: member.thinking } : {},
@@ -36293,7 +37645,7 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
36293
37645
  const admission = createDispatchAdmissionController(deps);
36294
37646
  let runnerPromise = null;
36295
37647
  const loadRunner = () => {
36296
- runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-B7MTOVKL.js")))();
37648
+ runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-VVA4SRRH.js")))();
36297
37649
  return runnerPromise;
36298
37650
  };
36299
37651
  return {
@@ -36531,7 +37883,7 @@ function registerAllTools(registry, deps = {}) {
36531
37883
  ...builtin(
36532
37884
  lazyTool(
36533
37885
  monitorToolSurface,
36534
- async () => (await import("./monitor-TJ7AMTGB.js")).createMonitorTool({ dispatch, runEvents: dispatchRunEvents })
37886
+ async () => (await import("./monitor-MMVTJABD.js")).createMonitorTool({ dispatch, runEvents: dispatchRunEvents })
36535
37887
  ),
36536
37888
  {
36537
37889
  path: "src/tools/monitor.ts",
@@ -36541,7 +37893,7 @@ function registerAllTools(registry, deps = {}) {
36541
37893
  });
36542
37894
  registry.register({
36543
37895
  ...builtin(
36544
- lazyTool(steerToolSurface, async () => (await import("./steer-GGWFUJUD.js")).createSteerTool({ dispatch })),
37896
+ lazyTool(steerToolSurface, async () => (await import("./steer-CF5TDANS.js")).createSteerTool({ dispatch })),
36545
37897
  {
36546
37898
  path: "src/tools/steer.ts",
36547
37899
  scope: "core"
@@ -36688,7 +38040,7 @@ async function resolveApiKeyForTarget(target, providers, signal) {
36688
38040
  const resolved = await providers.auth.resolveForTarget(target, runtime, signal ? { signal } : void 0);
36689
38041
  return resolved.apiKey;
36690
38042
  }
36691
- function createBackgroundMemoryModelClient(providers, settings, timeoutMs) {
38043
+ function createBackgroundMemoryModelClient(providers, settings, timeoutMs, bus) {
36692
38044
  const targetId = settings.background.target?.trim();
36693
38045
  const wireModelId = settings.background.model?.trim();
36694
38046
  if (!targetId || !wireModelId) return null;
@@ -36712,22 +38064,52 @@ function createBackgroundMemoryModelClient(providers, settings, timeoutMs) {
36712
38064
  const model = resolved.target.runtime.synthesizeModel(resolved.target.target, resolved.target.wireModelId, kbHit);
36713
38065
  const refined = refineRuntimeTargetWithModelHints(resolved.target, model, providers.knowledgeBase);
36714
38066
  applyModelCapabilityPatch(model, refined.capabilities);
38067
+ const costProvenance = normalizeCostProvenance(refined.costProvenance);
38068
+ const endpointKey = canonicalEndpointKey(refined.target);
36715
38069
  return {
36716
- async complete(request) {
36717
- const apiKey = targetRequiresAuth(refined.target, refined.runtime) ? (await providers.auth.resolveForTarget(refined.target, refined.runtime, { signal: request.signal })).apiKey : LOCAL_API_KEY_FALLBACK2;
36718
- return completeEngineText({
36719
- model,
36720
- systemPrompt: request.systemPrompt,
36721
- userPrompt: request.userPrompt,
36722
- maxTokens: request.maxTokens,
36723
- // Always off, never the operator's chat thinking level. A model that
36724
- // reasons anyway still works: `completeEngineText` keeps only text
36725
- // blocks, and the memory output budget leaves room for the preamble.
36726
- thinkingLevel: "off",
36727
- signal: request.signal,
36728
- timeoutMs,
36729
- ...apiKey === void 0 ? {} : { apiKey }
36730
- });
38070
+ targetId,
38071
+ wireModelId: refined.wireModelId,
38072
+ endpointKey,
38073
+ client: {
38074
+ // Wrapped at the layer that knows a request left the process: the step
38075
+ // holds endpoint capacity while it is out and publishes the cache
38076
+ // disturbance even when a timeout means the usage sink never sees it.
38077
+ complete: announceMemoryStepEndpoint({ bus, endpointKey, targetId }, async (request) => {
38078
+ const apiKey = targetRequiresAuth(refined.target, refined.runtime) ? (await providers.auth.resolveForTarget(refined.target, refined.runtime, { signal: request.signal })).apiKey : LOCAL_API_KEY_FALLBACK2;
38079
+ const startedAt = Date.now();
38080
+ const completion = await completeEngineText({
38081
+ model,
38082
+ systemPrompt: request.systemPrompt,
38083
+ userPrompt: request.userPrompt,
38084
+ maxTokens: request.maxTokens,
38085
+ // Always off, never the operator's chat thinking level. A model that
38086
+ // reasons anyway still works: `completeEngineText` keeps only text
38087
+ // blocks, and the memory output budget leaves room for the preamble.
38088
+ thinkingLevel: "off",
38089
+ signal: request.signal,
38090
+ timeoutMs,
38091
+ ...apiKey === void 0 ? {} : { apiKey }
38092
+ });
38093
+ return {
38094
+ text: completion.text,
38095
+ inputTokens: completion.inputTokens,
38096
+ outputTokens: completion.outputTokens,
38097
+ usage: {
38098
+ targetId,
38099
+ attributedModelId: refined.wireModelId,
38100
+ input: completion.usage.input,
38101
+ output: completion.usage.output,
38102
+ cacheRead: completion.usage.cacheRead,
38103
+ cacheWrite: completion.usage.cacheWrite,
38104
+ reasoning: completion.usage.reasoning,
38105
+ totalTokens: completion.usage.totalTokens,
38106
+ costUsd: completion.usage.costUsd,
38107
+ costProvenance,
38108
+ durationMs: Date.now() - startedAt,
38109
+ backend: completion.backend
38110
+ }
38111
+ };
38112
+ })
36731
38113
  }
36732
38114
  };
36733
38115
  }
@@ -36798,7 +38180,7 @@ async function resolveCompactionModel(settings, providers) {
36798
38180
  const model = synthesizeOrchestratorModel(providers, target, wireModelId);
36799
38181
  if (!model) return null;
36800
38182
  const apiKey = await resolveApiKeyForTarget(target, providers);
36801
- const resolution = { model, targetId };
38183
+ const resolution = { model, targetId, endpointKey: canonicalEndpointKey(target) };
36802
38184
  if (apiKey !== void 0) resolution.apiKey = apiKey;
36803
38185
  return resolution;
36804
38186
  }
@@ -36870,12 +38252,19 @@ async function runCompactionFlow(session, settings, providers, instructions, tri
36870
38252
  const activeLeafTurnId = session.tree(meta.id).leafId ?? void 0;
36871
38253
  const entries = filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId);
36872
38254
  if (entries.length === 0) return null;
36873
- const result = await compact({
36874
- entries,
36875
- model: resolved.model,
36876
- ...resolved.apiKey !== void 0 ? { apiKey: resolved.apiKey } : {},
36877
- ...instructions !== void 0 ? { instructions } : {}
36878
- });
38255
+ const releaseEndpointSlot = resolved.endpointKey === null ? () => {
38256
+ } : registerForegroundStream(resolved.endpointKey);
38257
+ let result;
38258
+ try {
38259
+ result = await compact({
38260
+ entries,
38261
+ model: resolved.model,
38262
+ ...resolved.apiKey !== void 0 ? { apiKey: resolved.apiKey } : {},
38263
+ ...instructions !== void 0 ? { instructions } : {}
38264
+ });
38265
+ } finally {
38266
+ releaseEndpointSlot();
38267
+ }
36879
38268
  if (result.messagesSummarized === 0 || result.summary.length === 0) return null;
36880
38269
  const entry = {
36881
38270
  kind: "compactionSummary",
@@ -37244,6 +38633,40 @@ async function bootOrchestrator(options = {}) {
37244
38633
  let deferredWatchdogNoticeSink = null;
37245
38634
  const memoryTracePath = taskMemoryTracePath();
37246
38635
  const memoryTrace = memoryTracePath === null ? null : createTaskMemoryTrace(memoryTracePath);
38636
+ let backgroundMemoryRoute = null;
38637
+ const recordBackgroundMemoryUsage = (usage) => {
38638
+ const meta = session?.current() ?? null;
38639
+ try {
38640
+ recordBackgroundMemoryStep({
38641
+ usage,
38642
+ stateDir: clioStateDir(),
38643
+ sessionId: meta?.id ?? null,
38644
+ // The identity the session ledger is filed under, so `usage report
38645
+ // --repo` selects these rows with the same hash it selects ledgers with.
38646
+ repoIdentity: meta ? meta.cwdHash || cwdHash(meta.cwd || process.cwd()) : null,
38647
+ ...observability === void 0 ? {} : { observability }
38648
+ });
38649
+ } catch {
38650
+ }
38651
+ };
38652
+ const proposeInjectedMemoryEntries = (entries) => {
38653
+ const meta = session?.current() ?? null;
38654
+ void proposeInjectedTaskMemory(clioDataDir(), {
38655
+ sessionId: meta?.id ?? null,
38656
+ cwd: meta?.cwd || process.cwd(),
38657
+ entries
38658
+ }).then((result2) => {
38659
+ for (const error of result2.errors) {
38660
+ process.stderr.write(`[clio:memory] proposed record not written for ${error}
38661
+ `);
38662
+ }
38663
+ }).catch((error) => {
38664
+ process.stderr.write(
38665
+ `[clio:memory] proposed records not written: ${error instanceof Error ? error.message : String(error)}
38666
+ `
38667
+ );
38668
+ });
38669
+ };
37247
38670
  const memoryIntervention = createMemoryInterventionRegistration({
37248
38671
  bank: taskMemoryBank,
37249
38672
  telemetry: createTaskMemoryTelemetrySink(),
@@ -37258,8 +38681,21 @@ async function bootOrchestrator(options = {}) {
37258
38681
  },
37259
38682
  getModelClient: () => {
37260
38683
  const settings = effectiveSettingsForDispatch?.();
37261
- return settings === void 0 ? null : createBackgroundMemoryModelClient(providers, settings, settings.memory.intervention.timeoutMs);
37262
- }
38684
+ backgroundMemoryRoute = settings === void 0 ? null : createBackgroundMemoryModelClient(providers, settings, settings.memory.intervention.timeoutMs, bus);
38685
+ return backgroundMemoryRoute?.client ?? null;
38686
+ },
38687
+ // A single-slot local server serves one request at a time, so a memory step
38688
+ // started while the operator's turn is streaming either waits behind it or
38689
+ // makes the server swap the resident model out to answer. The chat loop
38690
+ // registers its stream on the endpoint it streams against, so the two are
38691
+ // compared by the same canonical key dispatch admission counts slots on.
38692
+ backgroundEndpointBusy: () => {
38693
+ const endpointKey = backgroundMemoryRoute?.endpointKey ?? null;
38694
+ if (endpointKey === null) return false;
38695
+ return (foregroundStreamUsage()[endpointKey] ?? 0) > 0;
38696
+ },
38697
+ onStepUsage: (usage) => recordBackgroundMemoryUsage(usage),
38698
+ onInjectedEntries: (entries) => proposeInjectedMemoryEntries(entries)
37263
38699
  });
37264
38700
  middleware.registerHook(memoryIntervention);
37265
38701
  const unsubscribeMemoryLoop = bus.on(BusChannels.LoopBlocked, () => memoryIntervention.signalLoop());
@@ -37587,6 +39023,12 @@ async function bootOrchestrator(options = {}) {
37587
39023
  );
37588
39024
  }
37589
39025
  const chat = createChatLoop({
39026
+ // The pre-warm holds one slot on its endpoint while it runs, so dispatch
39027
+ // admission (#250) sees it exactly as it sees the orchestrator's own turn.
39028
+ registerPrewarmEndpointSlot: (runtime) => {
39029
+ const key = canonicalEndpointKey(runtime.runtimeResolution.target);
39030
+ return key === null ? null : registerForegroundStream(key);
39031
+ },
37590
39032
  getSettings: getCurrentSettings,
37591
39033
  providers,
37592
39034
  middleware,
@@ -37643,7 +39085,12 @@ async function bootOrchestrator(options = {}) {
37643
39085
  autoCompact: createProductionAutoCompact(session, getCurrentSettings, providers)
37644
39086
  } : {},
37645
39087
  toolRegistry,
37646
- hasAttachedDispatch: () => dispatchBackground.size() > 0
39088
+ hasAttachedDispatch: () => dispatchBackground.size() > 0,
39089
+ // The pre-warm buys latency for a person about to type the next turn. A
39090
+ // headless `run` submits its one prompt immediately and an unattended boot
39091
+ // never submits at all, so neither has latency to buy; the ACP surface has
39092
+ // an operator on the other end of the client and keeps it.
39093
+ isLatencySurface: () => interactive || acpMode
37647
39094
  });
37648
39095
  termination.onDrain(async () => {
37649
39096
  chat.dispose();
@@ -37846,7 +39293,11 @@ async function bootOrchestrator(options = {}) {
37846
39293
  lastDecision: memoryIntervention.lastDecision(),
37847
39294
  bank,
37848
39295
  activity: memoryIntervention.recentActivity(),
37849
- stepInFlight: memoryIntervention.stepInFlight()
39296
+ stepInFlight: memoryIntervention.stepInFlight(),
39297
+ // Folded from the telemetry ledger, which is durable across sessions,
39298
+ // so `/memory` answers what the tier has cost since it was turned on
39299
+ // rather than what it cost since this process started.
39300
+ spend: readTaskMemorySpendSummary(clioStateDir())
37850
39301
  };
37851
39302
  },
37852
39303
  getTaskMemorySeedOffer,
@@ -38019,4 +39470,4 @@ export {
38019
39470
  resolveApiKeyForTarget,
38020
39471
  synthesizeOrchestratorModel
38021
39472
  };
38022
- //# sourceMappingURL=orchestrator-WZYB54DM.js.map
39473
+ //# sourceMappingURL=orchestrator-ZKBPCHW6.js.map