@wardby/cli 0.6.0 → 0.7.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 (576) hide show
  1. package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
  2. package/dist/claude-coding-worker/driver.d.ts +21 -3
  3. package/dist/claude-coding-worker/driver.js +125 -17
  4. package/dist/claude-coding-worker/main.js +34 -6
  5. package/dist/claude-coding-worker/sdk.js +12 -1
  6. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  7. package/dist/claude-coding-worker/tool-socket.js +111 -0
  8. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  9. package/dist/claude-coding-worker/transcript.js +77 -0
  10. package/dist/cli-help.d.ts +1 -1
  11. package/dist/cli-help.js +1 -0
  12. package/dist/cli.js +24 -10
  13. package/dist/coding/continuation-wording.d.ts +35 -0
  14. package/dist/coding/continuation-wording.js +73 -0
  15. package/dist/coding/linked-issue-note.d.ts +23 -0
  16. package/dist/coding/linked-issue-note.js +47 -0
  17. package/dist/coding/merge-wording.d.ts +28 -0
  18. package/dist/coding/merge-wording.js +78 -0
  19. package/dist/coding/pr-description-note.d.ts +9 -0
  20. package/dist/coding/pr-description-note.js +32 -0
  21. package/dist/coding/profile.d.ts +46 -126
  22. package/dist/coding/profile.js +45 -4
  23. package/dist/coding/protected-path-wording.d.ts +8 -0
  24. package/dist/coding/protected-path-wording.js +1 -1
  25. package/dist/coding/protocol.d.ts +264 -346
  26. package/dist/coding/protocol.js +235 -12
  27. package/dist/coding/redact.d.ts +3 -0
  28. package/dist/coding/redact.js +12 -0
  29. package/dist/coding/registry/allowlist.d.ts +12 -0
  30. package/dist/coding/registry/allowlist.js +14 -1
  31. package/dist/coding/registry/audit-mode.d.ts +153 -0
  32. package/dist/coding/registry/audit-mode.js +304 -0
  33. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  34. package/dist/coding/registry/lockfile-shared.js +128 -0
  35. package/dist/coding/registry/lockfiles.js +1 -1
  36. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  37. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  38. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  39. package/dist/coding/registry/npm-lockfile.js +4 -6
  40. package/dist/coding/registry/npm.js +78 -8
  41. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  42. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  43. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  44. package/dist/coding/registry/pypi-plan.js +406 -0
  45. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  46. package/dist/coding/registry/pypi-requirements.js +155 -0
  47. package/dist/coding/registry/pypi.d.ts +3 -27
  48. package/dist/coding/registry/pypi.js +40 -154
  49. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  50. package/dist/coding/registry/refusal-hints.js +61 -0
  51. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  52. package/dist/coding/registry/refusal-wording.js +56 -0
  53. package/dist/coding/registry/report.d.ts +70 -8
  54. package/dist/coding/registry/report.js +112 -5
  55. package/dist/coding/registry/types.d.ts +58 -8
  56. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  57. package/dist/coding/registry/yarn-lockfile.js +367 -0
  58. package/dist/coding/services/catalog.d.ts +37 -351
  59. package/dist/coding/transcript/claude-code.d.ts +13 -0
  60. package/dist/coding/transcript/claude-code.js +273 -0
  61. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  62. package/dist/coding/transcript/download-protocol.js +18 -0
  63. package/dist/coding/transcript/format.d.ts +20 -0
  64. package/dist/coding/transcript/format.js +32 -0
  65. package/dist/coding/transcript/recorder.d.ts +51 -0
  66. package/dist/coding/transcript/recorder.js +225 -0
  67. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  68. package/dist/coding/transcript/resume/checkout.js +203 -0
  69. package/dist/coding/transcript/resume/command.d.ts +17 -0
  70. package/dist/coding/transcript/resume/command.js +176 -0
  71. package/dist/coding/transcript/resume/download.d.ts +20 -0
  72. package/dist/coding/transcript/resume/download.js +153 -0
  73. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  74. package/dist/coding/transcript/resume/launch.js +128 -0
  75. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  76. package/dist/coding/transcript/resume/session-file.js +79 -0
  77. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  78. package/dist/coding/transcript/resume/stand-in.js +49 -0
  79. package/dist/coding-worker/artifact.d.ts +8 -3
  80. package/dist/coding-worker/artifact.js +3 -1
  81. package/dist/coding-worker/debug-trace.d.ts +6 -5
  82. package/dist/coding-worker/debug-trace.js +13 -18
  83. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  84. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  85. package/dist/coding-worker/driver.d.ts +4 -3
  86. package/dist/coding-worker/driver.js +116 -38
  87. package/dist/coding-worker/errors.d.ts +1 -0
  88. package/dist/coding-worker/errors.js +32 -0
  89. package/dist/coding-worker/task-note.d.ts +11 -0
  90. package/dist/coding-worker/task-note.js +13 -0
  91. package/dist/coding-worker/types.d.ts +11 -0
  92. package/dist/config/dependency-cache.d.ts +23 -0
  93. package/dist/config/dependency-cache.js +32 -0
  94. package/dist/config/providers.d.ts +12 -3
  95. package/dist/config/providers.js +55 -5
  96. package/dist/config/test-simulators.d.ts +82 -0
  97. package/dist/config/test-simulators.js +305 -0
  98. package/dist/core/async-context.d.ts +2 -0
  99. package/dist/core/async-context.js +12 -0
  100. package/dist/core/budget-events.d.ts +108 -0
  101. package/dist/core/budget-events.js +346 -0
  102. package/dist/core/budget-groups.d.ts +50 -1
  103. package/dist/core/budget-groups.js +236 -27
  104. package/dist/core/budget-stopped-head.d.ts +46 -0
  105. package/dist/core/budget-stopped-head.js +81 -0
  106. package/dist/core/budget-topup.d.ts +51 -0
  107. package/dist/core/budget-topup.js +156 -0
  108. package/dist/core/budget-wording.d.ts +16 -2
  109. package/dist/core/budget-wording.js +40 -2
  110. package/dist/core/coding-queue.d.ts +2 -1
  111. package/dist/core/coding-queue.js +7 -0
  112. package/dist/core/cron.d.ts +19 -1
  113. package/dist/core/cron.js +17 -0
  114. package/dist/core/datastores.js +1 -1
  115. package/dist/core/deferred-coding.d.ts +14 -0
  116. package/dist/core/deferred-coding.js +62 -0
  117. package/dist/core/delegation-child.d.ts +25 -0
  118. package/dist/core/delegation-child.js +37 -0
  119. package/dist/core/dispatch.d.ts +42 -0
  120. package/dist/core/dispatch.js +131 -56
  121. package/dist/core/engine-native.js +1 -1
  122. package/dist/core/error-code.d.ts +38 -0
  123. package/dist/core/error-code.js +168 -0
  124. package/dist/core/grants.d.ts +19 -6
  125. package/dist/core/grants.js +55 -6
  126. package/dist/core/host-events.d.ts +18 -2
  127. package/dist/core/host-events.js +284 -24
  128. package/dist/core/host-status.d.ts +85 -3
  129. package/dist/core/host-status.js +298 -20
  130. package/dist/core/issue-bridge.d.ts +50 -6
  131. package/dist/core/issue-bridge.js +124 -33
  132. package/dist/core/issue-events.d.ts +1 -1
  133. package/dist/core/issue-events.js +4 -10
  134. package/dist/core/issue-status.d.ts +1 -1
  135. package/dist/core/issue-status.js +54 -26
  136. package/dist/core/logger.d.ts +5 -0
  137. package/dist/core/logger.js +14 -1
  138. package/dist/core/lost-run-children.d.ts +6 -0
  139. package/dist/core/lost-run-children.js +32 -0
  140. package/dist/core/mark-ready.d.ts +34 -0
  141. package/dist/core/mark-ready.js +152 -0
  142. package/dist/core/markdown-code.d.ts +8 -0
  143. package/dist/core/markdown-code.js +107 -0
  144. package/dist/core/memory-tools.js +7 -0
  145. package/dist/core/merge-order-check.d.ts +2 -1
  146. package/dist/core/merge-order-check.js +8 -1
  147. package/dist/core/notification-templates.d.ts +1 -7
  148. package/dist/core/notification-templates.js +36 -2
  149. package/dist/core/pull-request-state-sync.js +2 -2
  150. package/dist/core/reconciler.d.ts +4 -3
  151. package/dist/core/reconciler.js +8 -1
  152. package/dist/core/related-pull-requests.d.ts +11 -3
  153. package/dist/core/related-pull-requests.js +27 -14
  154. package/dist/core/reply-parts.d.ts +21 -0
  155. package/dist/core/reply-parts.js +73 -0
  156. package/dist/core/review-fix.d.ts +1 -1
  157. package/dist/core/review-fix.js +2 -1
  158. package/dist/core/review-host-checks.d.ts +1 -1
  159. package/dist/core/review-host-tools.d.ts +3 -0
  160. package/dist/core/review-host-tools.js +99 -13
  161. package/dist/core/review-reads.d.ts +55 -0
  162. package/dist/core/review-reads.js +233 -0
  163. package/dist/core/run-status.d.ts +12 -0
  164. package/dist/core/run-status.js +12 -0
  165. package/dist/core/runner.d.ts +80 -34
  166. package/dist/core/runner.js +439 -144
  167. package/dist/core/schedule-start.d.ts +12 -0
  168. package/dist/core/schedule-start.js +14 -0
  169. package/dist/core/secret-broker-config.d.ts +10 -74
  170. package/dist/core/secret-guard.d.ts +46 -0
  171. package/dist/core/secret-guard.js +104 -0
  172. package/dist/core/secret-guarded-stores.d.ts +12 -0
  173. package/dist/core/secret-guarded-stores.js +41 -0
  174. package/dist/core/secret-spans.d.ts +50 -0
  175. package/dist/core/secret-spans.js +94 -0
  176. package/dist/core/stop-run.d.ts +46 -0
  177. package/dist/core/stop-run.js +61 -0
  178. package/dist/core/workflow-events.d.ts +14 -2
  179. package/dist/core/workflow-events.js +4 -0
  180. package/dist/core/workflow-run-events.d.ts +5 -3
  181. package/dist/core/workflow-run-events.js +43 -8
  182. package/dist/core/zod-json-schema.d.ts +4 -0
  183. package/dist/core/zod-json-schema.js +39 -0
  184. package/dist/core/zod3-window.d.ts +35 -0
  185. package/dist/core/zod3-window.js +124 -0
  186. package/dist/generated/prisma/browser.d.ts +34 -3
  187. package/dist/generated/prisma/client.d.ts +34 -3
  188. package/dist/generated/prisma/commonInputTypes.d.ts +220 -60
  189. package/dist/generated/prisma/enums.d.ts +10 -0
  190. package/dist/generated/prisma/enums.js +8 -0
  191. package/dist/generated/prisma/internal/class.d.ts +44 -0
  192. package/dist/generated/prisma/internal/class.js +4 -4
  193. package/dist/generated/prisma/internal/prismaNamespace.d.ts +428 -9
  194. package/dist/generated/prisma/internal/prismaNamespace.js +92 -1
  195. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +95 -0
  196. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +92 -1
  197. package/dist/generated/prisma/models/Agent.d.ts +106 -8
  198. package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
  199. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +229 -1
  200. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  201. package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
  202. package/dist/generated/prisma/models/CodingRun.d.ts +1637 -1
  203. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  204. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  205. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  206. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  207. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
  208. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
  209. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  210. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  211. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  212. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  213. package/dist/generated/prisma/models/Run.d.ts +738 -2
  214. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  215. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  216. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  217. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  218. package/dist/generated/prisma/models.d.ts +4 -0
  219. package/dist/help-index.json +1320 -69
  220. package/dist/import/create.js +32 -3
  221. package/dist/import/neutral-schema.d.ts +50 -281
  222. package/dist/import/neutral-schema.js +5 -4
  223. package/dist/knowledge/check.d.ts +1 -1
  224. package/dist/knowledge/cli.d.ts +11 -1
  225. package/dist/knowledge/cli.js +37 -4
  226. package/dist/knowledge/concept.d.ts +3 -19
  227. package/dist/knowledge/location.d.ts +31 -0
  228. package/dist/knowledge/location.js +78 -0
  229. package/dist/mcp/auth/access.d.ts +10 -2
  230. package/dist/mcp/auth/access.js +15 -1
  231. package/dist/mcp/auth/ownership.d.ts +7 -7
  232. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  233. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  234. package/dist/mcp/host-events/github-ingress.d.ts +2 -0
  235. package/dist/mcp/host-events/github-ingress.js +2 -1
  236. package/dist/mcp/index.d.ts +6 -0
  237. package/dist/mcp/index.js +58 -10
  238. package/dist/mcp/server.d.ts +13 -0
  239. package/dist/mcp/server.js +33 -14
  240. package/dist/mcp/tools/agents.d.ts +4 -0
  241. package/dist/mcp/tools/agents.js +198 -16
  242. package/dist/mcp/tools/datastore.js +17 -8
  243. package/dist/mcp/tools/grants.js +9 -3
  244. package/dist/mcp/tools/memory.js +11 -1
  245. package/dist/mcp/tools/notification-channels.js +2 -2
  246. package/dist/mcp/tools/packages.d.ts +2 -0
  247. package/dist/mcp/tools/packages.js +195 -0
  248. package/dist/mcp/tools/repositories.js +18 -5
  249. package/dist/mcp/tools/run-access.d.ts +16 -0
  250. package/dist/mcp/tools/run-access.js +25 -0
  251. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  252. package/dist/mcp/tools/run-transcript-download.js +129 -0
  253. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  254. package/dist/mcp/tools/run-transcript.js +70 -0
  255. package/dist/mcp/tools/runs.js +34 -12
  256. package/dist/mcp/tools/scheduling.js +3 -1
  257. package/dist/mcp/tools/secret-elicitation-form.js +5 -0
  258. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  259. package/dist/mcp/tools/secret-elicitation-server.js +10 -61
  260. package/dist/mcp/tools/secrets.js +2 -2
  261. package/dist/mcp/tools/stop-run.d.ts +2 -0
  262. package/dist/mcp/tools/stop-run.js +82 -0
  263. package/dist/mcp/tools/subagents.js +2 -2
  264. package/dist/mcp/tools/tools.d.ts +1 -1
  265. package/dist/mcp/tools/tools.js +25 -9
  266. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  267. package/dist/mcp/transport/stdio-link-host.js +67 -0
  268. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  269. package/dist/mcp/transport/streamable-http.js +41 -1
  270. package/dist/native-worker/docker-launcher.d.ts +38 -2
  271. package/dist/native-worker/docker-launcher.js +65 -5
  272. package/dist/native-worker/gateway-server.d.ts +41 -3
  273. package/dist/native-worker/gateway-server.js +124 -27
  274. package/dist/native-worker/gateway.d.ts +27 -1
  275. package/dist/native-worker/gateway.js +70 -4
  276. package/dist/native-worker/http-server.d.ts +3 -1
  277. package/dist/native-worker/http-server.js +11 -7
  278. package/dist/native-worker/http-transport.js +1 -1
  279. package/dist/native-worker/kubernetes-launcher.d.ts +7 -3
  280. package/dist/native-worker/kubernetes-launcher.js +43 -3
  281. package/dist/native-worker/launch.d.ts +18 -1
  282. package/dist/native-worker/launch.js +6 -1
  283. package/dist/native-worker/ledger.d.ts +18 -2
  284. package/dist/native-worker/ledger.js +57 -4
  285. package/dist/native-worker/loopback.js +3 -8
  286. package/dist/native-worker/main.d.ts +2 -1
  287. package/dist/native-worker/main.js +14 -3
  288. package/dist/native-worker/protocol.d.ts +129 -577
  289. package/dist/native-worker/protocol.js +47 -1
  290. package/dist/native-worker/sandbox-executor.d.ts +17 -2
  291. package/dist/native-worker/sandbox-executor.js +78 -4
  292. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  293. package/dist/native-worker/stderr-redaction.js +237 -0
  294. package/dist/native-worker/stdio.d.ts +1 -1
  295. package/dist/native-worker/stdio.js +6 -5
  296. package/dist/native-worker/warm-pool.d.ts +2 -2
  297. package/dist/native-worker/warm-pool.js +4 -4
  298. package/dist/native-worker/worker.js +28 -2
  299. package/dist/observability/metrics.js +6 -1
  300. package/dist/providers/auth/self-hosted.d.ts +1 -1
  301. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  302. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  303. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  304. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  305. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  306. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  307. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  308. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  309. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  310. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  311. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  312. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  313. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  314. package/dist/providers/coding-proxy/hold.js +86 -0
  315. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  316. package/dist/providers/coding-proxy/interrupted.js +104 -0
  317. package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
  318. package/dist/providers/coding-proxy/memory-ledger.js +84 -8
  319. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  320. package/dist/providers/coding-proxy/metering.js +27 -4
  321. package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
  322. package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
  323. package/dist/providers/coding-proxy/proxy.d.ts +14 -1
  324. package/dist/providers/coding-proxy/proxy.js +166 -14
  325. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  326. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  327. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  328. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  329. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  330. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  331. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  332. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  333. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  334. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  335. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  336. package/dist/providers/coding-proxy/registry/service.js +579 -112
  337. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  338. package/dist/providers/coding-proxy/registry/store.js +54 -1
  339. package/dist/providers/coding-proxy/runtime.d.ts +4 -0
  340. package/dist/providers/coding-proxy/runtime.js +78 -16
  341. package/dist/providers/coding-proxy/server.d.ts +6 -1
  342. package/dist/providers/coding-proxy/server.js +45 -1
  343. package/dist/providers/coding-proxy/types.d.ts +65 -1
  344. package/dist/providers/datastore/types.d.ts +5 -0
  345. package/dist/providers/engine/types.d.ts +17 -2
  346. package/dist/providers/engine/types.js +17 -0
  347. package/dist/providers/executor/composition.d.ts +10 -3
  348. package/dist/providers/executor/composition.js +47 -7
  349. package/dist/providers/executor/container.d.ts +361 -8
  350. package/dist/providers/executor/container.js +1136 -91
  351. package/dist/providers/executor/dbos-status.d.ts +31 -0
  352. package/dist/providers/executor/dbos-status.js +64 -0
  353. package/dist/providers/executor/dbos.d.ts +50 -1
  354. package/dist/providers/executor/dbos.js +207 -20
  355. package/dist/providers/executor/deferred.d.ts +12 -24
  356. package/dist/providers/executor/deferred.js +10 -29
  357. package/dist/providers/executor/in-process.d.ts +9 -1
  358. package/dist/providers/executor/in-process.js +14 -4
  359. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  360. package/dist/providers/executor/linked-issue-reader.js +30 -0
  361. package/dist/providers/executor/routing.d.ts +2 -0
  362. package/dist/providers/executor/routing.js +4 -0
  363. package/dist/providers/executor/types.d.ts +13 -0
  364. package/dist/providers/index.d.ts +2 -1
  365. package/dist/providers/issue-tracker/types.d.ts +17 -0
  366. package/dist/providers/issue-tracker/types.js +39 -1
  367. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  368. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  369. package/dist/providers/jobs/docker-isolation.d.ts +8 -0
  370. package/dist/providers/jobs/docker-isolation.js +17 -0
  371. package/dist/providers/jobs/docker.d.ts +1 -0
  372. package/dist/providers/jobs/docker.js +27 -2
  373. package/dist/providers/jobs/fake-kubernetes-api.d.ts +2 -0
  374. package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
  375. package/dist/providers/jobs/kubernetes-api.d.ts +8 -0
  376. package/dist/providers/jobs/kubernetes-api.js +10 -0
  377. package/dist/providers/jobs/kubernetes-client.js +10 -1
  378. package/dist/providers/jobs/kubernetes-isolation.d.ts +2 -0
  379. package/dist/providers/jobs/kubernetes-isolation.js +17 -1
  380. package/dist/providers/jobs/kubernetes.d.ts +6 -1
  381. package/dist/providers/jobs/kubernetes.js +105 -16
  382. package/dist/providers/jobs/types.d.ts +33 -0
  383. package/dist/providers/jobs/types.js +13 -1
  384. package/dist/providers/llm/anthropic.js +5 -1
  385. package/dist/providers/llm/bedrock.d.ts +0 -12
  386. package/dist/providers/llm/bedrock.js +4 -0
  387. package/dist/providers/llm/claude-messages.d.ts +3 -1
  388. package/dist/providers/llm/claude-messages.js +4 -1
  389. package/dist/providers/llm/claude-provider.d.ts +2 -2
  390. package/dist/providers/llm/claude-provider.js +2 -2
  391. package/dist/providers/llm/openai.d.ts +2 -2
  392. package/dist/providers/llm/openai.js +6 -2
  393. package/dist/providers/llm/routing.d.ts +2 -2
  394. package/dist/providers/llm/routing.js +2 -2
  395. package/dist/providers/llm/types.d.ts +12 -2
  396. package/dist/providers/review-host/github-events.d.ts +9 -1
  397. package/dist/providers/review-host/github-events.js +34 -12
  398. package/dist/providers/review-host/github.d.ts +29 -2
  399. package/dist/providers/review-host/github.js +224 -29
  400. package/dist/providers/review-host/local.d.ts +8 -4
  401. package/dist/providers/review-host/local.js +49 -31
  402. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  403. package/dist/providers/review-host/patch-pages.js +176 -0
  404. package/dist/providers/review-host/review-format.d.ts +19 -1
  405. package/dist/providers/review-host/review-format.js +38 -7
  406. package/dist/providers/review-host/types.d.ts +134 -2
  407. package/dist/providers/review-host/types.js +8 -0
  408. package/dist/providers/storage/gcs.d.ts +63 -0
  409. package/dist/providers/storage/gcs.js +69 -0
  410. package/dist/providers/storage/index.d.ts +15 -0
  411. package/dist/providers/storage/index.js +14 -0
  412. package/dist/providers/storage/local.d.ts +24 -0
  413. package/dist/providers/storage/local.js +92 -0
  414. package/dist/providers/storage/meter.d.ts +14 -0
  415. package/dist/providers/storage/meter.js +34 -0
  416. package/dist/providers/storage/s3.d.ts +41 -0
  417. package/dist/providers/storage/s3.js +107 -0
  418. package/dist/providers/storage/types.d.ts +37 -3
  419. package/dist/providers/storage/types.js +21 -4
  420. package/dist/providers/vcs/git.d.ts +33 -2
  421. package/dist/providers/vcs/git.js +324 -22
  422. package/dist/providers/vcs/github-remote.d.ts +26 -3
  423. package/dist/providers/vcs/github-remote.js +124 -14
  424. package/dist/providers/vcs/github.d.ts +214 -6
  425. package/dist/providers/vcs/github.js +447 -45
  426. package/dist/providers/vcs/index.js +8 -1
  427. package/dist/providers/vcs/pr-description.d.ts +127 -0
  428. package/dist/providers/vcs/pr-description.js +270 -0
  429. package/dist/providers/vcs/remote.d.ts +33 -1
  430. package/dist/providers/vcs/routing.d.ts +4 -2
  431. package/dist/providers/vcs/routing.js +6 -0
  432. package/dist/providers/vcs/types.d.ts +80 -3
  433. package/dist/quickstart/coding-seed.d.ts +14 -3
  434. package/dist/quickstart/coding-seed.js +213 -4
  435. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  436. package/dist/quickstart/reviewer-prompt.js +6 -6
  437. package/dist/quickstart-images.json +1 -1
  438. package/dist/sandbox/generated/zod.bundle.js +62 -1
  439. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  440. package/dist/sandbox/host-functions.d.ts +1 -0
  441. package/dist/sandbox/host-functions.js +6 -11
  442. package/dist/sandbox/secret-broker.js +3 -4
  443. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  444. package/dist/sandbox/zod-params.d.ts +37 -5
  445. package/dist/sandbox/zod-params.js +181 -26
  446. package/dist/serve.js +8 -1
  447. package/dist/viewer/api-schema.d.ts +349 -2627
  448. package/dist/viewer/api-schema.js +7 -0
  449. package/dist/viewer/build-schemas.js +6 -2
  450. package/dist/viewer/openapi.js +2 -4
  451. package/dist/wardby-bin.js +10 -0
  452. package/docs/agent-recipes.md +58 -20
  453. package/docs/code-review-agents.md +551 -41
  454. package/docs/coding-agent-setup.md +489 -7
  455. package/docs/coding-packages.md +1033 -90
  456. package/docs/coding-services.md +27 -12
  457. package/docs/coding-worker-byo-images.md +20 -0
  458. package/docs/coding-worker-isolation.md +105 -30
  459. package/docs/getting-started-gke.md +124 -137
  460. package/docs/getting-started-identity-provider.md +10 -1
  461. package/docs/getting-started.md +9 -0
  462. package/docs/jira-agents.md +17 -8
  463. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  464. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  465. package/docs/knowledge/delegation-admission-slots.md +52 -0
  466. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  467. package/docs/knowledge/import-rename-target.md +52 -0
  468. package/docs/knowledge/index.md +57 -0
  469. package/docs/knowledge/log.md +9 -0
  470. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  471. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  472. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  473. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  474. package/docs/knowledge/overview-cli.md +74 -0
  475. package/docs/knowledge/overview-coding-proxy.md +72 -0
  476. package/docs/knowledge/overview-coding.md +72 -0
  477. package/docs/knowledge/overview-config.md +60 -0
  478. package/docs/knowledge/overview-core.md +72 -0
  479. package/docs/knowledge/overview-deploy.md +83 -0
  480. package/docs/knowledge/overview-mcp.md +61 -0
  481. package/docs/knowledge/overview-prisma.md +72 -0
  482. package/docs/knowledge/overview-providers.md +89 -0
  483. package/docs/knowledge/overview-sandbox.md +83 -0
  484. package/docs/knowledge/overview-surfaces.md +83 -0
  485. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  486. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  487. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  488. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  489. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  490. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  491. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  492. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  493. package/docs/knowledge/warm-input-publication.md +30 -0
  494. package/docs/knowledge/workspace-staging-failure.md +54 -0
  495. package/docs/knowledge.md +54 -14
  496. package/docs/native-sandbox.md +119 -23
  497. package/docs/observability.md +4 -0
  498. package/docs/security-deployment.md +33 -2
  499. package/docs/slack-notifications.md +35 -19
  500. package/docs/tool-secrets.md +42 -10
  501. package/docs/viewer-api.openapi.yml +1 -1
  502. package/help/admin-viewer.md +24 -2
  503. package/help/architecture-agent.md +11 -6
  504. package/help/build-worker-image.md +3 -1
  505. package/help/builder-agent.md +19 -6
  506. package/help/code-review-agents.md +177 -6
  507. package/help/coding-packages.md +156 -6
  508. package/help/cost-attribution.md +9 -5
  509. package/help/creating-agents.md +14 -1
  510. package/help/dependency-cache.md +143 -0
  511. package/help/deploy-gke.md +15 -8
  512. package/help/errors/budget-exhausted.md +187 -0
  513. package/help/errors/budget-group-exhausted.md +5 -1
  514. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  515. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  516. package/help/errors/continuation-closed.md +9 -12
  517. package/help/errors/delegation-conflict.md +24 -0
  518. package/help/errors/file-list-truncated.md +45 -0
  519. package/help/errors/full-read-required.md +49 -0
  520. package/help/errors/github-account-not-allowed.md +4 -0
  521. package/help/errors/graph-incomplete.md +43 -0
  522. package/help/errors/graph-limit.md +43 -0
  523. package/help/errors/merge-conflict.md +49 -0
  524. package/help/errors/native-sandbox-gateway-error.md +20 -0
  525. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  526. package/help/errors/native-sandbox-worker-exited.md +3 -2
  527. package/help/errors/package-not-allowed-pending.md +52 -0
  528. package/help/errors/package-not-allowed.md +51 -0
  529. package/help/errors/package-refusals.md +43 -0
  530. package/help/errors/patch-cursor-malformed.md +31 -0
  531. package/help/errors/run-lost.md +39 -0
  532. package/help/errors/run-transcript-download.md +44 -0
  533. package/help/errors/secret-in-value.md +69 -0
  534. package/help/errors/target-merge.md +40 -0
  535. package/help/fix-merge-conflicts.md +73 -0
  536. package/help/github-app-setup.md +132 -0
  537. package/help/github.md +22 -0
  538. package/help/identity-and-access.md +2 -0
  539. package/help/jira.md +23 -6
  540. package/help/knowledge.md +16 -7
  541. package/help/local-repositories.md +1 -1
  542. package/help/low-power-mode.md +7 -1
  543. package/help/merge-order-check.md +5 -0
  544. package/help/native-capabilities.md +29 -1
  545. package/help/native-sandbox.md +15 -1
  546. package/help/operating-agents.md +5 -0
  547. package/help/package-audit-mode.md +91 -0
  548. package/help/related-pull-requests.md +10 -7
  549. package/help/resume-runs-locally.md +131 -0
  550. package/help/review-fix-rounds.md +33 -1
  551. package/help/sharing-agents.md +59 -0
  552. package/help/slack-notifications.md +19 -5
  553. package/help/status-comments.md +31 -0
  554. package/help/stop-run.md +58 -0
  555. package/help/troubleshooting/budgets.md +28 -0
  556. package/help/troubleshooting/coding-workers.md +78 -7
  557. package/package.json +17 -10
  558. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  559. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  560. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  561. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  562. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  563. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  564. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  565. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  566. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  567. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  568. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  569. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  570. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  571. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  572. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  573. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  574. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  575. package/prisma/schema.prisma +311 -97
  576. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -0,0 +1,86 @@
