@iowarp/clio-coder 0.3.4 → 0.3.6

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 (265) hide show
  1. package/CHANGELOG.md +37 -2
  2. package/CONTRIBUTING.md +6 -6
  3. package/README.md +2 -2
  4. package/dist/{acp-S5R4RR5B.js → acp-2BEHC4DL.js} +4 -4
  5. package/dist/{agents-P6DMMVZY.js → agents-LNNFTM53.js} +13 -11
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-2XCZLPKS.js → auth-KXXFI2VS.js} +6 -6
  8. package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
  9. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  10. package/dist/chunk-3BPUFZDL.js +37 -0
  11. package/dist/{chunk-WPQLXFOZ.js → chunk-43AOLP7E.js} +2 -2
  12. package/dist/{chunk-N4CZJQRK.js → chunk-5JGRAMKL.js} +4 -4
  13. package/dist/{chunk-BRXQQJFP.js → chunk-6US73PDB.js} +568 -47
  14. package/dist/{chunk-K6WL7QZT.js → chunk-6XXKFVSN.js} +2 -2
  15. package/dist/{chunk-QQK64KLB.js → chunk-CJUB2JJ2.js} +138 -20
  16. package/dist/{chunk-HV5X7OR2.js → chunk-CKXWIANG.js} +12 -12
  17. package/dist/{chunk-UZHIZC5S.js → chunk-CYQKWTG3.js} +61 -76
  18. package/dist/{chunk-QWU7ZBO7.js → chunk-DJVECN66.js} +204 -45
  19. package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
  20. package/dist/{chunk-7RXG6QRZ.js → chunk-EKY57CSP.js} +2 -75
  21. package/dist/{chunk-EDRHSCIE.js → chunk-EYPA3EGJ.js} +10 -2
  22. package/dist/{chunk-TTNYS3EA.js → chunk-G7MUEIGA.js} +1 -1
  23. package/dist/{chunk-BPGS2WCQ.js → chunk-GEYXPTRF.js} +2 -1
  24. package/dist/{chunk-BEY543CS.js → chunk-GOXNB3AO.js} +5 -2
  25. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  26. package/dist/chunk-HWUFFB6L.js +83 -0
  27. package/dist/{chunk-35MKKU5R.js → chunk-K7T3E2SR.js} +15 -8
  28. package/dist/{chunk-VAWWTKDP.js → chunk-KHSFENX2.js} +2 -2
  29. package/dist/chunk-LCGCVYZ4.js +57 -0
  30. package/dist/{chunk-X6COSD2O.js → chunk-LYF7OHWH.js} +41 -14
  31. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  32. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  33. package/dist/{chunk-5M54SPOL.js → chunk-ODFEOB4F.js} +161 -5
  34. package/dist/{chunk-3JLKSKD7.js → chunk-OH3TOQTB.js} +5 -1
  35. package/dist/{chunk-MEQ45TQ4.js → chunk-PBTHKCPN.js} +18 -4
  36. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  37. package/dist/{chunk-QQL5RT5M.js → chunk-QM3F2GKX.js} +94 -36
  38. package/dist/{chunk-A2GZF7DC.js → chunk-QNQHSOLF.js} +4 -4
  39. package/dist/{chunk-KRPY7NTG.js → chunk-R46L2BIR.js} +3 -3
  40. package/dist/{chunk-BP4OYD6A.js → chunk-RY3LY4J5.js} +20 -2
  41. package/dist/{chunk-34475P3I.js → chunk-TSHXZTOQ.js} +5 -4
  42. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  43. package/dist/{chunk-2TZWSW76.js → chunk-WHGPSPT5.js} +2 -2
  44. package/dist/{chunk-TW3WDMVS.js → chunk-WHJYKASB.js} +2 -2
  45. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  46. package/dist/{chunk-HXG4IURW.js → chunk-XE2VEJHX.js} +2 -2
  47. package/dist/{chunk-3HZ5RWN2.js → chunk-XF5N4U5A.js} +7 -6
  48. package/dist/{chunk-ZYKPLLNQ.js → chunk-XXQNGV4M.js} +590 -32
  49. package/dist/{chunk-4JUF2NNX.js → chunk-XYDYPRZI.js} +4 -4
  50. package/dist/{chunk-VMNQ6OZA.js → chunk-ZRGEBJ4T.js} +971 -794
  51. package/dist/{chunk-2LZI5CAG.js → chunk-ZXF4XRKW.js} +75 -33
  52. package/dist/{chunk-VSNATDE6.js → chunk-ZZMN5OM4.js} +2 -2
  53. package/dist/cli/index.js +31 -31
  54. package/dist/{clio-J5JIOIDS.js → clio-M2KGYUFZ.js} +2 -2
  55. package/dist/{code-nav-AXCXSBHX.js → code-nav-GQNL7XA6.js} +5 -5
  56. package/dist/codewiki/build-worker.js +4 -4
  57. package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
  58. package/dist/{config-OEBMIN2U.js → config-XUUYQIWO.js} +27 -25
  59. package/dist/{configure-PUQOSIXQ.js → configure-IHJ7YOMV.js} +7 -7
  60. package/dist/{context-URSXPBCK.js → context-74JLXAWD.js} +12 -12
  61. package/dist/{context-MGSE4Z2T.js → context-75MIWW3U.js} +24 -22
  62. package/dist/{context-EKDCKUUZ.js → context-ZQ7SIFJV.js} +8 -7
  63. package/dist/{context-clear-KDAJRNUK.js → context-clear-GYKWNUML.js} +24 -22
  64. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  65. package/dist/{context-working-set-SBKMPPI2.js → context-working-set-UX5KEP4J.js} +11 -10
  66. package/dist/{dispatch-runner-MSWN72NK.js → dispatch-runner-GIJBHNFL.js} +21 -20
  67. package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
  68. package/dist/{doctor-7BSE27PJ.js → doctor-SVJ5BZCW.js} +4 -4
  69. package/dist/{eval-IZGDOO4H.js → eval-CG6LLBLD.js} +47 -232
  70. package/dist/{evidence-SR7WXB5B.js → evidence-ZYFIEN42.js} +19 -18
  71. package/dist/{evolve-K7VE2CBX.js → evolve-QGEXEMDW.js} +19 -18
  72. package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
  73. package/dist/{fleet-7XMJNQNF.js → fleet-S5R4ZOQY.js} +49 -30
  74. package/dist/{fleet-preflight-AQNAH644.js → fleet-preflight-BHSNPBMH.js} +2 -2
  75. package/dist/{init-JGNPAYXT.js → init-5DRU55YR.js} +31 -29
  76. package/dist/memory-7YKKR6UC.js +467 -0
  77. package/dist/{models-ZMMLFJNN.js → models-ZPOLRU2C.js} +10 -10
  78. package/dist/{monitor-2F3T5KHP.js → monitor-US5F5YGZ.js} +33 -18
  79. package/dist/{orchestrator-ORHT43JB.js → orchestrator-E2AL4T5N.js} +1092 -659
  80. package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
  81. package/dist/{reset-NXGTYNUO.js → reset-KZ652EK6.js} +3 -3
  82. package/dist/{run-RF4WJGMT.js → run-SRNBKDWD.js} +52 -40
  83. package/dist/{share-UT3W6E4M.js → share-CGZE33UP.js} +3 -3
  84. package/dist/{skills-PSACKC5Q.js → skills-S2X4DLY5.js} +4 -4
  85. package/dist/{skills-eval-WJSI55RZ.js → skills-eval-W2GGIC4R.js} +19 -18
  86. package/dist/{targets-PIIRAOYS.js → targets-54SWINWB.js} +14 -12
  87. package/dist/{terminal-lease-ULWXWNVY.js → terminal-lease-SAIF2OGY.js} +5 -4
  88. package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
  89. package/dist/{upgrade-346TZ6AV.js → upgrade-JKAR27XC.js} +8 -8
  90. package/dist/{usage-6KKXR32N.js → usage-MSAWCLX4.js} +60 -27
  91. package/dist/{verifiers-4UUM6TEE.js → verifiers-NCBTHHN2.js} +60 -54
  92. package/dist/{wiki-generate-7STOCIFZ.js → wiki-generate-GUSOQ6ZP.js} +30 -28
  93. package/dist/worker/entry.js +69 -58
  94. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  95. package/docs/README.md +3 -3
  96. package/docs/acp.md +1 -1
  97. package/docs/alcf-provider.md +1 -1
  98. package/docs/architecture.md +2 -2
  99. package/docs/artifact-placement.md +1 -2
  100. package/docs/artifact-versions.md +1 -1
  101. package/docs/built-in-agents.md +1 -1
  102. package/docs/capacity-and-scheduling.md +1 -1
  103. package/docs/commands-and-modes.md +9 -7
  104. package/docs/configuration-and-targets.md +12 -1
  105. package/docs/context-engine.md +4 -2
  106. package/docs/context-working-set.md +4 -4
  107. package/docs/development-pipeline.md +1 -1
  108. package/docs/documentation-coverage.md +3 -3
  109. package/docs/documentation-guide.md +2 -2
  110. package/docs/eval-runner.md +1 -1
  111. package/docs/evals-internal.md +4 -45
  112. package/docs/evidence-and-memory.md +67 -7
  113. package/docs/evolution.md +1 -1
  114. package/docs/exit-codes-and-output.md +1 -1
  115. package/docs/extensions-and-sharing.md +2 -2
  116. package/docs/fleet-dispatch.md +28 -2
  117. package/docs/installation-and-lifecycle.md +2 -2
  118. package/docs/middleware-and-components.md +19 -2
  119. package/docs/model-catalog.md +1 -1
  120. package/docs/observability.md +3 -3
  121. package/docs/proactive-memory.md +26 -16
  122. package/docs/prompt-envelope-and-tools.md +4 -2
  123. package/docs/provider-adapter-cookbook.md +1 -1
  124. package/docs/release-cut-checklist.md +38 -35
  125. package/docs/safety-model.md +29 -7
  126. package/docs/scientific-validation.md +3 -3
  127. package/docs/session-lifecycle.md +1 -1
  128. package/docs/skills-marketplace.md +1 -1
  129. package/docs/tool-usage.md +2 -2
  130. package/docs/trace-store.md +1 -1
  131. package/docs/troubleshooting.md +1 -1
  132. package/docs/tui-design.md +38 -4
  133. package/docs/worker-dispatch-mechanics.md +1 -1
  134. package/package.json +7 -4
  135. package/src/cli/agents.ts +2 -3
  136. package/src/cli/argv.ts +14 -1
  137. package/src/cli/fleet.ts +15 -0
  138. package/src/cli/index.ts +1 -1
  139. package/src/cli/memory.ts +272 -10
  140. package/src/cli/modes/json-stream.ts +2 -2
  141. package/src/cli/modes/print.ts +12 -1
  142. package/src/cli/run.ts +22 -2
  143. package/src/cli/targets.ts +12 -3
  144. package/src/cli/usage.ts +55 -7
  145. package/src/core/bus-events.ts +3 -0
  146. package/src/core/response-model-id.ts +134 -0
  147. package/src/core/toml.ts +62 -0
  148. package/src/core/workspace-files.ts +0 -1
  149. package/src/domains/agents/builtins/architect.md +1 -1
  150. package/src/domains/agents/catalog.ts +5 -4
  151. package/src/domains/agents/recipe.ts +54 -14
  152. package/src/domains/agents/result-contract.ts +7 -4
  153. package/src/domains/context/bootstrap.ts +36 -27
  154. package/src/domains/context/project-metadata.ts +19 -63
  155. package/src/domains/context/prompt-context.ts +8 -0
  156. package/src/domains/context/working-set/policies/index.ts +3 -4
  157. package/src/domains/dispatch/budget-envelope.ts +396 -0
  158. package/src/domains/dispatch/contract.ts +2 -0
  159. package/src/domains/dispatch/extension.ts +81 -27
  160. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  161. package/src/domains/dispatch/receipt-integrity.ts +4 -0
  162. package/src/domains/dispatch/state.ts +1 -0
  163. package/src/domains/dispatch/types.ts +10 -3
  164. package/src/domains/dispatch/validation.ts +14 -0
  165. package/src/domains/dispatch/worker-spawn.ts +14 -3
  166. package/src/domains/eval/metrics/evidence.ts +0 -116
  167. package/src/domains/eval/metrics/invariants.ts +1 -1
  168. package/src/domains/eval/runners/clio-run.ts +1 -10
  169. package/src/domains/eval/runners/external-command.ts +2 -29
  170. package/src/domains/eval/schema/suite.ts +0 -7
  171. package/src/domains/eval/suites/run.ts +1 -7
  172. package/src/domains/memory/index.ts +22 -0
  173. package/src/domains/memory/operations.ts +58 -1
  174. package/src/domains/memory/promotion.ts +281 -0
  175. package/src/domains/memory/prompt-section.ts +25 -5
  176. package/src/domains/memory/proposal.ts +51 -7
  177. package/src/domains/memory/task-bank.ts +3 -2
  178. package/src/domains/memory/task-memory-handoff.ts +181 -24
  179. package/src/domains/memory/task-memory-policy.ts +3 -1
  180. package/src/domains/memory/types.ts +37 -0
  181. package/src/domains/memory/validate.ts +178 -0
  182. package/src/domains/middleware/memory-intervention.ts +35 -25
  183. package/src/domains/middleware/runtime.ts +6 -0
  184. package/src/domains/middleware/skills-reminder.ts +19 -4
  185. package/src/domains/middleware/stalled-turn.ts +43 -1
  186. package/src/domains/middleware/types.ts +10 -0
  187. package/src/domains/observability/contract.ts +6 -1
  188. package/src/domains/observability/cost.ts +20 -4
  189. package/src/domains/observability/extension.ts +2 -2
  190. package/src/domains/providers/index.ts +3 -0
  191. package/src/domains/providers/model-discovery.ts +9 -0
  192. package/src/domains/providers/runtime-resolution.ts +38 -1
  193. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  194. package/src/domains/providers/types/context-window-slots.ts +18 -0
  195. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  196. package/src/domains/safety/call-target.ts +211 -14
  197. package/src/domains/safety/decision-presentation.ts +268 -0
  198. package/src/domains/safety/redaction.ts +73 -0
  199. package/src/domains/session/context-ledger.ts +10 -1
  200. package/src/domains/session/decision-board.ts +4 -0
  201. package/src/domains/session/entries.ts +3 -0
  202. package/src/domains/session/history.ts +68 -19
  203. package/src/domains/session/usage.ts +24 -7
  204. package/src/engine/acp/event-mapper.ts +7 -0
  205. package/src/engine/acp/server.ts +29 -2
  206. package/src/engine/apis/lmstudio.ts +25 -4
  207. package/src/engine/apis/openai-completions.ts +147 -22
  208. package/src/engine/claude/sdk-runtime.ts +8 -2
  209. package/src/engine/claude/tool-safety.ts +13 -0
  210. package/src/engine/loop-guard.ts +27 -3
  211. package/src/engine/worker-events.ts +4 -3
  212. package/src/engine/worker-runtime.ts +59 -54
  213. package/src/entry/orchestrator.ts +18 -1
  214. package/src/interactive/chat-loop-messages.ts +22 -0
  215. package/src/interactive/chat-loop.ts +13 -0
  216. package/src/interactive/chat-renderer.ts +19 -3
  217. package/src/interactive/clio-editor.ts +44 -7
  218. package/src/interactive/context-overlay.ts +43 -5
  219. package/src/interactive/cost-overlay.ts +39 -8
  220. package/src/interactive/dispatch-board.ts +212 -35
  221. package/src/interactive/footer/widgets.ts +13 -0
  222. package/src/interactive/interactive-application.ts +6 -1
  223. package/src/interactive/interactive-input-runtime.ts +11 -1
  224. package/src/interactive/interactive-presentation.ts +11 -1
  225. package/src/interactive/memory-overlay.ts +89 -4
  226. package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
  227. package/src/interactive/overlay-frame.ts +5 -2
  228. package/src/interactive/overlay-general-openers.ts +40 -1
  229. package/src/interactive/overlay-key-routing.ts +41 -1
  230. package/src/interactive/overlay-lifecycle.ts +11 -4
  231. package/src/interactive/overlay-permission-lifecycle.ts +23 -8
  232. package/src/interactive/overlay-transitions.ts +11 -0
  233. package/src/interactive/overlays/ask-user.ts +74 -30
  234. package/src/interactive/overlays/decisions.ts +3 -1
  235. package/src/interactive/permission-hint.ts +35 -0
  236. package/src/interactive/permission-overlay.ts +95 -45
  237. package/src/interactive/renderers/tool-execution.ts +19 -49
  238. package/src/interactive/session-last-turn.ts +8 -1
  239. package/src/interactive/session-usage-reseed.ts +36 -10
  240. package/src/interactive/slash-commands.ts +2 -2
  241. package/src/interactive/status/summary.ts +5 -0
  242. package/src/interactive/status/types.ts +5 -0
  243. package/src/interactive/terminal-lease.ts +1 -0
  244. package/src/interactive/turn-context.ts +96 -23
  245. package/src/interactive/turn-middleware.ts +1 -0
  246. package/src/interactive/turn-runtime.ts +37 -8
  247. package/src/interactive/turn-state.ts +3 -0
  248. package/src/interactive/worker-progress.ts +440 -0
  249. package/src/interactive/worker-stream.ts +51 -110
  250. package/src/tools/agent-tools.ts +28 -3
  251. package/src/tools/ask-user.ts +21 -1
  252. package/src/tools/context/index.ts +2 -2
  253. package/src/tools/dispatch-arguments.ts +8 -0
  254. package/src/tools/dispatch-event-text.ts +19 -0
  255. package/src/tools/dispatch.ts +24 -1
  256. package/src/tools/monitor.ts +15 -0
  257. package/src/tools/registry.ts +15 -5
  258. package/src/tools/result-disposition.ts +156 -0
  259. package/src/tools/result-shaping.ts +59 -1
  260. package/src/tools/verify/authoring.ts +55 -54
  261. package/src/tools/worker-evidence.ts +19 -0
  262. package/src/worker/spec-contract.ts +43 -3
  263. package/dist/chunk-EFADSJET.js +0 -18
  264. package/dist/memory-4ALKDJ4Q.js +0 -246
  265. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
@@ -6,7 +6,7 @@ import {
6
6
  bootstrapInputFromInitOptions,
7
7
  modelBootstrapGenerate,
8
8
  resolveBootstrapRoute
9
- } from "./chunk-HV5X7OR2.js";
9
+ } from "./chunk-CKXWIANG.js";
10
10
  import "./chunk-J5Q24KAG.js";
11
11
  import {
12
12
  DEFAULT_KEEP_RECENT_TOKENS,
@@ -21,7 +21,7 @@ import {
21
21
  projectWorkingSet,
22
22
  resolveWorkingSetPolicy,
23
23
  selectVisibleEntries
24
- } from "./chunk-TW3WDMVS.js";
24
+ } from "./chunk-WHJYKASB.js";
25
25
  import {
26
26
  assistantSessionPayload,
27
27
  backendCacheVerdict,
@@ -54,34 +54,33 @@ import {
54
54
  toolNamesFromAgentState,
55
55
  toolResultSummary,
56
56
  toolSignatureFromState
57
- } from "./chunk-MEQ45TQ4.js";
57
+ } from "./chunk-PBTHKCPN.js";
58
58
  import {
59
59
  SchedulingDomainModule,
60
60
  createPromptsDomainModule,
61
61
  renderAgentCatalogSectionsFromSpecs
62
- } from "./chunk-3HZ5RWN2.js";
62
+ } from "./chunk-XF5N4U5A.js";
63
63
  import {
64
64
  AgentsDomainModule,
65
65
  SafetyDomainModule
66
- } from "./chunk-X6COSD2O.js";
66
+ } from "./chunk-LYF7OHWH.js";
67
67
  import {
68
68
  LifecycleDomainModule,
69
69
  describeUpgradeNotice
70
- } from "./chunk-K6WL7QZT.js";
70
+ } from "./chunk-6XXKFVSN.js";
71
71
  import {
72
72
  ensureClioState,
73
73
  takeUpgradeNotice
74
- } from "./chunk-VAWWTKDP.js";
74
+ } from "./chunk-KHSFENX2.js";
75
75
  import {
76
76
  ConfigDomainModule,
77
77
  createConfigDomainModule,
78
78
  loadDomains
79
- } from "./chunk-KRPY7NTG.js";
79
+ } from "./chunk-R46L2BIR.js";
80
80
  import {
81
81
  compileScoutTransition,
82
82
  createDispatchRunEventRegistry
83
- } from "./chunk-N4CZJQRK.js";
84
- import "./chunk-EFADSJET.js";
83
+ } from "./chunk-5JGRAMKL.js";
85
84
  import {
86
85
  monitorToolSurface
87
86
  } from "./chunk-FJ3H4MN5.js";
@@ -92,9 +91,10 @@ import {
92
91
  costAggregateForAmount,
93
92
  formatCostAggregate,
94
93
  readAccountabilitySummary
95
- } from "./chunk-35MKKU5R.js";
94
+ } from "./chunk-K7T3E2SR.js";
96
95
  import "./chunk-HC4CLZ2Y.js";
97
96
  import "./chunk-HFSBBKSQ.js";
97
+ import "./chunk-3BPUFZDL.js";
98
98
  import {
99
99
  steerToolSurface
100
100
  } from "./chunk-WEH5XRJQ.js";
@@ -106,7 +106,8 @@ import "./chunk-E25LMLRW.js";
106
106
  import {
107
107
  createContextDomainModule,
108
108
  loadProjectClioMd
109
- } from "./chunk-UZHIZC5S.js";
109
+ } from "./chunk-CYQKWTG3.js";
110
+ import "./chunk-LCGCVYZ4.js";
110
111
  import {
111
112
  renderCodewikiDigest
112
113
  } from "./chunk-5WIGXA4T.js";
@@ -116,12 +117,13 @@ import {
116
117
  createTaskMemoryTrace,
117
118
  describeTaskMemoryActivity,
118
119
  loadMemoryRecordsSync,
120
+ proposeMemoryPromotion,
119
121
  renderTaskMemoryHandoffSource,
120
122
  seedTaskMemoryFromNewestHandoff,
121
123
  taskMemoryBankSize,
122
124
  taskMemoryHandoffSeedOffer,
123
125
  taskMemoryTracePath
124
- } from "./chunk-BRXQQJFP.js";
126
+ } from "./chunk-6US73PDB.js";
125
127
  import {
126
128
  ACP_MAX_CHUNK_BYTES,
127
129
  ACP_MAX_RAW_RECORD_BYTES,
@@ -148,15 +150,21 @@ import {
148
150
  readPendingGateDecisions,
149
151
  recoverCleanupReadyCompeteGroups,
150
152
  requireAgentSteps
151
- } from "./chunk-QQL5RT5M.js";
153
+ } from "./chunk-QM3F2GKX.js";
152
154
  import {
153
155
  SessionDomainModule,
156
+ addResponseModelIdObservationCount,
157
+ addResponseModelIdObservationCounts,
158
+ attributedModelId,
154
159
  collectSessionEntries,
160
+ emptyResponseModelIdObservationCounts,
155
161
  ledgerUsageCalls,
156
162
  protectedArtifactEntryFromArtifact,
157
163
  protectedArtifactStateFromSessionEntries,
158
- readAuditRows
159
- } from "./chunk-QQK64KLB.js";
164
+ readAuditRows,
165
+ responseModelIdObservationCountsLabel,
166
+ responseModelIdObservationFromRecord
167
+ } from "./chunk-CJUB2JJ2.js";
160
168
  import {
161
169
  parseRigorOverride,
162
170
  resolveRigor
@@ -164,8 +172,8 @@ import {
164
172
  import {
165
173
  isReceiptIntegrity,
166
174
  verifyReceiptIntegrity
167
- } from "./chunk-3JLKSKD7.js";
168
- import "./chunk-34475P3I.js";
175
+ } from "./chunk-OH3TOQTB.js";
176
+ import "./chunk-TSHXZTOQ.js";
169
177
  import {
170
178
  shellQuote
171
179
  } from "./chunk-TXOTCRLG.js";
@@ -173,13 +181,13 @@ import {
173
181
  emptyWorkspaceSnapshot,
174
182
  probeGitStatusAsync,
175
183
  probeWorkspaceAsync
176
- } from "./chunk-G4BMMOKF.js";
184
+ } from "./chunk-HVDIIIQW.js";
177
185
  import {
178
186
  listWikiPages,
179
187
  wikiCompleteness,
180
188
  wikiStaleness,
181
189
  wikiStalenessAsync
182
- } from "./chunk-X4RCMKVQ.js";
190
+ } from "./chunk-NDINPTJ4.js";
183
191
  import "./chunk-MVVUPGPW.js";
184
192
  import {
185
193
  buildRecallFields,
@@ -187,7 +195,7 @@ import {
187
195
  recallParentTurnId,
188
196
  recallableRefListing,
189
197
  resolveRecall
190
- } from "./chunk-VSNATDE6.js";
198
+ } from "./chunk-ZZMN5OM4.js";
191
199
  import {
192
200
  foldWorkingSet
193
201
  } from "./chunk-TZSKNMZG.js";
@@ -217,13 +225,17 @@ import {
217
225
  ASK_USER_OTHER_LABEL,
218
226
  INTERACTIVE_LOOP_BLOCK_BUDGET,
219
227
  askAxis,
228
+ askUserExposure,
220
229
  assertRegisteredBuiltinTools,
221
230
  cancelledAskUserResult,
231
+ classifyDecisionPresentation,
222
232
  createEngineAgent,
223
233
  createLoopGuardRegistration,
224
234
  createProtectedArtifactsRegistration,
225
235
  createRegistry,
226
- describeCallTarget,
236
+ decisionActionClass,
237
+ decisionFactsForAnswer,
238
+ decisionFactsForPermission,
227
239
  diffWords,
228
240
  finalizeAskUserInterviewForHost,
229
241
  lazyTool,
@@ -234,9 +246,8 @@ import {
234
246
  registerCoreTools,
235
247
  resolveFdBinary,
236
248
  resolveSessionTools,
237
- sanitizeCallTargetText,
238
249
  sanitizeLockedSynthesisMessage
239
- } from "./chunk-VMNQ6OZA.js";
250
+ } from "./chunk-ZRGEBJ4T.js";
240
251
  import {
241
252
  HEADLESS_PERMISSION_DENIED_REASON
242
253
  } from "./chunk-K7VKOLQQ.js";
@@ -255,7 +266,7 @@ import {
255
266
  installUserHooks,
256
267
  openDetachedBatchViews,
257
268
  writeMiddlewareDiagnosticToStderr
258
- } from "./chunk-2LZI5CAG.js";
269
+ } from "./chunk-ZXF4XRKW.js";
259
270
  import "./chunk-IR4CFBFN.js";
