@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
@@ -1,12 +1,7 @@
1
1
  import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
2
2
  import {
3
- DEFAULT_AUTONOMY_LEVEL,
4
- autonomyAskRejection,
5
- autonomyDenyRejection,
6
- isAutonomyLevel,
7
- mapAutonomy,
8
3
  typedValidationSummary
9
- } from "./chunk-7RXG6QRZ.js";
4
+ } from "./chunk-EKY57CSP.js";
10
5
  import {
11
6
  ROUTE_POLICY_VERSION,
12
7
  deriveExecutionRole,
@@ -31,6 +26,13 @@ import {
31
26
  expandPath,
32
27
  resolveReadPath
33
28
  } from "./chunk-OQE5J4C6.js";
29
+ import {
30
+ DEFAULT_AUTONOMY_LEVEL,
31
+ autonomyAskRejection,
32
+ autonomyDenyRejection,
33
+ isAutonomyLevel,
34
+ mapAutonomy
35
+ } from "./chunk-HWUFFB6L.js";
34
36
  import {
35
37
  DEFAULT_MAX_LINES,
36
38
  OBSERVATION_POLICY_SLACK_BYTES,
@@ -43,7 +45,7 @@ import {
43
45
  splitLinesForCounting,
44
46
  truncateHead,
45
47
  truncateTail
46
- } from "./chunk-5M54SPOL.js";
48
+ } from "./chunk-ODFEOB4F.js";
47
49
  import {
48
50
  formatSize
49
51
  } from "./chunk-OZNBF4L3.js";
@@ -799,10 +801,13 @@ function validateAllowedTools(value) {
799
801
  }
800
802
  function validateWorkerBudget(value) {
801
803
  const budget = readRecord(value, "WorkerSpec.budget");
802
- const expected = ["hardCap", "readReserve", "synthesis", "toolCalls"];
804
+ const expected = ["hardCap", "readReserve", "revision", "synthesis", "toolCalls"];
803
805
  const actual = Object.keys(budget).sort();
804
- if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
805
- throw new Error(`WorkerSpec.budget must contain exactly: ${expected.join(", ")}`);
806
+ if (actual.some((key) => !expected.includes(key)) || actual.some((key) => key === "revision" && budget.revision === void 0)) {
807
+ throw new Error(`WorkerSpec.budget may contain only: ${expected.join(", ")}`);
808
+ }
809
+ for (const required of ["hardCap", "readReserve", "synthesis", "toolCalls"]) {
810
+ if (!Object.hasOwn(budget, required)) throw new Error(`WorkerSpec.budget.${required} is required`);
806
811
  }
807
812
  for (const key of ["toolCalls", "readReserve", "hardCap"]) {
808
813
  const value2 = budget[key];
@@ -819,6 +824,30 @@ function validateWorkerBudget(value) {
819
824
  throw new Error("WorkerSpec.budget.readReserve must be an integer in [0, toolCalls)");
820
825
  }
821
826
  if (typeof budget.synthesis !== "boolean") throw new Error("WorkerSpec.budget.synthesis must be a boolean");
827
+ if (budget.revision !== void 0) {
828
+ const revision = readRecord(budget.revision, "WorkerSpec.budget.revision");
829
+ const revisionKeys = Object.keys(revision).sort();
830
+ if (revisionKeys.length !== 2 || revisionKeys[0] !== "readReserve" || revisionKeys[1] !== "toolCalls") {
831
+ throw new Error("WorkerSpec.budget.revision must contain exactly: readReserve, toolCalls");
832
+ }
833
+ for (const key of ["toolCalls", "readReserve"]) {
834
+ if (typeof revision[key] !== "number" || !Number.isSafeInteger(revision[key])) {
835
+ throw new Error(`WorkerSpec.budget.revision.${key} must be a safe integer`);
836
+ }
837
+ }
838
+ if (revision.toolCalls < budget.toolCalls) {
839
+ throw new Error("WorkerSpec.budget.revision.toolCalls must not be smaller than WorkerSpec.budget.toolCalls");
840
+ }
841
+ if (revision.toolCalls === budget.toolCalls && revision.readReserve <= budget.readReserve) {
842
+ throw new Error("WorkerSpec.budget.revision must increase toolCalls or readReserve");
843
+ }
844
+ if (revision.toolCalls > budget.hardCap) {
845
+ throw new Error("WorkerSpec.budget.revision.toolCalls must not exceed WorkerSpec.budget.hardCap");
846
+ }
847
+ if (revision.readReserve < 0 || revision.readReserve >= revision.toolCalls) {
848
+ throw new Error("WorkerSpec.budget.revision.readReserve must be an integer in [0, toolCalls)");
849
+ }
850
+ }
822
851
  }
823
852
  function validateRuntimeCapabilityDecision(value, source) {
824
853
  const caps = readRecord(value, source);
@@ -1042,6 +1071,293 @@ function validateRehydratedWorkerRuntime(spec, runtime) {
1042
1071
  }
1043
1072
  }
1044
1073
 
1074
+ // src/domains/dispatch/budget-envelope.ts
1075
+ init_esm_shims();
1076
+ var BudgetAdmissionError = class extends Error {
1077
+ code;
1078
+ constructor(code, message) {
1079
+ super(`dispatch: budget admission denied (${code}): ${message}`);
1080
+ this.name = "BudgetAdmissionError";
1081
+ this.code = code;
1082
+ }
1083
+ };
1084
+ function isRecord(value) {
1085
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1086
+ }
1087
+ function clonePhase(value, prefix) {
1088
+ if (!isRecord(value)) throw new Error(`${prefix} must be an object`);
1089
+ for (const key of Object.keys(value)) {
1090
+ if (key !== "toolCalls" && key !== "readReserve") throw new Error(`${prefix}.${key} is unknown`);
1091
+ }
1092
+ for (const key of ["toolCalls", "readReserve"]) {
1093
+ if (!Object.hasOwn(value, key)) throw new Error(`${prefix}.${key} is required`);
1094
+ }
1095
+ const toolCalls = value.toolCalls;
1096
+ if (typeof toolCalls !== "number" || !Number.isSafeInteger(toolCalls) || toolCalls <= 0) {
1097
+ throw new Error(`${prefix}.toolCalls must be a positive safe integer`);
1098
+ }
1099
+ const readReserve = value.readReserve;
1100
+ if (typeof readReserve !== "number" || !Number.isSafeInteger(readReserve) || readReserve < 0) {
1101
+ throw new Error(`${prefix}.readReserve must be a non-negative safe integer`);
1102
+ }
1103
+ if (readReserve >= toolCalls) throw new Error(`${prefix}.readReserve must be less than ${prefix}.toolCalls`);
1104
+ return { toolCalls, readReserve };
1105
+ }
1106
+ function cloneDispatchBudgetRequest(value, prefix = "budget") {
1107
+ if (!isRecord(value)) throw new Error(`${prefix} must be an object`);
1108
+ for (const key of Object.keys(value)) {
1109
+ if (key !== "toolCalls" && key !== "readReserve" && key !== "retryRevision") {
1110
+ throw new Error(`${prefix}.${key} is unknown`);
1111
+ }
1112
+ }
1113
+ const phase = clonePhase({ toolCalls: value.toolCalls, readReserve: value.readReserve }, prefix);
1114
+ const retryRevision = value.retryRevision === void 0 ? void 0 : clonePhase(value.retryRevision, `${prefix}.retryRevision`);
1115
+ return { ...phase, ...retryRevision === void 0 ? {} : { retryRevision } };
1116
+ }
1117
+ function freezeEnvelope(envelope) {
1118
+ Object.freeze(envelope.policy.default);
1119
+ Object.freeze(envelope.policy.maximum);
1120
+ Object.freeze(envelope.policy);
1121
+ if (envelope.request !== null) {
1122
+ if (envelope.request.retryRevision !== void 0) Object.freeze(envelope.request.retryRevision);
1123
+ Object.freeze(envelope.request);
1124
+ }
1125
+ Object.freeze(envelope.effective);
1126
+ for (const reason of envelope.reasons) Object.freeze(reason);
1127
+ Object.freeze(envelope.reasons);
1128
+ return Object.freeze(envelope);
1129
+ }
1130
+ function phaseWithin(candidate, maximum) {
1131
+ return candidate.toolCalls <= maximum.toolCalls && candidate.readReserve <= maximum.readReserve;
1132
+ }
1133
+ function samePhase(left, right) {
1134
+ return left.toolCalls === right.toolCalls && left.readReserve === right.readReserve;
1135
+ }
1136
+ function assertRequestAdmitted(input) {
1137
+ const { request, policy, hardCap } = input;
1138
+ const authoredMaximum = policy.maximum ?? policy;
1139
+ if (policy.maximum === void 0 && !samePhase(request, policy)) {
1140
+ throw new BudgetAdmissionError(
1141
+ "exact-recipe-policy",
1142
+ `the recipe pins ${policy.toolCalls} tool calls with a read reserve of ${policy.readReserve}`
1143
+ );
1144
+ }
1145
+ if (!phaseWithin(request, authoredMaximum)) {
1146
+ throw new BudgetAdmissionError(
1147
+ "recipe-maximum",
1148
+ `the requested phase ${request.toolCalls}/${request.readReserve} exceeds recipe maximum ${authoredMaximum.toolCalls}/${authoredMaximum.readReserve}`
1149
+ );
1150
+ }
1151
+ if (request.toolCalls > hardCap) {
1152
+ throw new BudgetAdmissionError(
1153
+ "global-cap",
1154
+ `the requested ${request.toolCalls} tool calls exceed the operator cap of ${hardCap}`
1155
+ );
1156
+ }
1157
+ const ceiling = request.retryRevision;
1158
+ if (ceiling === void 0) return;
1159
+ if (ceiling.toolCalls < request.toolCalls || ceiling.readReserve < request.readReserve) {
1160
+ throw new BudgetAdmissionError(
1161
+ "ceiling-below-request",
1162
+ `retryRevision ${ceiling.toolCalls}/${ceiling.readReserve} must not be smaller than the requested phase ${request.toolCalls}/${request.readReserve}`
1163
+ );
1164
+ }
1165
+ if (policy.maximum === void 0 && !samePhase(ceiling, policy)) {
1166
+ throw new BudgetAdmissionError(
1167
+ "exact-recipe-policy",
1168
+ `the recipe pins ${policy.toolCalls} tool calls with a read reserve of ${policy.readReserve}`
1169
+ );
1170
+ }
1171
+ if (!phaseWithin(ceiling, authoredMaximum)) {
1172
+ throw new BudgetAdmissionError(
1173
+ "recipe-maximum",
1174
+ `retryRevision ${ceiling.toolCalls}/${ceiling.readReserve} exceeds recipe maximum ${authoredMaximum.toolCalls}/${authoredMaximum.readReserve}`
1175
+ );
1176
+ }
1177
+ if (ceiling.toolCalls > hardCap) {
1178
+ throw new BudgetAdmissionError(
1179
+ "global-cap",
1180
+ `retryRevision ${ceiling.toolCalls} exceeds the operator cap of ${hardCap}`
1181
+ );
1182
+ }
1183
+ }
1184
+ function resolveToolBudgetEnvelope(input) {
1185
+ if (!Number.isSafeInteger(input.hardCap) || input.hardCap <= 0) {
1186
+ throw new Error("dispatch: worker tool-call cap must be a positive safe integer");
1187
+ }
1188
+ if (input.request !== void 0)
1189
+ assertRequestAdmitted({ request: input.request, policy: input.policy, hardCap: input.hardCap });
1190
+ const request = input.request === void 0 ? null : cloneDispatchBudgetRequest(input.request);
1191
+ const base = request ?? input.policy;
1192
+ const reasons = [];
1193
+ let selected = base;
1194
+ const phaseKind = input.retry ? "retry" : input.revision ? "revision" : null;
1195
+ if (phaseKind !== null) {
1196
+ const ceiling = request?.retryRevision;
1197
+ if (ceiling !== void 0 && !samePhase(ceiling, base)) {
1198
+ selected = ceiling;
1199
+ reasons.push({
1200
+ code: phaseKind === "retry" ? "retry-growth-authorized" : "revision-growth-authorized",
1201
+ detail: `${phaseKind} phase grew from ${base.toolCalls}/${base.readReserve} to the preauthorized ceiling ${ceiling.toolCalls}/${ceiling.readReserve}`
1202
+ });
1203
+ } else {
1204
+ reasons.push({
1205
+ code: phaseKind === "retry" ? "retry-growth-denied" : "revision-growth-denied",
1206
+ detail: ceiling === void 0 ? `${phaseKind} phase retained ${base.toolCalls}/${base.readReserve} because the original request declared no ceiling` : `${phaseKind} phase retained ${base.toolCalls}/${base.readReserve} because the declared ceiling did not authorize growth`
1207
+ });
1208
+ }
1209
+ }
1210
+ const revisionCeiling = phaseKind === null ? request?.retryRevision : void 0;
1211
+ if (revisionCeiling !== void 0 && !samePhase(revisionCeiling, selected)) {
1212
+ reasons.push({
1213
+ code: "revision-growth-authorized",
1214
+ detail: `a result-contract revision may grow from ${selected.toolCalls}/${selected.readReserve} to the preauthorized ceiling ${revisionCeiling.toolCalls}/${revisionCeiling.readReserve}`
1215
+ });
1216
+ }
1217
+ let toolCalls = selected.toolCalls;
1218
+ if (toolCalls > input.hardCap) {
1219
+ reasons.push({
1220
+ code: "global-cap-clamp",
1221
+ detail: `tool calls were clamped from ${toolCalls} to the operator cap of ${input.hardCap}`
1222
+ });
1223
+ toolCalls = input.hardCap;
1224
+ }
1225
+ let readReserve = selected.readReserve;
1226
+ if (!input.hasReadTool && readReserve > 0) {
1227
+ reasons.push({
1228
+ code: "read-reserve-unavailable-clamp",
1229
+ detail: `read reserve was clamped from ${readReserve} to 0 because the read tool is unavailable`
1230
+ });
1231
+ readReserve = 0;
1232
+ }
1233
+ const maximumEffectiveReserve = Math.max(0, toolCalls - 1);
1234
+ if (readReserve > maximumEffectiveReserve) {
1235
+ reasons.push({
1236
+ code: "read-reserve-cap-clamp",
1237
+ detail: `read reserve was clamped from ${readReserve} to ${maximumEffectiveReserve} after the tool-call cap`
1238
+ });
1239
+ readReserve = maximumEffectiveReserve;
1240
+ }
1241
+ let effectiveRevision;
1242
+ if (revisionCeiling !== void 0 && !samePhase(revisionCeiling, selected)) {
1243
+ let revisionReadReserve = revisionCeiling.readReserve;
1244
+ if (!input.hasReadTool && revisionReadReserve > 0) {
1245
+ reasons.push({
1246
+ code: "read-reserve-unavailable-clamp",
1247
+ detail: `result-contract revision read reserve was clamped from ${revisionReadReserve} to 0 because the read tool is unavailable`
1248
+ });
1249
+ revisionReadReserve = 0;
1250
+ }
1251
+ effectiveRevision = { toolCalls: revisionCeiling.toolCalls, readReserve: revisionReadReserve };
1252
+ }
1253
+ const authoredMaximum = input.policy.maximum ?? input.policy;
1254
+ return freezeEnvelope({
1255
+ version: 1,
1256
+ policy: {
1257
+ recipeId: input.recipeId,
1258
+ default: {
1259
+ toolCalls: input.policy.toolCalls,
1260
+ readReserve: input.policy.readReserve,
1261
+ synthesis: input.policy.synthesis
1262
+ },
1263
+ maximum: { toolCalls: authoredMaximum.toolCalls, readReserve: authoredMaximum.readReserve },
1264
+ exact: input.policy.maximum === void 0
1265
+ },
1266
+ request,
1267
+ effective: {
1268
+ toolCalls,
1269
+ readReserve,
1270
+ synthesis: input.policy.synthesis,
1271
+ hardCap: input.hardCap,
1272
+ ...effectiveRevision === void 0 ? {} : { revision: effectiveRevision }
1273
+ },
1274
+ reasons
1275
+ });
1276
+ }
1277
+ function formatBudgetPolicy(envelope) {
1278
+ const policy = envelope.policy;
1279
+ const range = policy.exact ? `exact ${policy.default.toolCalls}/${policy.default.readReserve}` : `default ${policy.default.toolCalls}/${policy.default.readReserve}, max ${policy.maximum.toolCalls}/${policy.maximum.readReserve}`;
1280
+ return `${policy.recipeId} ${range}, synthesis=${policy.default.synthesis ? "on" : "off"}`;
1281
+ }
1282
+ function formatBudgetRequest(envelope) {
1283
+ const request = envelope.request;
1284
+ if (request === null) return "recipe default";
1285
+ const ceiling = request.retryRevision;
1286
+ return ceiling === void 0 ? `${request.toolCalls}/${request.readReserve}, no retry/revision growth` : `${request.toolCalls}/${request.readReserve}, retry/revision ceiling ${ceiling.toolCalls}/${ceiling.readReserve}`;
1287
+ }
1288
+ function formatEffectiveBudget(envelope) {
1289
+ const budget = envelope.effective;
1290
+ const revision = budget.revision ? `, result revision ${budget.revision.toolCalls}/${budget.revision.readReserve}` : "";
1291
+ return `${budget.toolCalls}/${budget.readReserve}${revision}, lifetime cap ${budget.hardCap}, synthesis=${budget.synthesis ? "on" : "off"}`;
1292
+ }
1293
+ function formatBudgetReasons(envelope) {
1294
+ return envelope.reasons.length === 0 ? "none" : envelope.reasons.map((reason) => reason.code).join(",");
1295
+ }
1296
+ var BUDGET_REASON_CODES = /* @__PURE__ */ new Set([
1297
+ "global-cap-clamp",
1298
+ "read-reserve-unavailable-clamp",
1299
+ "read-reserve-cap-clamp",
1300
+ "retry-growth-authorized",
1301
+ "retry-growth-denied",
1302
+ "revision-growth-authorized",
1303
+ "revision-growth-denied"
1304
+ ]);
1305
+ function cloneRunToolBudgetEnvelope(value) {
1306
+ try {
1307
+ if (!isRecord(value) || value.version !== 1 || !isRecord(value.policy) || !isRecord(value.effective)) {
1308
+ return void 0;
1309
+ }
1310
+ const recipeId = value.policy.recipeId;
1311
+ if (typeof recipeId !== "string" || recipeId.length === 0 || typeof value.policy.exact !== "boolean") {
1312
+ return void 0;
1313
+ }
1314
+ if (!isRecord(value.policy.default) || typeof value.policy.default.synthesis !== "boolean") return void 0;
1315
+ const defaultPhase = clonePhase(
1316
+ { toolCalls: value.policy.default.toolCalls, readReserve: value.policy.default.readReserve },
1317
+ "budget.policy.default"
1318
+ );
1319
+ const maximum = clonePhase(value.policy.maximum, "budget.policy.maximum");
1320
+ const request = value.request === null ? null : cloneDispatchBudgetRequest(value.request);
1321
+ const effectivePhase = clonePhase(
1322
+ { toolCalls: value.effective.toolCalls, readReserve: value.effective.readReserve },
1323
+ "budget.effective"
1324
+ );
1325
+ const revision = value.effective.revision === void 0 ? void 0 : clonePhase(value.effective.revision, "budget.effective.revision");
1326
+ if (typeof value.effective.synthesis !== "boolean" || typeof value.effective.hardCap !== "number" || !Number.isSafeInteger(value.effective.hardCap) || value.effective.hardCap <= 0 || !Array.isArray(value.reasons)) {
1327
+ return void 0;
1328
+ }
1329
+ if (maximum.toolCalls < defaultPhase.toolCalls || maximum.readReserve < defaultPhase.readReserve || value.policy.exact && !samePhase(maximum, defaultPhase) || effectivePhase.toolCalls > value.effective.hardCap || value.effective.synthesis !== value.policy.default.synthesis || revision !== void 0 && (revision.toolCalls < effectivePhase.toolCalls || revision.toolCalls > value.effective.hardCap || revision.toolCalls === effectivePhase.toolCalls && revision.readReserve <= effectivePhase.readReserve)) {
1330
+ return void 0;
1331
+ }
1332
+ const reasons = [];
1333
+ for (const reason of value.reasons) {
1334
+ if (!isRecord(reason) || typeof reason.code !== "string" || !BUDGET_REASON_CODES.has(reason.code) || typeof reason.detail !== "string") {
1335
+ return void 0;
1336
+ }
1337
+ reasons.push({ code: reason.code, detail: reason.detail });
1338
+ }
1339
+ return freezeEnvelope({
1340
+ version: 1,
1341
+ policy: {
1342
+ recipeId,
1343
+ default: { ...defaultPhase, synthesis: value.policy.default.synthesis },
1344
+ maximum,
1345
+ exact: value.policy.exact
1346
+ },
1347
+ request,
1348
+ effective: {
1349
+ ...effectivePhase,
1350
+ synthesis: value.effective.synthesis,
1351
+ hardCap: value.effective.hardCap,
1352
+ ...revision === void 0 ? {} : { revision }
1353
+ },
1354
+ reasons
1355
+ });
1356
+ } catch {
1357
+ return void 0;
1358
+ }
1359
+ }
1360
+
1045
1361
  // src/domains/dispatch/gate-role-prompts.ts
1046
1362
  init_esm_shims();
1047
1363
  var REVIEWER_GATE_PROMPT = [
@@ -1096,6 +1412,219 @@ function runKindSupportsLiveSteering(kind) {
1096
1412
  return kind === "http" || kind === "sdk";
1097
1413
  }
1098
1414
 
1415
+ // src/domains/safety/call-target.ts
1416
+ init_esm_shims();
1417
+
1418
+ // src/domains/safety/redaction.ts
1419
+ init_esm_shims();
1420
+ function isPlainObject2(value) {
1421
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1422
+ }
1423
+ var SECRET_KEY_RE = /(?:api[-_]?key|access[-_]?key|auth(?:orization)?|credential|password|private[-_]?key|secret|token)/iu;
1424
+ var ENV_KEY_RE = /^env(?:ironment)?$/iu;
1425
+ var SECRET_STRING_RE = /(https?:\/\/[^\s/@]+:)[^\s/@]+@/giu;
1426
+ var SECRET_URL_PARAM_RE = /([?&](?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[^=\s]*=)[^&#\s]+/giu;
1427
+ 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;
1428
+ var SECRET_FLAG_RE = /(--?(?:[a-z0-9-]*(?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[a-z0-9-]*))(=|\s+)([^\s;&|]+)/giu;
1429
+ function redactSecretString(value) {
1430
+ 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]");
1431
+ }
1432
+ function isSecretArgKey(key) {
1433
+ return SECRET_KEY_RE.test(key);
1434
+ }
1435
+ function isEnvironmentArgKey(key) {
1436
+ return ENV_KEY_RE.test(key);
1437
+ }
1438
+ function redactEnvironmentValue(value, depth) {
1439
+ if (depth > 8) return "[redacted nested values]";
1440
+ if (typeof value === "string") return "[redacted]";
1441
+ if (Array.isArray(value)) return value.map((item) => redactEnvironmentValue(item, depth + 1));
1442
+ if (!isPlainObject2(value)) return value;
1443
+ const out = {};
1444
+ for (const [childKey, childValue] of Object.entries(value)) {
1445
+ out[childKey] = redactEnvironmentValue(childValue, depth + 1);
1446
+ }
1447
+ return out;
1448
+ }
1449
+ function redactToolArgs(value, key = "", depth = 0) {
1450
+ if (isSecretArgKey(key)) return "[redacted]";
1451
+ if (isEnvironmentArgKey(key)) return redactEnvironmentValue(value, depth);
1452
+ if (typeof value === "string") return redactSecretString(value);
1453
+ if (depth > 8) return "[redacted nested values]";
1454
+ if (Array.isArray(value)) return value.map((item) => redactToolArgs(item, key, depth + 1));
1455
+ if (!isPlainObject2(value)) return value;
1456
+ const out = {};
1457
+ for (const [childKey, childValue] of Object.entries(value)) {
1458
+ out[childKey] = redactToolArgs(childValue, childKey, depth + 1);
1459
+ }
1460
+ return out;
1461
+ }
1462
+
1463
+ // src/domains/safety/call-target.ts
1464
+ var ESC_CHAR = String.fromCharCode(27);
1465
+ var BEL_CHAR = String.fromCharCode(7);
1466
+ var OSC_PATTERN = new RegExp(`${ESC_CHAR}\\][\\s\\S]*?(?:${BEL_CHAR}|${ESC_CHAR}\\\\|$)`, "g");
1467
+ var CSI_PATTERN = new RegExp(`${ESC_CHAR}\\[[0-9;?]*[0-9A-Za-z]`, "g");
1468
+ function sanitizeForDisplay(value) {
1469
+ const stripped = value.replace(OSC_PATTERN, "").replace(CSI_PATTERN, "");
1470
+ let out = "";
1471
+ for (const ch of stripped) {
1472
+ const code = ch.codePointAt(0) ?? 0;
1473
+ out += code < 32 || code === 127 ? " " : ch;
1474
+ }
1475
+ return out;
1476
+ }
1477
+ function oneLine(value) {
1478
+ return value.replace(/\s+/g, " ").trim();
1479
+ }
1480
+ function sanitizeCallTargetText(value) {
1481
+ return oneLine(sanitizeForDisplay(value));
1482
+ }
1483
+ var CALL_ACTION_OBJECT_MAX_CHARS = 64;
1484
+ var CALL_TARGET_MAX_CHARS = 120;
1485
+ var CALL_ACTION_VOCABULARY = {
1486
+ read: { verb: "reading", field: "path" },
1487
+ edit: { verb: "editing", field: "path" },
1488
+ write: { verb: "writing", field: "path" },
1489
+ ls: { verb: "listing", field: "path" },
1490
+ bash: { verb: "running", field: "command" },
1491
+ grep: { verb: "searching", field: "pattern" },
1492
+ find: { verb: "finding", field: "pattern" },
1493
+ web_fetch: { verb: "fetching", field: "url" },
1494
+ git: { verb: "git", field: "op" },
1495
+ verify: { verb: "verifying", field: "check" },
1496
+ code_nav: { verb: "navigating", field: "query" },
1497
+ context: { verb: "context", field: "scope" },
1498
+ artifact: { verb: "writing", field: "kind" },
1499
+ monitor: { verb: "monitoring", field: "run_id" },
1500
+ steer: { verb: "steering", field: "run_id" },
1501
+ tasks: { verb: "tasks", field: "action" },
1502
+ dispatch: { verb: "dispatching", field: "agent" },
1503
+ // ACP tool kinds. A peer names its own argument fields, so these rely on
1504
+ // the shared allowlist below rather than on a field this side can predict.
1505
+ execute: { verb: "running", field: "command" },
1506
+ search: { verb: "searching", field: "query" },
1507
+ fetch: { verb: "fetching", field: "url" },
1508
+ delete: { verb: "deleting", field: "path" },
1509
+ move: { verb: "moving", field: "path" },
1510
+ think: { verb: "thinking", field: "" }
1511
+ };
1512
+ var CALL_ACTION_OBJECT_FIELDS = ["path", "file_path", "command", "pattern", "query", "url"];
1513
+ var CALL_TARGET_FIELDS = {
1514
+ read: ["path", "offset", "limit", "tail"],
1515
+ grep: ["pattern", "path", "mode", "glob", "ignore_case", "literal", "context", "limit", "include_ignored"],
1516
+ find: ["pattern", "path", "order", "limit", "include_ignored"],
1517
+ ls: ["path", "limit"],
1518
+ code_nav: ["mode", "query", "limit"],
1519
+ context: ["scope", "query", "name", "limit", "ref", "include_tree"],
1520
+ credential_present: ["name", "source", "file"],
1521
+ write: ["path"],
1522
+ edit: ["path"],
1523
+ bash: ["command", "cwd", "timeout_ms", "output_policy"],
1524
+ git: ["op", "path", "cached", "stat", "name_only", "limit", "cwd", "timeout_ms", "max_output_bytes"],
1525
+ verify: ["check", "path", "browser", "cwd", "timeout_ms", "max_output_bytes"],
1526
+ dispatch: [
1527
+ "list",
1528
+ "mode",
1529
+ "agent",
1530
+ "target",
1531
+ "model",
1532
+ "node",
1533
+ "autonomy",
1534
+ "tool_profile",
1535
+ "thinking_level",
1536
+ "detach",
1537
+ "timeout_ms"
1538
+ ],
1539
+ monitor: ["run_id", "mode"],
1540
+ steer: ["run_id", "action"],
1541
+ tasks: ["action", "id"],
1542
+ ledger: ["action", "kind", "path", "line", "target", "passed", "since"],
1543
+ web_fetch: ["url", "method", "timeout_ms", "max_bytes", "format"],
1544
+ ask_user: ["action", "mode", "max_rounds", "exposure"],
1545
+ artifact: ["kind", "path", "title"],
1546
+ // ACP tool kinds use only fields whose meaning the protocol defines.
1547
+ execute: ["command", "cwd"],
1548
+ search: ["query", "path"],
1549
+ fetch: ["url", "method"],
1550
+ delete: ["path"],
1551
+ move: ["path", "target"]
1552
+ };
1553
+ function boundActionObject(value) {
1554
+ if (typeof value !== "string") return null;
1555
+ const clean = sanitizeCallTargetText(redactSecretString(value));
1556
+ if (clean.length === 0) return null;
1557
+ if (clean.length <= CALL_ACTION_OBJECT_MAX_CHARS) return { object: clean, truncated: false };
1558
+ return { object: clean.slice(0, CALL_ACTION_OBJECT_MAX_CHARS), truncated: true };
1559
+ }
1560
+ function describeCallAction(tool, args) {
1561
+ const known = CALL_ACTION_VOCABULARY[tool];
1562
+ const candidates = known?.field ? [known.field, ...CALL_ACTION_OBJECT_FIELDS] : [...CALL_ACTION_OBJECT_FIELDS];
1563
+ let bounded = null;
1564
+ if (args) {
1565
+ for (const field of candidates) {
1566
+ if (isSecretArgKey(field)) continue;
1567
+ bounded = boundActionObject(args[field]);
1568
+ if (bounded !== null) break;
1569
+ }
1570
+ }
1571
+ if (known === void 0 && bounded === null) return null;
1572
+ const verb = known?.verb ?? "calling";
1573
+ if (bounded === null) return { verb };
1574
+ return { verb, object: bounded.object, ...bounded.truncated ? { truncated: true } : {} };
1575
+ }
1576
+ function renderAllowedTargetValue(value) {
1577
+ if (typeof value === "string") {
1578
+ const rendered = sanitizeCallTargetText(redactSecretString(value));
1579
+ return rendered.length > 0 ? rendered : null;
1580
+ }
1581
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
1582
+ if (typeof value === "boolean") return String(value);
1583
+ return null;
1584
+ }
1585
+ function countLabel(count, singular, plural) {
1586
+ return `${count} ${count === 1 ? singular : plural}`;
1587
+ }
1588
+ function summarizeUnlistedTargetValue(value) {
1589
+ if (typeof value === "string") {
1590
+ return `<string ${countLabel(Buffer.byteLength(value, "utf8"), "byte", "bytes")}>`;
1591
+ }
1592
+ if (Array.isArray(value)) return `<array ${countLabel(value.length, "item", "items")}>`;
1593
+ if (value !== null && typeof value === "object") {
1594
+ return `<object ${countLabel(Object.keys(value).length, "field", "fields")}>`;
1595
+ }
1596
+ if (value === null) return "<null 0 values>";
1597
+ if (typeof value === "undefined") return "<undefined 0 values>";
1598
+ return `<${typeof value} 1 value>`;
1599
+ }
1600
+ function targetFieldName(value) {
1601
+ return sanitizeCallTargetText(value).slice(0, 32) || "field";
1602
+ }
1603
+ function describeCallTarget(tool, args) {
1604
+ if (!args) return "";
1605
+ const allowedFields = CALL_TARGET_FIELDS[tool] ?? [];
1606
+ const allowed = new Set(allowedFields);
1607
+ const parts = [];
1608
+ for (const field of allowedFields) {
1609
+ if (!(field in args)) continue;
1610
+ if (isSecretArgKey(field)) {
1611
+ parts.push(`${targetFieldName(field)}=${summarizeUnlistedTargetValue(args[field])}`);
1612
+ continue;
1613
+ }
1614
+ const rendered = renderAllowedTargetValue(args[field]);
1615
+ if (rendered === null) {
1616
+ parts.push(`${targetFieldName(field)}=${summarizeUnlistedTargetValue(args[field])}`);
1617
+ continue;
1618
+ }
1619
+ parts.push(parts.length === 0 ? rendered : `${targetFieldName(field)}=${rendered}`);
1620
+ }
1621
+ for (const [field, value] of Object.entries(args)) {
1622
+ if (allowed.has(field)) continue;
1623
+ parts.push(`${targetFieldName(field)}=${summarizeUnlistedTargetValue(value)}`);
1624
+ }
1625
+ return sanitizeCallTargetText(parts.join(" \xB7 ")).slice(0, CALL_TARGET_MAX_CHARS);
1626
+ }
1627
+
1099
1628
  // src/engine/antigravity/subprocess-runtime.ts
1100
1629
  init_esm_shims();
1101
1630
  import { spawn as spawn2 } from "node:child_process";
@@ -2513,6 +3042,7 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
2513
3042
  "target",
2514
3043
  "model",
2515
3044
  "thinkingLevel",
3045
+ "budget",
2516
3046
  "node",
2517
3047
  "routingIntent",
2518
3048
  "failover",
@@ -2543,12 +3073,12 @@ var VALID_COMPETE_STANCES = new Set(COMPETE_STANCES);
2543
3073
  var VALID_THINKING = new Set(THINKING_LEVELS);
2544
3074
  var VALID_REQUEST_ORIGINS = /* @__PURE__ */ new Set(["user", "agent", "internal"]);
2545
3075
  var VALID_FAILOVER_MODES = /* @__PURE__ */ new Set(["none", "approved", "automatic"]);
2546
- function isPlainObject2(value) {
3076
+ function isPlainObject3(value) {
2547
3077
  return typeof value === "object" && value !== null && !Array.isArray(value);
2548
3078
  }
2549
3079
  function validateJobSpec(spec) {
2550
3080
  const errors = [];
2551
- if (!isPlainObject2(spec)) {
3081
+ if (!isPlainObject3(spec)) {
2552
3082
  return { ok: false, errors: ["spec must be an object"] };
2553
3083
  }
2554
3084
  for (const key of Object.keys(spec)) {
@@ -2637,7 +3167,7 @@ function validateJobSpec(spec) {
2637
3167
  errors.push("failover automatic is not allowed on a plan-approved dispatch");
2638
3168
  }
2639
3169
  if ("plannedNode" in spec && spec.plannedNode !== void 0) {
2640
- if (!isPlainObject2(spec.plannedNode)) {
3170
+ if (!isPlainObject3(spec.plannedNode)) {
2641
3171
  errors.push("plannedNode must be an object");
2642
3172
  } else {
2643
3173
  for (const key of Object.keys(spec.plannedNode)) {
@@ -2658,7 +3188,7 @@ function validateJobSpec(spec) {
2658
3188
  }
2659
3189
  }
2660
3190
  if ("protectedArtifactRemap" in spec && spec.protectedArtifactRemap !== void 0) {
2661
- if (!isPlainObject2(spec.protectedArtifactRemap) || Object.keys(spec.protectedArtifactRemap).some((key) => key !== "sourceRoot" && key !== "workerRoot") || typeof spec.protectedArtifactRemap.sourceRoot !== "string" || !path2.isAbsolute(spec.protectedArtifactRemap.sourceRoot) || typeof spec.protectedArtifactRemap.workerRoot !== "string" || !path2.isAbsolute(spec.protectedArtifactRemap.workerRoot)) {
3191
+ if (!isPlainObject3(spec.protectedArtifactRemap) || Object.keys(spec.protectedArtifactRemap).some((key) => key !== "sourceRoot" && key !== "workerRoot") || typeof spec.protectedArtifactRemap.sourceRoot !== "string" || !path2.isAbsolute(spec.protectedArtifactRemap.sourceRoot) || typeof spec.protectedArtifactRemap.workerRoot !== "string" || !path2.isAbsolute(spec.protectedArtifactRemap.workerRoot)) {
2662
3192
  errors.push("protectedArtifactRemap must carry absolute sourceRoot and workerRoot paths");
2663
3193
  }
2664
3194
  }
@@ -2672,6 +3202,14 @@ function validateJobSpec(spec) {
2672
3202
  errors.push("thinkingLevel must be one of: off|minimal|low|medium|high|xhigh");
2673
3203
  }
2674
3204
  }
3205
+ let budget;
3206
+ if ("budget" in spec && spec.budget !== void 0) {
3207
+ try {
3208
+ budget = cloneDispatchBudgetRequest(spec.budget);
3209
+ } catch (error) {
3210
+ errors.push(error instanceof Error ? error.message : String(error));
3211
+ }
3212
+ }
2675
3213
  if ("requiredCapabilities" in spec && spec.requiredCapabilities !== void 0) {
2676
3214
  if (!Array.isArray(spec.requiredCapabilities) || spec.requiredCapabilities.some((c) => typeof c !== "string")) {
2677
3215
  errors.push("requiredCapabilities must be a string[]");
@@ -2798,6 +3336,7 @@ function validateJobSpec(spec) {
2798
3336
  out.reroutes = spec.reroutes.map((hop) => ({ ...hop }));
2799
3337
  }
2800
3338
  if (typeof spec.thinkingLevel === "string") out.thinkingLevel = spec.thinkingLevel;
3339
+ if (budget !== void 0) out.budget = budget;
2801
3340
  if (Array.isArray(spec.requiredCapabilities)) {
2802
3341
  out.requiredCapabilities = spec.requiredCapabilities.map((c) => String(c));
2803
3342
  }
@@ -2834,7 +3373,7 @@ function isValidPredecessorHandoffs(value) {
2834
3373
  if (!Array.isArray(value) || value.length > EXECUTION_HANDOFF_MAX_ITEMS || Buffer.byteLength(JSON.stringify(value), "utf8") > EXECUTION_HANDOFF_MAX_TEXT_BYTES * 2)
2835
3374
  return false;
2836
3375
  return value.every((candidate) => {
2837
- if (!isPlainObject2(candidate)) return false;
3376
+ if (!isPlainObject3(candidate)) return false;
2838
3377
  const fields = [
2839
3378
  candidate.stepId,
2840
3379
  candidate.assignmentId,
@@ -2846,14 +3385,14 @@ function isValidPredecessorHandoffs(value) {
2846
3385
  });
2847
3386
  }
2848
3387
  function isValidPipelineInput(value) {
2849
- if (!isPlainObject2(value)) return false;
3388
+ if (!isPlainObject3(value)) return false;
2850
3389
  const fromRunOk = value.fromRunId === null || typeof value.fromRunId === "string" && value.fromRunId.length > 0;
2851
3390
  const positionOk = typeof value.position === "number" && Number.isInteger(value.position) && value.position >= 1;
2852
3391
  const textOk = typeof value.text === "string";
2853
3392
  return fromRunOk && positionOk && textOk;
2854
3393
  }
2855
3394
  function isValidReroute(value) {
2856
- if (!isPlainObject2(value)) return false;
3395
+ if (!isPlainObject3(value)) return false;
2857
3396
  const attemptOk = typeof value.attempt === "number" && Number.isInteger(value.attempt) && value.attempt >= 1;
2858
3397
  const fromOk = typeof value.fromNode === "string" && value.fromNode.length > 0;
2859
3398
  const toOk = typeof value.toNode === "string";
@@ -2861,7 +3400,7 @@ function isValidReroute(value) {
2861
3400
  return attemptOk && fromOk && toOk && reasonOk;
2862
3401
  }
2863
3402
  function isValidFailoverCandidate(value) {
2864
- if (!isPlainObject2(value)) return false;
3403
+ if (!isPlainObject3(value)) return false;
2865
3404
  if (Object.keys(value).some((key) => key !== "agentId" && key !== "target" && key !== "model" && key !== "node")) {
2866
3405
  return false;
2867
3406
  }
@@ -2870,26 +3409,26 @@ function isValidFailoverCandidate(value) {
2870
3409
  );
2871
3410
  }
2872
3411
  function isValidPlannedNode(value) {
2873
- if (!isPlainObject2(value) || typeof value.id !== "string" || value.id.trim().length === 0) return false;
3412
+ if (!isPlainObject3(value) || typeof value.id !== "string" || value.id.trim().length === 0) return false;
2874
3413
  if (value.kind === "local") return value.host === void 0;
2875
3414
  return value.kind === "ssh" && typeof value.host === "string" && value.host.trim().length > 0;
2876
3415
  }
2877
3416
  function isValidProtectedArtifactRemap(value) {
2878
- return isPlainObject2(value) && typeof value.sourceRoot === "string" && path2.isAbsolute(value.sourceRoot) && typeof value.workerRoot === "string" && path2.isAbsolute(value.workerRoot);
3417
+ return isPlainObject3(value) && typeof value.sourceRoot === "string" && path2.isAbsolute(value.sourceRoot) && typeof value.workerRoot === "string" && path2.isAbsolute(value.workerRoot);
2879
3418
  }
2880
3419
  var VALID_GATE_ROLES = /* @__PURE__ */ new Set(["builder", "reviewer", "candidate", "judge"]);
2881
3420
  var VALID_GATE_VERDICTS = /* @__PURE__ */ new Set(["pass", "fail", "revise"]);
2882
3421
  var VALID_PLAN_TOPOLOGIES = /* @__PURE__ */ new Set(["parallel", "sequential", "pipeline", "review", "compete", "detached", "fleet"]);
2883
3422
  var VALID_PLAN_APPROVALS = /* @__PURE__ */ new Set(["operator", "full-auto"]);
2884
3423
  function isValidGate(value) {
2885
- if (!isPlainObject2(value)) return false;
3424
+ if (!isPlainObject3(value)) return false;
2886
3425
  if (typeof value.role !== "string" || !VALID_GATE_ROLES.has(value.role)) return false;
2887
3426
  if (typeof value.group !== "string" || value.group.length === 0) return false;
2888
3427
  if (typeof value.cycle !== "number" || !Number.isInteger(value.cycle) || value.cycle < 1) return false;
2889
3428
  if (value.subjects !== void 0) {
2890
3429
  if (!Array.isArray(value.subjects)) return false;
2891
3430
  for (const subject of value.subjects) {
2892
- if (!isPlainObject2(subject)) return false;
3431
+ if (!isPlainObject3(subject)) return false;
2893
3432
  if (typeof subject.runId !== "string" || subject.runId.length === 0) return false;
2894
3433
  if (subject.digest !== null && typeof subject.digest !== "string") return false;
2895
3434
  }
@@ -2909,13 +3448,13 @@ function cloneGate(gate) {
2909
3448
  };
2910
3449
  }
2911
3450
  function isValidPlan(value) {
2912
- if (!isPlainObject2(value)) return false;
3451
+ if (!isPlainObject3(value)) return false;
2913
3452
  if (typeof value.hash !== "string" || value.hash.length === 0) return false;
2914
3453
  if (typeof value.topology !== "string" || !VALID_PLAN_TOPOLOGIES.has(value.topology)) return false;
2915
3454
  if (typeof value.taskCount !== "number" || !Number.isInteger(value.taskCount) || value.taskCount < 1) return false;
2916
3455
  if (typeof value.approval !== "string" || !VALID_PLAN_APPROVALS.has(value.approval)) return false;
2917
3456
  if (value.source !== null) {
2918
- if (!isPlainObject2(value.source) || value.source.kind !== "scout-transition" || typeof value.source.runId !== "string" || value.source.runId.length === 0 || typeof value.source.receiptDigest !== "string" || !/^[0-9a-f]{64}$/u.test(value.source.receiptDigest) || typeof value.source.executionPlanHash !== "string" || !/^[0-9a-f]{64}$/u.test(value.source.executionPlanHash))
3457
+ if (!isPlainObject3(value.source) || value.source.kind !== "scout-transition" || typeof value.source.runId !== "string" || value.source.runId.length === 0 || typeof value.source.receiptDigest !== "string" || !/^[0-9a-f]{64}$/u.test(value.source.receiptDigest) || typeof value.source.executionPlanHash !== "string" || !/^[0-9a-f]{64}$/u.test(value.source.executionPlanHash))
2919
3458
  return false;
2920
3459
  }
2921
3460
  if (value.approvalRequestId !== void 0 && (typeof value.approvalRequestId !== "string" || value.approvalRequestId.length === 0)) {
@@ -2930,7 +3469,7 @@ function isValidPlan(value) {
2930
3469
  return true;
2931
3470
  }
2932
3471
  function isValidLineage(value) {
2933
- if (!isPlainObject2(value)) return false;
3472
+ if (!isPlainObject3(value)) return false;
2934
3473
  const parentOk = value.parentRunId === null || typeof value.parentRunId === "string" && value.parentRunId.length > 0;
2935
3474
  const rootOk = typeof value.rootRunId === "string" && value.rootRunId.length > 0;
2936
3475
  const attemptOk = typeof value.attempt === "number" && Number.isInteger(value.attempt) && value.attempt >= 0;
@@ -2941,7 +3480,7 @@ function isValidLineage(value) {
2941
3480
  // src/engine/claude/tool-safety.ts
2942
3481
  init_esm_shims();
2943
3482
  import { performance } from "node:perf_hooks";
2944
- function isRecord(value) {
3483
+ function isRecord2(value) {
2945
3484
  return typeof value === "object" && value !== null && !Array.isArray(value);
2946
3485
  }
2947
3486
  function stringField(record2, ...keys) {
@@ -3145,9 +3684,10 @@ function finishDecision(decision) {
3145
3684
  if (decision.kind === "ask") return "permission_requested";
3146
3685
  return "blocked";
3147
3686
  }
3148
- function emitToolFinish(emit, mapped, startedAtClock, decision, outcome, reason, reasonCode) {
3687
+ function emitToolFinish(emit, mapped, startedAtClock, decision, outcome, reason, reasonCode, toolCallId) {
3149
3688
  const event = {
3150
3689
  tool: mapped.clioToolName,
3690
+ ...toolCallId !== void 0 ? { toolCallId } : {},
3151
3691
  posture: "operating",
3152
3692
  durationMs: Math.round(performance.now() - startedAtClock),
3153
3693
  outcome,
@@ -3165,10 +3705,14 @@ function emitClaudeToolPermissionDecision(input) {
3165
3705
  const startedAt = Date.now();
3166
3706
  const startedAtClock = performance.now();
3167
3707
  const decision = evaluateClaudeToolPermission(input);
3708
+ const toolCallId = input.toolCallId?.trim() ? input.toolCallId : void 0;
3709
+ const action = describeCallAction(decision.mapped.clioToolName, decision.mapped.args);
3168
3710
  const start = {
3169
3711
  tool: decision.mapped.clioToolName,
3712
+ ...toolCallId !== void 0 ? { toolCallId } : {},
3170
3713
  posture: "operating",
3171
- startedAt
3714
+ startedAt,
3715
+ ...action !== null ? { action } : {}
3172
3716
  };
3173
3717
  input.emit({ type: "clio_tool_start", payload: start });
3174
3718
  if (decision.kind === "allow") {
@@ -3179,7 +3723,8 @@ function emitClaudeToolPermissionDecision(input) {
3179
3723
  decision.decision,
3180
3724
  "ok",
3181
3725
  decision.reason,
3182
- decision.reasonCode
3726
+ decision.reasonCode,
3727
+ toolCallId
3183
3728
  );
3184
3729
  return decision;
3185
3730
  }
@@ -3202,12 +3747,13 @@ function emitClaudeToolPermissionDecision(input) {
3202
3747
  decision.decision,
3203
3748
  "blocked",
3204
3749
  decision.reason,
3205
- decision.reasonCode
3750
+ decision.reasonCode,
3751
+ toolCallId
3206
3752
  );
3207
3753
  return decision;
3208
3754
  }
3209
3755
  function coerceToolInput(value) {
3210
- return isRecord(value) ? value : {};
3756
+ return isRecord2(value) ? value : {};
3211
3757
  }
3212
3758
 
3213
3759
  // src/domains/dispatch/agent-candidates.ts
@@ -3384,6 +3930,11 @@ export {
3384
3930
  responseSchemaConflictsWithTools,
3385
3931
  UnsupportedResponseSchemaError,
3386
3932
  isResponseSchemaRejection,
3933
+ redactSecretString,
3934
+ redactToolArgs,
3935
+ sanitizeCallTargetText,
3936
+ describeCallAction,
3937
+ describeCallTarget,
3387
3938
  TOOL_PROFILE_NAMES,
3388
3939
  isToolProfileName,
3389
3940
  assertToolProfileEnforceable,
@@ -3429,6 +3980,13 @@ export {
3429
3980
  AGENT_LEDGER_PROMPT_MAX_CHARS,
3430
3981
  claimConflicts,
3431
3982
  renderAgentLedger,
3983
+ cloneDispatchBudgetRequest,
3984
+ resolveToolBudgetEnvelope,
3985
+ formatBudgetPolicy,
3986
+ formatBudgetRequest,
3987
+ formatEffectiveBudget,
3988
+ formatBudgetReasons,
3989
+ cloneRunToolBudgetEnvelope,
3432
3990
  REVIEWER_GATE_PROMPT,
3433
3991
  JUDGE_GATE_PROMPT,
3434
3992
  COMPETE_STANCES,
@@ -3442,4 +4000,4 @@ export {
3442
4000
  DISPATCH_BRIEFING_MAX_BYTES,
3443
4001
  validateJobSpec
3444
4002
  };
3445
- //# sourceMappingURL=chunk-ZYKPLLNQ.js.map
4003
+ //# sourceMappingURL=chunk-XXQNGV4M.js.map