1
+ /**
2
+ * A model request's hold: what the proxy reserves against the run's budget before forwarding it.
3
+ * After a mostly cached reply in the same conversation, the part of the prompt the previous reply
4
+ * read from (or wrote to) the cache is priced at the cache-read rate; everything else, including
5
+ * what the body grew by (one token per byte), at the input + cache-write rates. Capped at the
6
+ * ceiling, today's worst case (the whole body as uncached input), which a reply may never exceed.
7
+ */
8
+ import { createHash } from "node:crypto";
9
+ import { estimateReservationUsd } from "./metering.js";
10
+ /**
11
+ * Anthropic's prompt cache lives 5 minutes from when a request is processed, not from when its reply
12
+ * finishes: a previous request sent longer ago than this says nothing about the cache.
13
+ */
14
+ export const CACHE_WINDOW_MS = 5 * 60_000;
15
+ export const MIN_CACHED_SHARE = 0.5;
16
+ function withoutCacheControl(value) {
17
+ if (Array.isArray(value))
18
+ return value.map(withoutCacheControl);
19
+ if (!value || typeof value !== "object")
20
+ return value;
21
+ return Object.fromEntries(Object.entries(value)
22
+ .filter(([key]) => key !== "cache_control")
23
+ .map(([key, inner]) => [key, withoutCacheControl(inner)]));
24
+ }
25
+ /**
26
+ * What identifies one conversation within a run (Claude Code runs several: the main one and its
27
+ * sub-agents). Anthropic: the first message without cache markers (the system prompt carries a
28
+ * per-version billing line). OpenAI: prompt_cache_key, else instructions + the first input item.
29
+ */
30
+ export function conversationKey(protocol, body) {
31
+ let basis;
32
+ if (protocol === "anthropic-messages") {
33
+ const messages = body.messages;
34
+ if (!Array.isArray(messages) || messages.length === 0)
35
+ return null;
36
+ // Claude Code's first message can carry the date, so a conversation crossing midnight starts a
37
+ // new key (its next request falls back to the worst case once).
38
+ basis = ["anthropic", withoutCacheControl(messages[0])];
39
+ }
40
+ else if (typeof body.prompt_cache_key === "string" && body.prompt_cache_key) {
41
+ basis = ["openai-key", body.prompt_cache_key];
42
+ }
43
+ else {
44
+ const input = body.input;
45
+ const first = typeof input === "string" ? input : Array.isArray(input) ? input[0] : undefined;
46
+ if (first === undefined)
47
+ return null;
48
+ basis = ["openai-first", body.instructions ?? null, first];
49
+ }
50
+ return createHash("sha256").update(JSON.stringify(basis)).digest("base64url");
51
+ }
52
+ export function estimateHold(input) {
53
+ const ceilingUsd = estimateReservationUsd(input.bodyBytes, input.maxOutputTokens, input.pricing);
54
+ const full = (fallback) => ({ holdUsd: ceilingUsd, ceilingUsd, basis: "full", fallback });
55
+ const previous = input.previous;
56
+ if (!previous)
57
+ return full("no_previous");
58
+ if (previous.model !== input.model)
59
+ return full("model_changed");
60
+ if (previous.costEstimated)
61
+ return full("previous_estimated");
62
+ if (previous.status !== "completed" || !previous.usage)
63
+ return full("previous_not_completed");
64
+ if (previous.requestBytes === null)
65
+ return full("no_request_bytes");
66
+ if (input.now.getTime() - previous.startedAt.getTime() > CACHE_WINDOW_MS)
67
+ return full("cache_expired");
68
+ if (input.bodyBytes < previous.requestBytes)
69
+ return full("body_shrank");
70
+ const usage = previous.usage;
71
+ const prevPrompt = usage.inputTokens + usage.cacheWriteTokens;
72
+ const cachedTokens = input.protocol === "anthropic-messages"
73
+ ? usage.cachedInputTokens + usage.cacheWriteTokens
74
+ : usage.cachedInputTokens;
75
+ if (prevPrompt <= 0 || cachedTokens < prevPrompt * MIN_CACHED_SHARE)
76
+ return full("low_cache_share");
77
+ const uncachedTokens = prevPrompt + (input.bodyBytes - previous.requestBytes) - cachedTokens;
78
+ const { pricing } = input;
79
+ const cacheReadRate = pricing.cachedInputPerMTok ?? pricing.inputPerMTok;
80
+ const cacheWriteRate = pricing.cacheWritePerMTok ?? pricing.inputPerMTok;
81
+ const holdUsd = (cachedTokens * cacheReadRate +
82
+ uncachedTokens * (pricing.inputPerMTok + cacheWriteRate) +
83
+ input.maxOutputTokens * pricing.outputPerMTok) /
84
+ 1_000_000;
85
+ return { holdUsd: Math.min(holdUsd, ceilingUsd), ceilingUsd, basis: "cached", cachedTokens, uncachedTokens };
86
+ }
@@ -0,0 +1,70 @@
1
+ import { type ModelPricing } from "../llm/pricing-core.js";
2
+ import type { PreviousReply, ProxyUsage } from "./types.js";
3
+ export interface InterruptedFacts {
4
+ /** Anthropic message_start usage already read (inputTokens includes cache reads, not writes). */
5
+ readUsage?: {
6
+ inputTokens: number;
7
+ cachedInputTokens: number;
8
+ cacheWriteTokens: number;
9
+ };
10
+ /** Output tokens the upstream reported so far (Anthropic message_delta), if any. */
11
+ reportedOutputTokens?: number;
12
+ /** message_start's output count: a placeholder (usually 1), so only a floor, never the count. */
13
+ outputFloorTokens?: number;
14
+ /** A stream that failed before its response started: the provider generated no output. */
15
+ beforeResponse?: boolean;
16
+ /** UTF-8 bytes of output relayed to the client before the break: text, tool input, thinking. */
17
+ relayedOutputBytes: number;
18
+ /** The input of the request's own prompt, from its conversation's previous reply (previousInput). */
19
+ previous?: ProxyUsage;
20
+ /** UTF-8 bytes of the request body the proxy forwarded, when known. */
21
+ bodyBytes?: number;
22
+ /** Median outputTokens of the session's completed replies for the same model, if any. */
23
+ medianOutputTokens?: number;
24
+ /** The request's hold and the output tokens it reserved for. */
25
+ reservationUsd: number;
26
+ maxOutputTokens: number;
27
+ /** The request's worst case (its ceiling); the estimate never exceeds it. Defaults to the hold. */
28
+ ceilingUsd?: number;
29
+ }
30
+ export interface InterruptedEstimate {
31
+ usage: ProxyUsage;
32
+ costUsd: number;
33
+ }
34
+ /** Output tokens for relayed text: ceil(bytes / 3), a deliberately high count. */
35
+ export declare function relayedOutputTokens(bytes: number): number;
36
+ /**
37
+ * Prompt tokens for request-body bytes in a settled estimate: ceil(bytes / 3), the same high count
38
+ * as the native gateway's byte estimate. Coding-agent bodies are mostly code, JSON and English,
39
+ * which tokenize at about 3.5 to 4.5 bytes a token, so a token per 3 bytes stays above the real
40
+ * count. Text that tokenizes tighter is mostly multi-byte UTF-8 (3 bytes a character, rarely more
41
+ * than a token each), and base64 images are billed by size, not bytes, so both still lean high.
42
+ * The hold itself still counts a token per byte (hold.ts): this is only the settled estimate.
43
+ */
44
+ export declare function bodyInputTokens(bytes: number): number;
45
+ /**
46
+ * The input of a cut request from its conversation's previous reply: that reply's prompt and cache
47
+ * split, plus the body's growth since (bodyInputTokens) as uncached input (uncachedInput).
48
+ * Undefined when that reply can't stand for this prompt, as for the hold (hold.ts): another model,
49
+ * estimated or unfinished, an unknown or larger body, or a cache that had expired by the time the
50
+ * request was reserved. The estimate then prices the whole body as uncached input.
51
+ */
52
+ export declare function previousInput(input: {
53
+ model: string;
54
+ bodyBytes: number | undefined;
55
+ previous: PreviousReply | null;
56
+ pricing: ModelPricing;
57
+ /** When the request was reserved: the hold's own clock. */
58
+ now: Date;
59
+ }): ProxyUsage | undefined;
60
+ /**
61
+ * The best known cost of a reply that broke before its final usage (spec PR 1
62
+ * › 1b): usage already read, else the input from its conversation's previous
63
+ * reply (previousInput), else the whole body as uncached input
64
+ * (bodyInputTokens), else (body size unknown) the input part of the hold; plus
65
+ * the output seen so far. With no output seen, the model's median completed
66
+ * reply, or none while there is no completed reply (a deliberate rule: one cut
67
+ * must not book a whole reserved reply). A stream that failed before its
68
+ * response started generated none. Never more than the request's worst case.
69
+ */
70
+ export declare function estimateInterrupted(facts: InterruptedFacts, pricing: ModelPricing): InterruptedEstimate;
@@ -0,0 +1,104 @@
1
+ import { computeCost } from "../llm/pricing-core.js";
2
+ import { CACHE_WINDOW_MS } from "./hold.js";
3
+ /** Output tokens for relayed text: ceil(bytes / 3), a deliberately high count. */
4
+ export function relayedOutputTokens(bytes) {
5
+ return bytes > 0 ? Math.ceil(bytes / 3) : 0;
6
+ }
7
+ /**
8
+ * Prompt tokens for request-body bytes in a settled estimate: ceil(bytes / 3), the same high count
9
+ * as the native gateway's byte estimate. Coding-agent bodies are mostly code, JSON and English,
10
+ * which tokenize at about 3.5 to 4.5 bytes a token, so a token per 3 bytes stays above the real
11
+ * count. Text that tokenizes tighter is mostly multi-byte UTF-8 (3 bytes a character, rarely more
12
+ * than a token each), and base64 images are billed by size, not bytes, so both still lean high.
13
+ * The hold itself still counts a token per byte (hold.ts): this is only the settled estimate.
14
+ */
15
+ export function bodyInputTokens(bytes) {
16
+ return bytes > 0 ? Math.ceil(bytes / 3) : 0;
17
+ }
18
+ /**
19
+ * New prompt tokens as usage, at the higher of the model's fresh-input and cache-write rates: the
20
+ * provider may write them to its cache (Claude Code marks the latest message; OpenAI GPT-5.6 and
21
+ * later bill cache writes above input), or bill them as input.
22
+ */
23
+ function uncachedInput(tokens, pricing) {
24
+ const written = (pricing.cacheWritePerMTok ?? pricing.inputPerMTok) > pricing.inputPerMTok;
25
+ return { inputTokens: written ? 0 : tokens, cacheWriteTokens: written ? tokens : 0 };
26
+ }
27
+ /**
28
+ * The input of a cut request from its conversation's previous reply: that reply's prompt and cache
29
+ * split, plus the body's growth since (bodyInputTokens) as uncached input (uncachedInput).
30
+ * Undefined when that reply can't stand for this prompt, as for the hold (hold.ts): another model,
31
+ * estimated or unfinished, an unknown or larger body, or a cache that had expired by the time the
32
+ * request was reserved. The estimate then prices the whole body as uncached input.
33
+ */
34
+ export function previousInput(input) {
35
+ const { previous, bodyBytes } = input;
36
+ if (!previous || previous.model !== input.model || previous.costEstimated)
37
+ return undefined;
38
+ if (previous.status !== "completed" || !previous.usage)
39
+ return undefined;
40
+ if (bodyBytes === undefined || previous.requestBytes === null || bodyBytes < previous.requestBytes)
41
+ return undefined;
42
+ if (input.now.getTime() - previous.startedAt.getTime() > CACHE_WINDOW_MS)
43
+ return undefined;
44
+ const growth = uncachedInput(bodyInputTokens(bodyBytes - previous.requestBytes), input.pricing);
45
+ const usage = previous.usage;
46
+ return {
47
+ inputTokens: usage.inputTokens + growth.inputTokens,
48
+ cachedInputTokens: usage.cachedInputTokens,
49
+ cacheWriteTokens: usage.cacheWriteTokens + growth.cacheWriteTokens,
50
+ outputTokens: 0,
51
+ reasoningTokens: 0,
52
+ };
53
+ }
54
+ /**
55
+ * The best known cost of a reply that broke before its final usage (spec PR 1
56
+ * › 1b): usage already read, else the input from its conversation's previous
57
+ * reply (previousInput), else the whole body as uncached input
58
+ * (bodyInputTokens), else (body size unknown) the input part of the hold; plus
59
+ * the output seen so far. With no output seen, the model's median completed
60
+ * reply, or none while there is no completed reply (a deliberate rule: one cut
61
+ * must not book a whole reserved reply). A stream that failed before its
62
+ * response started generated none. Never more than the request's worst case.
63
+ */
64
+ export function estimateInterrupted(facts, pricing) {
65
+ const relayed = relayedOutputTokens(facts.relayedOutputBytes);
66
+ const output = relayed > 0 || facts.beforeResponse ? relayed : (facts.medianOutputTokens ?? 0);
67
+ const clamp = (cost) => Math.max(0, Math.min(cost, facts.ceilingUsd ?? facts.reservationUsd));
68
+ if (facts.readUsage) {
69
+ const usage = {
70
+ ...facts.readUsage,
71
+ outputTokens: facts.reportedOutputTokens ?? Math.max(facts.outputFloorTokens ?? 0, output),
72
+ reasoningTokens: 0,
73
+ };
74
+ return { usage, costUsd: clamp(computeCost(pricing, usage)) };
75
+ }
76
+ if (facts.previous) {
77
+ const usage = {
78
+ inputTokens: facts.previous.inputTokens,
79
+ cachedInputTokens: facts.previous.cachedInputTokens,
80
+ cacheWriteTokens: facts.previous.cacheWriteTokens,
81
+ outputTokens: output,
82
+ reasoningTokens: 0,
83
+ };
84
+ return { usage, costUsd: clamp(computeCost(pricing, usage)) };
85
+ }
86
+ if (facts.bodyBytes !== undefined) {
87
+ const usage = {
88
+ ...uncachedInput(bodyInputTokens(facts.bodyBytes), pricing),
89
+ cachedInputTokens: 0,
90
+ outputTokens: output,
91
+ reasoningTokens: 0,
92
+ };
93
+ return { usage, costUsd: clamp(computeCost(pricing, usage)) };
94
+ }
95
+ const usage = {
96
+ inputTokens: 0,
97
+ cachedInputTokens: 0,
98
+ cacheWriteTokens: 0,
99
+ outputTokens: output,
100
+ reasoningTokens: 0,
101
+ };
102
+ const inputPart = facts.reservationUsd - (facts.maxOutputTokens * pricing.outputPerMTok) / 1_000_000;
103
+ return { usage, costUsd: clamp(inputPart + (usage.outputTokens * pricing.outputPerMTok) / 1_000_000) };
104
+ }
@@ -1,18 +1,31 @@
1
- import { type CreateProxySessionInput, type ProxyLedger, type ProxyRequest, type ProxySession, type ProxyUsage, type ReserveProxyRequestInput, type ReserveProxyRequestResult } from "./types.js";
1
+ import { type PreviousReply, type CreateProxySessionInput, type ProxyLedger, type ProxyRefusalRecord, type ProxyRequest, type ProxySession, type ProxyUsage, type ReserveProxyRequestInput, type ReserveProxyRequestResult } from "./types.js";
2
2
  /** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
3
3
  export declare class MemoryProxyLedger implements ProxyLedger {
4
+ private readonly options;
4
5
  private readonly sessions;
5
6
  private readonly sessionByCapability;
6
7
  private readonly requests;
7
8
  private readonly requestBySessionKey;
9
+ private readonly startedAt;
10
+ constructor(options?: {
11
+ now?: () => Date;
12
+ });
8
13
  createSession(input: CreateProxySessionInput): Promise<void>;
9
14
  findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
10
15
  reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
11
16
  complete(requestId: string, usage: ProxyUsage, actualCostUsd: number, upstreamStatus: number): Promise<ProxyRequest>;
12
17
  release(requestId: string, upstreamStatus: number): Promise<void>;
13
- markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
18
+ markUncertain(requestId: string, upstreamStatus?: number, estimate?: {
19
+ usage: ProxyUsage;
20
+ costUsd: number;
21
+ }): Promise<void>;
22
+ settlementHints(sessionId: string, model: string): Promise<{
23
+ medianOutputTokens?: number;
24
+ }>;
25
+ previousReply(sessionId: string, conversationKey: string): Promise<PreviousReply | null>;
14
26
  cancelSession(sessionId: string): Promise<void>;
15
27
  budgetExhausted(sessionId: string): Promise<boolean>;
28
+ budgetRefusal(sessionId: string): Promise<ProxyRefusalRecord | null>;
16
29
  recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
17
30
  upstreamFailure(sessionId: string): Promise<string | null>;
18
31
  getRequest(requestId: string): Promise<ProxyRequest | null>;
@@ -5,6 +5,7 @@ function cloneSession(session) {
5
5
  allowedModels: [...session.allowedModels],
6
6
  deadlineAt: new Date(session.deadlineAt),
7
7
  budgetExhaustedAt: session.budgetExhaustedAt ? new Date(session.budgetExhaustedAt) : null,
8
+ budgetRefusal: session.budgetRefusal ? { ...session.budgetRefusal } : null,
8
9
  upstreamFailure: session.upstreamFailure ?? null,
9
10
  terms: session.terms
10
11
  ? { version: session.terms.version, entry: { ...session.terms.entry, efforts: [...session.terms.entry.efforts] } }
@@ -20,10 +21,15 @@ function cloneRequest(request) {
20
21
  }
21
22
  /** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
22
23
  export class MemoryProxyLedger {
24
+ options;
23
25
  sessions = new Map();
24
26
  sessionByCapability = new Map();
25
27
  requests = new Map();
26
28
  requestBySessionKey = new Map();
29
+ startedAt = new Map();
30
+ constructor(options = {}) {
31
+ this.options = options;
32
+ }
27
33
  async createSession(input) {
28
34
  if ([...this.sessions.values()].some((session) => session.runId === input.runId)) {
29
35
  throw new Error("proxy_session_exists");
@@ -54,22 +60,47 @@ export class MemoryProxyLedger {
54
60
  const existingId = this.requestBySessionKey.get(lookupKey);
55
61
  if (existingId)
56
62
  return { outcome: "duplicate", request: cloneRequest(this.requests.get(existingId)) };
57
- let committedOrHeld = 0;
63
+ let spent = 0;
64
+ let heldReserved = 0;
65
+ let heldUncertain = 0;
66
+ let done = 0;
58
67
  for (const request of this.requests.values()) {
59
68
  if (request.sessionId !== input.sessionId)
60
69
  continue;
61
- if (request.status === "completed")
62
- committedOrHeld += request.actualCostUsd;
63
- if (request.status === "reserved" || request.status === "uncertain")
64
- committedOrHeld += request.reservationUsd;
70
+ // An uncertain request settled at an estimate counts at it; one without an estimate keeps its hold.
71
+ const settled = request.status === "completed" || (request.status === "uncertain" && request.costEstimated);
72
+ if (settled) {
73
+ spent += request.actualCostUsd;
74
+ done += 1;
75
+ }
76
+ else if (request.status === "reserved")
77
+ heldReserved += request.reservationUsd;
78
+ else if (request.status === "uncertain")
79
+ heldUncertain += request.reservationUsd;
65
80
  }
81
+ const committedOrHeld = spent + heldReserved + heldUncertain;
66
82
  if (committedOrHeld + input.reservationUsd >= session.budgetUsd) {
67
- session.budgetExhaustedAt ??= new Date(input.now);
68
- return { outcome: "budget_exhausted" };
83
+ const details = {
84
+ budgetUsd: session.budgetUsd,
85
+ spentUsd: spent,
86
+ heldReservedUsd: heldReserved,
87
+ heldUncertainUsd: heldUncertain,
88
+ refusedHoldUsd: input.reservationUsd,
89
+ ...(input.reservationBasis ? { refusedHoldBasis: input.reservationBasis } : {}),
90
+ ...(input.ceilingUsd !== undefined ? { refusedHoldCeilingUsd: input.ceilingUsd } : {}),
91
+ model: input.model,
92
+ turn: done + 1,
93
+ };
94
+ if (!session.budgetExhaustedAt) {
95
+ session.budgetExhaustedAt = new Date(input.now);
96
+ session.budgetRefusal = { source: "proxy", ...details };
97
+ }
98
+ return { outcome: "budget_exhausted", details };
69
99
  }
70
100
  const request = { ...input, pricing: { ...input.pricing }, status: "reserved" };
71
101
  this.requests.set(request.id, request);
72
102
  this.requestBySessionKey.set(lookupKey, request.id);
103
+ this.startedAt.set(request.id, new Date(input.now));
73
104
  return { outcome: "reserved", request: cloneRequest(request) };
74
105
  }
75
106
  async complete(requestId, usage, actualCostUsd, upstreamStatus) {
@@ -86,6 +117,7 @@ export class MemoryProxyLedger {
86
117
  request.actualCostUsd = actualCostUsd;
87
118
  request.usage = { ...usage };
88
119
  request.upstreamStatus = upstreamStatus;
120
+ request.costEstimated = false;
89
121
  return cloneRequest(request);
90
122
  }
91
123
  async release(requestId, upstreamStatus) {
@@ -95,12 +127,52 @@ export class MemoryProxyLedger {
95
127
  request.status = "released";
96
128
  request.upstreamStatus = upstreamStatus;
97
129
  }
98
- async markUncertain(requestId, upstreamStatus) {
130
+ async markUncertain(requestId, upstreamStatus, estimate) {
99
131
  const request = this.requiredRequest(requestId);
100
132
  if (request.status !== "reserved")
101
133
  return;
102
134
  request.status = "uncertain";
103
135
  request.upstreamStatus = upstreamStatus;
136
+ if (estimate) {
137
+ request.actualCostUsd = estimate.costUsd;
138
+ request.usage = { ...estimate.usage };
139
+ request.costEstimated = true;
140
+ }
141
+ }
142
+ async settlementHints(sessionId, model) {
143
+ const outputs = [];
144
+ for (const request of this.requests.values()) {
145
+ if (request.sessionId !== sessionId || request.model !== model)
146
+ continue;
147
+ if (request.status !== "completed" || !request.usage)
148
+ continue;
149
+ outputs.push(request.usage.outputTokens);
150
+ }
151
+ outputs.sort((a, b) => a - b);
152
+ return {
153
+ // The lower middle for an even count, as Postgres's percentile_disc(0.5).
154
+ ...(outputs.length > 0 ? { medianOutputTokens: outputs[Math.ceil(outputs.length / 2) - 1] } : {}),
155
+ };
156
+ }
157
+ async previousReply(sessionId, conversationKey) {
158
+ let latest;
159
+ // Map iteration follows insertion order: the last match is the latest request.
160
+ for (const request of this.requests.values()) {
161
+ if (request.sessionId !== sessionId || request.conversationKey !== conversationKey)
162
+ continue;
163
+ if (request.status === "completed" || request.status === "uncertain")
164
+ latest = request;
165
+ }
166
+ if (!latest)
167
+ return null;
168
+ return {
169
+ model: latest.model,
170
+ status: latest.status,
171
+ costEstimated: latest.costEstimated === true,
172
+ ...(latest.usage ? { usage: { ...latest.usage } } : {}),
173
+ requestBytes: latest.requestBytes ?? null,
174
+ startedAt: this.startedAt.get(latest.id) ?? new Date(0),
175
+ };
104
176
  }
105
177
  async cancelSession(sessionId) {
106
178
  const session = this.sessions.get(sessionId);
@@ -110,6 +182,10 @@ export class MemoryProxyLedger {
110
182
  async budgetExhausted(sessionId) {
111
183
  return Boolean(this.sessions.get(sessionId)?.budgetExhaustedAt);
112
184
  }
185
+ async budgetRefusal(sessionId) {
186
+ const refusal = this.sessions.get(sessionId)?.budgetRefusal;
187
+ return refusal ? { ...refusal } : null;
188
+ }
113
189
  async recordUpstreamFailure(sessionId, code) {
114
190
  const session = this.sessions.get(sessionId);
115
191
  if (session)
@@ -17,9 +17,25 @@ export declare function safeUpstreamErrorCode(record: Record<string, unknown>):
17
17
  /** Accumulates Anthropic's split input/output usage until message_stop. */