260
271
  import "./chunk-UOV2BYIW.js";
261
272
  import {
@@ -269,11 +280,11 @@ import {
269
280
  stringArg,
270
281
  timeoutMsArg,
271
282
  withResolvedDispatchPlan
272
- } from "./chunk-EDRHSCIE.js";
283
+ } from "./chunk-EYPA3EGJ.js";
273
284
  import {
274
285
  TaskMemoryBank,
275
286
  createTaskMemoryTelemetrySink
276
- } from "./chunk-2TZWSW76.js";
287
+ } from "./chunk-WHGPSPT5.js";
277
288
  import {
278
289
  DISPATCH_BRIEFING_MAX_BYTES,
279
290
  JUDGE_GATE_PROMPT,
@@ -282,24 +293,32 @@ import {
282
293
  approvedRouteCandidates,
283
294
  builtin,
284
295
  classifyResourceRead,
296
+ cloneRunToolBudgetEnvelope,
285
297
  combineBashOutput,
298
+ describeCallTarget,
299
+ formatBudgetPolicy,
300
+ formatBudgetReasons,
301
+ formatBudgetRequest,
302
+ formatEffectiveBudget,
286
303
  isToolProfileName,
304
+ redactSecretString,
305
+ redactToolArgs,
287
306
  runBashCommand,
288
307
  runKindSupportsLiveSteering,
308
+ sanitizeCallTargetText,
289
309
  toolPresentationPolicy
290
- } from "./chunk-ZYKPLLNQ.js";
310
+ } from "./chunk-XXQNGV4M.js";
291
311
  import {
292
312
  createTaskBoardStore,
293
313
  foldSessionTaskHistory,
294
314
  taskBoardCounts
295
- } from "./chunk-WPQLXFOZ.js";
315
+ } from "./chunk-43AOLP7E.js";
296
316
  import {
297
- DEFAULT_AUTONOMY_LEVEL,
298
317
  DEFAULT_RECENT_ENTRY_LIMIT,
299
318
  assessFinishContract,
300
319
  parseScoutResult,
301
320
  resultContractSourceId
302
- } from "./chunk-7RXG6QRZ.js";
321
+ } from "./chunk-EKY57CSP.js";
303
322
  import {
304
323
  agentRoleFactsResolver,
305
324
  defaultRoutingIntent,
@@ -331,11 +350,15 @@ import {
331
350
  SKILL_SUGGESTION_PREFIX,
332
351
  isSkillActivation,
333
352
  skillActivationFromToolDetails
334
- } from "./chunk-BEY543CS.js";
353
+ } from "./chunk-GOXNB3AO.js";
354
+ import {
355
+ DEFAULT_AUTONOMY_LEVEL
356
+ } from "./chunk-HWUFFB6L.js";
335
357
  import {
358
+ sweepExpiredToolOffloads,
336
359
  toolResultPresentationPolicy,
337
360
  toolResultPresentationText
338
- } from "./chunk-5M54SPOL.js";
361
+ } from "./chunk-ODFEOB4F.js";
339
362
  import {
340
363
  formatSize
341
364
  } from "./chunk-OZNBF4L3.js";
