@wardby/cli 0.6.0 → 0.8.0

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 (740) hide show
  1. package/.env.example +5 -5
  2. package/README.md +6 -1
  3. package/deploy/local/docker-compose.quickstart-coding.yml +19 -0
  4. package/dist/claude-coding-worker/driver.d.ts +33 -3
  5. package/dist/claude-coding-worker/driver.js +151 -21
  6. package/dist/claude-coding-worker/main.js +38 -6
  7. package/dist/claude-coding-worker/sdk.js +29 -2
  8. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  9. package/dist/claude-coding-worker/tool-socket.js +111 -0
  10. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  11. package/dist/claude-coding-worker/transcript.js +77 -0
  12. package/dist/claude-plugin/command.d.ts +61 -0
  13. package/dist/claude-plugin/command.js +376 -0
  14. package/dist/cli-help.d.ts +1 -1
  15. package/dist/cli-help.js +3 -1
  16. package/dist/cli.js +71 -13
  17. package/dist/coding/code-host.d.ts +16 -0
  18. package/dist/coding/code-host.js +60 -0
  19. package/dist/coding/continuation-wording.d.ts +35 -0
  20. package/dist/coding/continuation-wording.js +73 -0
  21. package/dist/coding/linked-issue-note.d.ts +23 -0
  22. package/dist/coding/linked-issue-note.js +47 -0
  23. package/dist/coding/mcp-token.d.ts +12 -0
  24. package/dist/coding/mcp-token.js +26 -0
  25. package/dist/coding/merge-wording.d.ts +28 -0
  26. package/dist/coding/merge-wording.js +78 -0
  27. package/dist/coding/pr-description-note.d.ts +9 -0
  28. package/dist/coding/pr-description-note.js +32 -0
  29. package/dist/coding/profile.d.ts +46 -126
  30. package/dist/coding/profile.js +45 -4
  31. package/dist/coding/protected-path-wording.d.ts +8 -0
  32. package/dist/coding/protected-path-wording.js +1 -1
  33. package/dist/coding/protocol.d.ts +264 -346
  34. package/dist/coding/protocol.js +237 -12
  35. package/dist/coding/redact.d.ts +3 -0
  36. package/dist/coding/redact.js +17 -0
  37. package/dist/coding/registry/allowlist.d.ts +12 -0
  38. package/dist/coding/registry/allowlist.js +14 -1
  39. package/dist/coding/registry/audit-mode.d.ts +153 -0
  40. package/dist/coding/registry/audit-mode.js +304 -0
  41. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  42. package/dist/coding/registry/lockfile-shared.js +128 -0
  43. package/dist/coding/registry/lockfiles.js +1 -1
  44. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  45. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  46. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  47. package/dist/coding/registry/npm-lockfile.js +4 -6
  48. package/dist/coding/registry/npm.js +78 -8
  49. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  50. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  51. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  52. package/dist/coding/registry/pypi-plan.js +406 -0
  53. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  54. package/dist/coding/registry/pypi-requirements.js +155 -0
  55. package/dist/coding/registry/pypi.d.ts +3 -27
  56. package/dist/coding/registry/pypi.js +40 -154
  57. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  58. package/dist/coding/registry/refusal-hints.js +61 -0
  59. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  60. package/dist/coding/registry/refusal-wording.js +56 -0
  61. package/dist/coding/registry/report.d.ts +70 -8
  62. package/dist/coding/registry/report.js +112 -5
  63. package/dist/coding/registry/types.d.ts +58 -8
  64. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  65. package/dist/coding/registry/yarn-lockfile.js +367 -0
  66. package/dist/coding/services/catalog.d.ts +37 -351
  67. package/dist/coding/transcript/claude-code.d.ts +13 -0
  68. package/dist/coding/transcript/claude-code.js +273 -0
  69. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  70. package/dist/coding/transcript/download-protocol.js +18 -0
  71. package/dist/coding/transcript/format.d.ts +20 -0
  72. package/dist/coding/transcript/format.js +32 -0
  73. package/dist/coding/transcript/recorder.d.ts +52 -0
  74. package/dist/coding/transcript/recorder.js +225 -0
  75. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  76. package/dist/coding/transcript/resume/checkout.js +203 -0
  77. package/dist/coding/transcript/resume/command.d.ts +17 -0
  78. package/dist/coding/transcript/resume/command.js +176 -0
  79. package/dist/coding/transcript/resume/download.d.ts +20 -0
  80. package/dist/coding/transcript/resume/download.js +153 -0
  81. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  82. package/dist/coding/transcript/resume/launch.js +128 -0
  83. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  84. package/dist/coding/transcript/resume/session-file.js +79 -0
  85. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  86. package/dist/coding/transcript/resume/stand-in.js +49 -0
  87. package/dist/coding-worker/artifact.d.ts +8 -3
  88. package/dist/coding-worker/artifact.js +3 -1
  89. package/dist/coding-worker/debug-trace.d.ts +9 -6
  90. package/dist/coding-worker/debug-trace.js +16 -19
  91. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  92. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  93. package/dist/coding-worker/driver.d.ts +4 -3
  94. package/dist/coding-worker/driver.js +124 -39
  95. package/dist/coding-worker/errors.d.ts +1 -0
  96. package/dist/coding-worker/errors.js +32 -0
  97. package/dist/coding-worker/main.js +5 -1
  98. package/dist/coding-worker/mcp-config.d.ts +27 -0
  99. package/dist/coding-worker/mcp-config.js +32 -0
  100. package/dist/coding-worker/sdk.d.ts +36 -0
  101. package/dist/coding-worker/sdk.js +28 -1
  102. package/dist/coding-worker/task-note.d.ts +11 -0
  103. package/dist/coding-worker/task-note.js +13 -0
  104. package/dist/coding-worker/types.d.ts +15 -0
  105. package/dist/config/dependency-cache.d.ts +23 -0
  106. package/dist/config/dependency-cache.js +32 -0
  107. package/dist/config/mcp-call-limit.d.ts +8 -0
  108. package/dist/config/mcp-call-limit.js +18 -0
  109. package/dist/config/mcp-servers.d.ts +8 -0
  110. package/dist/config/mcp-servers.js +12 -0
  111. package/dist/config/providers.d.ts +12 -3
  112. package/dist/config/providers.js +55 -5
  113. package/dist/config/test-simulators.d.ts +92 -0
  114. package/dist/config/test-simulators.js +333 -0
  115. package/dist/config/tool-timeout.d.ts +1 -0
  116. package/dist/config/tool-timeout.js +18 -0
  117. package/dist/core/async-context.d.ts +2 -0
  118. package/dist/core/async-context.js +12 -0
  119. package/dist/core/budget-events.d.ts +108 -0
  120. package/dist/core/budget-events.js +346 -0
  121. package/dist/core/budget-groups.d.ts +50 -1
  122. package/dist/core/budget-groups.js +236 -27
  123. package/dist/core/budget-stopped-head.d.ts +46 -0
  124. package/dist/core/budget-stopped-head.js +81 -0
  125. package/dist/core/budget-topup.d.ts +51 -0
  126. package/dist/core/budget-topup.js +156 -0
  127. package/dist/core/budget-wording.d.ts +16 -2
  128. package/dist/core/budget-wording.js +40 -2
  129. package/dist/core/coding-mcp.d.ts +36 -0
  130. package/dist/core/coding-mcp.js +253 -0
  131. package/dist/core/coding-queue.d.ts +2 -1
  132. package/dist/core/coding-queue.js +7 -0
  133. package/dist/core/coding-repository.d.ts +46 -0
  134. package/dist/core/coding-repository.js +92 -0
  135. package/dist/core/cron.d.ts +19 -1
  136. package/dist/core/cron.js +17 -0
  137. package/dist/core/datastores.js +1 -1
  138. package/dist/core/deferred-coding.d.ts +14 -0
  139. package/dist/core/deferred-coding.js +62 -0
  140. package/dist/core/delegation-child.d.ts +25 -0
  141. package/dist/core/delegation-child.js +37 -0
  142. package/dist/core/delegation-slots.d.ts +27 -0
  143. package/dist/core/delegation-slots.js +44 -0
  144. package/dist/core/dispatch.d.ts +48 -2
  145. package/dist/core/dispatch.js +166 -66
  146. package/dist/core/engine-native.js +1 -1
  147. package/dist/core/error-code.d.ts +38 -0
  148. package/dist/core/error-code.js +169 -0
  149. package/dist/core/grants.d.ts +46 -8
  150. package/dist/core/grants.js +99 -8
  151. package/dist/core/host-events.d.ts +18 -2
  152. package/dist/core/host-events.js +291 -27
  153. package/dist/core/host-status.d.ts +85 -3
  154. package/dist/core/host-status.js +300 -22
  155. package/dist/core/issue-bridge.d.ts +50 -6
  156. package/dist/core/issue-bridge.js +124 -33
  157. package/dist/core/issue-events.d.ts +1 -1
  158. package/dist/core/issue-events.js +4 -10
  159. package/dist/core/issue-status.d.ts +1 -1
  160. package/dist/core/issue-status.js +58 -29
  161. package/dist/core/logger.d.ts +5 -0
  162. package/dist/core/logger.js +14 -1
  163. package/dist/core/lost-run-children.d.ts +6 -0
  164. package/dist/core/lost-run-children.js +32 -0
  165. package/dist/core/mark-ready.d.ts +34 -0
  166. package/dist/core/mark-ready.js +152 -0
  167. package/dist/core/markdown-code.d.ts +8 -0
  168. package/dist/core/markdown-code.js +107 -0
  169. package/dist/core/mcp-client/client.d.ts +47 -0
  170. package/dist/core/mcp-client/client.js +141 -0
  171. package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
  172. package/dist/core/mcp-client/jsonrpc.js +54 -0
  173. package/dist/core/mcp-client/results.d.ts +13 -0
  174. package/dist/core/mcp-client/results.js +42 -0
  175. package/dist/core/mcp-servers.d.ts +90 -0
  176. package/dist/core/mcp-servers.js +230 -0
  177. package/dist/core/mcp-tools.d.ts +108 -0
  178. package/dist/core/mcp-tools.js +287 -0
  179. package/dist/core/memory-tools.js +7 -0
  180. package/dist/core/merge-order-check.d.ts +2 -1
  181. package/dist/core/merge-order-check.js +44 -18
  182. package/dist/core/notification-dispatcher.js +2 -1
  183. package/dist/core/notification-templates.d.ts +1 -7
  184. package/dist/core/notification-templates.js +36 -2
  185. package/dist/core/pull-request-state-sync.js +2 -2
  186. package/dist/core/reconciler.d.ts +4 -3
  187. package/dist/core/reconciler.js +8 -1
  188. package/dist/core/related-pull-requests.d.ts +11 -3
  189. package/dist/core/related-pull-requests.js +49 -20
  190. package/dist/core/reply-parts.d.ts +21 -0
  191. package/dist/core/reply-parts.js +73 -0
  192. package/dist/core/review-fix.d.ts +1 -1
  193. package/dist/core/review-fix.js +4 -3
  194. package/dist/core/review-host-checks.d.ts +1 -1
  195. package/dist/core/review-host-tools.d.ts +3 -0
  196. package/dist/core/review-host-tools.js +102 -14
  197. package/dist/core/review-reads.d.ts +55 -0
  198. package/dist/core/review-reads.js +233 -0
  199. package/dist/core/run-status.d.ts +12 -0
  200. package/dist/core/run-status.js +12 -0
  201. package/dist/core/runner.d.ts +145 -49
  202. package/dist/core/runner.js +719 -216
  203. package/dist/core/schedule-start.d.ts +12 -0
  204. package/dist/core/schedule-start.js +14 -0
  205. package/dist/core/secret-broker-config.d.ts +12 -74
  206. package/dist/core/secret-broker-config.js +1 -1
  207. package/dist/core/secret-guard.d.ts +49 -0
  208. package/dist/core/secret-guard.js +119 -0
  209. package/dist/core/secret-guarded-stores.d.ts +12 -0
  210. package/dist/core/secret-guarded-stores.js +41 -0
  211. package/dist/core/secret-spans.d.ts +50 -0
  212. package/dist/core/secret-spans.js +94 -0
  213. package/dist/core/secrets.d.ts +11 -1
  214. package/dist/core/secrets.js +27 -1
  215. package/dist/core/serializable-retry.d.ts +18 -0
  216. package/dist/core/serializable-retry.js +43 -0
  217. package/dist/core/stop-run.d.ts +46 -0
  218. package/dist/core/stop-run.js +61 -0
  219. package/dist/core/tool-admin.d.ts +5 -1
  220. package/dist/core/tool-admin.js +7 -2
  221. package/dist/core/tool-names.d.ts +13 -0
  222. package/dist/core/tool-names.js +20 -0
  223. package/dist/core/webhooks.d.ts +4 -0
  224. package/dist/core/webhooks.js +68 -49
  225. package/dist/core/workflow-events.d.ts +14 -2
  226. package/dist/core/workflow-events.js +4 -0
  227. package/dist/core/workflow-run-events.d.ts +5 -3
  228. package/dist/core/workflow-run-events.js +45 -9
  229. package/dist/core/zod-json-schema.d.ts +4 -0
  230. package/dist/core/zod-json-schema.js +39 -0
  231. package/dist/core/zod3-window.d.ts +35 -0
  232. package/dist/core/zod3-window.js +124 -0
  233. package/dist/generated/prisma/browser.d.ts +65 -3
  234. package/dist/generated/prisma/client.d.ts +65 -3
  235. package/dist/generated/prisma/commonInputTypes.d.ts +266 -106
  236. package/dist/generated/prisma/enums.d.ts +10 -0
  237. package/dist/generated/prisma/enums.js +8 -0
  238. package/dist/generated/prisma/internal/class.d.ts +110 -0
  239. package/dist/generated/prisma/internal/class.js +4 -4
  240. package/dist/generated/prisma/internal/prismaNamespace.d.ts +957 -9
  241. package/dist/generated/prisma/internal/prismaNamespace.js +166 -2
  242. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +174 -0
  243. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +166 -2
  244. package/dist/generated/prisma/models/Agent.d.ts +377 -8
  245. package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
  246. package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
  247. package/dist/generated/prisma/models/AgentRepository.d.ts +81 -1
  248. package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
  249. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +228 -7
  250. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  251. package/dist/generated/prisma/models/CodingProxySession.d.ts +232 -2
  252. package/dist/generated/prisma/models/CodingRun.d.ts +1712 -1
  253. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  254. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  255. package/dist/generated/prisma/models/HostProvider.d.ts +2176 -0
  256. package/dist/generated/prisma/models/HostProvider.js +1 -0
  257. package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
  258. package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
  259. package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
  260. package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
  261. package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
  262. package/dist/generated/prisma/models/HostProviderTrustedAccount.js +1 -0
  263. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  264. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  265. package/dist/generated/prisma/models/McpServer.d.ts +1500 -0
  266. package/dist/generated/prisma/models/McpServer.js +1 -0
  267. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +77 -1
  268. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
  269. package/dist/generated/prisma/models/Principal.d.ts +167 -0
  270. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  271. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  272. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  273. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  274. package/dist/generated/prisma/models/ResourceGrant.d.ts +1 -1
  275. package/dist/generated/prisma/models/Run.d.ts +738 -2
  276. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  277. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  278. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  279. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  280. package/dist/generated/prisma/models/Secret.d.ts +387 -0
  281. package/dist/generated/prisma/models/Tool.d.ts +223 -1
  282. package/dist/generated/prisma/models.d.ts +10 -0
  283. package/dist/help/search.js +12 -3
  284. package/dist/help-index.json +2033 -110
  285. package/dist/import/create.js +48 -4
  286. package/dist/import/neutral-schema.d.ts +51 -281
  287. package/dist/import/neutral-schema.js +7 -4
  288. package/dist/knowledge/check.d.ts +1 -1
  289. package/dist/knowledge/cli.d.ts +11 -1
  290. package/dist/knowledge/cli.js +37 -4
  291. package/dist/knowledge/concept.d.ts +3 -19
  292. package/dist/knowledge/location.d.ts +31 -0
  293. package/dist/knowledge/location.js +78 -0
  294. package/dist/mcp/auth/access.d.ts +10 -2
  295. package/dist/mcp/auth/access.js +15 -1
  296. package/dist/mcp/auth/grants-cli.d.ts +6 -4
  297. package/dist/mcp/auth/grants-cli.js +42 -3
  298. package/dist/mcp/auth/ownership.d.ts +7 -7
  299. package/dist/mcp/auth/resource-server.d.ts +3 -1
  300. package/dist/mcp/auth/resource-server.js +17 -2
  301. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  302. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  303. package/dist/mcp/context.d.ts +3 -0
  304. package/dist/mcp/host-events/github-ingress.d.ts +2 -0
  305. package/dist/mcp/host-events/github-ingress.js +2 -1
  306. package/dist/mcp/index.d.ts +6 -0
  307. package/dist/mcp/index.js +69 -10
  308. package/dist/mcp/server.d.ts +13 -0
  309. package/dist/mcp/server.js +33 -14
  310. package/dist/mcp/tools/agents.d.ts +4 -0
  311. package/dist/mcp/tools/agents.js +295 -28
  312. package/dist/mcp/tools/datastore.js +17 -8
  313. package/dist/mcp/tools/grants.js +73 -29
  314. package/dist/mcp/tools/host-providers.d.ts +2 -0
  315. package/dist/mcp/tools/host-providers.js +215 -0
  316. package/dist/mcp/tools/mcp-servers.d.ts +26 -0
  317. package/dist/mcp/tools/mcp-servers.js +481 -0
  318. package/dist/mcp/tools/memory.js +11 -1
  319. package/dist/mcp/tools/notification-channels.js +2 -2
  320. package/dist/mcp/tools/packages.d.ts +2 -0
  321. package/dist/mcp/tools/packages.js +195 -0
  322. package/dist/mcp/tools/repositories.js +65 -12
  323. package/dist/mcp/tools/run-access.d.ts +16 -0
  324. package/dist/mcp/tools/run-access.js +25 -0
  325. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  326. package/dist/mcp/tools/run-transcript-download.js +129 -0
  327. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  328. package/dist/mcp/tools/run-transcript.js +70 -0
  329. package/dist/mcp/tools/runs.js +209 -27
  330. package/dist/mcp/tools/scheduling.js +3 -1
  331. package/dist/mcp/tools/secret-elicitation-form.js +5 -0
  332. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  333. package/dist/mcp/tools/secret-elicitation-server.js +10 -61
  334. package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
  335. package/dist/mcp/tools/secret-elicitation.js +25 -2
  336. package/dist/mcp/tools/secrets.js +40 -6
  337. package/dist/mcp/tools/stop-run.d.ts +2 -0
  338. package/dist/mcp/tools/stop-run.js +82 -0
  339. package/dist/mcp/tools/subagents.js +2 -2
  340. package/dist/mcp/tools/tools.d.ts +7 -5
  341. package/dist/mcp/tools/tools.js +64 -16
  342. package/dist/mcp/tools/trigger.js +28 -6
  343. package/dist/mcp/transport/http-limits.d.ts +2 -0
  344. package/dist/mcp/transport/http-limits.js +6 -2
  345. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  346. package/dist/mcp/transport/stdio-link-host.js +67 -0
  347. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  348. package/dist/mcp/transport/streamable-http.js +41 -1
  349. package/dist/mcp/webhooks/ingress.js +10 -0
  350. package/dist/native-worker/docker-launcher.d.ts +38 -2
  351. package/dist/native-worker/docker-launcher.js +65 -5
  352. package/dist/native-worker/gateway-server.d.ts +55 -3
  353. package/dist/native-worker/gateway-server.js +152 -34
  354. package/dist/native-worker/gateway.d.ts +29 -1
  355. package/dist/native-worker/gateway.js +74 -4
  356. package/dist/native-worker/http-server.d.ts +7 -1
  357. package/dist/native-worker/http-server.js +62 -7
  358. package/dist/native-worker/http-transport.js +1 -1
  359. package/dist/native-worker/kubernetes-launcher.d.ts +7 -3
  360. package/dist/native-worker/kubernetes-launcher.js +43 -3
  361. package/dist/native-worker/launch.d.ts +18 -1
  362. package/dist/native-worker/launch.js +6 -1
  363. package/dist/native-worker/ledger.d.ts +24 -4
  364. package/dist/native-worker/ledger.js +62 -8
  365. package/dist/native-worker/loopback.js +3 -8
  366. package/dist/native-worker/main.d.ts +2 -1
  367. package/dist/native-worker/main.js +14 -3
  368. package/dist/native-worker/protocol.d.ts +130 -577
  369. package/dist/native-worker/protocol.js +51 -2
  370. package/dist/native-worker/sandbox-executor.d.ts +17 -2
  371. package/dist/native-worker/sandbox-executor.js +78 -4
  372. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  373. package/dist/native-worker/stderr-redaction.js +237 -0
  374. package/dist/native-worker/stdio.d.ts +1 -1
  375. package/dist/native-worker/stdio.js +6 -5
  376. package/dist/native-worker/warm-pool.d.ts +2 -2
  377. package/dist/native-worker/warm-pool.js +4 -4
  378. package/dist/native-worker/worker.js +28 -2
  379. package/dist/observability/metrics.js +6 -1
  380. package/dist/providers/auth/self-hosted.d.ts +1 -1
  381. package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
  382. package/dist/providers/coding-proxy/capability-hash.js +5 -0
  383. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  384. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  385. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  386. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  387. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  388. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  389. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  390. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  391. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  392. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  393. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  394. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  395. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  396. package/dist/providers/coding-proxy/hold.js +86 -0
  397. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  398. package/dist/providers/coding-proxy/interrupted.js +104 -0
  399. package/dist/providers/coding-proxy/mcp-route.d.ts +34 -0
  400. package/dist/providers/coding-proxy/mcp-route.js +166 -0
  401. package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -2
  402. package/dist/providers/coding-proxy/memory-ledger.js +99 -8
  403. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  404. package/dist/providers/coding-proxy/metering.js +27 -4
  405. package/dist/providers/coding-proxy/prisma-ledger.d.ts +16 -2
  406. package/dist/providers/coding-proxy/prisma-ledger.js +209 -69
  407. package/dist/providers/coding-proxy/proxy.d.ts +21 -2
  408. package/dist/providers/coding-proxy/proxy.js +300 -48
  409. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  410. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  411. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  412. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  413. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  414. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  415. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  416. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  417. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  418. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  419. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  420. package/dist/providers/coding-proxy/registry/service.js +579 -112
  421. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  422. package/dist/providers/coding-proxy/registry/store.js +54 -1
  423. package/dist/providers/coding-proxy/runtime.d.ts +10 -0
  424. package/dist/providers/coding-proxy/runtime.js +109 -16
  425. package/dist/providers/coding-proxy/server.d.ts +9 -1
  426. package/dist/providers/coding-proxy/server.js +55 -1
  427. package/dist/providers/coding-proxy/types.d.ts +78 -1
  428. package/dist/providers/datastore/types.d.ts +5 -0
  429. package/dist/providers/engine/types.d.ts +17 -2
  430. package/dist/providers/engine/types.js +17 -0
  431. package/dist/providers/executor/composition.d.ts +10 -3
  432. package/dist/providers/executor/composition.js +52 -7
  433. package/dist/providers/executor/container.d.ts +394 -9
  434. package/dist/providers/executor/container.js +1210 -96
  435. package/dist/providers/executor/dbos-status.d.ts +31 -0
  436. package/dist/providers/executor/dbos-status.js +64 -0
  437. package/dist/providers/executor/dbos.d.ts +50 -1
  438. package/dist/providers/executor/dbos.js +207 -20
  439. package/dist/providers/executor/deferred.d.ts +12 -24
  440. package/dist/providers/executor/deferred.js +10 -29
  441. package/dist/providers/executor/in-process.d.ts +9 -1
  442. package/dist/providers/executor/in-process.js +14 -4
  443. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  444. package/dist/providers/executor/linked-issue-reader.js +30 -0
  445. package/dist/providers/executor/routing.d.ts +2 -0
  446. package/dist/providers/executor/routing.js +4 -0
  447. package/dist/providers/executor/types.d.ts +13 -0
  448. package/dist/providers/host-tools/invoke.d.ts +37 -0
  449. package/dist/providers/host-tools/invoke.js +117 -0
  450. package/dist/providers/host-tools/operations.d.ts +65 -0
  451. package/dist/providers/host-tools/operations.js +149 -0
  452. package/dist/providers/host-tools/registry.d.ts +79 -0
  453. package/dist/providers/host-tools/registry.js +362 -0
  454. package/dist/providers/host-tools/request-guard.d.ts +17 -0
  455. package/dist/providers/host-tools/request-guard.js +99 -0
  456. package/dist/providers/host-tools/self-test.d.ts +64 -0
  457. package/dist/providers/host-tools/self-test.js +142 -0
  458. package/dist/providers/index.d.ts +2 -1
  459. package/dist/providers/issue-tracker/types.d.ts +17 -0
  460. package/dist/providers/issue-tracker/types.js +39 -1
  461. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  462. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  463. package/dist/providers/jobs/docker-isolation.d.ts +10 -2
  464. package/dist/providers/jobs/docker-isolation.js +47 -8
  465. package/dist/providers/jobs/docker.d.ts +9 -0
  466. package/dist/providers/jobs/docker.js +60 -11
  467. package/dist/providers/jobs/fake-kubernetes-api.d.ts +2 -0
  468. package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
  469. package/dist/providers/jobs/kubernetes-api.d.ts +8 -0
  470. package/dist/providers/jobs/kubernetes-api.js +10 -0
  471. package/dist/providers/jobs/kubernetes-client.js +10 -1
  472. package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
  473. package/dist/providers/jobs/kubernetes-isolation.js +32 -3
  474. package/dist/providers/jobs/kubernetes.d.ts +11 -1
  475. package/dist/providers/jobs/kubernetes.js +111 -17
  476. package/dist/providers/jobs/types.d.ts +39 -0
  477. package/dist/providers/jobs/types.js +13 -1
  478. package/dist/providers/llm/anthropic.js +5 -1
  479. package/dist/providers/llm/bedrock.d.ts +0 -12
  480. package/dist/providers/llm/bedrock.js +4 -0
  481. package/dist/providers/llm/claude-messages.d.ts +3 -1
  482. package/dist/providers/llm/claude-messages.js +4 -1
  483. package/dist/providers/llm/claude-provider.d.ts +2 -2
  484. package/dist/providers/llm/claude-provider.js +2 -2
  485. package/dist/providers/llm/openai.d.ts +2 -2
  486. package/dist/providers/llm/openai.js +6 -2
  487. package/dist/providers/llm/routing.d.ts +2 -2
  488. package/dist/providers/llm/routing.js +2 -2
  489. package/dist/providers/llm/types.d.ts +12 -2
  490. package/dist/providers/review-host/github-events.d.ts +9 -1
  491. package/dist/providers/review-host/github-events.js +34 -12
  492. package/dist/providers/review-host/github.d.ts +29 -2
  493. package/dist/providers/review-host/github.js +224 -29
  494. package/dist/providers/review-host/local.d.ts +8 -4
  495. package/dist/providers/review-host/local.js +49 -31
  496. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  497. package/dist/providers/review-host/patch-pages.js +176 -0
  498. package/dist/providers/review-host/review-format.d.ts +19 -1
  499. package/dist/providers/review-host/review-format.js +38 -7
  500. package/dist/providers/review-host/types.d.ts +140 -6
  501. package/dist/providers/review-host/types.js +9 -1
  502. package/dist/providers/storage/gcs.d.ts +63 -0
  503. package/dist/providers/storage/gcs.js +69 -0
  504. package/dist/providers/storage/index.d.ts +15 -0
  505. package/dist/providers/storage/index.js +14 -0
  506. package/dist/providers/storage/local.d.ts +24 -0
  507. package/dist/providers/storage/local.js +92 -0
  508. package/dist/providers/storage/meter.d.ts +14 -0
  509. package/dist/providers/storage/meter.js +34 -0
  510. package/dist/providers/storage/s3.d.ts +41 -0
  511. package/dist/providers/storage/s3.js +107 -0
  512. package/dist/providers/storage/types.d.ts +37 -3
  513. package/dist/providers/storage/types.js +21 -4
  514. package/dist/providers/vcs/git.d.ts +39 -4
  515. package/dist/providers/vcs/git.js +339 -26
  516. package/dist/providers/vcs/github-remote.d.ts +26 -3
  517. package/dist/providers/vcs/github-remote.js +124 -14
  518. package/dist/providers/vcs/github.d.ts +183 -44
  519. package/dist/providers/vcs/github.js +455 -56
  520. package/dist/providers/vcs/index.d.ts +1 -1
  521. package/dist/providers/vcs/index.js +9 -2
  522. package/dist/providers/vcs/pr-description.d.ts +127 -0
  523. package/dist/providers/vcs/pr-description.js +270 -0
  524. package/dist/providers/vcs/remote.d.ts +37 -1
  525. package/dist/providers/vcs/remote.js +7 -1
  526. package/dist/providers/vcs/routing.d.ts +16 -8
  527. package/dist/providers/vcs/routing.js +27 -6
  528. package/dist/providers/vcs/types.d.ts +150 -5
  529. package/dist/quickstart/coding-seed.d.ts +14 -3
  530. package/dist/quickstart/coding-seed.js +213 -4
  531. package/dist/quickstart/index.d.ts +5 -0
  532. package/dist/quickstart/index.js +21 -0
  533. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  534. package/dist/quickstart/reviewer-prompt.js +6 -6
  535. package/dist/quickstart-images.json +1 -1
  536. package/dist/sandbox/eval-core.d.ts +12 -2
  537. package/dist/sandbox/eval-core.js +20 -4
  538. package/dist/sandbox/generated/zod.bundle.js +62 -1
  539. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  540. package/dist/sandbox/host-functions.d.ts +5 -0
  541. package/dist/sandbox/host-functions.js +13 -13
  542. package/dist/sandbox/limits.d.ts +4 -1
  543. package/dist/sandbox/limits.js +4 -1
  544. package/dist/sandbox/run-in-sandbox.d.ts +6 -0
  545. package/dist/sandbox/run-in-sandbox.js +14 -2
  546. package/dist/sandbox/safe-fetch.d.ts +2 -0
  547. package/dist/sandbox/safe-fetch.js +1 -1
  548. package/dist/sandbox/secret-broker.d.ts +1 -0
  549. package/dist/sandbox/secret-broker.js +4 -5
  550. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  551. package/dist/sandbox/tool-timeout.d.ts +32 -0
  552. package/dist/sandbox/tool-timeout.js +52 -0
  553. package/dist/sandbox/user-tool.d.ts +8 -1
  554. package/dist/sandbox/user-tool.js +9 -3
  555. package/dist/sandbox/zod-params.d.ts +37 -5
  556. package/dist/sandbox/zod-params.js +181 -26
  557. package/dist/serve.js +8 -1
  558. package/dist/viewer/api-schema.d.ts +349 -2627
  559. package/dist/viewer/api-schema.js +7 -0
  560. package/dist/viewer/build-schemas.js +6 -2
  561. package/dist/viewer/graph.js +2 -1
  562. package/dist/viewer/openapi.js +2 -4
  563. package/dist/wardby-bin.js +15 -0
  564. package/docs/README.md +11 -1
  565. package/docs/agent-recipes.md +95 -24
  566. package/docs/architecture-runtime.md +1 -1
  567. package/docs/claude-code-plugin.md +164 -0
  568. package/docs/code-review-agents.md +557 -41
  569. package/docs/coding-agent-setup.md +566 -8
  570. package/docs/coding-packages.md +1033 -90
  571. package/docs/coding-services.md +27 -12
  572. package/docs/coding-worker-byo-images.md +24 -2
  573. package/docs/coding-worker-isolation.md +183 -37
  574. package/docs/debugging-agent-runs.md +242 -0
  575. package/docs/getting-started-gke.md +129 -141
  576. package/docs/getting-started-identity-provider.md +53 -38
  577. package/docs/getting-started.md +17 -0
  578. package/docs/host-providers.md +294 -0
  579. package/docs/jira-agents.md +17 -8
  580. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  581. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  582. package/docs/knowledge/delegation-admission-slots.md +52 -0
  583. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  584. package/docs/knowledge/import-rename-target.md +52 -0
  585. package/docs/knowledge/index.md +57 -0
  586. package/docs/knowledge/log.md +9 -0
  587. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  588. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  589. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  590. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  591. package/docs/knowledge/overview-cli.md +74 -0
  592. package/docs/knowledge/overview-coding-proxy.md +72 -0
  593. package/docs/knowledge/overview-coding.md +72 -0
  594. package/docs/knowledge/overview-config.md +60 -0
  595. package/docs/knowledge/overview-core.md +72 -0
  596. package/docs/knowledge/overview-deploy.md +83 -0
  597. package/docs/knowledge/overview-mcp.md +61 -0
  598. package/docs/knowledge/overview-prisma.md +72 -0
  599. package/docs/knowledge/overview-providers.md +89 -0
  600. package/docs/knowledge/overview-sandbox.md +83 -0
  601. package/docs/knowledge/overview-surfaces.md +83 -0
  602. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  603. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  604. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  605. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  606. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  607. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  608. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  609. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  610. package/docs/knowledge/warm-input-publication.md +30 -0
  611. package/docs/knowledge/workspace-staging-failure.md +54 -0
  612. package/docs/knowledge.md +54 -14
  613. package/docs/mcp-servers.md +254 -0
  614. package/docs/native-sandbox.md +143 -31
  615. package/docs/observability.md +4 -0
  616. package/docs/security-deployment.md +139 -29
  617. package/docs/slack-notifications.md +35 -19
  618. package/docs/tool-secrets.md +45 -10
  619. package/docs/viewer-api.md +6 -0
  620. package/docs/viewer-api.openapi.yml +1 -1
  621. package/help/admin-viewer.md +28 -2
  622. package/help/agent-recipes.md +33 -2
  623. package/help/architecture-agent.md +11 -6
  624. package/help/brokered-secrets.md +3 -0
  625. package/help/build-claude-code-image.md +1 -1
  626. package/help/build-worker-image.md +3 -1
  627. package/help/builder-agent.md +19 -6
  628. package/help/claude-code-run-pane.md +40 -0
  629. package/help/code-review-agents.md +177 -6
  630. package/help/coding-packages.md +156 -6
  631. package/help/cost-attribution.md +9 -5
  632. package/help/creating-agents.md +14 -1
  633. package/help/dependency-cache.md +143 -0
  634. package/help/deploy-gke.md +15 -8
  635. package/help/errors/budget-exhausted.md +187 -0
  636. package/help/errors/budget-group-exhausted.md +5 -1
  637. package/help/errors/coding-mcp-pins-unavailable.md +35 -0
  638. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  639. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  640. package/help/errors/continuation-closed.md +9 -12
  641. package/help/errors/database-auth-invalid.md +1 -1
  642. package/help/errors/delegation-conflict.md +24 -0
  643. package/help/errors/file-list-truncated.md +45 -0
  644. package/help/errors/full-read-required.md +49 -0
  645. package/help/errors/github-account-not-allowed.md +4 -0
  646. package/help/errors/graph-incomplete.md +43 -0
  647. package/help/errors/graph-limit.md +43 -0
  648. package/help/errors/host-provider-error.md +40 -0
  649. package/help/errors/host-tool-failed.md +36 -0
  650. package/help/errors/mcp-call-limit.md +22 -0
  651. package/help/errors/mcp-call-timeout.md +22 -0
  652. package/help/errors/mcp-server-auth-failed.md +22 -0
  653. package/help/errors/mcp-server-credentials-unavailable.md +45 -0
  654. package/help/errors/mcp-server-error.md +28 -0
  655. package/help/errors/mcp-server-unreachable.md +22 -0
  656. package/help/errors/mcp-servers-off.md +21 -0
  657. package/help/errors/mcp-tool-not-allowed.md +26 -0
  658. package/help/errors/mcp-tool-removed.md +22 -0
  659. package/help/errors/mcp-unavailable.md +25 -0
  660. package/help/errors/merge-conflict.md +49 -0
  661. package/help/errors/native-sandbox-capacity.md +1 -1
  662. package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
  663. package/help/errors/native-sandbox-docker-failed.md +1 -1
  664. package/help/errors/native-sandbox-gateway-error.md +20 -0
  665. package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
  666. package/help/errors/native-sandbox-image-not-pinned.md +1 -1
  667. package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
  668. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  669. package/help/errors/native-sandbox-network-unenforced.md +1 -1
  670. package/help/errors/native-sandbox-requires-catalog.md +1 -1
  671. package/help/errors/native-sandbox-unavailable.md +1 -1
  672. package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
  673. package/help/errors/native-sandbox-worker-exited.md +4 -3
  674. package/help/errors/native-sandbox-worker-lost.md +1 -1
  675. package/help/errors/native-sandbox-worker-unready.md +1 -1
  676. package/help/errors/package-not-allowed-pending.md +52 -0
  677. package/help/errors/package-not-allowed.md +51 -0
  678. package/help/errors/package-refusals.md +43 -0
  679. package/help/errors/patch-cursor-malformed.md +31 -0
  680. package/help/errors/repository-not-listed.md +36 -0
  681. package/help/errors/repository-required.md +36 -0
  682. package/help/errors/run-lost.md +39 -0
  683. package/help/errors/run-transcript-download.md +44 -0
  684. package/help/errors/secret-in-value.md +69 -0
  685. package/help/errors/target-merge.md +40 -0
  686. package/help/errors/tool-timeout.md +38 -0
  687. package/help/fix-merge-conflicts.md +73 -0
  688. package/help/github-app-setup.md +132 -0
  689. package/help/github.md +22 -0
  690. package/help/host-providers.md +40 -0
  691. package/help/identity-and-access.md +6 -1
  692. package/help/jira.md +23 -6
  693. package/help/knowledge.md +16 -7
  694. package/help/local-repositories.md +1 -1
  695. package/help/low-power-mode.md +7 -1
  696. package/help/mcp-servers.md +73 -0
  697. package/help/mcp.md +7 -2
  698. package/help/merge-order-check.md +5 -0
  699. package/help/native-capabilities.md +55 -1
  700. package/help/native-sandbox.md +16 -2
  701. package/help/operating-agents.md +21 -0
  702. package/help/package-audit-mode.md +91 -0
  703. package/help/related-pull-requests.md +17 -10
  704. package/help/repo-instructions-and-skills.md +3 -1
  705. package/help/resume-runs-locally.md +134 -0
  706. package/help/review-fix-rounds.md +33 -1
  707. package/help/sharing-agents.md +59 -0
  708. package/help/slack-notifications.md +19 -5
  709. package/help/status-comments.md +31 -0
  710. package/help/stop-run.md +58 -0
  711. package/help/troubleshooting/budgets.md +28 -0
  712. package/help/troubleshooting/coding-workers.md +86 -7
  713. package/help/troubleshooting/debugging-agent-runs.md +29 -0
  714. package/package.json +18 -10
  715. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  716. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  717. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  718. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  719. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  720. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  721. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  722. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  723. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  724. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  725. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  726. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  727. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  728. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  729. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  730. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  731. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  732. package/prisma/migrations/20261102000000_host_providers/migration.sql +56 -0
  733. package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
  734. package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
  735. package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
  736. package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
  737. package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
  738. package/prisma/schema.prisma +468 -109
  739. package/scripts/git-askpass.sh +1 -1
  740. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -1,8 +1,12 @@