18
18
  export declare class AnthropicSseUsageTracker {
19
19
  private startUsage?;
20
+ /** message_start's output count: a placeholder (usually 1), not a running count. */
21
+ private startOutputTokens?;
22
+ /** message_delta's running output count. */
20
23
  private outputTokens?;
21
24
  private stopped;
22
25
  consume(frame: string): TerminalUsage;
26
+ /**
27
+ * What a cut stream reported before its message_stop: start usage (input incl. cache reads), the
28
+ * output count message_delta reported, and message_start's output count as a floor only.
29
+ */
30
+ partial(): {
31
+ readUsage?: {
32
+ inputTokens: number;
33
+ cachedInputTokens: number;
34
+ cacheWriteTokens: number;
35
+ };
36
+ reportedOutputTokens?: number;
37
+ outputFloorTokens?: number;
38
+ };
23
39
  }
24
40
  /** The rates a request is billed at, tagged with their version. Picks only the price fields: a catalog entry's routing/shape fields stay out of the ledger. */
25
41
  export declare function pricingSnapshot(version: string, pricing: ModelPricing): PricingSnapshot;
@@ -134,6 +134,9 @@ function sseEvent(frame) {
134
134
  /** Accumulates Anthropic's split input/output usage until message_stop. */
135
135
  export class AnthropicSseUsageTracker {
136
136
  startUsage;
137
+ /** message_start's output count: a placeholder (usually 1), not a running count. */
138
+ startOutputTokens;
139
+ /** message_delta's running output count. */
137
140
  outputTokens;
138
141
  stopped = false;
139
142
  consume(frame) {
@@ -156,8 +159,9 @@ export class AnthropicSseUsageTracker {
156
159
  tokenCount(record.cache_read_input_tokens ?? 0, "cache_read_input_tokens");
157
160
  tokenCount(record.cache_creation_input_tokens ?? 0, "cache_creation_input_tokens");
158
161
  this.startUsage = record;
159
- if (record.output_tokens !== undefined)
160
- this.outputTokens = tokenCount(record.output_tokens, "output_tokens");
162
+ if (record.output_tokens !== undefined) {
163
+ this.startOutputTokens = tokenCount(record.output_tokens, "output_tokens");
164
+ }
161
165
  return { terminal: false };
162
166
  }
163
167
  case "message_delta": {
@@ -168,19 +172,38 @@ export class AnthropicSseUsageTracker {
168
172
  return { terminal: false };
169
173
  }
170
174
  case "message_stop": {
171
- if (this.stopped || !this.startUsage || this.outputTokens === undefined) {
175
+ const outputTokens = this.outputTokens ?? this.startOutputTokens;
176
+ if (this.stopped || !this.startUsage || outputTokens === undefined) {
172
177
  return { terminal: true };
173
178
  }
174
179
  this.stopped = true;
175
180
  return {
176
181
  terminal: true,
177
- usage: parseAnthropicAuthoritativeUsage({ ...this.startUsage, output_tokens: this.outputTokens }),
182
+ usage: parseAnthropicAuthoritativeUsage({ ...this.startUsage, output_tokens: outputTokens }),
178
183
  };
179
184
  }
180
185
  default:
181
186
  return { terminal: false };
182
187
  }
183
188
  }
189
+ /**
190
+ * What a cut stream reported before its message_stop: start usage (input incl. cache reads), the
191
+ * output count message_delta reported, and message_start's output count as a floor only.
192
+ */
193
+ partial() {
194
+ if (!this.startUsage)
195
+ return this.outputTokens === undefined ? {} : { reportedOutputTokens: this.outputTokens };
196
+ const cached = tokenCount(this.startUsage.cache_read_input_tokens ?? 0, "cache_read_input_tokens");
197
+ return {
198
+ readUsage: {
199
+ inputTokens: tokenCount(this.startUsage.input_tokens, "input_tokens") + cached,
200
+ cachedInputTokens: cached,
201
+ cacheWriteTokens: tokenCount(this.startUsage.cache_creation_input_tokens ?? 0, "cache_creation_input_tokens"),
202
+ },
203
+ ...(this.outputTokens !== undefined ? { reportedOutputTokens: this.outputTokens } : {}),
204
+ ...(this.startOutputTokens !== undefined ? { outputFloorTokens: this.startOutputTokens } : {}),
205
+ };
206
+ }
184
207
  }
185
208
  /** The rates a request is billed at, tagged with their version. Picks only the price fields: a catalog entry's routing/shape fields stay out of the ledger. */
186
209
  export function pricingSnapshot(version, pricing) {
@@ -1,5 +1,5 @@
1
1
  import type { PrismaClient } from "#prisma";
2
- import type { CreateProxySessionInput, ProxyLedger, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
2
+ import type { CreateProxySessionInput, PreviousReply, ProxyLedger, ProxyRefusalRecord, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
3
3
  export type PrismaProxyLedgerDb = Pick<PrismaClient, "$transaction" | "$queryRaw" | "$executeRaw">;
4
4
  /** How long a ledger transaction waits for a pool connection (Prisma's
5
5
  * default is 2 s). A model request fails outright when this runs out, so it
@@ -22,10 +22,23 @@ export declare class PrismaProxyLedger implements ProxyLedger {
22
22
  findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
23
23
  reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
24
24
  complete(requestId: string, usage: ProxyUsage, actualCostUsd: number, upstreamStatus: number): Promise<ProxyRequest>;
25
+ /**
26
+ * Recomputes the run's totals (Run) and this model's usage (RunModelUsage) from its settled
27
+ * requests: completed ones and uncertain ones settled at an estimate. Set, never incremented.
28
+ */
29
+ private recomputeRunTotals;
25
30
  release(requestId: string, upstreamStatus: number): Promise<void>;
26
- markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
31
+ markUncertain(requestId: string, upstreamStatus?: number, estimate?: {
32
+ usage: ProxyUsage;
33
+ costUsd: number;
34
+ }): Promise<void>;
35
+ settlementHints(sessionId: string, model: string): Promise<{
36
+ medianOutputTokens?: number;
37
+ }>;
38
+ previousReply(sessionId: string, conversationKey: string): Promise<PreviousReply | null>;
27
39
  cancelSession(sessionId: string): Promise<void>;
28
40
  budgetExhausted(sessionId: string): Promise<boolean>;
41
+ budgetRefusal(sessionId: string): Promise<ProxyRefusalRecord | null>;
29
42
  recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
30
43
  upstreamFailure(sessionId: string): Promise<string | null>;
31
44
  getRequest(requestId: string): Promise<ProxyRequest | null>;