@@ -352,14 +375,14 @@ import {
352
375
  import {
353
376
  incompleteInstallationAdvice
354
377
  } from "./chunk-65DEGPJ6.js";
355
- import "./chunk-POHLU5DW.js";
356
- import "./chunk-YHZX5GEU.js";
357
- import "./chunk-VJWL6YS5.js";
378
+ import "./chunk-M6L6IDJG.js";
379
+ import "./chunk-XAKHZX5N.js";
380
+ import "./chunk-UUVG37B4.js";
358
381
  import {
359
382
  readCodewiki,
360
383
  readCodewikiAsync
361
384
  } from "./chunk-LBMZMYH2.js";
362
- import "./chunk-EKMEHE4H.js";
385
+ import "./chunk-33YXPOE3.js";
363
386
  import {
364
387
  getVersionInfo
365
388
  } from "./chunk-XPLRXC72.js";
@@ -379,6 +402,7 @@ import {
379
402
  VALID_THINKING_LEVELS,
380
403
  applyModelCapabilityPatch,
381
404
  firstRuntimeResolutionError,
405
+ formatContextWindowSlots,
382
406
  getRuntimeRegistry,
383
407
  isDispatchEligibleRuntime,
384
408
  isOrchestratorEligibleRuntime,
@@ -393,14 +417,14 @@ import {
393
417
  resolveProviderReference,
394
418
  resolveReservedOutputTokens,
395
419
  resolveRuntimeTarget,
396
- runtimeResolutionWarnings,
420
+ runtimeResolutionWarningsBesideThinkingNotice,
397
421
  runtimeTargetSnapshot,
398
422
  setProtectedModelsProvider,
399
423
  supportsAgentRoleTools,
400
424
  thinkingLevelChoiceLabel,
401
425
  thinkingLevelFromChoiceLabel,
402
426
  withRunOverrides
403
- } from "./chunk-QWU7ZBO7.js";
427
+ } from "./chunk-DJVECN66.js";
404
428
  import "./chunk-CFGTUFWB.js";
405
429
  import {
406
430
  bindAgentProfileInSettings,
@@ -449,7 +473,7 @@ import {
449
473
  reconcileSnapshot,
450
474
  shouldCompact,
451
475
  snapshotInputTokens
452
- } from "./chunk-BPGS2WCQ.js";
476
+ } from "./chunk-GEYXPTRF.js";
453
477
  import "./chunk-SST6Z5JA.js";
454
478
  import {
455
479
  atomicWrite,
@@ -483,10 +507,12 @@ import {
483
507
  safeResourceWrite
484
508
  } from "./chunk-WEPFGWHJ.js";
485
509
  import {
486
- Box,
487
510
  ClioEditor,
488
511
  CombinedAutocompleteProvider,
489
512
  Container,
513
+ DEFAULT_SELECT_THEME,
514
+ FILTER_HINT,
515
+ FocusBox,
490
516
  GLYPH,
491
517
  Input,
492
518
  Markdown,
@@ -500,6 +526,8 @@ import {
500
526
  abbreviateModelId,
501
527
  barSep,
502
528
  brandMark,
529
+ buildHint,
530
+ clioError,
503
531
  clioTheme,
504
532
  collapseHomePath,
505
533
  createAgentProgress,
@@ -509,11 +537,13 @@ import {
509
537
  detectTerminalKeySupport,
510
538
  dotSep,
511
539
  fgSequence,
540
+ fitHintEntries,
512
541
  fitUnits,
513
542
  formatCompactMs,
514
543
  formatContextPercent,
515
544
  formatInvalidKeybindingNotice,
516
545
  formatPlatformKeybindingNotice,
546
+ formatRuntimeResolutionDiagnostic,
517
547
  formatTargetLabel,
518
548
  frame,
519
549
  fuzzyFilter,
@@ -527,28 +557,30 @@ import {
527
557
  markdownTheme,
528
558
  matchesKey,
529
559
  padAnsi,
560
+ permissionHintEntries,
530
561
  rule,
562
+ runtimeResolutionDiagnosticLine,
531
563
  screenTitle,
532
564
  sectionTag,
533
565
  selectListTheme,
534
- settingsListTheme,
566
+ showClioOverlayFrame,
535
567
  spinnerFrame,
536
568
  stripTerminalSequences,
537
569
  truncateToWidth,
538
570
  validateKeybindings,
539
571
  visibleWidth,
540
572
  wrapTextWithAnsi
541
- } from "./chunk-ZWMF7253.js";
573
+ } from "./chunk-E2ER4LJF.js";
542
574
  import {
543
575
  getTerminationCoordinator
544
- } from "./chunk-HXG4IURW.js";
576
+ } from "./chunk-XE2VEJHX.js";
545
577
  import {
546
578
  getSharedBus
547
579
  } from "./chunk-ZGVHUX3M.js";
548
580
  import {
549
581
  BusChannels,
550
582
  isRunAbortedPayload
551
- } from "./chunk-TTNYS3EA.js";
583
+ } from "./chunk-G7MUEIGA.js";
552
584
  import "./chunk-JVCV3ICN.js";
553
585
  import "./chunk-7CR24IG7.js";
554
586
  import {
@@ -646,6 +678,10 @@ function recordToolEnd(stats, event) {
646
678
  }
647
679
  }
648
680
  function addRunUsage(left, right) {
681
+ const responseModelIdObservationCounts = emptyResponseModelIdObservationCounts();
682
+ addResponseModelIdObservationCounts(responseModelIdObservationCounts, left.responseModelIdObservationCounts);
683
+ addResponseModelIdObservationCounts(responseModelIdObservationCounts, right.responseModelIdObservationCounts);
684
+ const last = right.hadUsage ? right : left;
649
685
  return {
650
686
  tokens: left.tokens + right.tokens,
651
687
  costUsd: left.costUsd + right.costUsd,
@@ -656,7 +692,10 @@ function addRunUsage(left, right) {
656
692
  reasoning: left.reasoning + right.reasoning,
657
693
  apiCalls: left.apiCalls + right.apiCalls,
658
694
  hadReasoning: left.hadReasoning || right.hadReasoning,
659
- hadUsage: true
695
+ hadUsage: left.hadUsage || right.hadUsage,
696
+ responseModelIdObservationCounts,
697
+ lastResponseModelIdObservation: last.lastResponseModelIdObservation,
698
+ lastDifferingResponseModelId: last.lastDifferingResponseModelId
660
699
  };
661
700
  }
662
701
  function sortedToolStats(stats) {
@@ -1956,6 +1995,7 @@ function finalizedInterviewEntryFields(policy) {
1956
1995
  roundCount: policy.rounds.length,
1957
1996
  ...policy.summary ? { summary: policy.summary } : {},
1958
1997
  ...policy.transcriptPath ? { transcriptPath: policy.transcriptPath } : {},
1998
+ exposure: policy.exposure ?? "local",
1959
1999
  decisions: [...decisionsByKey.values()]
1960
2000
  };
1961
2001
  }
@@ -2033,6 +2073,7 @@ function createDecisionBoardStore(deps = {}) {
2033
2073
  roundCount: interview.roundCount,
2034
2074
  ...interview.summary ? { summary: interview.summary } : {},
2035
2075
  ...interview.transcriptPath ? { transcriptPath: interview.transcriptPath } : {},
2076
+ ...interview.exposure ? { exposure: interview.exposure } : {},
2036
2077
  decisions: interview.decisions.map((decision) => {
2037
2078
  if (decision.key !== selected.key) return { ...decision };
2038
2079
  const next = { ...decision, status: "superseded", revisedAt };
@@ -2563,8 +2604,8 @@ function boundRawRecord(value) {
2563
2604
  return { truncated: true, bytes: originalRawRecordBytes(value) ?? boundedBytes };
2564
2605
  }
2565
2606
  var PATH_BEARING_TOOLS = /* @__PURE__ */ new Set(["read", "write", "edit", "ls", "grep", "find"]);
2566
- function toolLocations(toolName2, args, cwd) {
2567
- if (toolName2 === void 0 || !PATH_BEARING_TOOLS.has(toolName2)) return null;
2607
+ function toolLocations(toolName, args, cwd) {
2608
+ if (toolName === void 0 || !PATH_BEARING_TOOLS.has(toolName)) return null;
2568
2609
  if (!isRecord3(args)) return null;
2569
2610
  const path = args.path;
2570
2611
  if (typeof path !== "string" || path.length === 0) return null;
@@ -2800,11 +2841,11 @@ function handleChatEvent(rawEvent, transport, sessionId, active, cwd, diagnostic
2800
2841
  onToolCallLimitReached();
2801
2842
  return;
2802
2843
  }
2803
- const toolName2 = eventString(event, "toolName");
2844
+ const toolName = eventString(event, "toolName");
2804
2845
  const toolCallId = startToolCallId(active, eventString(event, "toolCallId"));
2805
2846
  active.openToolCalls.add(toolCallId);
2806
2847
  active.lastEmittedToolCallId = toolCallId;
2807
- const locations = toolLocations(toolName2, event.args, cwd);
2848
+ const locations = toolLocations(toolName, event.args, cwd);
2808
2849
  const snapshot = {
2809
2850
  rawInput: boundRawRecord(event.args),
2810
2851
  ...locations !== null ? { locations } : {}
@@ -2813,8 +2854,8 @@ function handleChatEvent(rawEvent, transport, sessionId, active, cwd, diagnostic
2813
2854
  sendUpdate(transport, sessionId, active, {
2814
2855
  sessionUpdate: "tool_call",
2815
2856
  toolCallId,
2816
- title: boundString(toolName2 ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
2817
- kind: toolKind(toolName2),
2857
+ title: boundString(toolName ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
2858
+ kind: toolKind(toolName),
2818
2859
  status: "in_progress",
2819
2860
  rawInput: snapshot.rawInput,
2820
2861
  ...snapshot.locations !== void 0 ? { locations: snapshot.locations } : {}
@@ -2822,7 +2863,7 @@ function handleChatEvent(rawEvent, transport, sessionId, active, cwd, diagnostic
2822
2863
  return;
2823
2864
  }
2824
2865
  if (event.type === "tool_execution_end") {
2825
- const toolName2 = eventString(event, "toolName");
2866
+ const toolName = eventString(event, "toolName");
2826
2867
  const toolCallId = endToolCallId(active, eventString(event, "toolCallId"));
2827
2868
  if (toolCallId === null) {
2828
2869
  diagnostics?.("dropped tool_execution_end with no tool call to update");
@@ -2838,8 +2879,8 @@ function handleChatEvent(rawEvent, transport, sessionId, active, cwd, diagnostic
2838
2879
  sendUpdate(transport, sessionId, active, {
2839
2880
  sessionUpdate: "tool_call_update",
2840
2881
  toolCallId,
2841
- title: boundString(toolName2 ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
2842
- kind: toolKind(toolName2),
2882
+ title: boundString(toolName ?? "tool", ACP_MAX_TOOL_TITLE_BYTES),
2883
+ kind: toolKind(toolName),
2843
2884
  status: toolStatus(event),
2844
2885
  ...output.length > 0 ? { content: toolCallContent(output) } : {},
2845
2886
  rawOutput: boundRawRecord({ result: event.result, isError: event.isError === true })
@@ -3161,6 +3202,17 @@ function installPermissionBridge(input) {
3161
3202
  const queuedRequestDetails = /* @__PURE__ */ new Map();
3162
3203
  const unregister = input.toolRegistry.onPermissionRequired((call, decision, meta) => {
3163
3204
  if (queuedRequestIds.has(meta.requestId)) return;
3205
+ const presentation = classifyDecisionPresentation(
3206
+ decisionFactsForPermission({
3207
+ tool: call.tool,
3208
+ actionClass: decision.classification.actionClass,
3209
+ axis: meta.axis.startsWith("net:") ? { kind: "safety-net", ruleId: meta.axis.slice("net:".length) || "unknown" } : { kind: "autonomy", level: meta.axis.slice("autonomy:".length) || DEFAULT_AUTONOMY_LEVEL },
3210
+ origin: { kind: "main" },
3211
+ ...call.tool === ToolNames.AskUser ? { exposure: askUserExposure(call.args) } : {}
3212
+ })
3213
+ );
3214
+ const approveAction = presentation.requiredActions.find((action) => action.id === "approve-once");
3215
+ const denyAction = presentation.requiredActions.find((action) => action.id === "deny");
3164
3216
  queuedRequestIds.add(meta.requestId);
3165
3217
  queuedRequestDetails.set(meta.requestId, {
3166
3218
  tool: call.tool,
@@ -3250,8 +3302,16 @@ function installPermissionBridge(input) {
3250
3302
  ...snapshot.locations !== void 0 ? { locations: snapshot.locations } : {}
3251
3303
  },
3252
3304
  options: [
3253
- { optionId: "allow-once", name: "Allow once", kind: "allow_once" },
3254
- { optionId: "reject-once", name: "Reject", kind: "reject_once" }
3305
+ {
3306
+ optionId: "allow-once",
3307
+ name: approveAction?.label ?? "Approve once",
3308
+ kind: "allow_once"
3309
+ },
3310
+ {
3311
+ optionId: "reject-once",
3312
+ name: denyAction?.label ?? "Deny this request",
3313
+ kind: "reject_once"
3314
+ }
3255
3315
  ]
3256
3316
  },
3257
3317
  input.permissionTimeoutMs
@@ -4118,17 +4178,17 @@ function resultText(result) {
4118
4178
  function extractToolResultPayload(payload) {
4119
4179
  const obj = isRecord4(payload) ? payload : { result: payload };
4120
4180
  const result = obj.result ?? obj.output ?? obj.out ?? obj.content ?? payload;
4121
- const toolName2 = typeof obj.toolName === "string" && obj.toolName || typeof obj.name === "string" && obj.name || typeof obj.tool === "string" && obj.tool || "tool";
4122
- return { obj, result, toolName: toolName2 };
4181
+ const toolName = typeof obj.toolName === "string" && obj.toolName || typeof obj.name === "string" && obj.name || typeof obj.tool === "string" && obj.tool || "tool";
4182
+ return { obj, result, toolName };
4123
4183
  }
4124
4184
  function lineCount(text) {
4125
4185
  if (text.length === 0) return 0;
4126
4186
  return text.split(/\r\n|\r|\n/).length;
4127
4187
  }
4128
- function observationMarker(toolName2, text) {
4188
+ function observationMarker(toolName, text) {
4129
4189
  const preview = text.trim().replace(/\s+/g, " ").slice(0, 160);
4130
4190
  const suffix = preview.length > 0 ? ` Preview: ${preview}` : "";
4131
- return `[Observation masked: ${toolName2} output was ${lineCount(text)} lines, ${text.length} chars - contents masked to save context. Re-run the tool for current content.]${suffix}`;
4191
+ return `[Observation masked: ${toolName} output was ${lineCount(text)} lines, ${text.length} chars - contents masked to save context. Re-run the tool for current content.]${suffix}`;
4132
4192
  }
4133
4193
  function maskedToolResult(original, marker) {
4134
4194
  const details = isRecord4(original) && isRecord4(original.details) ? { ...original.details } : {};
@@ -4151,9 +4211,9 @@ function alreadyCompacted(payload) {
4151
4211
  }
4152
4212
  function maskObservation(entry) {
4153
4213
  const next = cloneEntry(entry);
4154
- const { obj, result, toolName: toolName2 } = extractToolResultPayload(next.payload);
4214
+ const { obj, result, toolName } = extractToolResultPayload(next.payload);
4155
4215
  const text = resultText(result);
4156
- const marker = observationMarker(toolName2, text);
4216
+ const marker = observationMarker(toolName, text);
4157
4217
  next.payload = {
4158
4218
  ...obj,
4159
4219
  result: maskedToolResult(result, marker),
@@ -4355,6 +4415,7 @@ init_esm_shims();
4355
4415
 
4356
4416
  // src/interactive/chat-renderer.ts
4357
4417
  init_esm_shims();
4418
+ import { existsSync as existsSync6 } from "node:fs";
4358
4419
 
4359
4420
  // src/engine/messages.ts
4360
4421
  init_esm_shims();
@@ -4683,39 +4744,6 @@ function truncate2(value, limit) {
4683
4744
  function isPlainObject(value) {
4684
4745
  return value !== null && typeof value === "object" && !Array.isArray(value);
4685
4746
  }
4686
- var SECRET_KEY_RE = /(?:api[-_]?key|access[-_]?key|auth(?:orization)?|credential|password|private[-_]?key|secret|token)/iu;
4687
- var ENV_KEY_RE = /^env(?:ironment)?$/iu;
4688
- var SECRET_STRING_RE = /(https?:\/\/[^\s/@]+:)[^\s/@]+@/giu;
4689
- var SECRET_URL_PARAM_RE = /([?&](?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[^=\s]*=)[^&#\s]+/giu;
4690
- var SECRET_ASSIGNMENT_RE = /(?<![A-Z0-9_])((?:[A-Z0-9_]*(?:ACCESS|API|AUTH|CREDENTIAL|KEY|PASS(?:WORD)?|PRIVATE|SECRET|TOKEN)[A-Z0-9_]*)=)[^\s;&|]+/giu;
4691
- var SECRET_FLAG_RE = /(--?(?:[a-z0-9-]*(?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[a-z0-9-]*))(=|\s+)([^\s;&|]+)/giu;
4692
- function redactSecretString(value) {
4693
- return value.replace(SECRET_STRING_RE, "$1[redacted]@").replace(SECRET_URL_PARAM_RE, "$1[redacted]").replace(SECRET_ASSIGNMENT_RE, "$1[redacted]").replace(SECRET_FLAG_RE, "$1$2[redacted]");
4694
- }
4695
- function redactEnvironmentValue(value, depth) {
4696
- if (depth > 8) return "[redacted nested values]";
4697
- if (typeof value === "string") return "[redacted]";
4698
- if (Array.isArray(value)) return value.map((item) => redactEnvironmentValue(item, depth + 1));
4699
- if (!isPlainObject(value)) return value;
4700
- const out = {};
4701
- for (const [childKey, childValue] of Object.entries(value)) {
4702
- out[childKey] = redactEnvironmentValue(childValue, depth + 1);
4703
- }
4704
- return out;
4705
- }
4706
- function redactToolArgs(value, key = "", depth = 0) {
4707
- if (SECRET_KEY_RE.test(key)) return "[redacted]";
4708
- if (ENV_KEY_RE.test(key)) return redactEnvironmentValue(value, depth);
4709
- if (typeof value === "string") return redactSecretString(value);
4710
- if (depth > 8) return "[redacted nested values]";
4711
- if (Array.isArray(value)) return value.map((item) => redactToolArgs(item, key, depth + 1));
4712
- if (!isPlainObject(value)) return value;
4713
- const out = {};
4714
- for (const [childKey, childValue] of Object.entries(value)) {
4715
- out[childKey] = redactToolArgs(childValue, childKey, depth + 1);
4716
- }
4717
- return out;
4718
- }
4719
4747
  function readStringField(args, key) {
4720
4748
  if (!isPlainObject(args)) return null;
4721
4749
  const value = args[key];
@@ -4749,8 +4777,8 @@ function stripShellWrapperForDisplay(command) {
4749
4777
  if (!match?.[1]) return command;
4750
4778
  return unquoteShellScript(match[1]);
4751
4779
  }
4752
- function displayArg(toolName2, value) {
4753
- return toolName2 === "bash" ? stripShellWrapperForDisplay(value) : value;
4780
+ function displayArg(toolName, value) {
4781
+ return toolName === "bash" ? stripShellWrapperForDisplay(value) : value;
4754
4782
  }
4755
4783
  function optionalCompactMs(durationMs) {
4756
4784
  if (durationMs === void 0 || !Number.isFinite(durationMs) || durationMs < 0) return null;
@@ -4780,8 +4808,8 @@ var PRIMARY_ARG_FIELD = {
4780
4808
  steer: "run_id",
4781
4809
  tasks: "action"
4782
4810
  };
4783
- function capturedPrimaryArg(toolName2, args) {
4784
- const field2 = PRIMARY_ARG_FIELD[toolName2];
4811
+ function capturedPrimaryArg(toolName, args) {
4812
+ const field2 = PRIMARY_ARG_FIELD[toolName];
4785
4813
  if (field2 === void 0) return null;
4786
4814
  return readStringField(args, field2);
4787
4815
  }
@@ -4793,12 +4821,12 @@ function summarizeWebFetchArgs(args) {
4793
4821
  }
4794
4822
  return truncate2(jsonStringifySafe(Object.keys(compact2).length > 0 ? compact2 : args), WEB_FETCH_ARG_PREVIEW_LIMIT);
4795
4823
  }
4796
- function summarizeArgs(toolName2, args) {
4824
+ function summarizeArgs(toolName, args) {
4797
4825
  if (isEmptyArgs(args)) return "";
4798
4826
  const safeArgs = redactToolArgs(args);
4799
- if (toolName2 === "web_fetch") return summarizeWebFetchArgs(safeArgs);
4800
- const primary = capturedPrimaryArg(toolName2, args);
4801
- if (primary !== null) return truncate2(displayArg(toolName2, primary), ARG_PREVIEW_LIMIT);
4827
+ if (toolName === "web_fetch") return summarizeWebFetchArgs(safeArgs);
4828
+ const primary = capturedPrimaryArg(toolName, args);
4829
+ if (primary !== null) return truncate2(displayArg(toolName, primary), ARG_PREVIEW_LIMIT);
4802
4830
  return truncate2(jsonStringifySafe(safeArgs), ARG_PREVIEW_LIMIT);
4803
4831
  }
4804
4832
  function detailsOf(result) {
@@ -4879,6 +4907,9 @@ function offloadPathOf(finished) {
4879
4907
  const resultSize = detailsOf(finished.result)?.resultSize;
4880
4908
  return isPlainObject(resultSize) ? stringField(resultSize, "offloadPath") : null;
4881
4909
  }
4910
+ function offloadFileMissing(finished) {
4911
+ return finished.resultSummary?.offloadFileMissing === true;
4912
+ }
4882
4913
  function shownBytesOf(finished) {
4883
4914
  const observation = observationOf(finished);
4884
4915
  const fromObservation = numberField(observation, "shownBytes");
@@ -4944,7 +4975,7 @@ function ledgerTail(finished) {
4944
4975
  const offloadPath = executed ? offloadPathOf(finished) : null;
4945
4976
  return {
4946
4977
  facts: parts.length > 0 ? dim(` \xB7 ${parts.join(" \xB7 ")}`) : "",
4947
- offload: offloadPath !== null ? dim(` \xB7 full: ${offloadPath}`) : ""
4978
+ offload: offloadPath === null ? "" : offloadFileMissing(finished) ? dim(" \xB7 full: gone after the 14-day retention sweep") : dim(` \xB7 full: ${offloadPath}`)
4948
4979
  };
4949
4980
  }
4950
4981
  var FAILURE_EXCERPT_LIMIT = 80;
@@ -4997,8 +5028,8 @@ function statusGlyph(status, meta = {}) {
4997
5028
  const reasonSuffix = reason ? dim(` \xB7 ${truncate2(reason, BLOCK_REASON_LIMIT)}`) : "";
4998
5029
  return ` ${red(STATUS_ERROR_GLYPH)}${outcomeSuffix}${reasonSuffix}${exitSuffix}${durationSuffix}`;
4999
5030
  }
5000
- function headerLine(toolName2, args, status, meta = {}) {
5001
- const body = styleSublineBody(buildSublineBody(toolName2, args, status, void 0, meta.outcome));
5031
+ function headerLine(toolName, args, status, meta = {}) {
5032
+ const body = styleSublineBody(buildSublineBody(toolName, args, status, void 0, meta.outcome));
5002
5033
  const head = `${dim(HEADER_PREFIX_PLAIN)}${body}`;
5003
5034
  return `${head}${statusGlyph(status, meta)}`;
5004
5035
  }
@@ -5010,8 +5041,8 @@ function styleSublineBody(body) {
5010
5041
  if (match?.groups?.lead === void 0 || match.groups.rest === void 0) return body;
5011
5042
  return sublineLead(match.groups.lead, match.groups.rest);
5012
5043
  }
5013
- function buildGenericToolBody(toolName2, args) {
5014
- const summary = summarizeArgs(toolName2, args);
5044
+ function buildGenericToolBody(toolName, args) {
5045
+ const summary = summarizeArgs(toolName, args);
5015
5046
  return summary.length > 0 ? `tool action ${summary}` : "tool action";
5016
5047
  }
5017
5048
  function buildFieldSublineBody(args, key, lead, options = {}) {
@@ -5103,25 +5134,25 @@ function webFetchMeta(result) {
5103
5134
  function isNonExecutedOutcome(outcome) {
5104
5135
  return outcome === "blocked";
5105
5136
  }
5106
- function buildSublineBody(toolName2, args, status, result, outcome) {
5137
+ function buildSublineBody(toolName, args, status, result, outcome) {
5107
5138
  if (isNonExecutedOutcome(outcome)) {
5108
- if (toolName2 === "bash") {
5109
- return buildFieldSublineBody(args, "command", "command ", { wrapInBackticks: true }) ?? buildGenericToolBody(toolName2, args);
5139
+ if (toolName === "bash") {
5140
+ return buildFieldSublineBody(args, "command", "command ", { wrapInBackticks: true }) ?? buildGenericToolBody(toolName, args);
5110
5141
  }
5111
- return SUBLINE_BODY_BUILDERS[toolName2]?.(args) ?? buildGenericToolBody(toolName2, args);
5142
+ return SUBLINE_BODY_BUILDERS[toolName]?.(args) ?? buildGenericToolBody(toolName, args);
5112
5143
  }
5113
- if (toolName2 === "web_fetch") {
5144
+ if (toolName === "web_fetch") {
5114
5145
  const meta = status === void 0 ? null : webFetchMeta(result);
5115
- const body2 = SUBLINE_BODY_BUILDERS.web_fetch?.(args) ?? buildGenericToolBody(toolName2, args);
5146
+ const body2 = SUBLINE_BODY_BUILDERS.web_fetch?.(args) ?? buildGenericToolBody(toolName, args);
5116
5147
  return `${body2}${meta ? dim(` \xB7 ${meta}`) : ""}`;
5117
5148
  }
5118
- if (toolName2 === "bash") {
5149
+ if (toolName === "bash") {
5119
5150
  const lead = status === "ok" || status === "error" ? "ran " : "running ";
5120
- return buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ?? buildGenericToolBody(toolName2, args);
5151
+ return buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ?? buildGenericToolBody(toolName, args);
5121
5152
  }
5122
- const body = SUBLINE_BODY_BUILDERS[toolName2]?.(args);
5153
+ const body = SUBLINE_BODY_BUILDERS[toolName]?.(args);
5123
5154
  if (body !== null && body !== void 0) return body;
5124
- return buildGenericToolBody(toolName2, args);
5155
+ return buildGenericToolBody(toolName, args);
5125
5156
  }
5126
5157
  function sublineParts(call, status, meta) {
5127
5158
  const finished = "result" in call ? call : null;
@@ -5172,7 +5203,7 @@ function scalarArgValue(value) {
5172
5203
  if (value === null) return dim("null");
5173
5204
  return null;
5174
5205
  }
5175
- function renderArgsBody(toolName2, args, width, isError) {
5206
+ function renderArgsBody(toolName, args, width, isError) {
5176
5207
  if (isEmptyArgs(args)) return [];
5177
5208
  const safeArgs = redactToolArgs(args);
5178
5209
  if (!isPlainObject(safeArgs)) {
@@ -5180,7 +5211,7 @@ function renderArgsBody(toolName2, args, width, isError) {
5180
5211
  const lines = tryRenderJson(safeArgs, bodyWidth2, { lineLimit: ARGS_BODY_LINE_LIMIT });
5181
5212
  return lines?.flatMap((line) => indentAndWrap(line, width, isError)) ?? [];
5182
5213
  }
5183
- const primary = PRIMARY_ARG_FIELD[toolName2];
5214
+ const primary = PRIMARY_ARG_FIELD[toolName];
5184
5215
  const entries = Object.entries(safeArgs).filter(([key]) => key !== primary);
5185
5216
  if (entries.length === 0) return [];
5186
5217
  const out = [];
@@ -5352,7 +5383,10 @@ function renderOutputMeta(finished, width, isError, label = "output") {
5352
5383
  function renderOutputFooter(finished, width, isError) {
5353
5384
  const out = [];
5354
5385
  const offloadPath = isNonExecutedOutcome(finished.outcome) ? null : offloadPathOf(finished);
5355
- if (offloadPath !== null) out.push(...indentAndWrap(`${yellow("full output")} ${offloadPath}`, width, isError));
5386
+ if (offloadPath !== null) {
5387
+ const pointer = offloadFileMissing(finished) ? "gone after the 14-day retention sweep" : offloadPath;
5388
+ out.push(...indentAndWrap(`${yellow("full output")} ${pointer}`, width, isError));
5389
+ }
5356
5390
  const hint = stringField(resultSizeOf(finished), "followUpHint") ?? stringField(finished.resultSummary ?? null, "followUpHint");
5357
5391
  if (hint !== null) out.push(...indentAndWrap(`${dim("next")} ${hint}`, width, isError));
5358
5392
  return out;
@@ -6393,6 +6427,267 @@ function buildSegmentedContextBar(theme6, barWidth, contextWindow, breakdown) {
6393
6427
  return `${systemPart}${toolPart}${conversationPart}${freePart}${contextPercentLabel(percent)}`;
6394
6428
  }
6395
6429
 
6430
+ // src/interactive/worker-progress.ts
6431
+ init_esm_shims();
6432
+ var WORKER_LIVE_TAIL_LINES = 40;
6433
+ var WORKER_LIVE_TAIL_MAX_BYTES = 4096;
6434
+ var WORKER_TOOL_NAME_LIMIT = 8;
6435
+ var WORKER_ACTION_TRAIL_LIMIT = 4;
6436
+ var WORKER_PROGRESS_WINDOW_MS = 250;
6437
+ var WORKER_PROGRESS_WINDOW_BYTES = 16384;
6438
+ var TAIL_TRUNCATION_MARKER = "";
6439
+ function isRecord7(value) {
6440
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6441
+ }
6442
+ function nonEmptyString(value) {
6443
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
6444
+ }
6445
+ function workerTextDelta(event) {
6446
+ if (!isRecord7(event)) return "";
6447
+ if (event.type === "message_update") {
6448
+ const assistantEvent = isRecord7(event.assistantMessageEvent) ? event.assistantMessageEvent : null;
6449
+ if (assistantEvent?.type !== "text_delta") return "";
6450
+ return typeof assistantEvent.delta === "string" ? assistantEvent.delta : "";
6451
+ }
6452
+ if (event.type !== "text_delta") return "";
6453
+ if (typeof event.delta === "string") return event.delta;
6454
+ return typeof event.text === "string" ? event.text : "";
6455
+ }
6456
+ function isThinkingEvent(event) {
6457
+ if (event.type === "thinking_delta") return true;
6458
+ if (event.type !== "message_update") return false;
6459
+ const assistantEvent = isRecord7(event.assistantMessageEvent) ? event.assistantMessageEvent : null;
6460
+ return assistantEvent?.type === "thinking_delta";
6461
+ }
6462
+ function toolEventAction(event) {
6463
+ if (event.type !== "clio_tool_start" && event.type !== "clio_tool_finish") return null;
6464
+ const payload = isRecord7(event.payload) ? event.payload : null;
6465
+ const tool = nonEmptyString(payload?.tool);
6466
+ if (tool === void 0) return null;
6467
+ const toolCallId = nonEmptyString(payload?.toolCallId);
6468
+ const raw = isRecord7(payload?.action) ? payload.action : void 0;
6469
+ const verb = nonEmptyString(raw?.verb);
6470
+ if (verb === void 0) return { tool, ...toolCallId !== void 0 ? { toolCallId } : {} };
6471
+ const object = nonEmptyString(raw?.object);
6472
+ return {
6473
+ tool,
6474
+ ...toolCallId !== void 0 ? { toolCallId } : {},
6475
+ descriptor: {
6476
+ verb,
6477
+ ...object !== void 0 ? { object } : {},
6478
+ ...raw?.truncated === true ? { truncated: true } : {}
6479
+ }
6480
+ };
6481
+ }
6482
+ function lineCount2(text) {
6483
+ if (text.length === 0) return 0;
6484
+ let lines = 1;
6485
+ for (let index = 0; index < text.length; index += 1) {
6486
+ if (text[index] === "\n") lines += 1;
6487
+ }
6488
+ return lines;
6489
+ }
6490
+ function keepTailBytes(text, maxBytes) {
6491
+ const buffer = Buffer.from(text, "utf8");
6492
+ if (buffer.byteLength <= maxBytes) return text;
6493
+ let cut = buffer.byteLength - maxBytes;
6494
+ while (cut < buffer.byteLength) {
6495
+ const byte = buffer[cut];
6496
+ if (byte === void 0 || (byte & 192) !== 128) break;
6497
+ cut += 1;
6498
+ }
6499
+ return buffer.subarray(cut).toString("utf8");
6500
+ }
6501
+ function boundLiveTail(text) {
6502
+ const lines = text.split("\n");
6503
+ let droppedLines = 0;
6504
+ if (lines.length > WORKER_LIVE_TAIL_LINES) {
6505
+ droppedLines = lines.length - WORKER_LIVE_TAIL_LINES;
6506
+ lines.splice(0, droppedLines);
6507
+ }
6508
+ while (lines.length > 1 && Buffer.byteLength(lines.join("\n"), "utf8") > WORKER_LIVE_TAIL_MAX_BYTES) {
6509
+ lines.shift();
6510
+ droppedLines += 1;
6511
+ }
6512
+ const joined = lines.join("\n");
6513
+ const bytes = Buffer.byteLength(joined, "utf8");
6514
+ if (bytes <= WORKER_LIVE_TAIL_MAX_BYTES) return { text: joined, droppedLines, droppedBytes: 0 };
6515
+ const kept = keepTailBytes(joined, WORKER_LIVE_TAIL_MAX_BYTES);
6516
+ return { text: kept, droppedLines, droppedBytes: bytes - Buffer.byteLength(kept, "utf8") };
6517
+ }
6518
+ function boundSettledText(text) {
6519
+ const bounded = truncateUtf8(text, WORKER_OUTPUT_MAX_BYTES, TAIL_TRUNCATION_MARKER);
6520
+ if (bounded === text) return { text, dropped: 0 };
6521
+ return { text: bounded, dropped: Math.max(0, lineCount2(text) - lineCount2(bounded)) };
6522
+ }
6523
+ var EMPTY_SNAPSHOT = {
6524
+ revision: 0,
6525
+ phase: "starting",
6526
+ tailText: "",
6527
+ droppedLines: 0,
6528
+ droppedBytes: 0,
6529
+ currentAction: null,
6530
+ recentActions: [],
6531
+ toolNames: [],
6532
+ settled: false
6533
+ };
6534
+ function createWorkerProgressFold() {
6535
+ let revision = 0;
6536
+ let phase = "starting";
6537
+ let tailText = "";
6538
+ let droppedLines = 0;
6539
+ let droppedBytes = 0;
6540
+ let currentAction = null;
6541
+ const recentActions = [];
6542
+ const toolNames = [];
6543
+ let settled = false;
6544
+ let durable = "";
6545
+ const pendingActions = [];
6546
+ const pendingActionsById = /* @__PURE__ */ new Map();
6547
+ let windowStartMs = 0;
6548
+ let windowBytes = 0;
6549
+ let cached = EMPTY_SNAPSHOT;
6550
+ const touch = () => {
6551
+ revision += 1;
6552
+ cached = null;
6553
+ return true;
6554
+ };
6555
+ const setPhase = (next) => {
6556
+ if (phase === next) return false;
6557
+ phase = next;
6558
+ return touch();
6559
+ };
6560
+ const admitDelta = (delta, nowMs) => {
6561
+ if (nowMs - windowStartMs >= WORKER_PROGRESS_WINDOW_MS) {
6562
+ windowStartMs = nowMs;
6563
+ windowBytes = 0;
6564
+ }
6565
+ const bytes = Buffer.byteLength(delta, "utf8");
6566
+ if (windowBytes + bytes <= WORKER_PROGRESS_WINDOW_BYTES) {
6567
+ windowBytes += bytes;
6568
+ return delta;
6569
+ }
6570
+ windowBytes = WORKER_PROGRESS_WINDOW_BYTES;
6571
+ droppedBytes += bytes;
6572
+ return "";
6573
+ };
6574
+ const appendTail = (text) => {
6575
+ if (text.length === 0) return false;
6576
+ const bounded = boundLiveTail(tailText + text);
6577
+ tailText = bounded.text;
6578
+ droppedLines += bounded.droppedLines;
6579
+ droppedBytes += bounded.droppedBytes;
6580
+ return touch();
6581
+ };
6582
+ const noteToolName = (tool) => {
6583
+ if (toolNames.includes(tool) || toolNames.length >= WORKER_TOOL_NAME_LIMIT) return false;
6584
+ toolNames.push(tool);
6585
+ return touch();
6586
+ };
6587
+ const removePendingAction = (action) => {
6588
+ const index = pendingActions.lastIndexOf(action);
6589
+ if (index >= 0) pendingActions.splice(index, 1);
6590
+ if (action.toolCallId !== void 0 && pendingActionsById.get(action.toolCallId) === action) {
6591
+ pendingActionsById.delete(action.toolCallId);
6592
+ }
6593
+ };
6594
+ const lastPendingActionForTool = (tool) => {
6595
+ for (let index = pendingActions.length - 1; index >= 0; index -= 1) {
6596
+ const candidate = pendingActions[index];
6597
+ if (candidate?.tool === tool) return candidate;
6598
+ }
6599
+ return void 0;
6600
+ };
6601
+ return {
6602
+ observe(event, nowMs = Date.now()) {
6603
+ if (!isRecord7(event) || settled) return false;
6604
+ let changed = false;
6605
+ const delta = workerTextDelta(event);
6606
+ if (delta.length > 0) {
6607
+ changed = appendTail(admitDelta(delta, nowMs)) || changed;
6608
+ changed = setPhase("writing") || changed;
6609
+ } else if (isThinkingEvent(event)) {
6610
+ changed = setPhase("thinking") || changed;
6611
+ }
6612
+ const durableText = durableAssistantTextFromEvent(event);
6613
+ if (durableText.trim().length > 0) {
6614
+ durable = durableText;
6615
+ if (delta.length === 0 && tailText.trim().length === 0) {
6616
+ changed = appendTail(durableText) || changed;
6617
+ }
6618
+ }
6619
+ const action = toolEventAction(event);
6620
+ if (action !== null && event.type === "clio_tool_start") {
6621
+ if (action.toolCallId !== void 0) {
6622
+ const duplicate = pendingActionsById.get(action.toolCallId);
6623
+ if (duplicate !== void 0) removePendingAction(duplicate);
6624
+ pendingActionsById.set(action.toolCallId, action);
6625
+ }
6626
+ pendingActions.push(action);
6627
+ currentAction = action;
6628
+ noteToolName(action.tool);
6629
+ touch();
6630
+ setPhase("tool");
6631
+ changed = true;
6632
+ } else if (action !== null && event.type === "clio_tool_finish") {
6633
+ const finished = (action.toolCallId !== void 0 ? pendingActionsById.get(action.toolCallId) : void 0) ?? lastPendingActionForTool(action.tool) ?? action;
6634
+ removePendingAction(finished);
6635
+ currentAction = pendingActions[pendingActions.length - 1] ?? null;
6636
+ recentActions.unshift(finished);
6637
+ if (recentActions.length > WORKER_ACTION_TRAIL_LIMIT) recentActions.length = WORKER_ACTION_TRAIL_LIMIT;
6638
+ noteToolName(finished.tool);
6639
+ touch();
6640
+ setPhase(currentAction === null ? "waiting" : "tool");
6641
+ changed = true;
6642
+ }
6643
+ if (event.type === "agent_start") changed = setPhase("starting") || changed;
6644
+ return changed;
6645
+ },
6646
+ settle(text) {
6647
+ const sealed = nonEmptyString(text) ?? nonEmptyString(durable);
6648
+ if (sealed !== void 0) {
6649
+ const bounded = boundSettledText(sealed);
6650
+ tailText = bounded.text;
6651
+ droppedLines = bounded.dropped;
6652
+ }
6653
+ currentAction = null;
6654
+ pendingActions.length = 0;
6655
+ pendingActionsById.clear();
6656
+ settled = true;
6657
+ phase = "settled";
6658
+ touch();
6659
+ return true;
6660
+ },
6661
+ restart() {
6662
+ currentAction = null;
6663
+ pendingActions.length = 0;
6664
+ pendingActionsById.clear();
6665
+ durable = "";
6666
+ settled = false;
6667
+ phase = "starting";
6668
+ touch();
6669
+ },
6670
+ snapshot() {
6671
+ if (cached !== null) return cached;
6672
+ cached = {
6673
+ revision,
6674
+ phase,
6675
+ tailText,
6676
+ droppedLines,
6677
+ droppedBytes,
6678
+ currentAction: currentAction === null ? null : { ...currentAction },
6679
+ recentActions: recentActions.map((entry) => ({ ...entry })),
6680
+ toolNames: [...toolNames],
6681
+ settled
6682
+ };
6683
+ return cached;
6684
+ },
6685
+ durableText() {
6686
+ return durable;
6687
+ }
6688
+ };
6689
+ }
6690
+
6396
6691
  // src/interactive/dispatch-board.ts
6397
6692
  function isDispatchBoardRowSteerable(row2) {
6398
6693
  return runKindSupportsLiveSteering(row2.runtimeKind) && (row2.status === "running" || row2.status === "stale" || row2.status === "enqueued");
@@ -6400,8 +6695,8 @@ function isDispatchBoardRowSteerable(row2) {
6400
6695
  function isDispatchBoardRowCancellable(row2) {
6401
6696
  return row2.status === "running" || row2.status === "stale" || row2.status === "enqueued" || row2.status === "retrying";
6402
6697
  }
6403
- var RECENT_TOOL_TRAIL_LIMIT = 4;
6404
6698
  var TASK_SUMMARY_MAX_WIDTH = 240;
6699
+ var WORKER_PROGRESS_CARD_ROWS = 6;
6405
6700
  var TASK_ISLAND_WIDTH = 44;
6406
6701
  var STATUS_ORDER = {
6407
6702
  running: 0,
@@ -6526,6 +6821,61 @@ function retryCountdown(retry, now = Date.now()) {
6526
6821
  const remainingMs = Math.max(0, retry.dueAtMs - now);
6527
6822
  return remainingMs === 0 ? "now" : `in ${formatCompactMs(remainingMs)}`;
6528
6823
  }
6824
+ function actionPhrase(action) {
6825
+ const descriptor = action.descriptor;
6826
+ if (descriptor === void 0) return action.tool;
6827
+ const object = descriptor.object === void 0 ? "" : ` ${descriptor.object}${descriptor.truncated ? "\u2026" : ""}`;
6828
+ return `${action.tool} ${descriptor.verb}${object}`;
6829
+ }
6830
+ function progressPhaseUnit(theme6, progress) {
6831
+ switch (progress.phase) {
6832
+ case "thinking":
6833
+ return theme6.fg("reason", `${GLYPH.phaseThinking} thinking`);
6834
+ case "writing":
6835
+ return theme6.fg("accent", `${GLYPH.phaseWriting} writing`);
6836
+ case "tool":
6837
+ return theme6.fg("action", `${GLYPH.phaseTool} tool`);
6838
+ case "waiting":
6839
+ return theme6.fg("info", `${GLYPH.phaseWaiting} waiting`);
6840
+ case "settled":
6841
+ case "starting":
6842
+ return null;
6843
+ }
6844
+ }
6845
+ function progressActionLine(theme6, progress, contentWidth) {
6846
+ const phase = progressPhaseUnit(theme6, progress);
6847
+ const current = progress.currentAction;
6848
+ const recent = progress.recentActions[0];
6849
+ const units = [];
6850
+ if (phase !== null) units.push(phase);
6851
+ if (current !== null) units.push(theme6.fg("muted", actionPhrase(current)));
6852
+ else if (recent !== void 0) units.push(theme6.fg("dim", `last ${actionPhrase(recent)}`));
6853
+ if (units.length === 0) return null;
6854
+ return cardUnitsLine(theme6, "doing", units, contentWidth);
6855
+ }
6856
+ function progressAnswerLines(theme6, progress, runId, contentWidth) {
6857
+ if (progress.tailText.length === 0) return [];
6858
+ const gutter = CARD_KV_KEY_WIDTH + 1;
6859
+ const railWidth = Math.max(1, contentWidth - gutter - 2);
6860
+ const wrapped = [];
6861
+ for (const line of progress.tailText.split("\n")) {
6862
+ for (const row2 of wrapTextWithAnsi(sanitizeCallTargetText(line), railWidth)) wrapped.push(row2);
6863
+ }
6864
+ const shown = wrapped.slice(Math.max(0, wrapped.length - WORKER_PROGRESS_CARD_ROWS));
6865
+ const hiddenRows = wrapped.length - shown.length;
6866
+ const rail = theme6.fg("dim", `${GLYPH.rail} `);
6867
+ const body = shown.map((row2) => `${rail}${theme6.fg("muted", row2)}`);
6868
+ const hiddenLines = progress.droppedLines + hiddenRows;
6869
+ if (hiddenLines > 0 || progress.droppedBytes > 0) {
6870
+ const facts = [
6871
+ ...hiddenLines > 0 ? [`${hiddenLines} more line${hiddenLines === 1 ? "" : "s"}`] : [],
6872
+ ...progress.droppedBytes > 0 ? [`${progress.droppedBytes} bytes outran the view`] : [],
6873
+ `/view dispatch:${runId}`
6874
+ ];
6875
+ body.push(`${rail}${theme6.fg("dim", truncateToWidth(facts.join(" \xB7 "), railWidth, "\u2026", false))}`);
6876
+ }
6877
+ return body.map((row2, index) => `${index === 0 ? cardKvKey(theme6, "answer") : " ".repeat(gutter)}${row2}`);
6878
+ }
6529
6879
  function renderDispatchCard(row2, width, evidence, options = {}) {
6530
6880
  const theme6 = clioTheme();
6531
6881
  const contentWidth = Math.max(0, width - 4);
@@ -6569,6 +6919,20 @@ function renderDispatchCard(row2, width, evidence, options = {}) {
6569
6919
  targetLine,
6570
6920
  ...row2.taskSummary ? [truncateToWidth(`${cardKvKey(theme6, "task")}${theme6.fg("muted", row2.taskSummary)}`, contentWidth, "\u2026", false)] : [],
6571
6921
  cardUnitsLine(theme6, "status", statusUnits, contentWidth),
6922
+ ...row2.budget !== void 0 ? [
6923
+ truncateToWidth(
6924
+ `${cardKvKey(theme6, "policy")}${theme6.fg("muted", `${formatBudgetPolicy(row2.budget)}; requested ${formatBudgetRequest(row2.budget)}`)}`,
6925
+ contentWidth,
6926
+ "\u2026",
6927
+ false
6928
+ ),
6929
+ truncateToWidth(
6930
+ `${cardKvKey(theme6, "budget")}${theme6.fg("muted", `${formatEffectiveBudget(row2.budget)}; reason ${formatBudgetReasons(row2.budget)}`)}`,
6931
+ contentWidth,
6932
+ "\u2026",
6933
+ false
6934
+ )
6935
+ ] : [],
6572
6936
  cardUnitsLine(theme6, "telemetry", [up, down, total, ...contextUnit !== null ? [contextUnit] : []], contentWidth)
6573
6937
  ];
6574
6938
  if (row2.retry) {
@@ -6594,6 +6958,11 @@ function renderDispatchCard(row2, width, evidence, options = {}) {
6594
6958
  ];
6595
6959
  bodyLines2.push(cardUnitsLine(theme6, "tools", toolUnits, contentWidth));
6596
6960
  }
6961
+ if (options.expanded === true && row2.progress) {
6962
+ const doing = progressActionLine(theme6, row2.progress, contentWidth);
6963
+ if (doing !== null) bodyLines2.push(doing);
6964
+ bodyLines2.push(...progressAnswerLines(theme6, row2.progress, row2.runId, contentWidth));
6965
+ }
6597
6966
  if (row2.steerAcknowledgement) {
6598
6967
  bodyLines2.push(
6599
6968
  cardUnitsLine(
@@ -6639,7 +7008,7 @@ function renderTaskIslandRow(row2, width) {
6639
7008
  const task = row2.taskSummary ? ` ${theme6.fg("muted", truncateToWidth(row2.taskSummary, Math.max(1, width - 2), "\u2026", false))}` : null;
6640
7009
  return [padAnsi(line1, width), ...task ? [padAnsi(task, width)] : [], padAnsi(telemetry, width)];
6641
7010
  }
6642
- function formatDispatchBoardLines(rows, width = 76, observability, selectedRunId) {
7011
+ function formatDispatchBoardLines(rows, width = 76, observability, selectedRunId, detailExpanded = false) {
6643
7012
  if (rows.length === 0) {
6644
7013
  const theme6 = clioTheme();
6645
7014
  const lines = ["", "No fleet runs yet", "Delegated runs appear here with task, status, and telemetry.", ""];
@@ -6650,7 +7019,8 @@ function formatDispatchBoardLines(rows, width = 76, observability, selectedRunId
6650
7019
  }
6651
7020
  const cards = rows.map(
6652
7021
  (row2) => renderDispatchCard(row2, width, deriveRunEvidenceState(observability, row2.runId), {
6653
- selected: row2.runId === selectedRunId
7022
+ selected: row2.runId === selectedRunId,
7023
+ expanded: detailExpanded && row2.runId === selectedRunId
6654
7024
  })
6655
7025
  );
6656
7026
  const body = [];
@@ -6662,6 +7032,7 @@ function formatDispatchBoardLines(rows, width = 76, observability, selectedRunId
6662
7032
  }
6663
7033
  function createDispatchBoardView(rows, observability) {
6664
7034
  let selectedRunId = null;
7035
+ let expanded = false;
6665
7036
  const normalizeSelection = (currentRows) => {
6666
7037
  if (currentRows.length === 0) {
6667
7038
  selectedRunId = null;
@@ -6683,7 +7054,7 @@ function createDispatchBoardView(rows, observability) {
6683
7054
  render(width) {
6684
7055
  const currentRows = rows();
6685
7056
  normalizeSelection(currentRows);
6686
- return formatDispatchBoardLines(currentRows, Math.max(1, width), observability(), selectedRunId);
7057
+ return formatDispatchBoardLines(currentRows, Math.max(1, width), observability(), selectedRunId, expanded);
6687
7058
  },
6688
7059
  selectedRow() {
6689
7060
  return normalizeSelection(rows());
@@ -6696,8 +7067,15 @@ function createDispatchBoardView(rows, observability) {
6696
7067
  },
6697
7068
  resetSelection() {
6698
7069
  selectedRunId = null;
7070
+ expanded = false;
6699
7071
  normalizeSelection(rows());
6700
7072
  },
7073
+ toggleDetail() {
7074
+ expanded = !expanded;
7075
+ },
7076
+ detailExpanded() {
7077
+ return expanded;
7078
+ },
6701
7079
  invalidate() {
6702
7080
  }
6703
7081
  };
@@ -6842,13 +7220,15 @@ function readRunningSnapshot(snapshot) {
6842
7220
  for (const value of snapshot.running) {
6843
7221
  const runId = parseRunId(value.runId);
6844
7222
  if (!runId) continue;
7223
+ const budget = cloneRunToolBudgetEnvelope(value.budget);
6845
7224
  running.set(runId, {
6846
7225
  inputTokens: parseFiniteNumberOrZero(value.tokens.input),
6847
7226
  outputTokens: parseFiniteNumberOrZero(value.tokens.output),
6848
7227
  tokenCount: parseFiniteNumberOrZero(value.tokens.total),
6849
7228
  costUsd: parseFiniteNumberOrZero(value.costUsd),
6850
7229
  costProvenance: value.costProvenance ?? "unknown",
6851
- outcomePhase: value.outcomePhase
7230
+ outcomePhase: value.outcomePhase,
7231
+ ...budget !== void 0 ? { budget } : {}
6852
7232
  });
6853
7233
  }
6854
7234
  } catch {
@@ -6863,7 +7243,9 @@ function resolveElapsedMs(entry, now) {
6863
7243
  }
6864
7244
  function toRow(entry, now) {
6865
7245
  const retry = entry.retry;
7246
+ const progress = entry.progress.snapshot();
6866
7247
  return {
7248
+ progress,
6867
7249
  runId: entry.runId,
6868
7250
  agentId: entry.agentId,
6869
7251
  ...entry.agentAudience !== void 0 ? { agentAudience: entry.agentAudience } : {},
@@ -6873,6 +7255,7 @@ function toRow(entry, now) {
6873
7255
  targetId: entry.targetId,
6874
7256
  wireModelId: entry.wireModelId,
6875
7257
  ...entry.taskSummary !== void 0 ? { taskSummary: entry.taskSummary } : {},
7258
+ ...entry.budget !== void 0 ? { budget: entry.budget } : {},
6876
7259
  status: retry ? "retrying" : entry.status,
6877
7260
  elapsedMs: resolveElapsedMs(entry, now),
6878
7261
  tokenCount: entry.tokenCount,
@@ -6889,8 +7272,10 @@ function toRow(entry, now) {
6889
7272
  ...entry.contextWindow !== void 0 ? { contextWindow: entry.contextWindow } : {},
6890
7273
  lastContextTokens: entry.lastContextTokens,
6891
7274
  ...entry.receiptId !== void 0 ? { receiptId: entry.receiptId } : {},
6892
- currentTool: retry ? null : entry.currentTool,
6893
- recentTools: [...entry.recentTools],
7275
+ // Both tool fields are views of the one projection, so the compact card and
7276
+ // the expanded detail can never disagree about what is running.
7277
+ currentTool: retry ? null : progress.currentAction?.tool ?? null,
7278
+ recentTools: progress.recentActions.map((action) => action.tool),
6894
7279
  ...retry ? { retry: { ...retry } } : {},
6895
7280
  ...entry.steerAcknowledgement ? { steerAcknowledgement: { ...entry.steerAcknowledgement } } : {}
6896
7281
  };
@@ -6914,10 +7299,14 @@ function pruneEntries(entries) {
6914
7299
  entries.delete(entry.runId);
6915
7300
  }
6916
7301
  }
6917
- function createDispatchBoardStore(bus, snapshot) {
7302
+ function createDispatchBoardStore(bus, snapshot, readReceipt) {
6918
7303
  const entries = /* @__PURE__ */ new Map();
6919
7304
  let nextSequence = 0;
6920
7305
  let reconciledAtMs = Date.now();
7306
+ const settleFromReceipt = (entry) => {
7307
+ const text = readReceipt?.(entry.runId)?.text;
7308
+ entry.progress.settle(typeof text === "string" && text.trim().length > 0 ? text : void 0);
7309
+ };
6921
7310
  const upsertBase = (raw, status, now) => {
6922
7311
  const runId = parseRunId(raw.runId);
6923
7312
  if (!runId) return null;
@@ -6929,6 +7318,7 @@ function createDispatchBoardStore(bus, snapshot) {
6929
7318
  const rerouteCount = parsePositiveInt(raw.rerouteCount) ?? previous?.rerouteCount;
6930
7319
  const contextWindow = parsePositiveInt(raw.contextWindow) ?? previous?.contextWindow;
6931
7320
  const taskSummary = parseTaskSummary(raw, previous?.taskSummary);
7321
+ const budget = cloneRunToolBudgetEnvelope(raw.budget) ?? previous?.budget;
6932
7322
  const entry = {
6933
7323
  runId,
6934
7324
  agentId: parseText(raw.agentId, previous?.agentId ?? "-"),
@@ -6939,6 +7329,7 @@ function createDispatchBoardStore(bus, snapshot) {
6939
7329
  targetId: parseText(raw.targetId, previous?.targetId ?? "-"),
6940
7330
  wireModelId: parseText(raw.wireModelId, previous?.wireModelId ?? "-"),
6941
7331
  ...taskSummary !== void 0 ? { taskSummary } : {},
7332
+ ...budget !== void 0 ? { budget } : {},
6942
7333
  status,
6943
7334
  tokenCount: previous?.tokenCount ?? 0,
6944
7335
  costUsd: previous?.costUsd ?? 0,
@@ -6959,8 +7350,7 @@ function createDispatchBoardStore(bus, snapshot) {
6959
7350
  ...contextWindow !== void 0 ? { contextWindow } : {},
6960
7351
  lastContextTokens: previous?.lastContextTokens ?? 0,
6961
7352
  ...previous?.receiptId !== void 0 ? { receiptId: previous.receiptId } : {},
6962
- currentTool: previous?.currentTool ?? null,
6963
- recentTools: previous?.recentTools ?? [],
7353
+ progress: previous?.progress ?? createWorkerProgressFold(),
6964
7354
  ...previous?.retry ? { retry: { ...previous.retry } } : {},
6965
7355
  ...previous?.steerAcknowledgement ? { steerAcknowledgement: { ...previous.steerAcknowledgement } } : {}
6966
7356
  };
@@ -6995,7 +7385,7 @@ function createDispatchBoardStore(bus, snapshot) {
6995
7385
  entry.costUsd = parseFiniteNumber(payload.costUsd, entry.costUsd);
6996
7386
  entry.costProvenance = payload.costProvenance ?? "unknown";
6997
7387
  entry.outcomeDetail = null;
6998
- entry.currentTool = null;
7388
+ settleFromReceipt(entry);
6999
7389
  entry.receiptId = entry.runId;
7000
7390
  delete entry.retry;
7001
7391
  if (typeof payload.inputTokenCount === "number") {
@@ -7021,7 +7411,7 @@ function createDispatchBoardStore(bus, snapshot) {
7021
7411
  entry.costUsd = parseFiniteNumber(payload.costUsd, entry.costUsd);
7022
7412
  entry.costProvenance = payload.costProvenance ?? "unknown";
7023
7413
  entry.outcomeDetail = resolveFailureDetail(payload, entry.outcomeDetail);
7024
- entry.currentTool = null;
7414
+ settleFromReceipt(entry);
7025
7415
  if (payload.reason !== "retry_denied") entry.receiptId = entry.runId;
7026
7416
  delete entry.retry;
7027
7417
  if (typeof payload.inputTokenCount === "number") {
@@ -7041,7 +7431,7 @@ function createDispatchBoardStore(bus, snapshot) {
7041
7431
  if (wasRetrying && raw?.startedAt === null) {
7042
7432
  entry.status = "aborted";
7043
7433
  entry.finishedAtMs = Date.now();
7044
- entry.currentTool = null;
7434
+ entry.progress.settle();
7045
7435
  } else {
7046
7436
  if (isTerminalStatus(entry.status) && !wasRetrying) return;
7047
7437
  entry.status = "cancelling";
@@ -7063,7 +7453,7 @@ function createDispatchBoardStore(bus, snapshot) {
7063
7453
  entry.status = status;
7064
7454
  if (status === "dead") {
7065
7455
  entry.finishedAtMs ??= Date.now();
7066
- entry.currentTool = null;
7456
+ entry.progress.settle();
7067
7457
  delete entry.retry;
7068
7458
  }
7069
7459
  return;
@@ -7072,7 +7462,7 @@ function createDispatchBoardStore(bus, snapshot) {
7072
7462
  entry.failoverHops = (entry.failoverHops ?? 0) + 1;
7073
7463
  entry.status = "running";
7074
7464
  entry.finishedAtMs = null;
7075
- entry.currentTool = null;
7465
+ entry.progress.restart();
7076
7466
  delete entry.retry;
7077
7467
  return;
7078
7468
  }
@@ -7087,20 +7477,7 @@ function createDispatchBoardStore(bus, snapshot) {
7087
7477
  entry.ttftMs = Math.round(performance3.now() - entry.startedAtClockMs);
7088
7478
  }
7089
7479
  }
7090
- if (type === "clio_tool_start") {
7091
- const payload2 = workerEvent.payload;
7092
- const tool = parseNonEmptyString(payload2?.tool);
7093
- if (tool !== void 0) entry.currentTool = tool;
7094
- }
7095
- if (type === "clio_tool_finish") {
7096
- const payload2 = workerEvent.payload;
7097
- const tool = parseNonEmptyString(payload2?.tool);
7098
- entry.currentTool = null;
7099
- if (tool !== void 0) {
7100
- entry.recentTools.unshift(tool);
7101
- if (entry.recentTools.length > RECENT_TOOL_TRAIL_LIMIT) entry.recentTools.length = RECENT_TOOL_TRAIL_LIMIT;
7102
- }
7103
- }
7480
+ entry.progress.observe(payload.event);
7104
7481
  if (type === "clio_steer_received") {
7105
7482
  const steerPayload = workerEvent.payload;
7106
7483
  entry.steerAcknowledgement = {
@@ -7123,7 +7500,7 @@ function createDispatchBoardStore(bus, snapshot) {
7123
7500
  if (!status) return;
7124
7501
  entry.status = status;
7125
7502
  entry.finishedAtMs ??= Date.now();
7126
- entry.currentTool = null;
7503
+ entry.progress.settle();
7127
7504
  delete entry.retry;
7128
7505
  }
7129
7506
  })
@@ -7165,7 +7542,6 @@ function createDispatchBoardStore(bus, snapshot) {
7165
7542
  now
7166
7543
  );
7167
7544
  if (entry) {
7168
- entry.currentTool = null;
7169
7545
  entry.retry = { ...projection.retry };
7170
7546
  if (entry.taskSummary === void 0 && projection.taskSummary !== void 0) {
7171
7547
  entry.taskSummary = projection.taskSummary;
@@ -7181,6 +7557,7 @@ function createDispatchBoardStore(bus, snapshot) {
7181
7557
  entry.tokenCount = live.tokenCount;
7182
7558
  entry.costUsd = live.costUsd;
7183
7559
  entry.costProvenance = live.costProvenance;
7560
+ if (live.budget !== void 0) entry.budget = live.budget;
7184
7561
  if (live.outcomePhase === "aborting") {
7185
7562
  if (entry.status !== "completed" && entry.status !== "aborted") {
7186
7563
  entry.status = "cancelling";
@@ -7245,7 +7622,8 @@ function emptyRunTally() {
7245
7622
  hadProviderReasoning: false,
7246
7623
  hadEstimatedReasoning: false,
7247
7624
  toolCount: 0,
7248
- toolErrorCount: 0
7625
+ toolErrorCount: 0,
7626
+ responseModelIdObservation: { state: "not-observed" }
7249
7627
  };
7250
7628
  }
7251
7629
  function foldMessageIntoRunTally(tally, message) {
@@ -7258,8 +7636,10 @@ function foldMessageIntoRunTally(tally, message) {
7258
7636
  }
7259
7637
  if (message.role !== "assistant") return tally;
7260
7638
  const usage = message.usage;
7639
+ const record2 = message;
7261
7640
  const next = {
7262
7641
  ...tally,
7642
+ responseModelIdObservation: responseModelIdObservationFromRecord(record2, "not-observed"),
7263
7643
  inputTokens: tally.inputTokens + (usage ? finite2(usage.input) : 0),
7264
7644
  outputTokens: tally.outputTokens + (usage ? finite2(usage.output) : 0),
7265
7645
  cacheReadTokens: tally.cacheReadTokens + (usage ? finite2(usage.cacheRead) : 0),
@@ -7293,7 +7673,8 @@ function summaryFromRunTally(tally, input) {
7293
7673
  stopReason: input.stopReason,
7294
7674
  ...input.stopDetail !== void 0 ? { stopDetail: input.stopDetail } : {},
7295
7675
  watchdogPeak: input.watchdogPeak,
7296
- truncated: input.truncated === true
7676
+ truncated: input.truncated === true,
7677
+ responseModelIdObservation: tally.responseModelIdObservation
7297
7678
  };
7298
7679
  if (tally.hadProviderReasoning || tally.hadEstimatedReasoning) {
7299
7680
  summary.reasoningTokens = tally.reasoningTokens;
@@ -8873,7 +9254,7 @@ var ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{
8873
9254
  function isIso8601(value) {
8874
9255
  return typeof value === "string" && ISO_8601_REGEX.test(value) && !Number.isNaN(Date.parse(value));
8875
9256
  }
8876
- function isRecord7(value) {
9257
+ function isRecord8(value) {
8877
9258
  return !!value && typeof value === "object" && !Array.isArray(value);
8878
9259
  }
8879
9260
  function isNonEmptyString(value) {
@@ -8952,7 +9333,7 @@ function readRunLedger(stateDir) {
8952
9333
  const raw = readFileSync5(runLedgerPath(stateDir), "utf8").trim();
8953
9334
  if (raw.length === 0) return [];
8954
9335
  const parsed = JSON.parse(raw);
8955
- return Array.isArray(parsed) ? parsed.filter(isRecord7) : [];
9336
+ return Array.isArray(parsed) ? parsed.filter(isRecord8) : [];
8956
9337
  } catch {
8957
9338
  return [];
8958
9339
  }
@@ -8974,7 +9355,7 @@ function validateToolStats(value) {
8974
9355
  }
8975
9356
  for (let i = 0; i < value.length; i++) {
8976
9357
  const entry = value[i];
8977
- if (!isRecord7(entry)) {
9358
+ if (!isRecord8(entry)) {
8978
9359
  return { ok: false, reason: `toolStats[${i}] not an object` };
8979
9360
  }
8980
9361
  if (!isNonEmptyString(entry.tool)) {
@@ -9014,7 +9395,7 @@ function verifyReceiptFile(stateDir, runId) {
9014
9395
  } catch (err) {
9015
9396
  return { ok: false, reason: `invalid json: ${err.message}` };
9016
9397
  }
9017
- if (!isRecord7(parsed)) {
9398
+ if (!isRecord8(parsed)) {
9018
9399
  return { ok: false, reason: "receipt is not an object" };
9019
9400
  }
9020
9401
  const r = parsed;
@@ -9360,17 +9741,17 @@ var ReceiptArtifactProvider = class {
9360
9741
  }
9361
9742
  };
9362
9743
  function resultText3(result) {
9363
- if (!isRecord7(result)) return "";
9744
+ if (!isRecord8(result)) return "";
9364
9745
  if (result.kind === "ok" && typeof result.output === "string") return result.output;
9365
9746
  if (result.kind === "error" && typeof result.message === "string") return result.message;
9366
9747
  return "";
9367
9748
  }
9368
9749
  function resultDetails(result) {
9369
- return isRecord7(result) && isRecord7(result.details) ? result.details : null;
9750
+ return isRecord8(result) && isRecord8(result.details) ? result.details : null;
9370
9751
  }
9371
9752
  function messagePayload(entry) {
9372
9753
  if (entry.kind !== "message") return null;
9373
- return isRecord7(entry.payload) ? entry.payload : null;
9754
+ return isRecord8(entry.payload) ? entry.payload : null;
9374
9755
  }
9375
9756
  function toolNameFor(entry) {
9376
9757
  const payload = messagePayload(entry);
@@ -9391,12 +9772,12 @@ function dispatchResultForRun(entries, runId) {
9391
9772
  for (const entry of entries) {
9392
9773
  const payload = messagePayload(entry);
9393
9774
  if (!payload) continue;
9394
- const toolName2 = typeof payload.toolName === "string" ? payload.toolName : "";
9395
- if (toolName2 !== "dispatch") continue;
9775
+ const toolName = typeof payload.toolName === "string" ? payload.toolName : "";
9776
+ if (toolName !== "dispatch") continue;
9396
9777
  const details = resultDetails(payload.result);
9397
9778
  const detailRunId = details?.runId;
9398
9779
  const runIds = details?.runIds;
9399
- const matches = detailRunId === runId || Array.isArray(runIds) && runIds.some((item) => item === runId) || Array.isArray(details?.runs) && details.runs.some((item) => isRecord7(item) && item.runId === runId);
9780
+ const matches = detailRunId === runId || Array.isArray(runIds) && runIds.some((item) => item === runId) || Array.isArray(details?.runs) && details.runs.some((item) => isRecord8(item) && item.runId === runId);
9400
9781
  if (!matches) continue;
9401
9782
  const text = resultText3(payload.result);
9402
9783
  if (text.length > 0) return text;
@@ -9692,16 +10073,16 @@ var ToolOutputArtifactProvider = class {
9692
10073
  };
9693
10074
  }
9694
10075
  toolResultArtifact(entry, path) {
9695
- const toolName2 = toolNameFor(entry);
10076
+ const toolName = toolNameFor(entry);
9696
10077
  const artifact = {
9697
10078
  id: `tool:${entry.turnId}`,
9698
10079
  category: this.category,
9699
- title: safeTitle(`${toolName2} \xB7 ${basename(path)}`, `${toolName2} output`),
10080
+ title: safeTitle(`${toolName} \xB7 ${basename(path)}`, `${toolName} output`),
9700
10081
  timestamp: parseTime(entry.timestamp),
9701
10082
  sizeBytes: maybeSizeBytes(path),
9702
10083
  path,
9703
- toolName: toolName2,
9704
- searchText: [toolName2, entry.turnId, path, basename(path)],
10084
+ toolName,
10085
+ searchText: [toolName, entry.turnId, path, basename(path)],
9705
10086
  load: () => loadTextPath(path)
9706
10087
  };
9707
10088
  const payload = messagePayload(entry);
@@ -10073,7 +10454,7 @@ async function listViewArtifacts(providers) {
10073
10454
  }
10074
10455
 
10075
10456
  // src/interactive/worker-receipts.ts
10076
- function isRecord8(value) {
10457
+ function isRecord9(value) {
10077
10458
  return typeof value === "object" && value !== null && !Array.isArray(value);
10078
10459
  }
10079
10460
  function optionalString(value) {
@@ -10089,19 +10470,19 @@ function elapsedMsFrom(receipt) {
10089
10470
  return Math.max(0, endedAt - startedAt);
10090
10471
  }
10091
10472
  function contractFrom(receipt) {
10092
- const quality = isRecord8(receipt.quality) ? receipt.quality : null;
10473
+ const quality = isRecord9(receipt.quality) ? receipt.quality : null;
10093
10474
  if (quality === null) return void 0;
10094
10475
  if (!Object.hasOwn(quality, "resultContract")) return void 0;
10095
10476
  const fact = quality.resultContract;
10096
10477
  if (fact === null) return "unmeasured";
10097
- if (!isRecord8(fact)) return void 0;
10478
+ if (!isRecord9(fact)) return void 0;
10098
10479
  const conformance = fact.conformance;
10099
10480
  return conformance === "pass" || conformance === "fail" || conformance === "not-reached" ? conformance : void 0;
10100
10481
  }
10101
10482
  function workerReceiptFacts(receipt) {
10102
10483
  const outcome = optionalString(receipt.outcome);
10103
10484
  if (outcome === void 0) return null;
10104
- const output = isRecord8(receipt.output) ? receipt.output : null;
10485
+ const output = isRecord9(receipt.output) ? receipt.output : null;
10105
10486
  const contract = contractFrom(receipt);
10106
10487
  const text = optionalString(output?.text);
10107
10488
  const failureMessage = optionalString(receipt.failureMessage);
@@ -10125,7 +10506,7 @@ function workerReceiptFacts(receipt) {
10125
10506
  function readReceiptFileFacts(runId, stateDir) {
10126
10507
  try {
10127
10508
  const parsed = JSON.parse(readFileSync6(receiptFilePath(stateDir, runId), "utf8"));
10128
- return isRecord8(parsed) ? workerReceiptFacts(parsed) : null;
10509
+ return isRecord9(parsed) ? workerReceiptFacts(parsed) : null;
10129
10510
  } catch {
10130
10511
  return null;
10131
10512
  }
@@ -10140,7 +10521,7 @@ function findRunRow(runId, stateDir) {
10140
10521
  const parsed = JSON.parse(readFileSync6(path, "utf8"));
10141
10522
  if (!Array.isArray(parsed)) return null;
10142
10523
  for (const entry of parsed) {
10143
- if (isRecord8(entry) && entry.id === runId) return entry;
10524
+ if (isRecord9(entry) && entry.id === runId) return entry;
10144
10525
  }
10145
10526
  return null;
10146
10527
  } catch {
@@ -10169,13 +10550,7 @@ init_esm_shims();
10169
10550
  function workerAskedByModel(state) {
10170
10551
  return state.parentToolCallId !== void 0 || state.origin === "agent";
10171
10552
  }
10172
- var WORKER_LIVE_TAIL_LINES = 40;
10173
- var WORKER_TOOL_NAME_LIMIT = 8;
10174
- var WORKER_TEXT_TRUNCATION_MARKER = "";
10175
- function isRecord9(value) {
10176
- return typeof value === "object" && value !== null && !Array.isArray(value);
10177
- }
10178
- function nonEmptyString(value) {
10553
+ function nonEmptyString2(value) {
10179
10554
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
10180
10555
  }
10181
10556
  function finiteNumber(value) {
@@ -10190,11 +10565,11 @@ function workerRuntimeKind(runtimeKind, runtimeId) {
10190
10565
  function runtimeIdentity(payload) {
10191
10566
  const kind = workerRuntimeKind(payload.runtimeKind, payload.runtimeId);
10192
10567
  if (kind === "acp") {
10193
- const peerId = nonEmptyString(payload.agentId);
10568
+ const peerId = nonEmptyString2(payload.agentId);
10194
10569
  return { kind, ...peerId !== void 0 ? { peerId } : {} };
10195
10570
  }
10196
- const targetId = nonEmptyString(payload.targetId);
10197
- const wireModelId = nonEmptyString(payload.wireModelId);
10571
+ const targetId = nonEmptyString2(payload.targetId);
10572
+ const wireModelId = nonEmptyString2(payload.wireModelId);
10198
10573
  return {
10199
10574
  kind,
10200
10575
  ...targetId !== void 0 ? { targetId } : {},
@@ -10208,44 +10583,8 @@ function workerTargetLabel(runtime) {
10208
10583
  }
10209
10584
  return runtime.targetId ?? runtime.wireModelId ?? "unknown";
10210
10585
  }
10211
- function textDelta(event) {
10212
- if (!isRecord9(event)) return "";
10213
- if (event.type === "message_update") {
10214
- const assistantEvent = isRecord9(event.assistantMessageEvent) ? event.assistantMessageEvent : null;
10215
- if (assistantEvent?.type !== "text_delta") return "";
10216
- return typeof assistantEvent.delta === "string" ? assistantEvent.delta : "";
10217
- }
10218
- if (event.type !== "text_delta") return "";
10219
- if (typeof event.delta === "string") return event.delta;
10220
- return typeof event.text === "string" ? event.text : "";
10221
- }
10222
- function toolName(event) {
10223
- if (!isRecord9(event)) return void 0;
10224
- if (event.type !== "clio_tool_start" && event.type !== "clio_tool_finish") return void 0;
10225
- const payload = isRecord9(event.payload) ? event.payload : null;
10226
- return nonEmptyString(payload?.tool);
10227
- }
10228
- function lineCount2(text) {
10229
- if (text.length === 0) return 0;
10230
- let lines = 1;
10231
- for (let index = 0; index < text.length; index += 1) {
10232
- if (text[index] === "\n") lines += 1;
10233
- }
10234
- return lines;
10235
- }
10236
- function boundLiveText(text) {
10237
- const lines = text.split("\n");
10238
- if (lines.length <= WORKER_LIVE_TAIL_LINES) return { text, dropped: 0 };
10239
- const dropped = lines.length - WORKER_LIVE_TAIL_LINES;
10240
- return { text: lines.slice(dropped).join("\n"), dropped };
10241
- }
10242
- function boundSettledText(text) {
10243
- const bounded = truncateUtf8(text, WORKER_OUTPUT_MAX_BYTES, WORKER_TEXT_TRUNCATION_MARKER);
10244
- if (bounded === text) return { text, dropped: 0 };
10245
- return { text: bounded, dropped: Math.max(0, lineCount2(text) - lineCount2(bounded)) };
10246
- }
10247
10586
  function terminalFacts(payload) {
10248
- const detail = nonEmptyString(payload.outcomeDetail);
10587
+ const detail = nonEmptyString2(payload.outcomeDetail);
10249
10588
  const tokenCount = finiteNumber(payload.tokenCount);
10250
10589
  const durationMs = finiteNumber(payload.durationMs);
10251
10590
  const exitCode = finiteNumber(payload.exitCode);
@@ -10268,9 +10607,16 @@ function createWorkerStream(options = {}) {
10268
10607
  const byAssignment = /* @__PURE__ */ new Map();
10269
10608
  const attemptByAssignment = /* @__PURE__ */ new Map();
10270
10609
  const assignmentByRun = /* @__PURE__ */ new Map();
10271
- const durableTextByRun = /* @__PURE__ */ new Map();
10610
+ const progressByAssignment = /* @__PURE__ */ new Map();
10611
+ const applyProgress = (entry, fold) => {
10612
+ const snapshot = fold.snapshot();
10613
+ entry.text = snapshot.tailText;
10614
+ entry.droppedLines = snapshot.droppedLines;
10615
+ entry.tools = [...snapshot.toolNames];
10616
+ entry.progress = snapshot;
10617
+ };
10272
10618
  const currentEntryForRun = (runId) => {
10273
- const id = nonEmptyString(runId);
10619
+ const id = nonEmptyString2(runId);
10274
10620
  if (id === void 0) return void 0;
10275
10621
  const assignmentId = assignmentByRun.get(id);
10276
10622
  const entry = assignmentId === void 0 ? void 0 : byAssignment.get(assignmentId);
@@ -10282,18 +10628,17 @@ function createWorkerStream(options = {}) {
10282
10628
  entry.pending = false;
10283
10629
  const attempt = entry.attempts[entry.attempts.length - 1];
10284
10630
  if (attempt !== void 0) attempt.outcome = facts.outcome;
10285
- const settled = nonEmptyString(facts.text) ?? nonEmptyString(durableTextByRun.get(entry.runId));
10286
- if (settled !== void 0) {
10287
- const bounded = boundSettledText(settled);
10288
- entry.text = bounded.text;
10289
- entry.droppedLines = bounded.dropped;
10631
+ const fold = progressByAssignment.get(entry.assignmentId);
10632
+ if (fold !== void 0) {
10633
+ fold.settle(nonEmptyString2(facts.text));
10634
+ applyProgress(entry, fold);
10290
10635
  }
10291
10636
  return { kind: "updated", entry };
10292
10637
  };
10293
10638
  return {
10294
10639
  started(payload) {
10295
- const runId = nonEmptyString(payload.runId);
10296
- const assignmentId = nonEmptyString(payload.assignmentId) ?? runId;
10640
+ const runId = nonEmptyString2(payload.runId);
10641
+ const assignmentId = nonEmptyString2(payload.assignmentId) ?? runId;
10297
10642
  if (runId === void 0 || assignmentId === void 0) return null;
10298
10643
  const runtime = runtimeIdentity(payload);
10299
10644
  const existing = byAssignment.get(assignmentId);
@@ -10306,10 +10651,16 @@ function createWorkerStream(options = {}) {
10306
10651
  delete existing.receipt;
10307
10652
  existing.attempts.push({ runId, targetLabel: workerTargetLabel(runtime) });
10308
10653
  assignmentByRun.set(runId, assignmentId);
10654
+ const progress2 = progressByAssignment.get(assignmentId);
10655
+ if (progress2 !== void 0) {
10656
+ progress2.restart();
10657
+ applyProgress(existing, progress2);
10658
+ }
10309
10659
  return { kind: "updated", entry: existing };
10310
10660
  }
10311
10661
  if (payload.requestOrigin !== "user" && payload.requestOrigin !== "agent") return null;
10312
10662
  attemptByAssignment.set(assignmentId, payload.attempt);
10663
+ const progress = createWorkerProgressFold();
10313
10664
  const entry = {
10314
10665
  assignmentId,
10315
10666
  runId,
@@ -10319,42 +10670,23 @@ function createWorkerStream(options = {}) {
10319
10670
  text: "",
10320
10671
  droppedLines: 0,
10321
10672
  tools: [],
10673
+ progress: progress.snapshot(),
10322
10674
  attempts: [{ runId, targetLabel: workerTargetLabel(runtime) }],
10323
10675
  pending: true,
10324
10676
  ...payload.parentToolCallId !== void 0 ? { parentToolCallId: payload.parentToolCallId } : {}
10325
10677
  };
10326
10678
  byAssignment.set(assignmentId, entry);
10327
10679
  assignmentByRun.set(runId, assignmentId);
10680
+ progressByAssignment.set(assignmentId, progress);
10328
10681
  return { kind: "created", entry };
10329
10682
  },
10330
10683
  progress(payload) {
10331
10684
  const entry = currentEntryForRun(payload.runId);
10332
10685
  if (entry === void 0 || !entry.pending) return null;
10333
- const event = payload.event;
10334
- let changed = false;
10335
- const delta = textDelta(event);
10336
- if (delta.length > 0) {
10337
- const bounded = boundLiveText(entry.text + delta);
10338
- entry.text = bounded.text;
10339
- entry.droppedLines += bounded.dropped;
10340
- changed = true;
10341
- }
10342
- const durable = durableAssistantTextFromEvent(event);
10343
- if (durable.trim().length > 0) {
10344
- durableTextByRun.set(entry.runId, durable);
10345
- if (delta.length === 0 && entry.text.trim().length === 0) {
10346
- const bounded = boundLiveText(durable);
10347
- entry.text = bounded.text;
10348
- entry.droppedLines += bounded.dropped;
10349
- }
10350
- changed = true;
10351
- }
10352
- const tool = toolName(event);
10353
- if (tool !== void 0 && !entry.tools.includes(tool) && entry.tools.length < WORKER_TOOL_NAME_LIMIT) {
10354
- entry.tools.push(tool);
10355
- changed = true;
10356
- }
10357
- return changed ? { kind: "updated", entry } : null;
10686
+ const fold = progressByAssignment.get(entry.assignmentId);
10687
+ if (fold === void 0 || !fold.observe(payload.event)) return null;
10688
+ applyProgress(entry, fold);
10689
+ return { kind: "updated", entry };
10358
10690
  },
10359
10691
  completed(payload) {
10360
10692
  const entry = currentEntryForRun(payload.runId);
@@ -10370,7 +10702,7 @@ function createWorkerStream(options = {}) {
10370
10702
  const entry = currentEntryForRun(payload.runId);
10371
10703
  if (entry === void 0 || !entry.pending) return null;
10372
10704
  const durationMs = finiteNumber(payload.elapsedMs);
10373
- const failureMessage = nonEmptyString(payload.reason);
10705
+ const failureMessage = nonEmptyString2(payload.reason);
10374
10706
  entry.pending = false;
10375
10707
  entry.receipt = {
10376
10708
  outcome: "canceled",
@@ -10389,7 +10721,7 @@ function createWorkerStream(options = {}) {
10389
10721
  byAssignment.clear();
10390
10722
  attemptByAssignment.clear();
10391
10723
  assignmentByRun.clear();
10392
- durableTextByRun.clear();
10724
+ progressByAssignment.clear();
10393
10725
  }
10394
10726
  };
10395
10727
  }
@@ -10712,6 +11044,7 @@ function richMessageFromEntry(entry, maxTextChars) {
10712
11044
  "api",
10713
11045
  "provider",
10714
11046
  "model",
11047
+ "responseModelIdObservation",
10715
11048
  "responseModel",
10716
11049
  "responseId",
10717
11050
  "diagnostics",
@@ -10867,6 +11200,12 @@ function extractToolCall(entry) {
10867
11200
  const args = obj?.arguments ?? obj?.args ?? obj?.input ?? parseMaybeJson(fn?.arguments) ?? block?.arguments ?? block?.args ?? void 0;
10868
11201
  return { id, name, args };
10869
11202
  }
11203
+ function replayResultSummary(result) {
11204
+ const summary = result.resultSummary ?? toolResultSummary(result.result);
11205
+ const offloadPath = typeof summary.offloadPath === "string" && summary.offloadPath.length > 0 ? summary.offloadPath : null;
11206
+ if (offloadPath === null) return result.resultSummary;
11207
+ return { ...summary, offloadFileMissing: !existsSync6(offloadPath) };
11208
+ }
10870
11209
  function extractToolResult(entry) {
10871
11210
  const payload = entry.payload;
10872
11211
  const obj = payloadObject3(payload);
@@ -11196,6 +11535,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
11196
11535
  }
11197
11536
  if (entry.role === "tool_result") {
11198
11537
  const result = extractToolResult(entry);
11538
+ const resultSummary = replayResultSummary(result);
11199
11539
  const evictedReason = workingSet.evicted.get(entry.turnId)?.reason;
11200
11540
  const fallbackId = result.id ?? pendingToolIds.pop() ?? null;
11201
11541
  if (fallbackId) {
@@ -11208,7 +11548,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
11208
11548
  result: displayReplayToolResult(result.result, options.unboundedToolBodies === true),
11209
11549
  isError: result.isError,
11210
11550
  ...result.durationMs !== void 0 ? { durationMs: result.durationMs } : {},
11211
- ...result.resultSummary !== void 0 ? { resultSummary: result.resultSummary } : {},
11551
+ ...resultSummary !== void 0 ? { resultSummary } : {},
11212
11552
  ...result.outcome !== void 0 ? { outcome: result.outcome } : {},
11213
11553
  ...result.blockReason !== void 0 ? { blockReason: result.blockReason } : {},
11214
11554
  ...evictedReason !== void 0 ? { evictedReason } : {}
@@ -11222,7 +11562,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
11222
11562
  result: displayReplayToolResult(result.result, options.unboundedToolBodies === true),
11223
11563
  isError: result.isError,
11224
11564
  ...result.durationMs !== void 0 ? { durationMs: result.durationMs } : {},
11225
- ...result.resultSummary !== void 0 ? { resultSummary: result.resultSummary } : {},
11565
+ ...resultSummary !== void 0 ? { resultSummary } : {},
11226
11566
  ...result.outcome === "blocked" ? { outcome: "blocked" } : {},
11227
11567
  ...result.blockReason !== void 0 ? { blockReason: result.blockReason } : {},
11228
11568
  ...evictedReason !== void 0 ? { evictedReason } : {}
@@ -11428,6 +11768,50 @@ function createTurnContext(deps) {
11428
11768
  }
11429
11769
  return ceilChars(snapshot.pendingUserInput.length);
11430
11770
  };
11771
+ const resolveWindowWithoutRuntime = () => {
11772
+ const settings = deps.getSettings();
11773
+ const targetId = settings.orchestrator?.target?.trim();
11774
+ const wireModelId = settings.orchestrator?.model?.trim();
11775
+ if (!targetId || !wireModelId) return null;
11776
+ const resolved = resolveRuntimeTarget(deps.providers, {
11777
+ targetId,
11778
+ wireModelId,
11779
+ requestedThinkingLevel: settings.orchestrator?.thinkingLevel ?? "off",
11780
+ use: "orchestrator",
11781
+ requireTools: false,
11782
+ requireOutputBudget: true
11783
+ });
11784
+ return resolved.ok ? resolved.target.contextWindowDetails : null;
11785
+ };
11786
+ const CONTEXT_WINDOW_SOURCES = /* @__PURE__ */ new Set([
11787
+ "catalog",
11788
+ "probe",
11789
+ "loaded",
11790
+ "target-override",
11791
+ "model-hint",
11792
+ "descriptor-default",
11793
+ "unknown"
11794
+ ]);
11795
+ const snapshotWindowSource = (snapshot) => CONTEXT_WINDOW_SOURCES.has(snapshot.contextWindowSource) ? snapshot.contextWindowSource : null;
11796
+ const windowWithoutRuntime = () => {
11797
+ const details = resolveWindowWithoutRuntime();
11798
+ if (details) {
11799
+ return {
11800
+ contextWindow: details.effectiveContextWindow,
11801
+ contextWindowSource: details.contextWindowSource,
11802
+ contextWindowSlots: details.contextWindowSlots
11803
+ };
11804
+ }
11805
+ const snapshot = currentContextSnapshot;
11806
+ if (snapshot && snapshot.effectiveContextWindow > 0) {
11807
+ return {
11808
+ contextWindow: snapshot.effectiveContextWindow,
11809
+ contextWindowSource: snapshotWindowSource(snapshot),
11810
+ contextWindowSlots: null
11811
+ };
11812
+ }
11813
+ return { contextWindow: 0, contextWindowSource: null, contextWindowSlots: null };
11814
+ };
11431
11815
  const liveContextEstimate = (agentRuntime, pendingUserText) => {
11432
11816
  const contextWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
11433
11817
  const estimateInput = {
@@ -11884,8 +12268,7 @@ function createTurnContext(deps) {
11884
12268
  return compacted ? continuationContextUpdate(agentRuntime) : void 0;
11885
12269
  },
11886
12270
  contextUsage() {
11887
- if (!state.runtime) return contextUsageSnapshot(null, 0);
11888
- const effectiveWindow = state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
12271
+ const effectiveWindow = state.runtime ? state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow : windowWithoutRuntime().contextWindow;
11889
12272
  if (!currentContextSnapshot) {
11890
12273
  return contextUsageSnapshot(null, effectiveWindow);
11891
12274
  }
@@ -11903,26 +12286,20 @@ function createTurnContext(deps) {
11903
12286
  const settings = deps.getSettings();
11904
12287
  const compactionThreshold = settings.compaction?.threshold ?? null;
11905
12288
  const compactionAuto = settings.compaction?.auto !== false;
11906
- if (!state.runtime) {
11907
- return buildContextLedger({
11908
- provider: settings.orchestrator?.target ?? null,
11909
- model: settings.orchestrator?.model ?? null,
11910
- contextWindow: 0,
11911
- compactionThreshold,
11912
- compactionAuto
11913
- });
11914
- }
11915
- const windowDetails = state.runtime.runtimeResolution.contextWindowDetails;
11916
- const effectiveWindow = windowDetails.effectiveContextWindow;
11917
- const provider = state.runtime.targetId ?? settings.orchestrator?.target ?? null;
11918
- const model = state.runtime.wireModelId ?? settings.orchestrator?.model ?? null;
12289
+ const window = state.runtime ? {
12290
+ contextWindow: state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow,
12291
+ contextWindowSource: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSource,
12292
+ contextWindowSlots: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSlots
12293
+ } : windowWithoutRuntime();
12294
+ const provider = state.runtime?.targetId ?? settings.orchestrator?.target ?? null;
12295
+ const model = state.runtime?.wireModelId ?? settings.orchestrator?.model ?? null;
12296
+ const liveToolCount = state.runtime?.agent.state.tools.length ?? 0;
11919
12297
  if (!currentContextSnapshot) {
11920
12298
  return buildContextLedger({
11921
12299
  provider,
11922
12300
  model,
11923
- contextWindow: effectiveWindow,
11924
- contextWindowSource: windowDetails.contextWindowSource,
11925
- toolCount: state.runtime.agent.state.tools.length,
12301
+ ...window,
12302
+ toolCount: liveToolCount,
11926
12303
  compactionThreshold,
11927
12304
  compactionAuto,
11928
12305
  promptCache: lastPromptCache
@@ -11935,15 +12312,14 @@ function createTurnContext(deps) {
11935
12312
  return buildContextLedger({
11936
12313
  provider,
11937
12314
  model,
11938
- contextWindow: effectiveWindow,
11939
- contextWindowSource: windowDetails.contextWindowSource,
12315
+ ...window,
11940
12316
  compactionThreshold,
11941
12317
  compactionAuto,
11942
12318
  systemPromptTokens: currentContextSnapshot.categories.system,
11943
12319
  toolSchemaTokens: currentContextSnapshot.categories.tools,
11944
12320
  // Persisted snapshots strip the captured schemas; fall back to
11945
12321
  // the live agent state after a session resume.
11946
- toolCount: currentContextSnapshot.activeToolSchemas?.length ?? state.runtime.agent.state.tools.length,
12322
+ toolCount: currentContextSnapshot.activeToolSchemas?.length ?? liveToolCount,
11947
12323
  messageTokens: currentContextSnapshot.categories.messages,
11948
12324
  agentsTokens: currentContextSnapshot.categories.agents,
11949
12325
  skillsTokens: currentContextSnapshot.categories.skills,
@@ -12135,6 +12511,7 @@ function createTurnMiddleware(deps) {
12135
12511
  runtimeTier: agentRuntime.runtimeResolution.runtimeTier ?? "",
12136
12512
  activeToolNames: toolNamesFromAgentState(agentRuntime.agent.state.tools).join(","),
12137
12513
  turnToolCalls: state.turnToolCalls,
12514
+ turnToolNames: state.turnToolNames.join(","),
12138
12515
  sharedWorkerNote: state.turnSharedWorkerNote
12139
12516
  };
12140
12517
  if (terminalToolResult !== void 0) {
@@ -12819,8 +13196,8 @@ function count(pattern, text) {
12819
13196
  while (pattern.exec(text)) matches += 1;
12820
13197
  return matches;
12821
13198
  }
12822
- function toolPattern(toolName2) {
12823
- const escaped = escapeRegExp(toolName2.trim().toLowerCase());
13199
+ function toolPattern(toolName) {
13200
+ const escaped = escapeRegExp(toolName.trim().toLowerCase());
12824
13201
  return escaped.replace(/[_-]+/g, "[ _-]+");
12825
13202
  }
12826
13203
  function normalizedToolNames(names) {
@@ -12842,8 +13219,8 @@ function assessToolProseLoop(input) {
12842
13219
  const text = input.text.toLowerCase().replace(/\s+/g, " ");
12843
13220
  let maxToolMatches = 0;
12844
13221
  let matchedTool = "";
12845
- for (const toolName2 of tools) {
12846
- const name = toolPattern(toolName2);
13222
+ for (const toolName of tools) {
13223
+ const name = toolPattern(toolName);
12847
13224
  const patterns = [
12848
13225
  new RegExp(`\\b(?:execute|call|make|use)\\s+the\\s+${name}\\s+tool\\s+call\\b`, "g"),
12849
13226
  new RegExp(`\\b(?:execute|call|use)\\s+the\\s+${name}\\s+tool\\b`, "g"),
@@ -12852,7 +13229,7 @@ function assessToolProseLoop(input) {
12852
13229
  const matches = patterns.reduce((sum, pattern) => sum + count(pattern, text), 0);
12853
13230
  if (matches > maxToolMatches) {
12854
13231
  maxToolMatches = matches;
12855
- matchedTool = toolName2;
13232
+ matchedTool = toolName;
12856
13233
  }
12857
13234
  }
12858
13235
  const genericMatches = count(
@@ -12927,7 +13304,10 @@ function createTurnRuntime(deps) {
12927
13304
  failure?.code ?? "admission-failed"
12928
13305
  );
12929
13306
  }
12930
- for (const message of runtimeResolutionWarnings(resolved.diagnostics)) {
13307
+ for (const message of runtimeResolutionWarningsBesideThinkingNotice(
13308
+ resolved.diagnostics,
13309
+ resolved.target.modelRuntime.thinking.notice
13310
+ )) {
12931
13311
  const key = `${targetId}|${wireModelId}|${message}`;
12932
13312
  if (announcedResolutionWarnings.has(key)) continue;
12933
13313
  announcedResolutionWarnings.add(key);
@@ -12942,6 +13322,7 @@ function createTurnRuntime(deps) {
12942
13322
  };
12943
13323
  const TARGET_PROBE_TTL_MS = 5 * 60 * 1e3;
12944
13324
  let lastTargetProbe = null;
13325
+ const targetProbesInFlight = /* @__PURE__ */ new Map();
12945
13326
  const ensureLiveCapabilitiesForSelectedModel = async () => {
12946
13327
  const settings = deps.getSettings();
12947
13328
  const targetId = settings.orchestrator.target?.trim();
@@ -12952,15 +13333,28 @@ function createTurnRuntime(deps) {
12952
13333
  const runtimeDesc = deps.providers.getRuntime(target.runtime);
12953
13334
  if (!runtimeDesc || runtimeDesc.tier === "cloud") return;
12954
13335
  const key = `${targetId}|${wireModelId}`;
13336
+ const inFlight = targetProbesInFlight.get(key);
13337
+ if (inFlight) {
13338
+ await inFlight;
13339
+ return;
13340
+ }
12955
13341
  const now = Date.now();
12956
13342
  if (lastTargetProbe?.key === key && now - lastTargetProbe.at < TARGET_PROBE_TTL_MS) return;
12957
13343
  lastTargetProbe = { key, at: now };
12958
- let status = null;
13344
+ const probe = (async () => {
13345
+ let status = null;
13346
+ try {
13347
+ status = await deps.providers.probeTarget(targetId);
13348
+ } catch {
13349
+ }
13350
+ announceColdModel(status, targetId, wireModelId);
13351
+ })();
13352
+ targetProbesInFlight.set(key, probe);
12959
13353
  try {
12960
- status = await deps.providers.probeTarget(targetId);
12961
- } catch {
13354
+ await probe;
13355
+ } finally {
13356
+ if (targetProbesInFlight.get(key) === probe) targetProbesInFlight.delete(key);
12962
13357
  }
12963
- announceColdModel(status, targetId, wireModelId);
12964
13358
  };
12965
13359
  const announcedColdModels = /* @__PURE__ */ new Set();
12966
13360
  const announceColdModel = (status, targetId, wireModelId) => {
@@ -13179,6 +13573,7 @@ function createTurnRuntime(deps) {
13179
13573
  middlewareToolChoice.toolStarted(event.toolName);
13180
13574
  deps.toolStartTimes.set(event.toolCallId, eventClock);
13181
13575
  state.turnToolCalls += 1;
13576
+ state.turnToolNames.push(event.toolName);
13182
13577
  } else if (event.type === "tool_execution_end") {
13183
13578
  toolsInFlight = Math.max(0, toolsInFlight - 1);
13184
13579
  const startedAt = deps.toolStartTimes.get(event.toolCallId);
@@ -13260,7 +13655,11 @@ function createTurnRuntime(deps) {
13260
13655
  if (summary.hadUsage && (summary.tokens > 0 || summary.costUsd > 0)) {
13261
13656
  deps.observability.recordTokens(
13262
13657
  localRuntime.targetId,
13263
- localRuntime.wireModelId,
13658
+ attributedModelId(
13659
+ summary.lastResponseModelIdObservation,
13660
+ localRuntime.wireModelId,
13661
+ summary.lastDifferingResponseModelId
13662
+ ),
13264
13663
  summary.tokens,
13265
13664
  summary.costUsd,
13266
13665
  {
@@ -13272,7 +13671,11 @@ function createTurnRuntime(deps) {
13272
13671
  totalTokens: summary.tokens,
13273
13672
  apiCalls: summary.apiCalls
13274
13673
  },
13275
- localRuntime.runtimeResolution.costProvenance
13674
+ localRuntime.runtimeResolution.costProvenance,
13675
+ {
13676
+ requestedModelIds: [localRuntime.wireModelId],
13677
+ responseModelIdObservationCounts: summary.responseModelIdObservationCounts
13678
+ }
13276
13679
  );
13277
13680
  }
13278
13681
  if (summary.output > 0 && firstAssistantDeltaAt !== null) {
@@ -13397,6 +13800,7 @@ function createTurnState(initialThinkingLevel) {
13397
13800
  streamStallReason: null,
13398
13801
  toolProseAssessedChars: 0,
13399
13802
  turnToolCalls: 0,
13803
+ turnToolNames: [],
13400
13804
  turnSharedWorkerNote: false,
13401
13805
  stalledTurnNudgeSpent: false,
13402
13806
  pendingRequestContinuation: false,
@@ -13575,6 +13979,8 @@ function createChatLoop(deps) {
13575
13979
  emitNotice,
13576
13980
  toolStartTimes
13577
13981
  });
13982
+ void turnRuntime.ensureLiveCapabilitiesForSelectedModel().catch(() => {
13983
+ });
13578
13984
  const unsubscribeConfigReload = deps.bus?.on(BusChannels.ConfigHotReload, () => {
13579
13985
  context.invalidateSessionPromptCache();
13580
13986
  }) ?? null;
@@ -13656,6 +14062,7 @@ function createChatLoop(deps) {
13656
14062
  return;
13657
14063
  }
13658
14064
  state.turnToolCalls = 0;
14065
+ state.turnToolNames = [];
13659
14066
  state.turnSharedWorkerNote = isWorkerShareNote(text);
13660
14067
  middlewareToolChoice.reset();
13661
14068
  if (options.requestContinuation !== true) state.stalledTurnNudgeSpent = false;
@@ -13894,6 +14301,8 @@ function createChatLoop(deps) {
13894
14301
  middlewareToolChoice.reset();
13895
14302
  state.lastTurnId = leafTurnId;
13896
14303
  context.resetForSession();
14304
+ void turnRuntime.ensureLiveCapabilitiesForSelectedModel().catch(() => {
14305
+ });
13897
14306
  state.replayedContextMessages = replayMessages ? [...replayMessages] : [];
13898
14307
  if (state.runtime) {
13899
14308
  state.runtime.agent.state.messages = [...state.replayedContextMessages];
@@ -14056,264 +14465,6 @@ init_esm_shims();
14056
14465
  // src/interactive/overlays/ask-user.ts
14057
14466
  init_esm_shims();
14058
14467
 
14059
- // src/interactive/overlay-frame.ts
14060
- init_esm_shims();
14061
- var DEFAULT_SELECT_THEME = selectListTheme(clioTheme());
14062
- var DEFAULT_SETTINGS_THEME = settingsListTheme(clioTheme());
14063
- var FocusBox = class extends Box {
14064
- inputTarget;
14065
- onInput;
14066
- constructor(children, options) {
14067
- super(options?.x ?? 1, options?.y ?? 0);
14068
- const childList = Array.isArray(children) ? children : [children];
14069
- for (const child of childList) this.addChild(child);
14070
- this.inputTarget = options?.inputTarget === void 0 ? childList[0] ?? null : options.inputTarget;
14071
- this.onInput = options?.onInput;
14072
- }
14073
- handleInput(data) {
14074
- if (this.onInput) {
14075
- this.onInput(data);
14076
- return;
14077
- }
14078
- this.inputTarget?.handleInput?.(data);
14079
- }
14080
- };
14081
- function resolveTone(tone) {
14082
- return typeof tone === "function" ? tone() : tone;
14083
- }
14084
- function clioFrame(text, token = "frame") {
14085
- return clioTheme().fg(token, text);
14086
- }
14087
- function clioTitle(text, token) {
14088
- return token === void 0 ? screenTitle(clioTheme(), text) : clioTheme().style(token, text, { bold: true });
14089
- }
14090
- function clioError(text) {
14091
- return clioTheme().fg("error", text);
14092
- }
14093
- function brandedTopBorder(label, innerWidth, tone) {
14094
- const frame2 = (text) => clioFrame(text, tone ?? "frame");
14095
- const clean = label.replace(/^[┌┐└┘├┤─│\s]+/, "").replace(/[┌┐└┘├┤─│\s]+$/, "");
14096
- const formatted = clean.length > 0 ? `\u2500 ${clean} ` : "\u2500";
14097
- const clipped = visibleWidth(formatted) > innerWidth ? truncateToWidth(formatted, innerWidth, "\u2026", true) : formatted;
14098
- const fill = "\u2500".repeat(Math.max(0, innerWidth - visibleWidth(clipped)));
14099
- const cleanIndex = clipped.indexOf(clean);
14100
- if (cleanIndex !== -1) {
14101
- const prefix = clipped.slice(0, cleanIndex);
14102
- const suffix = clipped.slice(cleanIndex + clean.length);
14103
- return `${frame2("\u250C")}${frame2(prefix)}${clioTitle(clean, tone)}${frame2(suffix)}${frame2(fill)}${frame2("\u2510")}`;
14104
- }
14105
- return `${frame2("\u250C")}${frame2(clipped)}${frame2(fill)}${frame2("\u2510")}`;
14106
- }
14107
- function isCriticalHintKey(key) {
14108
- const canonical = canonicalizeKey(key);
14109
- return canonical === "Esc" || canonical === "Enter" || canonical === "Enter/Space" || canonical === "type";
14110
- }
14111
- function isCriticalEntry(entry) {
14112
- return entry.critical ?? isCriticalHintKey(entry.key);
14113
- }
14114
- function renderHintEntries(entries, short) {
14115
- return entries.map((entry) => `[${canonicalizeKey(entry.key)}] ${short ? entry.short ?? entry.verb : entry.verb}`).join(" \xB7 ");
14116
- }
14117
- function fitHintEntries(entries, maxWidth) {
14118
- if (entries.length === 0) return "";
14119
- for (const short of [false, true]) {
14120
- const rendered = renderHintEntries(entries, short);
14121
- if (visibleWidth(rendered) <= maxWidth) return rendered;
14122
- }
14123
- const kept = [...entries];
14124
- for (const criticalPass of [false, true]) {
14125
- while (kept.length > 1) {
14126
- const index = kept.findIndex((entry) => criticalPass || !isCriticalEntry(entry));
14127
- if (index === -1) break;
14128
- kept.splice(index, 1);
14129
- const rendered = renderHintEntries(kept, true);
14130
- if (visibleWidth(rendered) <= maxWidth) return rendered;
14131
- }
14132
- }
14133
- return renderHintEntries(kept, true);
14134
- }
14135
- var FILTER_HINT = { key: "type", verb: "filter" };
14136
- function canonicalizeKey(key) {
14137
- const trimmed = key.trim();
14138
- if (trimmed === "R") return "R";
14139
- const lower = trimmed.toLowerCase();
14140
- if (lower === "up/down" || lower === "updown" || lower === "\u2191/\u2193" || lower === "up/down/j/k" || lower === "\u2191\u2193")
14141
- return "\u2191\u2193";
14142
- if (lower === "enter/space") return "Enter/Space";
14143
- if (lower === "enter") return "Enter";
14144
- if (lower === "esc" || lower === "escape") return "Esc";
14145
- if (lower === "space") return "Space";
14146
- if (lower === "tab") return "Tab";
14147
- if (lower === "r") return "r";
14148
- if (lower === "type") return "type";
14149
- return trimmed;
14150
- }
14151
- function buildHint(entries, esc = "close") {
14152
- const finalEntries = [
14153
- ...entries.map((e) => ({ key: canonicalizeKey(e.key), verb: e.verb })),
14154
- { key: "Esc", verb: esc }
14155
- ];
14156
- return finalEntries.map((e) => `[${e.key}] ${e.verb}`).join(" \xB7 ");
14157
- }
14158
- function buildResponsiveHint(entries, esc = "close") {
14159
- const escEntry = esc === null ? null : typeof esc === "string" ? { key: "Esc", verb: esc } : esc;
14160
- const all = escEntry ? [...entries, escEntry] : [...entries];
14161
- return (innerWidth) => fitHintEntries(all, innerWidth - 3);
14162
- }
14163
- function elideHint(hint, maxCleanWidth) {
14164
- const parts = hint.split(" \xB7 ");
14165
- if (parts.length <= 2) return hint;
14166
- const entries = parts.map((part) => {
14167
- const match = /^\[([^\]]+)\] ([\s\S]+)$/u.exec(part);
14168
- if (!match) return { key: "", verb: part, critical: false };
14169
- return { key: match[1] ?? "", verb: match[2] ?? "" };
14170
- });
14171
- const rendered = fitHintEntries(entries, maxCleanWidth);
14172
- return rendered.replace(/\[\] /gu, "");
14173
- }
14174
- function brandedBottomBorder(innerWidth, hint, tone) {
14175
- const frame2 = (text) => clioFrame(text, tone ?? "frame");
14176
- if (!hint || hint.trim().length === 0) {
14177
- return `${frame2("\u2514")}${frame2("\u2500".repeat(innerWidth))}${frame2("\u2518")}`;
14178
- }
14179
- let clean = hint.trim();
14180
- const maxCleanWidth = innerWidth - 3;
14181
- if (clean.includes(" \xB7 ") && visibleWidth(`\u2500 ${clean} `) > innerWidth) {
14182
- clean = elideHint(clean, maxCleanWidth);
14183
- }
14184
- const formatted = `\u2500 ${clean} `;
14185
- const clipped = visibleWidth(formatted) > innerWidth ? truncateToWidth(formatted, innerWidth, "\u2026", true) : formatted;
14186
- const fill = "\u2500".repeat(Math.max(0, innerWidth - visibleWidth(clipped)));
14187
- const cleanIndex = clipped.indexOf(clean);
14188
- if (cleanIndex !== -1) {
14189
- const prefix = clipped.slice(0, cleanIndex);
14190
- const suffix = clipped.slice(cleanIndex + clean.length);
14191
- return `${frame2("\u2514")}${frame2(prefix)}${clioTheme().fg("dim", clean)}${frame2(suffix)}${frame2(fill)}${frame2("\u2518")}`;
14192
- }
14193
- return `${frame2("\u2514")}${frame2(clipped)}${frame2(fill)}${frame2("\u2518")}`;
14194
- }
14195
- function formatRuntimeResolutionDiagnostic(diagnostic) {
14196
- return `${diagnostic.severity}: ${diagnostic.code}: ${diagnostic.message}`;
14197
- }
14198
- function diagnosticSeverityToken(severity) {
14199
- return severity === "error" ? "error" : severity === "warning" ? "warning" : "muted";
14200
- }
14201
- function runtimeResolutionDiagnosticLine(diagnostic, width) {
14202
- return clioTheme().fg(diagnosticSeverityToken(diagnostic.severity), fitDiagnosticLine(diagnostic, width));
14203
- }
14204
- function fitDiagnosticLine(diagnostic, width) {
14205
- return padAnsi(formatRuntimeResolutionDiagnostic(diagnostic), Math.max(1, width));
14206
- }
14207
- function frameAlignForAnchor(anchor) {
14208
- if (anchor === void 0) return "center";
14209
- if (anchor === "left-center" || anchor.endsWith("-left")) return "left";
14210
- if (anchor === "right-center" || anchor.endsWith("-right")) return "right";
14211
- return "center";
14212
- }
14213
- function fitBody(lines, rowBudget, contentWidth) {
14214
- if (rowBudget <= 0) return lines;
14215
- const bodyBudget = Math.max(1, rowBudget - 2);
14216
- if (lines.length <= bodyBudget) return lines;
14217
- const kept = lines.slice(0, bodyBudget - 1);
14218
- const hidden = lines.length - kept.length;
14219
- return [...kept, clioTheme().fg("dim", truncateToWidth(`\u2026 ${hidden} more rows`, contentWidth, "", true))];
14220
- }
14221
- var ClioOverlayFrame = class {
14222
- constructor(child, title, footerHint, boxWidth = 0, align = "center", tone) {
14223
- this.child = child;
14224
- this.title = title;
14225
- this.footerHint = footerHint;
14226
- this.boxWidth = boxWidth;
14227
- this.align = align;
14228
- this.tone = tone;
14229
- }
14230
- child;
14231
- title;
14232
- footerHint;
14233
- boxWidth;
14234
- align;
14235
- tone;
14236
- /**
14237
- * Rows the box may occupy, or zero while unknown.
14238
- *
14239
- * `Component.render` is handed a width and nothing else, so the frame learns
14240
- * its height budget from the engine's `visible` predicate, which is called
14241
- * with the live terminal size immediately before the render pass that
14242
- * composites this overlay.
14243
- */
14244
- rowBudget = 0;
14245
- /**
14246
- * Last rendered box, keyed by everything that shapes it. `childLines` is
14247
- * compared by array identity: a child that rebuilds its rows returns a fresh
14248
- * array and correctly misses, and one that serves a cache returns the same
14249
- * array and correctly hits.
14250
- */
14251
- cachedRender;
14252
- setRowBudget(rows) {
14253
- this.rowBudget = Math.max(0, Math.floor(rows));
14254
- }
14255
- render(width) {
14256
- const boxWidth = Math.max(5, Math.min(this.boxWidth > 0 ? this.boxWidth : width, width));
14257
- const contentWidth = Math.max(1, boxWidth - 4);
14258
- const childLines = this.child.render(contentWidth);
14259
- const titleText = typeof this.title === "function" ? this.title() : this.title;
14260
- const hint = typeof this.footerHint === "function" ? this.footerHint(contentWidth + 2) : this.footerHint;
14261
- const tone = resolveTone(this.tone);
14262
- const cached = this.cachedRender;
14263
- if (cached !== void 0 && cached.width === width && cached.rowBudget === this.rowBudget && cached.childLines === childLines && cached.title === titleText && cached.hint === hint && cached.tone === tone) {
14264
- return cached.lines;
14265
- }
14266
- const label = titleText.length > 0 ? `\u2500 ${titleText} ` : "\u2500 ";
14267
- const side = clioFrame("\u2502", tone ?? "frame");
14268
- const boxLines = [
14269
- brandedTopBorder(label, contentWidth + 2, tone),
14270
- ...fitBody(childLines, this.rowBudget, contentWidth).map((line) => `${side} ${padAnsi(line, contentWidth)} ${side}`),
14271
- brandedBottomBorder(contentWidth + 2, hint, tone)
14272
- ];
14273
- const slack = Math.max(0, width - boxWidth);
14274
- const lines = (() => {
14275
- if (slack === 0) return boxLines;
14276
- const leading = this.align === "left" ? 0 : this.align === "right" ? slack : Math.floor(slack / 2);
14277
- const lead = " ".repeat(leading);
14278
- const trail = " ".repeat(slack - leading);
14279
- return boxLines.map((line) => `${lead}${line}${trail}`);
14280
- })();
14281
- this.cachedRender = { width, rowBudget: this.rowBudget, childLines, title: titleText, hint, tone, lines };
14282
- return lines;
14283
- }
14284
- handleInput(data) {
14285
- this.child.handleInput?.(data);
14286
- }
14287
- invalidate() {
14288
- this.cachedRender = void 0;
14289
- this.child.invalidate?.();
14290
- }
14291
- };
14292
- function showClioOverlayFrame(tui, child, options) {
14293
- const { title, footerHint, tone, width, visible, maxHeight, margin, ...overlayOptions } = options;
14294
- const boxWidth = typeof width === "number" ? width : 0;
14295
- const frame2 = new ClioOverlayFrame(child, title, footerHint, boxWidth, frameAlignForAnchor(options.anchor), tone);
14296
- const marginRows = typeof margin === "number" ? margin * 2 : (margin?.top ?? 0) + (margin?.bottom ?? 0);
14297
- return tui.showOverlay(frame2, {
14298
- ...overlayOptions,
14299
- ...margin !== void 0 ? { margin } : {},
14300
- width: "100%",
14301
- visible: (termWidth, termHeight) => {
14302
- const available = Math.max(1, termHeight - marginRows);
14303
- const requested = resolveRowSize(maxHeight, termHeight);
14304
- frame2.setRowBudget(requested === null ? available : Math.min(requested, available));
14305
- return visible ? visible(termWidth, termHeight) : true;
14306
- }
14307
- });
14308
- }
14309
- function resolveRowSize(value, termHeight) {
14310
- if (typeof value === "number") return Math.max(1, Math.floor(value));
14311
- if (typeof value !== "string") return null;
14312
- const percent = /^(\d+(?:\.\d+)?)%$/u.exec(value.trim());
14313
- if (!percent?.[1]) return null;
14314
- return Math.max(1, Math.floor(termHeight * Number.parseFloat(percent[1]) / 100));
14315
- }
14316
-
14317
14468
  // src/interactive/view/view-overlay.ts
14318
14469
  init_esm_shims();
14319
14470
  var VIEW_OVERLAY_WIDTH = "100%";
@@ -14896,13 +15047,14 @@ function openViewOverlay(tui, options) {
14896
15047
  }
14897
15048
 
14898
15049
  // src/interactive/overlays/ask-user.ts
14899
- var ASK_USER_DECISION_TONE = "action";
14900
- var ASK_USER_DECISION_TITLE = "Decision required";
15050
+ var DEFAULT_ASK_USER_PRESENTATION = classifyDecisionPresentation(decisionFactsForAnswer("local"));
15051
+ var ASK_USER_DECISION_TONE = DEFAULT_ASK_USER_PRESENTATION.semanticToken;
15052
+ var ASK_USER_DECISION_TITLE = DEFAULT_ASK_USER_PRESENTATION.title;
14901
15053
  var ASK_USER_WAITING_TITLE = "Ask User";
14902
15054
  var ASK_USER_COMPACT_MAX_OPTIONS = 3;
14903
15055
  var ASK_USER_DEFAULT_SURFACE = "panel";
14904
15056
  var ASK_USER_SURFACE_GEOMETRY = {
14905
- compact: { width: 68, maxInnerRows: 10, anchor: "bottom-center", margin: { top: 1, right: 2, bottom: 1, left: 2 } },
15057
+ compact: { width: 68, maxInnerRows: 14, anchor: "bottom-center", margin: { top: 1, right: 2, bottom: 1, left: 2 } },
14906
15058
  panel: { width: 88, maxInnerRows: 18, anchor: "center", margin: 1 },
14907
15059
  // The interview is a workspace, not a modal. A cap of 42 turned a 66-row
14908
15060
  // terminal into a centered box with twenty blank rows around it, so the
@@ -15012,13 +15164,15 @@ var AskUserOverlayView = class {
15012
15164
  contentRegionHeight = 1;
15013
15165
  /** Rows the scroll region wanted on the last render. */
15014
15166
  contentTotalRows = 0;
15015
- begin(questions) {
15167
+ presentation = DEFAULT_ASK_USER_PRESENTATION;
15168
+ begin(questions, presentation = DEFAULT_ASK_USER_PRESENTATION) {
15016
15169
  if (this.phase === "closed") return Promise.resolve(cancelledAskUserResult());
15017
15170
  if (this.resolveCurrent) return Promise.resolve(cancelledAskUserResult());
15018
15171
  this.phase = "asking";
15019
15172
  this.index = 0;
15020
15173
  this.status = "";
15021
15174
  this.questions = [...questions];
15175
+ this.presentation = presentation;
15022
15176
  this.states = this.questions.map((question) => createQuestionState(question));
15023
15177
  this.list = null;
15024
15178
  this.input = null;
@@ -15047,6 +15201,12 @@ var AskUserOverlayView = class {
15047
15201
  currentSurface() {
15048
15202
  return this.surface;
15049
15203
  }
15204
+ decisionTitle() {
15205
+ return this.presentation.title;
15206
+ }
15207
+ decisionTone() {
15208
+ return this.presentation.semanticToken;
15209
+ }
15050
15210
  invalidate() {
15051
15211
  this.list?.invalidate();
15052
15212
  this.input?.invalidate();
@@ -15108,9 +15268,16 @@ var AskUserOverlayView = class {
15108
15268
  const statusLines = this.status.length > 0 ? ["", fitLine(clioTheme().fg("dim", this.status), safeWidth)] : [];
15109
15269
  const headerLine4 = this.renderQuestionHeader(question, safeWidth);
15110
15270
  const headerLines = headerLine4.length > 0 ? [headerLine4] : [];
15111
- const spent = headerLines.length + statusLines.length + 1 + controlLines.length;
15112
- const questionLines = wrapTextWithAnsi(question.question, safeWidth).slice(0, Math.max(1, maxRows - spent));
15113
- return [...headerLines, ...questionLines, ...statusLines, "", ...controlLines].slice(0, maxRows);
15271
+ const bottom = [...statusLines, "", ...controlLines];
15272
+ const topBudget = Math.max(1, maxRows - bottom.length);
15273
+ const contextLines = this.renderDecisionContext(safeWidth);
15274
+ const top = [
15275
+ contextLines[0] ?? "",
15276
+ ...headerLines,
15277
+ ...wrapTextWithAnsi(question.question, safeWidth),
15278
+ ...contextLines.slice(1)
15279
+ ].slice(0, topBudget);
15280
+ return [...top, ...bottom].slice(0, maxRows);
15114
15281
  }
15115
15282
  /**
15116
15283
  * The interview, as a workspace with fixed chrome and a scrolling middle.
@@ -15128,7 +15295,12 @@ var AskUserOverlayView = class {
15128
15295
  const headerLine4 = this.renderQuestionHeader(question, width);
15129
15296
  const headerLines = headerLine4.length > 0 ? [headerLine4] : [];
15130
15297
  const stripLines = [this.renderQuestionStrip(width), ""];
15131
- const content = [...wrapTextWithAnsi(question.question, width), ...this.renderAnswerLedger(width)];
15298
+ const content = [
15299
+ ...wrapTextWithAnsi(question.question, width),
15300
+ "",
15301
+ ...this.renderDecisionContext(width),
15302
+ ...this.renderAnswerLedger(width)
15303
+ ];
15132
15304
  let top = [...stripLines, ...headerLines];
15133
15305
  let bottom = [...statusLines, "", ...controlLines];
15134
15306
  const region = () => maxRows - top.length - bottom.length;
@@ -15192,26 +15364,40 @@ var AskUserOverlayView = class {
15192
15364
  const question = this.currentQuestion();
15193
15365
  const state = this.currentState();
15194
15366
  if (!question || !state) return buildHint([]);
15367
+ const recordAnswer = this.presentation.requiredActions.find((action) => action.id === "record-answer")?.label.toLowerCase() ?? "record answer";
15195
15368
  if (state.mode === "text") {
15196
15369
  return this.questions.length > 1 ? this.withScrollHint([
15197
- { key: "Enter", verb: "submit" },
15370
+ { key: "Enter", verb: recordAnswer },
15198
15371
  { key: "Alt+Left/Right", verb: "question" }
15199
- ]) : this.withScrollHint([{ key: "Enter", verb: "submit" }]);
15372
+ ]) : this.withScrollHint([{ key: "Enter", verb: recordAnswer }]);
15200
15373
  }
15201
15374
  if (question.multi_select === true) {
15202
15375
  return this.questions.length > 1 ? this.withScrollHint([
15203
15376
  { key: "Left/Right", verb: "question" },
15204
15377
  { key: "Space", verb: "toggle" },
15205
- { key: "Enter", verb: "accept" }
15378
+ { key: "Enter", verb: recordAnswer }
15206
15379
  ]) : this.withScrollHint([
15207
15380
  { key: "Space", verb: "toggle" },
15208
- { key: "Enter", verb: "accept" }
15381
+ { key: "Enter", verb: recordAnswer }
15209
15382
  ]);
15210
15383
  }
15211
15384
  return this.questions.length > 1 ? this.withScrollHint([
15212
15385
  { key: "Left/Right", verb: "question" },
15213
- { key: "Enter", verb: "accept" }
15214
- ]) : this.withScrollHint([{ key: "Enter", verb: "accept" }]);
15386
+ { key: "Enter", verb: recordAnswer }
15387
+ ]) : this.withScrollHint([{ key: "Enter", verb: recordAnswer }]);
15388
+ }
15389
+ renderDecisionContext(width) {
15390
+ const theme6 = clioTheme();
15391
+ const tier = theme6.style(this.presentation.semanticToken, this.presentation.tierLabel, { bold: true });
15392
+ const requested = theme6.fg("dim", `requested by ${this.presentation.requestedByCopy}`);
15393
+ const effect = `${theme6.fg("dim", "Effect:")} ${theme6.fg("muted", this.presentation.authorizationCopy)}`;
15394
+ return [
15395
+ fitLine(`${tier}${dotSep(theme6)}${requested}`, width),
15396
+ ...wrapTextWithAnsi(effect, width).map((line) => fitLine(line, width)),
15397
+ ...wrapTextWithAnsi(theme6.fg("muted", this.presentation.reversibilityCopy), width).map(
15398
+ (line) => fitLine(line, width)
15399
+ )
15400
+ ];
15215
15401
  }
15216
15402
  /**
15217
15403
  * The keys for this question, plus the scroll keys when there is something to
@@ -15649,8 +15835,8 @@ function openAskUserOverlay(tui, deps) {
15649
15835
  // the terminal has left after the margins.
15650
15836
  ...geometry.maxInnerRows > 0 ? { maxHeight: geometry.maxInnerRows + ASK_USER_FRAME_ROWS } : {},
15651
15837
  margin: geometry.margin,
15652
- title: () => view.isDecisionPending() ? ASK_USER_DECISION_TITLE : ASK_USER_WAITING_TITLE,
15653
- tone: () => view.isDecisionPending() ? ASK_USER_DECISION_TONE : void 0,
15838
+ title: () => view.isDecisionPending() ? view.decisionTitle() : ASK_USER_WAITING_TITLE,
15839
+ tone: () => view.isDecisionPending() ? view.decisionTone() : void 0,
15654
15840
  footerHint: () => view.footerHint()
15655
15841
  });
15656
15842
  mounted = surface;
@@ -15669,7 +15855,7 @@ function openAskUserOverlay(tui, deps) {
15669
15855
  focus: () => handle?.focus(),
15670
15856
  unfocus: (options) => options ? handle?.unfocus(options) : handle?.unfocus(),
15671
15857
  isFocused: () => handle?.isFocused() ?? false,
15672
- ask: (questions) => view.begin(questions),
15858
+ ask: (questions, presentation) => view.begin(questions, presentation),
15673
15859
  cancel: () => view.cancel(),
15674
15860
  close,
15675
15861
  hide: close,
@@ -15724,7 +15910,7 @@ function createOverlayAskUserLifecycle(deps) {
15724
15910
  const activeSession = ensureSession();
15725
15911
  if (!activeSession) return cancelledAskUserResult();
15726
15912
  pendingCancel = cancel;
15727
- const result = await activeSession.ask(questions);
15913
+ const result = await activeSession.ask(questions, invokeOptions?.decisionPresentation);
15728
15914
  if (result.cancelled === true || !toolBacked) {
15729
15915
  if (result.cancelled === true) cancelledForTurn = true;
15730
15916
  close();
@@ -16238,7 +16424,14 @@ function coldReasonLabel(reason) {
16238
16424
  return reason;
16239
16425
  }
16240
16426
  }
16241
- function renderWorkingSetLines(view) {
16427
+ function workingSetPolicyLabel(view, config) {
16428
+ if (config === null || config === void 0) return `policy ${view.lastPolicyId ?? "none"}`;
16429
+ if (!config.enabled) return "disabled";
16430
+ const state = view.evictionEvents === 0 ? " \xB7 no events yet" : "";
16431
+ const lastRan = view.lastPolicyId !== null && view.lastPolicyId !== config.policy ? ` (last event by ${view.lastPolicyId})` : "";
16432
+ return `policy ${config.policy}${lastRan}${state}`;
16433
+ }
16434
+ function renderWorkingSetLines(view, config) {
16242
16435
  const theme6 = clioTheme();
16243
16436
  const items = view.evicted.size;
16244
16437
  const summary = [
@@ -16249,11 +16442,11 @@ function renderWorkingSetLines(view) {
16249
16442
  `churn ${formatChurn(view)}`
16250
16443
  ].join(" \xB7 ");
16251
16444
  return [
16252
- `${theme6.fg("muted", "working set")} ${theme6.fg("dim", "\xB7")} ${theme6.fg("accent", `policy ${view.lastPolicyId ?? "none"}`)}`,
16445
+ `${theme6.fg("muted", "working set")} ${theme6.fg("dim", "\xB7")} ${theme6.fg("accent", workingSetPolicyLabel(view, config))}`,
16253
16446
  theme6.fg("dim", summary)
16254
16447
  ];
16255
16448
  }
16256
- function renderContextLedgerLines(ledger, contentWidth, workingSet) {
16449
+ function renderContextLedgerLines(ledger, contentWidth, workingSet, workingSetConfig) {
16257
16450
  const theme6 = clioTheme();
16258
16451
  const lines = [];
16259
16452
  const provider = ledger.provider ?? "no target";
@@ -16267,7 +16460,8 @@ function renderContextLedgerLines(ledger, contentWidth, workingSet) {
16267
16460
  lines.push("");
16268
16461
  if (ledger.contextWindow > 0) {
16269
16462
  const source = ledger.measured ? "measured" : "\u2248 estimated";
16270
- const summary = `${formatTokens(ledger.usedTokens)} / ${formatTokens(ledger.contextWindow)} tokens (${formatContextPercent(ledger.percent)})`;
16463
+ const window = ledger.contextWindowSlots ? formatContextWindowSlots(ledger.contextWindow, ledger.contextWindowSlots) : formatTokens(ledger.contextWindow);
16464
+ const summary = `${formatTokens(ledger.usedTokens)} / ${window} tokens (${formatContextPercent(ledger.percent)})`;
16271
16465
  const provenance = contextWindowProvenanceLabel(ledger.contextWindowSource);
16272
16466
  const trailer = provenance ? `${provenance} window \xB7 ${source}` : source;
16273
16467
  lines.push(`${theme6.fg("title", summary)} ${theme6.fg("dim", "\xB7")} ${theme6.fg("muted", trailer)}`);
@@ -16281,7 +16475,7 @@ function renderContextLedgerLines(ledger, contentWidth, workingSet) {
16281
16475
  if (workingSet && workingSet.evicted.size > 0) lines.push(renderEvictedTokensLine(evictedTokens(workingSet), theme6));
16282
16476
  lines.push("");
16283
16477
  if (workingSet) {
16284
- for (const line of renderWorkingSetLines(workingSet)) lines.push(line);
16478
+ for (const line of renderWorkingSetLines(workingSet, workingSetConfig)) lines.push(line);
16285
16479
  lines.push("");
16286
16480
  }
16287
16481
  if (ledger.projectPreload && ledger.groups.some((group) => group.category === "project")) {
@@ -16317,7 +16511,12 @@ function renderContextLedgerLines(ledger, contentWidth, workingSet) {
16317
16511
  }
16318
16512
  var STREAMING_FALLBACK_TICK_MS = 1e3;
16319
16513
  function openContextOverlay(tui, getLedger, options) {
16320
- const render2 = () => renderContextLedgerLines(getLedger(), DEFAULT_CONTENT_WIDTH, options?.getWorkingSet?.() ?? null).join("\n");
16514
+ const render2 = () => renderContextLedgerLines(
16515
+ getLedger(),
16516
+ DEFAULT_CONTENT_WIDTH,
16517
+ options?.getWorkingSet?.() ?? null,
16518
+ options?.getWorkingSetConfig?.() ?? null
16519
+ ).join("\n");
16321
16520
  const text = new Text(render2(), 0, 0);
16322
16521
  const handle = showClioOverlayFrame(tui, text, {
16323
16522
  anchor: "center",
@@ -16384,7 +16583,7 @@ function formatTokens2(n) {
16384
16583
  function aggregateCostEntries(entries) {
16385
16584
  const grouped = /* @__PURE__ */ new Map();
16386
16585
  for (const entry of entries) {
16387
- const key = `${entry.providerId}::${entry.modelId}`;
16586
+ const key = `${entry.providerId}::${entry.attributedModelId}`;
16388
16587
  const existing = grouped.get(key);
16389
16588
  if (existing) {
16390
16589
  existing.row.runs += 1;
@@ -16395,13 +16594,18 @@ function aggregateCostEntries(entries) {
16395
16594
  existing.row.cacheWrite += entry.cacheWrite;
16396
16595
  existing.row.reasoningTokens += entry.reasoningTokens;
16397
16596
  existing.row.apiCalls += entry.apiCalls ?? 1;
16597
+ for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
16598
+ addResponseModelIdObservationCounts(
16599
+ existing.responseModelIdObservationCounts,
16600
+ entry.responseModelIdObservationCounts
16601
+ );
16398
16602
  existing.entries.push(entry);
16399
16603
  continue;
16400
16604
  }
16401
16605
  grouped.set(key, {
16402
16606
  row: {
16403
16607
  providerId: entry.providerId,
16404
- modelId: entry.modelId,
16608
+ attributedModelId: entry.attributedModelId,
16405
16609
  runs: 1,
16406
16610
  tokens: entry.tokens,
16407
16611
  input: entry.input,
@@ -16411,16 +16615,20 @@ function aggregateCostEntries(entries) {
16411
16615
  reasoningTokens: entry.reasoningTokens,
16412
16616
  apiCalls: entry.apiCalls ?? 1
16413
16617
  },
16618
+ requestedModelIds: new Set(entry.requestedModelIds),
16619
+ responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
16414
16620
  entries: [entry]
16415
16621
  });
16416
16622
  }
16417
- const rows = Array.from(grouped.values(), ({ row: row2, entries: entries2 }) => ({
16623
+ const rows = Array.from(grouped.values(), ({ row: row2, entries: entries2, requestedModelIds, responseModelIdObservationCounts }) => ({
16418
16624
  ...row2,
16625
+ requestedModelIds: [...requestedModelIds].sort(),
16626
+ responseModelIdObservationCounts,
16419
16627
  cost: aggregateCostAmounts(entries2.map((entry) => ({ usd: entry.usd, provenance: entry.provenance })))
16420
16628
  }));
16421
16629
  rows.sort((a, b) => {
16422
16630
  if (a.providerId !== b.providerId) return a.providerId < b.providerId ? -1 : 1;
16423
- if (a.modelId !== b.modelId) return a.modelId < b.modelId ? -1 : 1;
16631
+ if (a.attributedModelId !== b.attributedModelId) return a.attributedModelId < b.attributedModelId ? -1 : 1;
16424
16632
  return 0;
16425
16633
  });
16426
16634
  return rows;
@@ -16477,6 +16685,8 @@ function summaryBlock(totalCost, totalTokens, rows) {
16477
16685
  function modelBlock(row2) {
16478
16686
  const cost = formatCostAggregate(row2.cost);
16479
16687
  return kvBlock([
16688
+ ["requested model ids", row2.requestedModelIds.join(", ")],
16689
+ ["response model id observation", responseModelIdObservationCountsLabel(row2.responseModelIdObservationCounts)],
16480
16690
  ["turns", formatTokens2(row2.runs)],
16481
16691
  ["model calls", formatTokens2(row2.apiCalls)],
16482
16692
  ...cost === null ? [] : [["cost", cost]],
@@ -16500,7 +16710,7 @@ function formatCostOverlayBodyLines(totalCost, totalTokens, rows, contentWidth)
16500
16710
  } else {
16501
16711
  for (const [index, row2] of rows.entries()) {
16502
16712
  if (index > 0) lines.push("");
16503
- lines.push(theme6.style("accent", `${row2.providerId} \xB7 ${row2.modelId}`, { bold: true }));
16713
+ lines.push(theme6.style("accent", `${row2.providerId} \xB7 attributed model ${row2.attributedModelId}`, { bold: true }));
16504
16714
  for (const line of modelBlock(row2)) {
16505
16715
  lines.push(line);
16506
16716
  }
@@ -17135,9 +17345,10 @@ function memorySignature(status, records) {
17135
17345
  return parts.join("|");
17136
17346
  }
17137
17347
  var MemoryOverlayView = class {
17138
- constructor(getStatus, getRecords, onClose, onChange) {
17348
+ constructor(getStatus, getRecords, onClose, onChange, promotion) {
17139
17349
  this.getStatus = getStatus;
17140
17350
  this.getRecords = getRecords;
17351
+ this.promotion = promotion;
17141
17352
  this.list = new ListOverlayView(
17142
17353
  {
17143
17354
  title: "Memory",
@@ -17145,6 +17356,16 @@ var MemoryOverlayView = class {
17145
17356
  filterable: true,
17146
17357
  layout: "split",
17147
17358
  emptyMessage: EMPTY_MESSAGE,
17359
+ ...promotion ? {
17360
+ hints: [
17361
+ { key: "p", verb: "propose repo" },
17362
+ { key: "g", verb: "propose global" }
17363
+ ],
17364
+ actions: {
17365
+ p: (item) => this.promote(item, "repo", onChange),
17366
+ g: (item) => this.promote(item, "global", onChange)
17367
+ }
17368
+ } : {},
17148
17369
  onClose
17149
17370
  },
17150
17371
  onChange
@@ -17152,9 +17373,13 @@ var MemoryOverlayView = class {
17152
17373
  }
17153
17374
  getStatus;
17154
17375
  getRecords;
17376
+ promotion;
17155
17377
  list;
17156
17378
  signature = null;
17157
17379
  renderMemo = null;
17380
+ pendingGlobalEntryId = null;
17381
+ promotionMessage = null;
17382
+ promotionInFlight = false;
17158
17383
  getHint() {
17159
17384
  this.sync();
17160
17385
  return this.list.getHint();
@@ -17162,11 +17387,19 @@ var MemoryOverlayView = class {
17162
17387
  render(width) {
17163
17388
  const status = this.sync();
17164
17389
  const statusLine = formatMemoryStatusLine(status, width);
17390
+ const promotionLine = this.promotionMessage === null ? null : fitUnits(clioTheme(), "", [clioTheme().fg(this.promotionMessage.token, this.promotionMessage.text)], width);
17391
+ const statusKey = promotionLine === null ? statusLine : `${statusLine}
17392
+ ${promotionLine}`;
17165
17393
  const listLines = this.list.render(width);
17166
17394
  const memo = this.renderMemo;
17167
- if (memo && memo.width === width && memo.status === statusLine && memo.listLines === listLines) return memo.lines;
17168
- const lines = [statusLine, rule(clioTheme(), width), ...listLines];
17169
- this.renderMemo = { width, status: statusLine, listLines, lines };
17395
+ if (memo && memo.width === width && memo.status === statusKey && memo.listLines === listLines) return memo.lines;
17396
+ const lines = [
17397
+ statusLine,
17398
+ ...promotionLine === null ? [] : [promotionLine],
17399
+ rule(clioTheme(), width),
17400
+ ...listLines
17401
+ ];
17402
+ this.renderMemo = { width, status: statusKey, listLines, lines };
17170
17403
  return lines;
17171
17404
  }
17172
17405
  handleInput(data) {
@@ -17187,13 +17420,62 @@ var MemoryOverlayView = class {
17187
17420
  }
17188
17421
  return status;
17189
17422
  }
17423
+ promote(item, scope, onChange) {
17424
+ if (this.promotion === void 0 || this.promotionInFlight) return;
17425
+ const entry = this.selectedBankEntry(item);
17426
+ if (entry === null) {
17427
+ this.pendingGlobalEntryId = null;
17428
+ this.promotionMessage = { token: "warning", text: "select a knowledge or procedural task-bank entry" };
17429
+ this.invalidate();
17430
+ onChange();
17431
+ return;
17432
+ }
17433
+ if (scope === "global" && this.pendingGlobalEntryId !== entry.id) {
17434
+ this.pendingGlobalEntryId = entry.id;
17435
+ this.promotionMessage = {
17436
+ token: "warning",
17437
+ text: `global scope broadens applicability for ${entry.id}; press g again to acknowledge`
17438
+ };
17439
+ this.invalidate();
17440
+ onChange();
17441
+ return;
17442
+ }
17443
+ this.pendingGlobalEntryId = null;
17444
+ this.promotionInFlight = true;
17445
+ this.promotionMessage = { token: "muted", text: `proposing ${entry.id} with ${scope} scope` };
17446
+ this.invalidate();
17447
+ onChange();
17448
+ void this.promotion.onPromote(entry, scope).then((result) => {
17449
+ this.promotionMessage = {
17450
+ token: "success",
17451
+ text: `${result.created ? "proposed" : "found existing"} ${result.record.id}; review, then run clio-coder memory approve ${result.record.id}`
17452
+ };
17453
+ }).catch((error) => {
17454
+ this.promotionMessage = {
17455
+ token: "error",
17456
+ text: `promotion failed: ${error instanceof Error ? error.message : String(error)}`
17457
+ };
17458
+ }).finally(() => {
17459
+ this.promotionInFlight = false;
17460
+ this.invalidate();
17461
+ onChange();
17462
+ });
17463
+ }
17464
+ selectedBankEntry(item) {
17465
+ if (!item.id.startsWith("bank:")) return null;
17466
+ const entryId = item.id.slice("bank:".length);
17467
+ const entry = bankEntries(this.getStatus().bank).find((candidate) => candidate.id === entryId);
17468
+ if (entry === void 0 || entry.kind === "status") return null;
17469
+ return entry;
17470
+ }
17190
17471
  };
17191
17472
  function openMemoryOverlay(tui, getStatus, getRecords, options = {}) {
17192
17473
  const view = new MemoryOverlayView(
17193
17474
  getStatus,
17194
17475
  getRecords,
17195
17476
  () => options.onClose?.(),
17196
- () => tui.requestRender()
17477
+ () => tui.requestRender(),
17478
+ options.onPromote ? { onPromote: options.onPromote } : void 0
17197
17479
  );
17198
17480
  const handle = showClioOverlayFrame(tui, view, {
17199
17481
  anchor: "center",
@@ -17322,9 +17604,10 @@ function selectableRows(interviews) {
17322
17604
  }
17323
17605
  function interviewHeader(interview, width, now) {
17324
17606
  const theme6 = clioTheme();
17607
+ const presentation = classifyDecisionPresentation(decisionFactsForAnswer(interview.exposure ?? "local"));
17325
17608
  const rounds = `${interview.roundCount} round${interview.roundCount === 1 ? "" : "s"}`;
17326
17609
  const status = interview.interviewStatus === "complete" ? theme6.fg("success", "complete") : theme6.fg("warning", "cancelled");
17327
- const heading = `${theme6.fg("accent", relativeTime(interview.endedAt, now))}${theme6.fg("dim", " \xB7 ")}${theme6.fg("muted", rounds)}${theme6.fg("dim", " \xB7 ")}${status}`;
17610
+ const heading = `${theme6.style(presentation.semanticToken, presentation.tierLabel, { bold: true })}${theme6.fg("dim", " \xB7 ")}${theme6.fg("accent", relativeTime(interview.endedAt, now))}${theme6.fg("dim", " \xB7 ")}${theme6.fg("muted", rounds)}${theme6.fg("dim", " \xB7 ")}${status}`;
17328
17611
  const lines = [fitLine3(heading, width)];
17329
17612
  if (interview.summary) {
17330
17613
  lines.push(...wrapTextWithAnsi(theme6.fg("dim", interview.summary), width).map((line) => fitLine3(line, width)));
@@ -21943,7 +22226,7 @@ ${usage}` : usage);
21943
22226
  },
21944
22227
  {
21945
22228
  name: "memory",
21946
- description: "Inspect task memory or seed it from the newest handoff",
22229
+ description: "Inspect, promote, or seed task memory",
21947
22230
  group: "Inspect",
21948
22231
  kinds: ["memory", "memory-seed"],
21949
22232
  subcommandDescriptions: { seed: "Seed the task bank from the newest handoff" },
@@ -22700,6 +22983,10 @@ function createOverlayGeneralOpeners(deps) {
22700
22983
  const readSessionEntries = deps.readSessionEntries;
22701
22984
  if (!readSessionEntries) return null;
22702
22985
  return foldWorkingSet(readSessionEntries(), deps.getSessionMeta()?.pinnedLeafTurnId ?? void 0);
22986
+ },
22987
+ getWorkingSetConfig: () => {
22988
+ const workingSet = deps.getSettings?.().context.workingSet;
22989
+ return workingSet ? { enabled: workingSet.enabled, policy: workingSet.policy } : null;
22703
22990
  }
22704
22991
  });
22705
22992
  deps.requestRender();
@@ -22795,7 +23082,30 @@ function createOverlayGeneralOpeners(deps) {
22795
23082
  }
22796
23083
  deps.transitions.state = "memory";
22797
23084
  deps.transitions.handle = openMemoryOverlayFactory(deps.tui, deps.getTaskMemoryStatus, () => records, {
22798
- onClose: deps.closeOverlay
23085
+ onClose: deps.closeOverlay,
23086
+ onPromote: async (entry, scope) => {
23087
+ const meta = deps.getSessionMeta();
23088
+ if (!meta) throw new Error("memory promotion requires an active session");
23089
+ const selection = scope === "global" ? { scope: "global", acknowledgeGlobal: true } : (() => {
23090
+ const repository = canonicalMemoryRepositoryIdentity(meta.cwd);
23091
+ if (repository === null) {
23092
+ throw new Error("repo promotion requires a canonical active repository identity");
23093
+ }
23094
+ return { scope: "repo", repository };
23095
+ })();
23096
+ const result = await proposeMemoryPromotion(
23097
+ deps.dataDir,
23098
+ {
23099
+ kind: "task-bank-entry",
23100
+ sessionId: meta.id,
23101
+ evidenceRefs: [`session-${meta.id}`],
23102
+ entry
23103
+ },
23104
+ selection
23105
+ );
23106
+ records = loadMemoryRecordsSync(deps.dataDir);
23107
+ return result;
23108
+ }
22799
23109
  });
22800
23110
  deps.requestRender();
22801
23111
  };
@@ -22836,6 +23146,7 @@ function createOverlayGeneralOpeners(deps) {
22836
23146
  const dispatchBoardHint = () => {
22837
23147
  const row2 = deps.dispatchBoard.selectedRow();
22838
23148
  const entries = [{ key: "\u2191\u2193", verb: "select" }];
23149
+ if (row2) entries.push({ key: "Enter", verb: deps.dispatchBoard.detailExpanded() ? "hide detail" : "detail" });
22839
23150
  if (row2 && isDispatchBoardRowSteerable(row2)) entries.push({ key: "s", verb: "steer" });
22840
23151
  if (row2 && isDispatchBoardRowCancellable(row2)) entries.push({ key: "x", verb: "cancel" });
22841
23152
  return buildHint(entries);
@@ -22948,6 +23259,26 @@ init_esm_shims();
22948
23259
  init_esm_shims();
22949
23260
  var PERMISSION_OVERLAY_CONTENT_WIDTH = 78;
22950
23261
  var PERMISSION_OVERLAY_WIDTH = PERMISSION_OVERLAY_CONTENT_WIDTH + 4;
23262
+ function permissionOverlayPlacement(tui, editor, footer) {
23263
+ const margin = { bottom: 0 };
23264
+ return {
23265
+ anchor: "bottom-center",
23266
+ margin,
23267
+ visible: (termWidth, termHeight) => {
23268
+ const dockHeight = editor.render(termWidth).length + footer.render(termWidth).length;
23269
+ if (tui.mode === "fullscreen") {
23270
+ margin.bottom = dockHeight;
23271
+ return true;
23272
+ }
23273
+ const baseHeight = tui.render(termWidth).length;
23274
+ const composerTop = Math.max(0, baseHeight - dockHeight);
23275
+ const viewportStart = Math.max(0, baseHeight - termHeight);
23276
+ const composerViewportRow = composerTop - viewportStart;
23277
+ margin.bottom = composerViewportRow >= 0 && composerViewportRow < termHeight ? Math.max(0, termHeight - composerViewportRow) : dockHeight;
23278
+ return true;
23279
+ }
23280
+ };
23281
+ }
22951
23282
  var PermissionOverlayBody = class {
22952
23283
  constructor(view) {
22953
23284
  this.view = view;
@@ -22998,45 +23329,48 @@ function wrapArtifactLine(value, max) {
22998
23329
  lines.push(remaining);
22999
23330
  return lines;
23000
23331
  }
23001
- function axisLabel(axis, style) {
23002
- if (axis.kind === "net") return `safety-net rail ${axis.ruleId}`;
23003
- return style === "worker" ? `autonomy level ${axis.level}` : `autonomy level (${axis.level})`;
23332
+ function permissionDecisionPresentation(view) {
23333
+ return classifyDecisionPresentation(
23334
+ decisionFactsForPermission({
23335
+ tool: view.tool,
23336
+ actionClass: view.actionClass,
23337
+ axis: view.axis.kind === "net" ? { kind: "safety-net", ruleId: view.axis.ruleId } : { kind: "autonomy", level: view.axis.level },
23338
+ origin: view.origin,
23339
+ ...view.exposure !== void 0 ? { exposure: view.exposure } : {}
23340
+ })
23341
+ );
23004
23342
  }
23005
- function askedBy(view) {
23006
- if (view.origin.kind === "worker") {
23007
- return `worker ${view.origin.agentId} (run ${view.origin.runId}), ${axisLabel(view.axis, "worker")}`;
23008
- }
23009
- return axisLabel(view.axis, "main");
23343
+ function permissionOverlayTitle(view) {
23344
+ return permissionDecisionPresentation(view).title;
23010
23345
  }
23011
- function permissionOverlayTitle() {
23012
- return "Allow this action once?";
23346
+ function permissionOverlayTone(view) {
23347
+ return permissionDecisionPresentation(view).semanticToken;
23348
+ }
23349
+ function permissionOverlayHint(innerWidth, composerHasDraft = false) {
23350
+ return fitHintEntries(permissionHintEntries(composerHasDraft), innerWidth - 3);
23351
+ }
23352
+ function actionConsequence(presentation, id) {
23353
+ return presentation.requiredActions.find((action) => action.id === id)?.consequence ?? "";
23013
23354
  }
23014
- var permissionOverlayHint = buildResponsiveHint(
23015
- [
23016
- { key: "Enter", verb: "allow once", short: "allow", critical: true },
23017
- { key: "s", verb: "stop turn", short: "stop", critical: true }
23018
- ],
23019
- { key: "Esc", verb: "close", critical: false }
23020
- );
23021
- var SAFETY_SENTENCES = [
23022
- "Parked until you decide; allow or deny applies to this call only.",
23023
- "Stopping the turn denies it and ends the run, so nothing asks again.",
23024
- "Hard-blocked actions remain blocked."
23025
- ];
23026
23355
  function permissionOverlayLines(view, width) {
23027
23356
  const content = Math.max(8, Math.floor(width));
23357
+ const presentation = permissionDecisionPresentation(view);
23028
23358
  const lines = [
23029
- field("Tool: ", view.tool, content),
23359
+ field("Tool: ", `${view.tool} \xB7 Action: ${view.actionClass}`, content),
23030
23360
  ...view.target !== void 0 && view.target.length > 0 ? [field("Target: ", view.target, content)] : [],
23031
- field("Action: ", view.actionClass, content),
23032
- field("Asked by: ", askedBy(view), content),
23361
+ ...wrapSentence(`Requested by: ${presentation.requestedByCopy}`, content),
23033
23362
  ...view.artifact !== void 0 ? [
23034
23363
  "",
23035
23364
  "Resolved dispatch plan:",
23036
23365
  ...view.artifact.text.split(/\r?\n/u).flatMap((line) => wrapArtifactLine(line, content))
23037
23366
  ] : [],
23038
23367
  "",
23039
- ...SAFETY_SENTENCES.flatMap((sentence) => wrapSentence(sentence, content))
23368
+ ...wrapSentence(`Approval: ${presentation.authorizationCopy}`, content),
23369
+ ...wrapSentence(`Consequence: ${presentation.consequenceCopy}`, content),
23370
+ ...wrapSentence(presentation.reversibilityCopy, content),
23371
+ ...wrapSentence(`Deny: ${actionConsequence(presentation, "deny")}`, content),
23372
+ ...wrapSentence(`Stop: ${actionConsequence(presentation, "stop")}`, content),
23373
+ ...wrapSentence("Hard-blocked actions remain blocked.", content)
23040
23374
  ];
23041
23375
  if (view.queueDepth !== void 0 && view.queueDepth > 1) {
23042
23376
  lines.splice(lines.indexOf(""), 0, `1 of ${view.queueDepth} parked`);
@@ -23251,7 +23585,7 @@ function mainApprovalRequestView(call, decision, meta, autonomy, queueDepth) {
23251
23585
  const axisFromMeta = axisViewFromId(meta?.axis, autonomy);
23252
23586
  const axisFromDecision = askAxis(decision);
23253
23587
  const axis = axisFromMeta ?? (axisFromDecision.kind === "net" ? { kind: "net", ruleId: axisFromDecision.ruleId } : { kind: "autonomy", level: autonomy });
23254
- const target = describeCallTarget(call.args);
23588
+ const target = describeCallTarget(call.tool, call.args);
23255
23589
  return {
23256
23590
  requestId: meta?.requestId ?? "permission-pending",
23257
23591
  tool: call.tool,
@@ -23260,6 +23594,7 @@ function mainApprovalRequestView(call, decision, meta, autonomy, queueDepth) {
23260
23594
  origin: { kind: "main" },
23261
23595
  reason: decision.kind === "ask" ? decision.rejection.short : `${call.tool} requests ${decision.classification.actionClass}`,
23262
23596
  ...call.tool === ToolNames.Dispatch && decision.kind === "ask" ? { artifact: { kind: "dispatch-plan", text: decision.rejection.detail } } : {},
23597
+ ...call.tool === ToolNames.AskUser ? { exposure: askUserExposure(call.args) } : {},
23263
23598
  ...target.length > 0 ? { target } : {},
23264
23599
  ...queueDepth !== void 0 && queueDepth > 1 ? { queueDepth } : {}
23265
23600
  };
@@ -23274,7 +23609,7 @@ function workerEscalationEntry(payload, autonomy) {
23274
23609
  requestId: payload.requestId,
23275
23610
  agentId: typeof payload.agentId === "string" ? payload.agentId : "worker",
23276
23611
  tool: typeof payload.tool === "string" ? payload.tool : "unknown",
23277
- actionClass: typeof payload.actionClass === "string" ? payload.actionClass : "unknown",
23612
+ actionClass: decisionActionClass(payload.actionClass),
23278
23613
  axis: axisViewFromId(typeof payload.axis === "string" ? payload.axis : void 0, autonomy) ?? (typeof payload.ruleId === "string" ? { kind: "net", ruleId: payload.ruleId } : { kind: "autonomy", level: autonomy }),
23279
23614
  reason: payload.rejection?.short ?? (typeof payload.summary === "string" ? payload.summary : `${payload.tool ?? "worker"} requires approval`),
23280
23615
  ...typeof payload.target === "string" && payload.target.length > 0 ? { target: sanitizeCallTargetText(payload.target).slice(0, 200) } : {}
@@ -23310,6 +23645,12 @@ function createOverlayPermissionLifecycle(deps) {
23310
23645
  const next = workerQueue.shift();
23311
23646
  if (next) openWorker(next);
23312
23647
  };
23648
+ const retryPending = () => {
23649
+ maybeOpenWorker();
23650
+ if (deps.getOverlayState() === "closed" && deps.toolRegistry?.hasParkedCalls()) {
23651
+ deps.toolRegistry.renotifyHead();
23652
+ }
23653
+ };
23313
23654
  const unsubscribePermission = deps.toolRegistry?.onPermissionRequired((call, decision, meta) => {
23314
23655
  const autonomy = deps.getAutonomy();
23315
23656
  const view = mainApprovalRequestView(call, decision, meta, autonomy, deps.toolRegistry?.parkedCount());
@@ -23415,10 +23756,7 @@ function createOverlayPermissionLifecycle(deps) {
23415
23756
  workerQueue.length = 0;
23416
23757
  return;
23417
23758
  }
23418
- maybeOpenWorker();
23419
- if (deps.getOverlayState() === "closed" && deps.toolRegistry?.hasParkedCalls()) {
23420
- deps.toolRegistry.renotifyHead();
23421
- }
23759
+ retryPending();
23422
23760
  };
23423
23761
  return {
23424
23762
  confirm: () => {
@@ -23435,6 +23773,7 @@ function createOverlayPermissionLifecycle(deps) {
23435
23773
  );
23436
23774
  },
23437
23775
  onPermissionOverlayClosed,
23776
+ retryPending,
23438
23777
  dispose: () => {
23439
23778
  unsubscribePermission();
23440
23779
  unsubscribeWorker();
@@ -24139,9 +24478,9 @@ init_esm_shims();
24139
24478
 
24140
24479
  // src/domains/session/cwd-fallback.ts
24141
24480
  init_esm_shims();
24142
- import { existsSync as existsSync6, statSync as statSync2 } from "node:fs";
24481
+ import { existsSync as existsSync7, statSync as statSync2 } from "node:fs";
24143
24482
  var defaultFsProbe = {
24144
- exists: (p) => existsSync6(p),
24483
+ exists: (p) => existsSync7(p),
24145
24484
  isDirectory: (p) => {
24146
24485
  try {
24147
24486
  return statSync2(p).isDirectory();
@@ -24889,7 +25228,7 @@ function payloadRecord2(value) {
24889
25228
  function positiveNumber(value) {
24890
25229
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
24891
25230
  }
24892
- function nonEmptyString2(source, ...keys) {
25231
+ function nonEmptyString3(source, ...keys) {
24893
25232
  for (const key of keys) {
24894
25233
  const value = source[key];
24895
25234
  if (typeof value === "string" && value.trim().length > 0) return value;
@@ -24958,6 +25297,10 @@ function lastTurnSummaryFromLedger(entries, defaults = {}, activeLeafTurnId) {
24958
25297
  let toolErrorCount = 0;
24959
25298
  let targetId = turn.targetId;
24960
25299
  let modelId = turn.modelId;
25300
+ let responseModelIdObservation = {
25301
+ state: "legacy-difference-only",
25302
+ differingModelId: null
25303
+ };
24961
25304
  for (const row2 of turn.rows) {
24962
25305
  const record2 = payloadRecord2(row2.payload);
24963
25306
  if (row2.role === "tool_result") {
@@ -24969,8 +25312,9 @@ function lastTurnSummaryFromLedger(entries, defaults = {}, activeLeafTurnId) {
24969
25312
  sawAssistant = true;
24970
25313
  const reason = stopReasonOf(record2.stopReason);
24971
25314
  if (reason && reason !== "stop") stopReason = reason;
24972
- targetId = targetId ?? nonEmptyString2(record2, "provider", "api");
24973
- modelId = modelId ?? nonEmptyString2(record2, "responseModel", "model");
25315
+ targetId = targetId ?? nonEmptyString3(record2, "provider", "api");
25316
+ modelId = modelId ?? nonEmptyString3(record2, "model");
25317
+ responseModelIdObservation = responseModelIdObservationFromRecord(record2, "legacy-difference-only");
24974
25318
  const usage = payloadRecord2(record2.usage);
24975
25319
  if (!usage) continue;
24976
25320
  inputTokens += positiveNumber(usage.input);
@@ -24997,7 +25341,8 @@ function lastTurnSummaryFromLedger(entries, defaults = {}, activeLeafTurnId) {
24997
25341
  toolErrorCount,
24998
25342
  stopReason,
24999
25343
  watchdogPeak: 0,
25000
- truncated: false
25344
+ truncated: false,
25345
+ responseModelIdObservation
25001
25346
  };
25002
25347
  if (sawReasoning) {
25003
25348
  summary.reasoningTokens = reasoningTokens;
@@ -25020,15 +25365,32 @@ function reseedSessionUsageFromLedger(sink, entries, defaults = {}, activeLeafTu
25020
25365
  sink.resetSession();
25021
25366
  const scoped = filterEntriesToActivePath(entries, activeLeafTurnId ?? void 0);
25022
25367
  for (const call of ledgerUsageCalls(scoped, defaults)) {
25023
- sink.recordTokens(call.providerId, call.modelId, call.totalTokens, call.costUsd, {
25024
- input: call.input,
25025
- output: call.output,
25026
- cacheRead: call.cacheRead,
25027
- cacheWrite: call.cacheWrite,
25028
- reasoningTokens: call.reasoningTokens,
25029
- totalTokens: call.totalTokens,
25030
- apiCalls: call.apiCalls ?? 1
25031
- });
25368
+ const responseModelIdObservationCounts = emptyResponseModelIdObservationCounts();
25369
+ addResponseModelIdObservationCount(
25370
+ responseModelIdObservationCounts,
25371
+ call.responseModelIdObservation,
25372
+ call.apiCalls ?? 1
25373
+ );
25374
+ sink.recordTokens(
25375
+ call.providerId,
25376
+ call.attributedModelId,
25377
+ call.totalTokens,
25378
+ call.costUsd,
25379
+ {
25380
+ input: call.input,
25381
+ output: call.output,
25382
+ cacheRead: call.cacheRead,
25383
+ cacheWrite: call.cacheWrite,
25384
+ reasoningTokens: call.reasoningTokens,
25385
+ totalTokens: call.totalTokens,
25386
+ apiCalls: call.apiCalls ?? 1
25387
+ },
25388
+ void 0,
25389
+ {
25390
+ requestedModelIds: [call.requestedModelId],
25391
+ responseModelIdObservationCounts
25392
+ }
25393
+ );
25032
25394
  }
25033
25395
  }
25034
25396
 
@@ -25257,7 +25619,9 @@ function createOverlayTransitions(deps) {
25257
25619
  return state;
25258
25620
  },
25259
25621
  set state(next) {
25622
+ const closing = state !== "closed" && next === "closed";
25260
25623
  state = next;
25624
+ if (closing) deps.onOverlayClosed?.();
25261
25625
  },
25262
25626
  get handle() {
25263
25627
  return handle;
@@ -25280,6 +25644,7 @@ function createOverlayTransitions(deps) {
25280
25644
  handle?.hide();
25281
25645
  handle = null;
25282
25646
  if (leaving === "permission-confirm") deps.onPermissionOverlayClosed();
25647
+ else deps.onOverlayClosed?.();
25283
25648
  deps.renderContextIsland();
25284
25649
  deps.renderTaskIsland();
25285
25650
  deps.requestRender();
@@ -25291,9 +25656,17 @@ init_esm_shims();
25291
25656
  function isEscapeKey(data) {
25292
25657
  return matchesKey(data, "escape") && !isKeyRelease(data);
25293
25658
  }
25659
+ var DRAFT_EDIT_KEYS = ["backspace", "delete", "ctrl+u", "ctrl+w", "alt+backspace", "ctrl+k"];
25660
+ function isDraftEditKey(data) {
25661
+ return !isKeyRelease(data) && DRAFT_EDIT_KEYS.some((key) => matchesKey(data, key));
25662
+ }
25294
25663
  function routePermissionOverlayKey(data, deps) {
25295
25664
  if (matchesKey(data, "enter") && !isKeyRelease(data)) {
25296
- deps.confirmPermission();
25665
+ if (!(deps.composerHasDraft?.() ?? false)) deps.confirmPermission();
25666
+ return true;
25667
+ }
25668
+ if (deps.editDraft && isDraftEditKey(data)) {
25669
+ deps.editDraft(data);
25297
25670
  return true;
25298
25671
  }
25299
25672
  if (isEscapeKey(data)) {
@@ -25328,6 +25701,10 @@ function routeDispatchBoardOverlayKey(data, deps) {
25328
25701
  deps.cancelSelectedDispatch();
25329
25702
  return true;
25330
25703
  }
25704
+ if (matchesKey(data, "enter")) {
25705
+ deps.toggleSelectedDispatchDetail();
25706
+ return true;
25707
+ }
25331
25708
  return false;
25332
25709
  }
25333
25710
  function routeAuthOverlayKey(data, deps) {
@@ -25467,7 +25844,8 @@ function createOverlayLifecycle(deps) {
25467
25844
  requestRender: () => tui.requestRender(),
25468
25845
  cancelPendingAskUser: () => overlayAskUser?.cancelPending() ?? false,
25469
25846
  finishAuth: (dismiss) => overlayAuth.finish(dismiss),
25470
- onPermissionOverlayClosed: () => overlayPermission?.onPermissionOverlayClosed()
25847
+ onPermissionOverlayClosed: () => overlayPermission?.onPermissionOverlayClosed(),
25848
+ onOverlayClosed: () => overlayPermission?.retryPending()
25471
25849
  });
25472
25850
  const closeOverlay = overlayTransitions.close;
25473
25851
  const overlayAuth = createOverlayAuthLifecycle({
@@ -25499,10 +25877,13 @@ function createOverlayLifecycle(deps) {
25499
25877
  if (overlayTransitions.state !== "closed") return false;
25500
25878
  overlayTransitions.state = "permission-confirm";
25501
25879
  overlayTransitions.handle = showOverlayFrame(tui, createPermissionOverlayBody(view), {
25502
- anchor: "center",
25880
+ ...permissionOverlayPlacement(tui, editor, footer.view),
25503
25881
  width: PERMISSION_OVERLAY_WIDTH,
25504
- title: permissionOverlayTitle(),
25505
- footerHint: (innerWidth) => permissionOverlayHint(innerWidth)
25882
+ title: permissionOverlayTitle(view),
25883
+ tone: permissionOverlayTone(view),
25884
+ // Read per frame: the footer names what Enter does right now, and
25885
+ // that depends on whether the composer holds a draft.
25886
+ footerHint: (innerWidth) => permissionOverlayHint(innerWidth, editor.getText().length > 0)
25506
25887
  });
25507
25888
  tui.requestRender();
25508
25889
  return true;
@@ -25617,6 +25998,7 @@ function createOverlayLifecycle(deps) {
25617
25998
  stateDir: deps.app.stateDir,
25618
25999
  getSessionMeta: () => deps.app.session?.current() ?? null,
25619
26000
  ...deps.app.readSessionEntries ? { readSessionEntries: deps.app.readSessionEntries } : {},
26001
+ ...deps.app.getSettings ? { getSettings: deps.app.getSettings } : {},
25620
26002
  terminal,
25621
26003
  dispatchBoard,
25622
26004
  startDispatchBoardTicker: () => interactiveTickers.startDispatchBoardTicker(),
@@ -27139,6 +27521,11 @@ function createInteractiveInputRuntime(deps) {
27139
27521
  cancelPermission: () => deps.overlay.closeOverlay(),
27140
27522
  confirmPermission: () => deps.overlay.confirmPermission(),
27141
27523
  stopTurnFromPermission: () => deps.overlay.stopTurnFromPermission(),
27524
+ composerHasDraft: () => deps.editor.getText().length > 0,
27525
+ editDraft: (data2) => {
27526
+ deps.editor.handleInput?.(data2);
27527
+ deps.requestRender();
27528
+ },
27142
27529
  closeOverlay: () => deps.overlay.closeOverlay(),
27143
27530
  selectPreviousDispatch: () => {
27144
27531
  deps.dispatchBoard.selectPrevious();
@@ -27148,6 +27535,10 @@ function createInteractiveInputRuntime(deps) {
27148
27535
  deps.dispatchBoard.selectNext();
27149
27536
  deps.requestRender();
27150
27537
  },
27538
+ toggleSelectedDispatchDetail: () => {
27539
+ deps.dispatchBoard.toggleDetail();
27540
+ deps.requestRender();
27541
+ },
27151
27542
  steerSelectedDispatch: deps.steerSelectedDispatch,
27152
27543
  cancelSelectedDispatch: deps.cancelSelectedDispatch,
27153
27544
  cancelAskUser: () => deps.overlay.cancelAskUser()
@@ -29721,7 +30112,7 @@ function processAutoPacingAllowed(backpressureObserved, env = process.env) {
29721
30112
 
29722
30113
  // src/interactive/welcome-dashboard.ts
29723
30114
  init_esm_shims();
29724
- import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
30115
+ import { existsSync as existsSync8, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
29725
30116
  import { basename as basename3, join as join8 } from "node:path";
29726
30117
  function activeStatus(status) {
29727
30118
  return status.available && status.health.status !== "down";
@@ -29789,7 +30180,7 @@ function wikiFactsFrom(cwd, staleness) {
29789
30180
  }
29790
30181
  function handoffFacts(cwd) {
29791
30182
  const handoffsDir = join8(cwd, ".clio-coder", "handoffs");
29792
- if (!existsSync7(handoffsDir)) return { handoffCount: 0, handoffFreshness: "none" };
30183
+ if (!existsSync8(handoffsDir)) return { handoffCount: 0, handoffFreshness: "none" };
29793
30184
  try {
29794
30185
  const files = readdirSync2(handoffsDir).filter((f) => f.startsWith("handoff-") && f.endsWith(".md"));
29795
30186
  if (files.length === 0) return { handoffCount: 0, handoffFreshness: "none" };
@@ -29833,7 +30224,7 @@ async function readWelcomeRepositoryFactsAsync(cwd) {
29833
30224
  function placeholderRepositoryFacts(cwd) {
29834
30225
  return {
29835
30226
  clioMdStatus: clioMdStatusFor(cwd),
29836
- hasCodewiki: existsSync7(join8(cwd, ".clio-coder", "codewiki.json")),
30227
+ hasCodewiki: existsSync8(join8(cwd, ".clio-coder", "codewiki.json")),
29837
30228
  codewikiCount: 0,
29838
30229
  wikiPageCount: 0,
29839
30230
  wikiStatus: NO_WIKI_STATUS,
@@ -30123,7 +30514,11 @@ function createInteractivePresentation(deps) {
30123
30514
  bus: deps.bus,
30124
30515
  ...deps.getSettings ? { getSettings: deps.getSettings } : {}
30125
30516
  });
30126
- const dispatchBoardStore = factories.createDispatchBoardStore(deps.bus, () => deps.dispatch.snapshot());
30517
+ const dispatchBoardStore = factories.createDispatchBoardStore(
30518
+ deps.bus,
30519
+ () => deps.dispatch.snapshot(),
30520
+ (runId) => readWorkerReceiptFacts(runId)
30521
+ );
30127
30522
  const contextActivityStore = factories.createContextActivityStore(deps.bus);
30128
30523
  const footerToolCounts = /* @__PURE__ */ new Map();
30129
30524
  const footerActiveTools = /* @__PURE__ */ new Set();
@@ -30268,6 +30663,7 @@ function createInteractivePresentation(deps) {
30268
30663
  )?.thinking.display ?? current?.orchestrator?.thinkingLevel ?? "off";
30269
30664
  },
30270
30665
  isStreaming: () => deps.chat.isStreaming(),
30666
+ ...deps.isAwaitingApproval ? { isAwaitingApproval: deps.isAwaitingApproval } : {},
30271
30667
  willEnterSteer: (text) => willEnterSteerActiveWork(deps, text),
30272
30668
  getSubmitKeyLabel: () => formatKeyLabel(keybindings.getKeys("tui.input.submit")[0], "Enter"),
30273
30669
  getNewlineKeyLabel: () => formatKeyLabel(keybindings.getKeys("tui.input.newLine")[0], "Shift+Enter")
@@ -30399,9 +30795,9 @@ function createInteractivePresentation(deps) {
30399
30795
  root,
30400
30796
  getObservabilitySnapshot: () => observabilitySnapshot,
30401
30797
  recordChatEvent,
30402
- recordToolStart: (toolCallId, toolName2) => {
30798
+ recordToolStart: (toolCallId, toolName) => {
30403
30799
  footerActiveTools.add(toolCallId);
30404
- footerToolCounts.set(toolName2, (footerToolCounts.get(toolName2) ?? 0) + 1);
30800
+ footerToolCounts.set(toolName, (footerToolCounts.get(toolName) ?? 0) + 1);
30405
30801
  },
30406
30802
  recordToolEnd: ({ toolCallId, isError, truncated }) => {
30407
30803
  footerActiveTools.delete(toolCallId);
@@ -31572,10 +31968,12 @@ async function createInteractiveApplication(deps) {
31572
31968
  const { readStructuredEntries, recordSubmittedTurn } = sessionTranscript;
31573
31969
  let leaderArmed = false;
31574
31970
  let shutdownArmed = false;
31971
+ let overlayLifecycle;
31575
31972
  const presentation = createInteractivePresentation({
31576
31973
  bus: deps.bus,
31577
31974
  getLeaderArmed: () => leaderArmed,
31578
31975
  getShutdownArmed: () => shutdownArmed,
31976
+ isAwaitingApproval: () => overlayLifecycle?.getState() === "permission-confirm",
31579
31977
  resolveVisibleEventSequence: (event) => visibleEventIngress.get(event)?.traceSequence ?? null,
31580
31978
  resolveStreamIngress: (event) => visibleEventIngress.get(event) ?? null,
31581
31979
  commitFrame: (reason) => shell.commitCurrentFrame(reason === "teardown" ? 300 : 3e4),
@@ -31644,7 +32042,7 @@ async function createInteractiveApplication(deps) {
31644
32042
  isAskUserWaiting: () => overlayLifecycle.isAskUserWaiting(),
31645
32043
  closeAskUserSession: () => overlayLifecycle.closeAskUserSession(),
31646
32044
  resetAskUserCancellation: () => overlayLifecycle.resetAskUserCancellation(),
31647
- recordToolStart: (toolName2, toolCallId) => presentation.recordToolStart(toolCallId, toolName2),
32045
+ recordToolStart: (toolName, toolCallId) => presentation.recordToolStart(toolCallId, toolName),
31648
32046
  recordToolEnd: (_toolName, toolCallId, isError, truncated) => presentation.recordToolEnd({ toolCallId, isError, truncated }),
31649
32047
  setStatusLine: (line) => chatPanel.setStatusLine(line),
31650
32048
  setLiveReasoning: (view) => chatPanel.setLiveReasoning(view),
@@ -31750,7 +32148,6 @@ async function createInteractiveApplication(deps) {
31750
32148
  notify
31751
32149
  });
31752
32150
  editor.onSubmit = editorSubmit.submitEditorText;
31753
- let overlayLifecycle;
31754
32151
  const interactiveTickers = createInteractiveTickers({
31755
32152
  tui,
31756
32153
  dispatchBoardStore,
@@ -32036,7 +32433,7 @@ import { resolve as resolve5 } from "node:path";
32036
32433
 
32037
32434
  // src/tools/dispatch-scout-admission.ts
32038
32435
  init_esm_shims();
32039
- import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
32436
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
32040
32437
  import { join as join10 } from "node:path";
32041
32438
  var MAX_SCOUT_PLAN_DEADLINE_MS = 36e5;
32042
32439
  function record(value) {
@@ -32085,7 +32482,7 @@ function loadVerifiedScoutSource(input) {
32085
32482
  const envelope = input.dispatch.getRun(input.ref.runId);
32086
32483
  if (envelope === null) throw new Error(`dispatch: Scout source run '${input.ref.runId}' is unavailable`);
32087
32484
  const receiptPath = envelope.receiptPath ?? join10(clioStateDir(), "receipts", `${input.ref.runId}.json`);
32088
- if (!existsSync8(receiptPath)) throw new Error(`dispatch: Scout source receipt '${input.ref.runId}' is unavailable`);
32485
+ if (!existsSync9(receiptPath)) throw new Error(`dispatch: Scout source receipt '${input.ref.runId}' is unavailable`);
32089
32486
  let receipt;
32090
32487
  try {
32091
32488
  receipt = JSON.parse(readFileSync8(receiptPath, "utf8"));
@@ -32678,6 +33075,24 @@ function createDispatchAdmissionController(deps) {
32678
33075
 
32679
33076
  // src/tools/dispatch.ts
32680
33077
  var THINKING_LEVELS2 = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
33078
+ var DispatchBudgetPhaseSchema = typebox_exports.Object(
33079
+ {
33080
+ toolCalls: typebox_exports.Integer({ minimum: 1 }),
33081
+ readReserve: typebox_exports.Integer({ minimum: 0 })
33082
+ },
33083
+ { additionalProperties: false }
33084
+ );
33085
+ var DispatchBudgetSchema = typebox_exports.Object(
33086
+ {
33087
+ toolCalls: typebox_exports.Integer({ minimum: 1, description: "Requested tool-call phase boundary." }),
33088
+ readReserve: typebox_exports.Integer({ minimum: 0, description: "Requested tail reserve for canonical read calls." }),
33089
+ retryRevision: typebox_exports.Optional(DispatchBudgetPhaseSchema)
33090
+ },
33091
+ {
33092
+ additionalProperties: false,
33093
+ description: "Invocation budget inside the recipe policy. retryRevision preauthorizes one ceiling for retry, result-contract revision, or review revision phases."
33094
+ }
33095
+ );
32681
33096
  function admissionFailureResult(message) {
32682
33097
  return {
32683
33098
  kind: "error",
@@ -32692,12 +33107,12 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
32692
33107
  const admission = createDispatchAdmissionController(deps);
32693
33108
  let runnerPromise = null;
32694
33109
  const loadRunner = () => {
32695
- runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-MSWN72NK.js")))();
33110
+ runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-GIJBHNFL.js")))();
32696
33111
  return runnerPromise;
32697
33112
  };
32698
33113
  return {
32699
33114
  name: ToolNames.Dispatch,
32700
- description: 'Dispatch one bounded task with task, or a batch with tasks (never both). Singular example: {agent:"debugger", task:"Verify the receipt boundary", briefing:"Prior receipt evidence...", detach:true}. task is the worker assignment; briefing is separate bounded parent context/data and cannot replace task. Ordinary calls auto-wait; detach:true returns ids for monitoring/steering, and collect is the authoritative terminal batch operation before final synthesis. Batch modes are parallel (default), sequential, pipeline, or compete. Task objects may include persona and tool_profile. Sealed receipts are durable evidence; report receipt integrity, evidence verification, briefing provenance, and project-context provenance separately. Call with list:true to see agents. Do not repeat an identical successful dispatch in the same user turn. Prefer this tool over inline exploration whenever work is read-only fan-out, parallel investigation, or the operator asked for a worker by name; if you cannot dispatch, say so plainly and name the reason, and never narrate or summarize a worker you did not actually dispatch.',
33115
+ description: 'Dispatch one bounded task with task, or a batch with tasks (never both). Singular example: {agent:"debugger", task:"Verify the receipt boundary", briefing:"Prior receipt evidence...", detach:true}. task is the worker assignment; briefing is separate bounded parent context/data and cannot replace task. Ordinary calls auto-wait; detach:true returns ids for monitoring/steering, and collect is the authoritative terminal batch operation before final synthesis. Batch modes are parallel (default), sequential, pipeline, or compete. Task objects may include persona, tool_profile, and a recipe-admitted budget envelope. Sealed receipts are durable evidence; report receipt integrity, evidence verification, briefing provenance, and project-context provenance separately. Call with list:true to see agents. Do not repeat an identical successful dispatch in the same user turn. Prefer this tool over inline exploration whenever work is read-only fan-out, parallel investigation, or the operator asked for a worker by name; if you cannot dispatch, say so plainly and name the reason, and never narrate or summarize a worker you did not actually dispatch.',
32701
33116
  parameters: typebox_exports.Object({
32702
33117
  list: typebox_exports.Optional(typebox_exports.Boolean({ description: "List available agents instead of dispatching." })),
32703
33118
  from_scout: typebox_exports.Optional(
@@ -32737,6 +33152,7 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
32737
33152
  tool_profile: typebox_exports.Optional(
32738
33153
  StringEnum(TOOL_PROFILE_NAMES, { description: "Narrow this worker's available tools." })
32739
33154
  ),
33155
+ budget: typebox_exports.Optional(DispatchBudgetSchema),
32740
33156
  target: typebox_exports.Optional(typebox_exports.String()),
32741
33157
  model: typebox_exports.Optional(typebox_exports.String()),
32742
33158
  node: typebox_exports.Optional(typebox_exports.String({ description: "Fleet node pin: local or a fleet.nodes id." })),
@@ -32818,6 +33234,7 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
32818
33234
  typebox_exports.String({ description: "Default ad-hoc specialist persona for dispatched tasks, max 8000 chars." })
32819
33235
  ),
32820
33236
  tool_profile: typebox_exports.Optional(StringEnum(TOOL_PROFILE_NAMES, { description: "Default worker tool profile." })),
33237
+ budget: typebox_exports.Optional(DispatchBudgetSchema),
32821
33238
  target: typebox_exports.Optional(typebox_exports.String({ description: "Default configured target id (omit for fleet default)." })),
32822
33239
  model: typebox_exports.Optional(typebox_exports.String({ description: "Default model override." })),
32823
33240
  node: typebox_exports.Optional(
@@ -32896,7 +33313,7 @@ function registerAllTools(registry, deps = {}) {
32896
33313
  ...builtin(
32897
33314
  lazyTool(
32898
33315
  monitorToolSurface,
32899
- async () => (await import("./monitor-2F3T5KHP.js")).createMonitorTool({ dispatch, runEvents: dispatchRunEvents })
33316
+ async () => (await import("./monitor-US5F5YGZ.js")).createMonitorTool({ dispatch, runEvents: dispatchRunEvents })
32900
33317
  ),
32901
33318
  {
32902
33319
  path: "src/tools/monitor.ts",
@@ -32970,11 +33387,11 @@ function createFileMutationObserver(sink) {
32970
33387
  hooks: ["after_tool"],
32971
33388
  evaluate(input) {
32972
33389
  if (input.metadata?.resultKind !== "ok") return NO_EFFECTS;
32973
- const toolName2 = input.toolName ?? "";
32974
- const paths = toolMutationPaths(toolName2, input.toolArgs !== void 0 ? { ...input.toolArgs } : void 0);
33390
+ const toolName = input.toolName ?? "";
33391
+ const paths = toolMutationPaths(toolName, input.toolArgs !== void 0 ? { ...input.toolArgs } : void 0);
32975
33392
  if (paths.length === 0) return NO_EFFECTS;
32976
33393
  try {
32977
- sink({ paths, toolName: toolName2 });
33394
+ sink({ paths, toolName });
32978
33395
  } catch {
32979
33396
  }
32980
33397
  return NO_EFFECTS;
@@ -33323,6 +33740,7 @@ async function bootOrchestrator(options = {}) {
33323
33740
  installBusTracer();
33324
33741
  termination.installSignalHandlers();
33325
33742
  ensureClioState();
33743
+ sweepExpiredToolOffloads();
33326
33744
  timer.mark("install check");
33327
33745
  if (isGitRepository(process.cwd())) {
33328
33746
  try {
@@ -33946,8 +34364,13 @@ async function bootOrchestrator(options = {}) {
33946
34364
  getMemorySection: () => {
33947
34365
  try {
33948
34366
  const records = loadMemoryRecordsSync(clioDataDir());
34367
+ const settings = getCurrentSettings();
34368
+ const targetId = session?.current()?.target ?? settings.orchestrator?.target;
34369
+ const runtimeId = targetId ? providers.getTarget(targetId)?.runtime : void 0;
33949
34370
  return buildMemoryPromptSection(records, {
33950
- activeRepository: canonicalMemoryRepositoryIdentity(process.cwd())
34371
+ scopes: ["global", "repo", "runtime"],
34372
+ activeRepository: canonicalMemoryRepositoryIdentity(process.cwd()),
34373
+ activeRuntime: runtimeId === void 0 ? null : { kind: "runtime", key: runtimeId }
33951
34374
  }).section;
33952
34375
  } catch {
33953
34376
  return "";
@@ -33955,7 +34378,17 @@ async function bootOrchestrator(options = {}) {
33955
34378
  },
33956
34379
  getTaskMemoryHandoffSource: () => {
33957
34380
  ensureTaskMemorySession();
33958
- return renderTaskMemoryHandoffSource(taskMemoryBank.snapshot());
34381
+ const meta = session?.current();
34382
+ if (!meta) throw new Error("task memory handoff requires an active session");
34383
+ const settings = getCurrentSettings();
34384
+ const targetId = meta.target ?? settings.orchestrator?.target;
34385
+ const runtimeId = targetId ? providers.getTarget(targetId)?.runtime : void 0;
34386
+ return renderTaskMemoryHandoffSource(taskMemoryBank.snapshot(), {
34387
+ sessionId: meta.id,
34388
+ evidenceRefs: [`session-${meta.id}`],
34389
+ runtimeIds: runtimeId === void 0 ? [] : [runtimeId],
34390
+ agentIds: []
34391
+ });
33959
34392
  },
33960
34393
  registerDeferredReminderSink: (sink) => {
33961
34394
  deferredMemoryReminderSink = sink;
@@ -34340,4 +34773,4 @@ export {
34340
34773
  resolveApiKeyForTarget,
34341
34774
  synthesizeOrchestratorModel
34342
34775
  };
34343
- //# sourceMappingURL=orchestrator-ORHT43JB.js.map
34776
+ //# sourceMappingURL=orchestrator-E2AL4T5N.js.map