1
- import { createHash, randomBytes, randomUUID } from "node:crypto";
1
+ import { randomBytes, randomUUID } from "node:crypto";
2
2
  import { shippedCatalog } from "../llm/catalog.js";
3
3
  import { SHIPPED_CATALOG_VERSION } from "../llm/catalog-shipped.js";
4
4
  import { deriveRegistryToken } from "../../coding/registry/token.js";
5
- import { AnthropicSseUsageTracker, actualCostUsd, estimateReservationUsd, fingerprintRequest, parseAnthropicAuthoritativeUsage, parseAuthoritativeUsage, pricingSnapshot, safeUpstreamErrorCode, terminalUsageFromSseFrame, } from "./metering.js";
5
+ import { capabilityHash } from "./capability-hash.js";
6
+ import { CLAUDE_MCP_TOOL_PREFIX } from "../../coding/mcp-token.js";
7
+ import { AnthropicSseUsageTracker, actualCostUsd, fingerprintRequest, parseAnthropicAuthoritativeUsage, parseAuthoritativeUsage, pricingSnapshot, safeUpstreamErrorCode, terminalUsageFromSseFrame, } from "./metering.js";
8
+ import { conversationKey, estimateHold } from "./hold.js";
9
+ import { estimateInterrupted, previousInput } from "./interrupted.js";
6
10
  import { createPinnedProxyFetch } from "./secure-fetch.js";
7
11
  export const PROXY_MAX_BODY_BYTES = 8 * 1024 * 1024;
8
12
  export const PROXY_MAX_OUTPUT_TOKENS = 1_000_000;
@@ -46,20 +50,19 @@ export class CodingProxyError extends Error {
46
50
  this.code = code;
47
51
  }
48
52
  }
49
- export function capabilityHash(capability) {
50
- return createHash("sha256").update(capability).digest("base64url");
51
- }
53
+ export { capabilityHash };
52
54
  // OpenAI Responses allowlist. Everything a request may carry is listed here;
53
55
  // anything else is refused before a credential is resolved. It mirrors what the
54
56
  // pinned Codex CLI (src/coding-worker/package.json) actually sends, recorded in
55
57
  // fixtures/codex-<version>-responses-requests.json. Only client-side tools
56
- // (function, custom, and namespaces of them) are allowed: a hosted tool (web
57
- // search, remote MCP, code interpreter, image generation, file search, ...), a
58
- // remote image or file, a stored prompt, or a previous response would make
59
- // OpenAI fetch or run something outside the worker's egress policy and outside
60
- // the token-metered budget. Tool names vary by model and Codex version, so they
61
- // are checked for shape, not against a fixed list: a client-side tool the model
62
- // calls is executed by the worker itself, which the container boundary governs.
58
+ // (function, custom, namespaces of them, and the client-executed tool_search)
59
+ // are allowed: a hosted tool (web search, remote MCP, code interpreter, image
60
+ // generation, file search, ...), a remote image or file, a stored prompt, or a
61
+ // previous response would make OpenAI fetch or run something outside the
62
+ // worker's egress policy and outside the token-metered budget. Tool names vary
63
+ // by model and Codex version, so they are checked for shape, not against a
64
+ // fixed list: a client-side tool the model calls is executed by the worker
65
+ // itself, which the container boundary governs.
63
66
  const OPENAI_REQUEST_KEYS = new Set([
64
67
  "model",
65
68
  "instructions",
@@ -149,13 +152,32 @@ function openAiToolName(value, code = "invalid_openai_request") {
149
152
  if (typeof value !== "string" || !OPENAI_TOOL_NAME.test(value))
150
153
  throw new CodingProxyError(400, code);
151
154
  }
152
- function validateOpenAiFunctionTool(tool) {
153
- openAiOnlyKeys(tool, ["type", "name", "description", "strict", "parameters"], "invalid_openai_tool");
155
+ function validateOpenAiFunctionTool(tool, inSearchOutput) {
156
+ openAiOnlyKeys(tool, inSearchOutput
157
+ ? ["type", "name", "description", "strict", "defer_loading", "parameters"]
158
+ : ["type", "name", "description", "strict", "parameters"], "invalid_openai_tool");
154
159
  openAiToolName(tool.name, "invalid_openai_tool");
155
160
  openAiOptional(tool.description, (value) => openAiString(value, MAX_TOOL_TEXT_BYTES, "invalid_openai_tool"));
156
161
  if (tool.strict !== undefined && typeof tool.strict !== "boolean") {
157
162
  throw new CodingProxyError(400, "invalid_openai_tool");
158
163
  }
164
+ // Codex marks the tools a tool_search_output loads with defer_loading: true,
165
+ // and sends it nowhere else. It only delays when the model sees the
166
+ // definition, which is checked in full.
167
+ if (tool.defer_loading !== undefined && tool.defer_loading !== true) {
168
+ throw new CodingProxyError(400, "invalid_openai_tool");
169
+ }
170
+ openAiOptional(tool.parameters, (value) => openAiRecord(value, "invalid_openai_tool"));
171
+ }
172
+ // The tool_search tool Codex sends for models whose metadata asks for it. Only
173
+ // client execution: Codex runs the search over its own deferred tools and
174
+ // returns them in a tool_search_output item. A server-executed search would
175
+ // have OpenAI run it.
176
+ function validateOpenAiToolSearchTool(tool) {
177
+ openAiOnlyKeys(tool, ["type", "execution", "description", "parameters"], "invalid_openai_tool");
178
+ if (tool.execution !== "client")
179
+ throw new CodingProxyError(400, "openai_tool_not_allowed:tool_search");
180
+ openAiOptional(tool.description, (value) => openAiString(value, MAX_TOOL_TEXT_BYTES, "invalid_openai_tool"));
159
181
  openAiOptional(tool.parameters, (value) => openAiRecord(value, "invalid_openai_tool"));
160
182
  }
161
183
  function validateOpenAiCustomTool(tool) {
@@ -173,30 +195,57 @@ function validateOpenAiCustomTool(tool) {
173
195
  }
174
196
  openAiString(format.definition, MAX_TOOL_TEXT_BYTES, "invalid_openai_tool");
175
197
  }
176
- function validateOpenAiTools(value, count, nested = false) {
198
+ // Every tool list (the request's tools, each additional_tools item, each
199
+ // tool_search_output item) is capped at MAX_OPENAI_TOOLS entries on its own.
200
+ // Across the request, `distinct` holds the `namespace/name` of each callable
201
+ // tool and is capped too. Codex replays every earlier tool_search_output on
202
+ // each turn, so a long run repeats the same definitions many times: each copy
203
+ // is still validated, but only a tool not seen before adds to the shared cap.
204
+ function validateOpenAiTools(value, distinct, { toolSearch = false, inSearchOutput = false, namespace, listed = { value: 0 }, } = {}) {
177
205
  if (!Array.isArray(value))
178
206
  throw new CodingProxyError(400, "invalid_openai_tool");
207
+ const callable = (name) => {
208
+ distinct.add(`${namespace ?? ""}/${name}`);
209
+ if (distinct.size > MAX_OPENAI_TOOLS)
210
+ throw new CodingProxyError(400, "invalid_openai_tool");
211
+ };
179
212
  for (const candidate of value) {
180
- if (++count.value > MAX_OPENAI_TOOLS)
213
+ if (++listed.value > MAX_OPENAI_TOOLS)
181
214
  throw new CodingProxyError(400, "invalid_openai_tool");
182
215
  const tool = openAiRecord(candidate, "invalid_openai_tool");
183
216
  if (tool.type === "function") {
184
- validateOpenAiFunctionTool(tool);
217
+ validateOpenAiFunctionTool(tool, inSearchOutput);
218
+ callable(tool.name);
185
219
  }
186
220
  else if (tool.type === "custom") {
187
221
  validateOpenAiCustomTool(tool);
222
+ callable(tool.name);
188
223
  }
189
- else if (tool.type === "namespace" && !nested) {
224
+ else if (tool.type === "namespace" && namespace === undefined) {
190
225
  openAiOnlyKeys(tool, ["type", "name", "description", "tools"], "invalid_openai_tool");
191
226
  openAiToolName(tool.name, "invalid_openai_tool");
192
227
  openAiOptional(tool.description, (value) => openAiString(value, MAX_TOOL_TEXT_BYTES, "invalid_openai_tool"));
193
- validateOpenAiTools(tool.tools, count, true);
228
+ validateOpenAiTools(tool.tools, distinct, { inSearchOutput, namespace: tool.name, listed });
229
+ }
230
+ else if (tool.type === "tool_search" && toolSearch) {
231
+ validateOpenAiToolSearchTool(tool);
232
+ callable("tool_search");
194
233
  }
195
234
  else {
196
235
  throw new CodingProxyError(400, openAiCode("openai_tool_not_allowed", tool.type));
197
236
  }
198
237
  }
199
238
  }
239
+ // The arguments the model gave the client-side tool_search, as its parameters
240
+ // in the captures declare them: a query and an optional result limit.
241
+ function validateOpenAiToolSearchArguments(value) {
242
+ const args = openAiRecord(value);
243
+ openAiOnlyKeys(args, ["query", "limit"]);
244
+ openAiString(args.query, MAX_TOOL_TEXT_BYTES);
245
+ if (args.limit !== undefined && !(Number.isSafeInteger(args.limit) && args.limit > 0)) {
246
+ throw new CodingProxyError(400, "invalid_openai_request");
247
+ }
248
+ }
200
249
  function validateOpenAiContentPart(value, allowed) {
201
250
  const part = openAiRecord(value);
202
251
  if (typeof part.type !== "string" || !allowed.has(part.type)) {
@@ -239,7 +288,7 @@ function validateOpenAiTextParts(value, type) {
239
288
  openAiString(part.text, PROXY_MAX_BODY_BYTES);
240
289
  }
241
290
  }
242
- function validateOpenAiInputItem(value, toolCount) {
291
+ function validateOpenAiInputItem(value, distinctTools) {
243
292
  const item = openAiRecord(value);
244
293
  switch (item.type) {
245
294
  case undefined:
@@ -298,12 +347,32 @@ function validateOpenAiInputItem(value, toolCount) {
298
347
  openAiOptional(item.recipient, (value) => openAiString(value, MAX_OPENAI_ID_LENGTH));
299
348
  validateOpenAiContent(item.content, OPENAI_AGENT_MESSAGE_PARTS, false);
300
349
  return;
350
+ case "tool_search_call":
351
+ openAiOnlyKeys(item, ["type", "id", "call_id", "status", "execution", "arguments"]);
352
+ openAiOptional(item.id, openAiId);
353
+ openAiId(item.call_id);
354
+ openAiOptional(item.status, (value) => openAiString(value, 64));
355
+ if (item.execution !== "client")
356
+ throw new CodingProxyError(400, openAiCode("openai_input_not_allowed", item.type));
357
+ validateOpenAiToolSearchArguments(item.arguments);
358
+ return;
359
+ case "tool_search_output":
360
+ // The tools the client-side search loaded: each one passes the same checks
361
+ // as a top-level tool, so this cannot bring in a shape the proxy refuses.
362
+ openAiOnlyKeys(item, ["type", "id", "call_id", "status", "execution", "tools"]);
363
+ openAiOptional(item.id, openAiId);
364
+ openAiId(item.call_id);
365
+ openAiOptional(item.status, (value) => openAiString(value, 64));
366
+ if (item.execution !== "client")
367
+ throw new CodingProxyError(400, openAiCode("openai_input_not_allowed", item.type));
368
+ validateOpenAiTools(item.tools, distinctTools, { inSearchOutput: true });
369
+ return;
301
370
  case "additional_tools":
302
371
  openAiOnlyKeys(item, ["type", "id", "role", "tools"]);
303
372
  openAiOptional(item.id, openAiId);
304
373
  if (item.role !== undefined && item.role !== "developer")
305
374
  throw new CodingProxyError(400, "invalid_openai_request");
306
- validateOpenAiTools(item.tools, toolCount);
375
+ validateOpenAiTools(item.tools, distinctTools);
307
376
  return;
308
377
  default:
309
378
  throw new CodingProxyError(400, openAiCode("openai_input_not_allowed", item.type));
@@ -370,9 +439,9 @@ function validateOpenAiBody(body) {
370
439
  throw new CodingProxyError(400, "invalid_openai_request");
371
440
  }
372
441
  openAiOptional(body.instructions, (value) => openAiString(value, PROXY_MAX_BODY_BYTES));
373
- const toolCount = { value: 0 };
442
+ const distinctTools = new Set();
374
443
  if (body.tools !== undefined)
375
- validateOpenAiTools(body.tools, toolCount);
444
+ validateOpenAiTools(body.tools, distinctTools, { toolSearch: true });
376
445
  if (body.tool_choice !== undefined) {
377
446
  if (typeof body.tool_choice !== "string" || !OPENAI_TOOL_CHOICES.has(body.tool_choice)) {
378
447
  throw new CodingProxyError(400, "openai_tool_choice_not_allowed");
@@ -399,7 +468,7 @@ function validateOpenAiBody(body) {
399
468
  throw new CodingProxyError(400, "invalid_openai_request");
400
469
  }
401
470
  for (const item of body.input)
402
- validateOpenAiInputItem(item, toolCount);
471
+ validateOpenAiInputItem(item, distinctTools);
403
472
  }
404
473
  function parseOpenAiRequest(rawBody) {
405
474
  if (Buffer.byteLength(rawBody) > PROXY_MAX_BODY_BYTES)
@@ -514,15 +583,33 @@ function validateStructuredOutputTool(value) {
514
583
  if (tool.cache_control !== undefined)
515
584
  validateCacheControl(tool.cache_control);
516
585
  }
517
- function validateApprovedTool(value) {
586
+ /**
587
+ * One of the run's pinned MCP tools, as Claude Code advertises it: a plain client tool named
588
+ * `mcp__wardby_mcp__<exposed name>` (fixtures/claude-code-2.1.286-mcp-requests.json). Only the name
589
+ * is checked against the pins; the gateway checks the call itself again.
590
+ */
591
+ function validateMcpTool(tool) {
592
+ onlyKeys(tool, ["name", "description", "input_schema", "cache_control", "type"]);
593
+ if ((tool.description !== undefined &&
594
+ (typeof tool.description !== "string" || tool.description.length > MAX_TOOL_TEXT_BYTES)) ||
595
+ (tool.type !== undefined && tool.type !== "custom")) {
596
+ throw new CodingProxyError(400, "tools_not_allowed");
597
+ }
598
+ record(tool.input_schema, "tools_not_allowed");
599
+ if (tool.cache_control !== undefined)
600
+ validateCacheControl(tool.cache_control);
601
+ }
602
+ function validateApprovedTool(value, mcpTools) {
518
603
  const tool = record(value, "tools_not_allowed");
519
604
  if (tool.name === WARDBY_COMMAND_TOOL)
520
605
  return validateCommandTool(tool);
521
606
  if (tool.name === STRUCTURED_OUTPUT_TOOL)
522
607
  return validateStructuredOutputTool(tool);
608
+ if (typeof tool.name === "string" && mcpTools.has(tool.name))
609
+ return validateMcpTool(tool);
523
610
  throw new CodingProxyError(400, "tools_not_allowed");
524
611
  }
525
- function validateToolUseBlock(value) {
612
+ function validateToolUseBlock(value, mcpTools) {
526
613
  onlyKeys(value, ["type", "id", "name", "input"]);
527
614
  if (typeof value.id !== "string" || value.id.length < 1 || value.id.length > 512) {
528
615
  throw new CodingProxyError(400, "unsupported_anthropic_feature");
@@ -531,6 +618,9 @@ function validateToolUseBlock(value) {
531
618
  return validateCommandInput(value.input);
532
619
  if (value.name === STRUCTURED_OUTPUT_TOOL)
533
620
  return void record(value.input, "unsupported_anthropic_feature");
621
+ if (typeof value.name === "string" && mcpTools.has(value.name)) {
622
+ return void record(value.input, "unsupported_anthropic_feature");
623
+ }
534
624
  throw new CodingProxyError(400, "unsupported_anthropic_feature");
535
625
  }
536
626
  function validateToolResultBlock(value) {
@@ -557,7 +647,7 @@ function validateThinkingBlock(value) {
557
647
  throw new CodingProxyError(400, "unsupported_anthropic_feature");
558
648
  }
559
649
  }
560
- function validateMessageBlocks(value, role) {
650
+ function validateMessageBlocks(value, role, mcpTools) {
561
651
  if (!Array.isArray(value) || value.length > 10_000)
562
652
  throw new CodingProxyError(400, "invalid_anthropic_request");
563
653
  for (const candidate of value) {
@@ -566,7 +656,7 @@ function validateMessageBlocks(value, role) {
566
656
  validateTextBlock(block);
567
657
  }
568
658
  else if (block.type === "tool_use" && role === "assistant") {
569
- validateToolUseBlock(block);
659
+ validateToolUseBlock(block, mcpTools);
570
660
  }
571
661
  else if (block.type === "tool_result" && role === "user") {
572
662
  validateToolResultBlock(block);
@@ -622,7 +712,7 @@ function validateEffortConfig(value, { thinkingMode, efforts }, betas) {
622
712
  throw new CodingProxyError(400, "unsupported_anthropic_feature");
623
713
  }
624
714
  }
625
- function parseAnthropicRequest(rawBody, betaHeader, shape) {
715
+ function parseAnthropicRequest(rawBody, betaHeader, shape, mcpTools) {
626
716
  const beta = parseAnthropicBeta(betaHeader);
627
717
  if (Buffer.byteLength(rawBody) > PROXY_MAX_BODY_BYTES)
628
718
  throw new CodingProxyError(413, "payload_too_large");
@@ -686,18 +776,20 @@ function parseAnthropicRequest(rawBody, betaHeader, shape) {
686
776
  continue;
687
777
  }
688
778
  }
689
- validateMessageBlocks(message.content, message.role);
779
+ validateMessageBlocks(message.content, message.role, mcpTools);
690
780
  }
691
781
  if (body.tools !== undefined) {
692
- if (!Array.isArray(body.tools) || body.tools.length > 2)
782
+ // run_command and StructuredOutput, plus one per pinned MCP tool.
783
+ if (!Array.isArray(body.tools) || body.tools.length > 2 + mcpTools.size) {
693
784
  throw new CodingProxyError(400, "tools_not_allowed");
785
+ }
694
786
  const names = new Set();
695
787
  for (const tool of body.tools) {
696
788
  const definition = record(tool, "tools_not_allowed");
697
789
  if (typeof definition.name !== "string" || names.has(definition.name))
698
790
  throw new CodingProxyError(400, "tools_not_allowed");
699
791
  names.add(definition.name);
700
- validateApprovedTool(definition);
792
+ validateApprovedTool(definition, mcpTools);
701
793
  }
702
794
  }
703
795
  if (body.metadata !== undefined) {
@@ -758,13 +850,17 @@ function parseAnthropicRequest(rawBody, betaHeader, shape) {
758
850
  anthropicBeta: beta.header,
759
851
  };
760
852
  }
761
- function parseRequest(protocol, rawBody, anthropicBeta, shape) {
853
+ /** The Claude tool names of a session's pinned MCP tools; empty for a session without pins. */
854
+ function claudeMcpToolNames(pins) {
855
+ return new Set((pins ?? []).map((pin) => `${CLAUDE_MCP_TOOL_PREFIX}${pin.exposedName}`));
856
+ }
857
+ function parseRequest(protocol, rawBody, anthropicBeta, shape, mcpTools) {
762
858
  if (protocol !== "anthropic-messages" && anthropicBeta !== undefined) {
763
859
  throw new CodingProxyError(400, "invalid_anthropic_beta");
764
860
  }
765
861
  try {
766
862
  return protocol === "anthropic-messages"
767
- ? parseAnthropicRequest(rawBody, anthropicBeta, shape)
863
+ ? parseAnthropicRequest(rawBody, anthropicBeta, shape, mcpTools)
768
864
  : parseOpenAiRequest(rawBody);
769
865
  }
770
866
  catch (error) {
@@ -818,8 +914,10 @@ export class CodingProxy {
818
914
  getPricing;
819
915
  priceVersion;
820
916
  activeRequests = new Map();
917
+ onModelRequest;
821
918
  constructor(options) {
822
919
  this.ledger = options.ledger;
920
+ this.onModelRequest = options.onModelRequest;
823
921
  this.credentials = options.credentials;
824
922
  this.upstreamUrls = {
825
923
  "openai-responses": options.upstreamUrl ?? "https://api.openai.com/v1/responses",
@@ -870,6 +968,11 @@ export class CodingProxy {
870
968
  throw new Error("invalid_proxy_deadline");
871
969
  if (!input.credentialRef || input.credentialRef.length > 200)
872
970
  throw new Error("invalid_proxy_credential_reference");
971
+ // Both or neither: pins without a token could never be called, a token without pins lists nothing.
972
+ const mcp = input.mcpTools !== undefined || input.mcpTokenHash !== undefined;
973
+ if (mcp && (!input.mcpTools || input.mcpTools.length === 0 || !input.mcpTokenHash)) {
974
+ throw new Error("invalid_proxy_mcp_tools");
975
+ }
873
976
  const capability = `rrp_${randomBytes(32).toString("base64url")}`;
874
977
  const id = randomUUID();
875
978
  const registryTokenHash = capabilityHash(deriveRegistryToken(capability));
@@ -884,6 +987,7 @@ export class CodingProxy {
884
987
  budgetUsd: input.budgetUsd,
885
988
  registryTokenHash,
886
989
  terms: input.terms,
990
+ ...(mcp ? { mcpTools: input.mcpTools, mcpTokenHash: input.mcpTokenHash } : {}),
887
991
  });
888
992
  this.audit({ type: "session.created", runId: input.runId });
889
993
  return {
@@ -905,12 +1009,19 @@ export class CodingProxy {
905
1009
  budgetExhausted(sessionId) {
906
1010
  return this.ledger.budgetExhausted(sessionId);
907
1011
  }
1012
+ /** The numbers behind this session's first budget refusal, if any. */
1013
+ budgetRefusal(sessionId) {
1014
+ return this.ledger.budgetRefusal(sessionId);
1015
+ }
908
1016
  /** The code of the first upstream failure relayed for this session's run, if any. */
909
1017
  upstreamFailure(sessionId) {
910
1018
  return this.ledger.upstreamFailure(sessionId);
911
1019
  }
912
1020
  async execute(input, sink) {
913
1021
  const session = await this.authenticate(input.bearer);
1022
+ // The run's agent exists from its first model request on (both protocols arrive here).
1023
+ if (this.onModelRequest)
1024
+ await this.onModelRequest(session.runId).catch(() => undefined);
914
1025
  if (session.protocol !== input.protocol) {
915
1026
  this.audit({ type: "request.rejected", runId: session.runId, reason: "protocol_mismatch" });
916
1027
  throw new CodingProxyError(403, "protocol_mismatch");
@@ -923,7 +1034,7 @@ export class CodingProxy {
923
1034
  };
924
1035
  let parsed;
925
1036
  try {
926
- parsed = parseRequest(input.protocol, input.rawBody, input.anthropicBeta, shape);
1037
+ parsed = parseRequest(input.protocol, input.rawBody, input.anthropicBeta, shape, claudeMcpToolNames(session.mcpTools));
927
1038
  }
928
1039
  catch (error) {
929
1040
  // The session is already authenticated and no credential has been
@@ -948,7 +1059,32 @@ export class CodingProxy {
948
1059
  }
949
1060
  const requestKey = safeRequestKey(input.requestKey, parsed.fingerprint);
950
1061
  const snapshot = pricingSnapshot(terms.version, terms.pricing);
951
- const reservationUsd = estimateReservationUsd(Buffer.byteLength(parsed.encoded), parsed.maxOutputTokens, snapshot);
1062
+ const bodyBytes = Buffer.byteLength(parsed.encoded);
1063
+ const conversation = conversationKey(session.protocol, parsed.body);
1064
+ // A failed lookup holds the ceiling: never a reason to fail the request.
1065
+ const previous = conversation ? await this.ledger.previousReply(session.id, conversation).catch(() => null) : null;
1066
+ const holdNow = this.now();
1067
+ const hold = estimateHold({
1068
+ protocol: session.protocol,
1069
+ model: parsed.model,
1070
+ bodyBytes,
1071
+ maxOutputTokens: parsed.maxOutputTokens,
1072
+ pricing: snapshot,
1073
+ previous,
1074
+ now: holdNow,
1075
+ });
1076
+ // An interrupted reply's input, from the same previous reply and clock as the hold.
1077
+ const previousPrompt = previousInput({ model: parsed.model, bodyBytes, previous, pricing: snapshot, now: holdNow });
1078
+ const reservationUsd = hold.holdUsd;
1079
+ const holdAudit = {
1080
+ reservationUsd,
1081
+ ceilingUsd: hold.ceilingUsd,
1082
+ reservationBasis: hold.basis,
1083
+ ...(hold.fallback ? { holdFallback: hold.fallback } : {}),
1084
+ ...(hold.cachedTokens !== undefined
1085
+ ? { holdCachedTokens: hold.cachedTokens, holdUncachedTokens: hold.uncachedTokens }
1086
+ : {}),
1087
+ };
952
1088
  const reservation = await this.ledger.reserve({
953
1089
  id: randomUUID(),
954
1090
  sessionId: session.id,
@@ -956,6 +1092,10 @@ export class CodingProxy {
956
1092
  requestFingerprint: parsed.fingerprint,
957
1093
  model: parsed.model,
958
1094
  reservationUsd,
1095
+ requestBytes: bodyBytes,
1096
+ ceilingUsd: hold.ceilingUsd,
1097
+ reservationBasis: hold.basis,
1098
+ conversationKey: conversation,
959
1099
  pricing: snapshot,
960
1100
  now: this.now(),
961
1101
  });
@@ -969,7 +1109,12 @@ export class CodingProxy {
969
1109
  runId: session.runId,
970
1110
  model: parsed.model,
971
1111
  reason: "budget_exhausted",
972
- reservationUsd,
1112
+ ...holdAudit,
1113
+ budgetUsd: reservation.details.budgetUsd,
1114
+ spentUsd: reservation.details.spentUsd,
1115
+ heldReservedUsd: reservation.details.heldReservedUsd,
1116
+ heldUncertainUsd: reservation.details.heldUncertainUsd,
1117
+ turn: reservation.details.turn,
973
1118
  });
974
1119
  throw new CodingProxyError(429, "wardby_budget_exhausted");
975
1120
  }
@@ -982,7 +1127,7 @@ export class CodingProxy {
982
1127
  runId: session.runId,
983
1128
  requestId: request.id,
984
1129
  model: request.model,
985
- reservationUsd,
1130
+ ...holdAudit,
986
1131
  });
987
1132
  let key;
988
1133
  try {
@@ -1010,6 +1155,13 @@ export class CodingProxy {
1010
1155
  const deadlineTimer = setTimeout(() => controller.abort(), remainingMs);
1011
1156
  deadlineTimer.unref();
1012
1157
  this.trackActive(session.id, controller);
1158
+ const progress = {
1159
+ maxOutputTokens: parsed.maxOutputTokens,
1160
+ stream: parsed.stream,
1161
+ bodyBytes,
1162
+ ...(previousPrompt ? { previousInput: previousPrompt } : {}),
1163
+ relayedOutputBytes: 0,
1164
+ };
1013
1165
  const cleanupActive = () => {
1014
1166
  clearTimeout(deadlineTimer);
1015
1167
  const active = this.activeRequests.get(session.id);
@@ -1042,10 +1194,11 @@ export class CodingProxy {
1042
1194
  redirect: "error",
1043
1195
  signal: controller.signal,
1044
1196
  });
1197
+ progress.responseStarted = true;
1045
1198
  }
1046
1199
  catch {
1047
1200
  cleanupActive();
1048
- await this.markUncertain(session, request, undefined, controller.signal.aborted ? "upstream_aborted" : "upstream_transport");
1201
+ await this.markUncertain(session, request, undefined, controller.signal.aborted ? "upstream_aborted" : "upstream_transport", {}, progress);
1049
1202
  throw new CodingProxyError(502, controller.signal.aborted ? "upstream_aborted" : "upstream_transport_error");
1050
1203
  }
1051
1204
  if (!upstream.ok) {
@@ -1068,12 +1221,12 @@ export class CodingProxy {
1068
1221
  }
1069
1222
  try {
1070
1223
  if (parsed.stream)
1071
- await this.forwardStream(session, request, upstream, sink);
1224
+ await this.forwardStream(session, request, upstream, sink, progress);
1072
1225
  else
1073
1226
  await this.forwardJson(session, request, upstream, sink);
1074
1227
  }
1075
1228
  catch (error) {
1076
- await this.markUncertain(session, request, upstream.status, failureReason(error), responseHeadersOf(upstream));
1229
+ await this.markUncertain(session, request, upstream.status, failureReason(error), responseHeadersOf(upstream), progress);
1077
1230
  sink.destroy();
1078
1231
  throw error instanceof CodingProxyError ? error : new CodingProxyError(502, "invalid_upstream_response");
1079
1232
  }
@@ -1117,6 +1270,7 @@ export class CodingProxy {
1117
1270
  async complete(session, request, usage, upstreamStatus) {
1118
1271
  const costUsd = actualCostUsd(usage, request.pricing);
1119
1272
  await this.ledger.complete(request.id, usage, costUsd, upstreamStatus);
1273
+ const overshootUsd = costUsd - request.reservationUsd;
1120
1274
  this.audit({
1121
1275
  type: "response.completed",
1122
1276
  runId: session.runId,
@@ -1124,13 +1278,17 @@ export class CodingProxy {
1124
1278
  model: request.model,
1125
1279
  status: upstreamStatus,
1126
1280
  costUsd,
1281
+ reservationUsd: request.reservationUsd,
1282
+ ...(overshootUsd > Number.EPSILON ? { reason: "reservation_exceeded", overshootUsd } : {}),
1127
1283
  inputTokens: usage.inputTokens,
1128
1284
  outputTokens: usage.outputTokens,
1129
1285
  cachedInputTokens: usage.cachedInputTokens,
1130
1286
  cacheWriteTokens: usage.cacheWriteTokens,
1131
1287
  reasoningTokens: usage.reasoningTokens,
1132
1288
  });
1133
- if (costUsd > request.reservationUsd + Number.EPSILON) {
1289
+ // A cached hold may be exceeded when the cache misses (settled, audited above); the ceiling may not.
1290
+ const ceilingUsd = request.ceilingUsd ?? request.reservationUsd;
1291
+ if (costUsd > ceilingUsd + Number.EPSILON) {
1134
1292
  await this.ledger.cancelSession(session.id);
1135
1293
  throw new CodingProxyError(502, "reservation_invariant_violated");
1136
1294
  }
@@ -1156,7 +1314,7 @@ export class CodingProxy {
1156
1314
  await safeWrite(sink, bytes, { value: true });
1157
1315
  sink.end();
1158
1316
  }
1159
- async forwardStream(session, request, upstream, sink) {
1317
+ async forwardStream(session, request, upstream, sink, progress) {
1160
1318
  if (!upstream.body)
1161
1319
  throw new Error("missing_upstream_body");
1162
1320
  sink.start(upstream.status, { "content-type": "text/event-stream", "cache-control": "no-store" });
@@ -1166,7 +1324,7 @@ export class CodingProxy {
1166
1324
  let receivedBytes = 0;
1167
1325
  let completed = false;
1168
1326
  let failedWithoutUsage = false;
1169
- const anthropicUsage = session.protocol === "anthropic-messages" ? new AnthropicSseUsageTracker() : undefined;
1327
+ const anthropicUsage = session.protocol === "anthropic-messages" ? (progress.anthropic = new AnthropicSseUsageTracker()) : undefined;
1170
1328
  const body = upstream.body;
1171
1329
  for await (const chunk of body) {
1172
1330
  receivedBytes += chunk.byteLength;
@@ -1181,6 +1339,7 @@ export class CodingProxy {
1181
1339
  buffer = buffer.slice(boundary + 2);
1182
1340
  const terminal = anthropicUsage ? anthropicUsage.consume(frame) : terminalUsageFromSseFrame(frame);
1183
1341
  if (!terminal.terminal) {
1342
+ progress.relayedOutputBytes += relayedTextBytes(frame, session.protocol);
1184
1343
  await safeWrite(sink, Buffer.from(`${frame}\n\n`), connected);
1185
1344
  continue;
1186
1345
  }
@@ -1191,7 +1350,7 @@ export class CodingProxy {
1191
1350
  // client sees the real error instead of a cut connection; the reservation stays held.
1192
1351
  await this.recordUpstreamFailure(session, terminal.failure);
1193
1352
  if (!completed) {
1194
- await this.markUncertain(session, request, upstream.status, `upstream_failed:${terminal.failure}`, responseHeadersOf(upstream));
1353
+ await this.markUncertain(session, request, upstream.status, `upstream_failed:${terminal.failure}`, responseHeadersOf(upstream), progress);
1195
1354
  }
1196
1355
  failedWithoutUsage = true;
1197
1356
  await safeWrite(sink, Buffer.from(`${frame}\n\n`), connected);
@@ -1214,9 +1373,102 @@ export class CodingProxy {
1214
1373
  async recordUpstreamFailure(session, code) {
1215
1374
  await this.ledger.recordUpstreamFailure(session.id, code).catch(() => undefined);
1216
1375
  }
1217
- async markUncertain(session, request, status, reason, headers = {}) {
1218
- await this.ledger.markUncertain(request.id, status);
1219
- this.audit({ type: "request.uncertain", runId: session.runId, requestId: request.id, status, reason, ...headers });
1376
+ async markUncertain(session, request, status, reason, headers, progress) {
1377
+ if (progress.marked)
1378
+ return;
1379
+ progress.marked = true;
1380
+ let estimate = await this.estimateInterrupted(session, request, progress);
1381
+ if (estimate) {
1382
+ try {
1383
+ await this.ledger.markUncertain(request.id, status, estimate);
1384
+ }
1385
+ catch {
1386
+ // Settling at the estimate failed: mark it uncertain without one, so it keeps its full hold.
1387
+ estimate = undefined;
1388
+ }
1389
+ }
1390
+ if (!estimate)
1391
+ await this.ledger.markUncertain(request.id, status);
1392
+ this.audit({
1393
+ type: "request.uncertain",
1394
+ runId: session.runId,
1395
+ requestId: request.id,
1396
+ status,
1397
+ reason,
1398
+ ...(estimate ? { estimatedCostUsd: estimate.costUsd } : {}),
1399
+ ...headers,
1400
+ });
1401
+ }
1402
+ /**
1403
+ * The best known cost of a request that broke before its final usage (interrupted.ts), or
1404
+ * undefined when none can be made: the request then keeps its full hold. Never throws.
1405
+ */
1406
+ async estimateInterrupted(session, request, progress) {
1407
+ try {
1408
+ const hints = await this.ledger.settlementHints(session.id, request.model);
1409
+ const estimate = estimateInterrupted({
1410
+ ...progress.anthropic?.partial(),
1411
+ beforeResponse: progress.stream && !progress.responseStarted,
1412
+ relayedOutputBytes: progress.relayedOutputBytes,
1413
+ ...hints,
1414
+ ...(progress.previousInput ? { previous: progress.previousInput } : {}),
1415
+ bodyBytes: progress.bodyBytes,
1416
+ reservationUsd: request.reservationUsd,
1417
+ maxOutputTokens: progress.maxOutputTokens,
1418
+ ceilingUsd: request.ceilingUsd ?? request.reservationUsd,
1419
+ }, request.pricing);
1420
+ return Number.isFinite(estimate.costUsd) ? estimate : undefined;
1421
+ }
1422
+ catch {
1423
+ return undefined;
1424
+ }
1425
+ }
1426
+ }
1427
+ /** OpenAI Responses events whose string `delta` is generated output: text, tool input, reasoning. */
1428
+ const OPENAI_OUTPUT_DELTAS = new Set([
1429
+ "response.output_text.delta",
1430
+ "response.refusal.delta",
1431
+ "response.function_call_arguments.delta",
1432
+ "response.custom_tool_call_input.delta",
1433
+ "response.reasoning_text.delta",
1434
+ "response.reasoning_summary_text.delta",
1435
+ ]);
1436
+ /** The generated-output field of each Anthropic content_block_delta type (signatures are not output). */
1437
+ const ANTHROPIC_OUTPUT_DELTAS = {
1438
+ text_delta: "text",
1439
+ input_json_delta: "partial_json",
1440
+ thinking_delta: "thinking",
1441
+ };
1442
+ /**
1443
+ * UTF-8 bytes of generated output in a relayed SSE frame: text, tool-call input and thinking or
1444
+ * reasoning deltas, which are most of a coding agent's output.
1445
+ */
1446
+ function relayedTextBytes(frame, protocol) {
1447
+ if (!frame.includes(protocol === "anthropic-messages" ? "content_block_delta" : ".delta"))
1448
+ return 0;
1449
+ try {
1450
+ const data = frame
1451
+ .split("\n")
1452
+ .filter((line) => line.startsWith("data:"))
1453
+ .map((line) => line.slice(5).trimStart())
1454
+ .join("\n");
1455
+ const value = JSON.parse(data);
1456
+ if (!value || typeof value.type !== "string")
1457
+ return 0;
1458
+ if (protocol === "openai-responses") {
1459
+ return OPENAI_OUTPUT_DELTAS.has(value.type) && typeof value.delta === "string"
1460
+ ? Buffer.byteLength(value.delta)
1461
+ : 0;
1462
+ }
1463
+ if (value.type !== "content_block_delta")
1464
+ return 0;
1465
+ const delta = value.delta;
1466
+ const field = typeof delta?.type === "string" ? ANTHROPIC_OUTPUT_DELTAS[delta.type] : undefined;
1467
+ const text = field ? delta?.[field] : undefined;
1468
+ return typeof text === "string" ? Buffer.byteLength(text) : 0;
1469
+ }
1470
+ catch {
1471
+ return 0;
1220
1472
  }
1221
1473
  }
1222
1474
  /** The safe error code in a rejected upstream's JSON body, or undefined when it names none or cannot be read. */