@wardby/cli 0.5.3 → 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 (763) hide show
  1. package/.env.example +33 -0
  2. package/README.md +25 -14
  3. package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
  4. package/dist/claude-coding-worker/context.d.ts +22 -0
  5. package/dist/claude-coding-worker/context.js +92 -0
  6. package/dist/claude-coding-worker/driver.d.ts +27 -3
  7. package/dist/claude-coding-worker/driver.js +161 -20
  8. package/dist/claude-coding-worker/main.js +34 -6
  9. package/dist/claude-coding-worker/sdk.js +25 -5
  10. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  11. package/dist/claude-coding-worker/tool-socket.js +111 -0
  12. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  13. package/dist/claude-coding-worker/transcript.js +77 -0
  14. package/dist/cli-help.d.ts +1 -1
  15. package/dist/cli-help.js +6 -2
  16. package/dist/cli-native-mode.d.ts +9 -0
  17. package/dist/cli-native-mode.js +20 -0
  18. package/dist/cli.d.ts +3 -1
  19. package/dist/cli.js +161 -11
  20. package/dist/coding/claude-context.d.ts +45 -0
  21. package/dist/coding/claude-context.js +434 -0
  22. package/dist/coding/continuation-wording.d.ts +35 -0
  23. package/dist/coding/continuation-wording.js +73 -0
  24. package/dist/coding/linked-issue-note.d.ts +23 -0
  25. package/dist/coding/linked-issue-note.js +47 -0
  26. package/dist/coding/merge-wording.d.ts +28 -0
  27. package/dist/coding/merge-wording.js +78 -0
  28. package/dist/coding/pr-description-note.d.ts +9 -0
  29. package/dist/coding/pr-description-note.js +32 -0
  30. package/dist/coding/profile.d.ts +50 -118
  31. package/dist/coding/profile.js +51 -4
  32. package/dist/coding/protected-path-wording.d.ts +8 -0
  33. package/dist/coding/protected-path-wording.js +1 -1
  34. package/dist/coding/protocol.d.ts +292 -270
  35. package/dist/coding/protocol.js +322 -15
  36. package/dist/coding/redact.d.ts +3 -0
  37. package/dist/coding/redact.js +12 -0
  38. package/dist/coding/registry/allowlist.d.ts +12 -0
  39. package/dist/coding/registry/allowlist.js +14 -1
  40. package/dist/coding/registry/audit-mode.d.ts +153 -0
  41. package/dist/coding/registry/audit-mode.js +304 -0
  42. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  43. package/dist/coding/registry/lockfile-shared.js +128 -0
  44. package/dist/coding/registry/lockfiles.js +1 -1
  45. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  46. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  47. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  48. package/dist/coding/registry/npm-lockfile.js +4 -6
  49. package/dist/coding/registry/npm.js +78 -8
  50. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  51. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  52. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  53. package/dist/coding/registry/pypi-plan.js +406 -0
  54. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  55. package/dist/coding/registry/pypi-requirements.js +155 -0
  56. package/dist/coding/registry/pypi.d.ts +3 -27
  57. package/dist/coding/registry/pypi.js +40 -154
  58. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  59. package/dist/coding/registry/refusal-hints.js +61 -0
  60. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  61. package/dist/coding/registry/refusal-wording.js +56 -0
  62. package/dist/coding/registry/report.d.ts +70 -8
  63. package/dist/coding/registry/report.js +112 -5
  64. package/dist/coding/registry/types.d.ts +58 -8
  65. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  66. package/dist/coding/registry/yarn-lockfile.js +367 -0
  67. package/dist/coding/services/catalog.d.ts +37 -351
  68. package/dist/coding/transcript/claude-code.d.ts +13 -0
  69. package/dist/coding/transcript/claude-code.js +273 -0
  70. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  71. package/dist/coding/transcript/download-protocol.js +18 -0
  72. package/dist/coding/transcript/format.d.ts +20 -0
  73. package/dist/coding/transcript/format.js +32 -0
  74. package/dist/coding/transcript/recorder.d.ts +51 -0
  75. package/dist/coding/transcript/recorder.js +225 -0
  76. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  77. package/dist/coding/transcript/resume/checkout.js +203 -0
  78. package/dist/coding/transcript/resume/command.d.ts +17 -0
  79. package/dist/coding/transcript/resume/command.js +176 -0
  80. package/dist/coding/transcript/resume/download.d.ts +20 -0
  81. package/dist/coding/transcript/resume/download.js +153 -0
  82. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  83. package/dist/coding/transcript/resume/launch.js +128 -0
  84. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  85. package/dist/coding/transcript/resume/session-file.js +79 -0
  86. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  87. package/dist/coding/transcript/resume/stand-in.js +49 -0
  88. package/dist/coding-worker/artifact.d.ts +16 -3
  89. package/dist/coding-worker/artifact.js +5 -3
  90. package/dist/coding-worker/debug-trace.d.ts +6 -5
  91. package/dist/coding-worker/debug-trace.js +13 -18
  92. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  93. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  94. package/dist/coding-worker/driver.d.ts +4 -3
  95. package/dist/coding-worker/driver.js +118 -38
  96. package/dist/coding-worker/errors.d.ts +1 -0
  97. package/dist/coding-worker/errors.js +32 -0
  98. package/dist/coding-worker/sdk.d.ts +6 -0
  99. package/dist/coding-worker/sdk.js +1 -0
  100. package/dist/coding-worker/skills.d.ts +23 -0
  101. package/dist/coding-worker/skills.js +117 -0
  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 +13 -0
  105. package/dist/config/dependency-cache.d.ts +23 -0
  106. package/dist/config/dependency-cache.js +32 -0
  107. package/dist/config/github-allowed-accounts.d.ts +15 -0
  108. package/dist/config/github-allowed-accounts.js +36 -0
  109. package/dist/config/low-power.d.ts +12 -0
  110. package/dist/config/low-power.js +18 -0
  111. package/dist/config/mobile.d.ts +12 -0
  112. package/dist/config/mobile.js +18 -0
  113. package/dist/config/providers.d.ts +65 -3
  114. package/dist/config/providers.js +147 -11
  115. package/dist/config/test-simulators.d.ts +82 -0
  116. package/dist/config/test-simulators.js +305 -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-queue.d.ts +2 -1
  130. package/dist/core/coding-queue.js +7 -0
  131. package/dist/core/cron.d.ts +19 -1
  132. package/dist/core/cron.js +17 -0
  133. package/dist/core/datastores.js +1 -1
  134. package/dist/core/db.d.ts +16 -6
  135. package/dist/core/db.js +12 -10
  136. package/dist/core/deferred-coding.d.ts +14 -0
  137. package/dist/core/deferred-coding.js +62 -0
  138. package/dist/core/delegation-child.d.ts +25 -0
  139. package/dist/core/delegation-child.js +37 -0
  140. package/dist/core/dispatch.d.ts +53 -0
  141. package/dist/core/dispatch.js +167 -57
  142. package/dist/core/engine-native.js +10 -6
  143. package/dist/core/error-code.d.ts +38 -0
  144. package/dist/core/error-code.js +168 -0
  145. package/dist/core/grants.d.ts +19 -6
  146. package/dist/core/grants.js +55 -6
  147. package/dist/core/host-events.d.ts +67 -5
  148. package/dist/core/host-events.js +571 -37
  149. package/dist/core/host-status.d.ts +85 -3
  150. package/dist/core/host-status.js +298 -20
  151. package/dist/core/issue-bridge.d.ts +50 -6
  152. package/dist/core/issue-bridge.js +151 -20
  153. package/dist/core/issue-events.d.ts +1 -1
  154. package/dist/core/issue-events.js +16 -11
  155. package/dist/core/issue-status.d.ts +1 -1
  156. package/dist/core/issue-status.js +68 -29
  157. package/dist/core/logger.d.ts +5 -0
  158. package/dist/core/logger.js +14 -1
  159. package/dist/core/lost-run-children.d.ts +6 -0
  160. package/dist/core/lost-run-children.js +32 -0
  161. package/dist/core/mark-ready.d.ts +34 -0
  162. package/dist/core/mark-ready.js +152 -0
  163. package/dist/core/markdown-code.d.ts +8 -0
  164. package/dist/core/markdown-code.js +107 -0
  165. package/dist/core/memory-tools.js +7 -0
  166. package/dist/core/merge-order-check.d.ts +130 -0
  167. package/dist/core/merge-order-check.js +343 -0
  168. package/dist/core/notification-dispatcher.d.ts +70 -0
  169. package/dist/core/notification-dispatcher.js +368 -0
  170. package/dist/core/notification-templates.d.ts +19 -0
  171. package/dist/core/notification-templates.js +139 -0
  172. package/dist/core/notifications.d.ts +10 -0
  173. package/dist/core/notifications.js +38 -0
  174. package/dist/core/pg-auth.d.ts +22 -0
  175. package/dist/core/pg-auth.js +152 -0
  176. package/dist/core/power-composition.d.ts +16 -0
  177. package/dist/core/power-composition.js +37 -0
  178. package/dist/core/power-idle.d.ts +14 -0
  179. package/dist/core/power-idle.js +30 -0
  180. package/dist/core/power.d.ts +71 -0
  181. package/dist/core/power.js +202 -0
  182. package/dist/core/pull-request-state-sync.js +2 -2
  183. package/dist/core/reconciler.d.ts +8 -5
  184. package/dist/core/reconciler.js +37 -6
  185. package/dist/core/related-pull-requests.d.ts +59 -7
  186. package/dist/core/related-pull-requests.js +140 -25
  187. package/dist/core/reply-parts.d.ts +21 -0
  188. package/dist/core/reply-parts.js +73 -0
  189. package/dist/core/repo-access.d.ts +15 -0
  190. package/dist/core/repo-access.js +66 -0
  191. package/dist/core/review-fix.d.ts +38 -1
  192. package/dist/core/review-fix.js +209 -7
  193. package/dist/core/review-host-checks.d.ts +1 -1
  194. package/dist/core/review-host-tools.d.ts +23 -0
  195. package/dist/core/review-host-tools.js +156 -14
  196. package/dist/core/review-reads.d.ts +55 -0
  197. package/dist/core/review-reads.js +233 -0
  198. package/dist/core/run-status.d.ts +12 -0
  199. package/dist/core/run-status.js +12 -0
  200. package/dist/core/runner.d.ts +384 -5
  201. package/dist/core/runner.js +1244 -372
  202. package/dist/core/schedule-start.d.ts +12 -0
  203. package/dist/core/schedule-start.js +14 -0
  204. package/dist/core/secret-broker-config.d.ts +39 -0
  205. package/dist/core/secret-broker-config.js +112 -0
  206. package/dist/core/secret-guard.d.ts +46 -0
  207. package/dist/core/secret-guard.js +104 -0
  208. package/dist/core/secret-guarded-stores.d.ts +12 -0
  209. package/dist/core/secret-guarded-stores.js +41 -0
  210. package/dist/core/secret-spans.d.ts +50 -0
  211. package/dist/core/secret-spans.js +94 -0
  212. package/dist/core/secrets.d.ts +39 -4
  213. package/dist/core/secrets.js +148 -40
  214. package/dist/core/stop-run.d.ts +46 -0
  215. package/dist/core/stop-run.js +61 -0
  216. package/dist/core/workflow-event-recorder.d.ts +14 -0
  217. package/dist/core/workflow-event-recorder.js +120 -0
  218. package/dist/core/workflow-events.d.ts +94 -0
  219. package/dist/core/workflow-events.js +48 -0
  220. package/dist/core/workflow-run-events.d.ts +18 -0
  221. package/dist/core/workflow-run-events.js +75 -0
  222. package/dist/core/zod-json-schema.d.ts +4 -0
  223. package/dist/core/zod-json-schema.js +39 -0
  224. package/dist/core/zod3-window.d.ts +35 -0
  225. package/dist/core/zod3-window.js +124 -0
  226. package/dist/generated/prisma/browser.d.ts +92 -3
  227. package/dist/generated/prisma/client.d.ts +92 -3
  228. package/dist/generated/prisma/commonInputTypes.d.ts +364 -54
  229. package/dist/generated/prisma/enums.d.ts +37 -0
  230. package/dist/generated/prisma/enums.js +31 -0
  231. package/dist/generated/prisma/internal/class.d.ts +132 -0
  232. package/dist/generated/prisma/internal/class.js +4 -4
  233. package/dist/generated/prisma/internal/prismaNamespace.d.ts +1332 -142
  234. package/dist/generated/prisma/internal/prismaNamespace.js +227 -5
  235. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +234 -0
  236. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +227 -5
  237. package/dist/generated/prisma/models/Agent.d.ts +464 -7
  238. package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
  239. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +301 -1
  240. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  241. package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
  242. package/dist/generated/prisma/models/CodingRun.d.ts +1841 -1
  243. package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
  244. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  245. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  246. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  247. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  248. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1713 -0
  249. package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
  250. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1551 -0
  251. package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
  252. package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
  253. package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
  254. package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
  255. package/dist/generated/prisma/models/NotificationChannel.js +1 -0
  256. package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
  257. package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
  258. package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
  259. package/dist/generated/prisma/models/NotificationThread.js +1 -0
  260. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  261. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  262. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  263. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  264. package/dist/generated/prisma/models/Run.d.ts +1619 -58
  265. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  266. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  267. package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
  268. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  269. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  270. package/dist/generated/prisma/models/Secret.d.ts +37 -1
  271. package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
  272. package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
  273. package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
  274. package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
  275. package/dist/generated/prisma/models.d.ts +12 -0
  276. package/dist/help/build.js +4 -2
  277. package/dist/help/catalog.d.ts +1 -1
  278. package/dist/help/catalog.js +31 -6
  279. package/dist/help-index.json +2584 -146
  280. package/dist/import/create.js +49 -3
  281. package/dist/import/neutral-schema.d.ts +50 -277
  282. package/dist/import/neutral-schema.js +7 -4
  283. package/dist/knowledge/check.d.ts +1 -1
  284. package/dist/knowledge/cli.d.ts +11 -1
  285. package/dist/knowledge/cli.js +37 -4
  286. package/dist/knowledge/concept.d.ts +3 -19
  287. package/dist/knowledge/location.d.ts +31 -0
  288. package/dist/knowledge/location.js +78 -0
  289. package/dist/mcp/auth/access.d.ts +11 -2
  290. package/dist/mcp/auth/access.js +15 -1
  291. package/dist/mcp/auth/ownership.d.ts +7 -7
  292. package/dist/mcp/auth/repo-authorization.js +14 -0
  293. package/dist/mcp/auth/resource-server.d.ts +2 -1
  294. package/dist/mcp/auth/resource-server.js +7 -2
  295. package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
  296. package/dist/mcp/auth/self-hosted/browser.js +19 -6
  297. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  298. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  299. package/dist/mcp/context.d.ts +6 -0
  300. package/dist/mcp/host-events/github-ingress.d.ts +25 -1
  301. package/dist/mcp/host-events/github-ingress.js +70 -1
  302. package/dist/mcp/index.d.ts +19 -0
  303. package/dist/mcp/index.js +117 -20
  304. package/dist/mcp/server.d.ts +13 -0
  305. package/dist/mcp/server.js +33 -14
  306. package/dist/mcp/tools/agents.d.ts +4 -0
  307. package/dist/mcp/tools/agents.js +277 -24
  308. package/dist/mcp/tools/datastore.js +17 -8
  309. package/dist/mcp/tools/grants.js +9 -3
  310. package/dist/mcp/tools/memory.js +11 -1
  311. package/dist/mcp/tools/notification-channels.d.ts +2 -0
  312. package/dist/mcp/tools/notification-channels.js +293 -0
  313. package/dist/mcp/tools/packages.d.ts +2 -0
  314. package/dist/mcp/tools/packages.js +195 -0
  315. package/dist/mcp/tools/power.d.ts +2 -0
  316. package/dist/mcp/tools/power.js +77 -0
  317. package/dist/mcp/tools/repositories.js +18 -5
  318. package/dist/mcp/tools/run-access.d.ts +16 -0
  319. package/dist/mcp/tools/run-access.js +25 -0
  320. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  321. package/dist/mcp/tools/run-transcript-download.js +129 -0
  322. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  323. package/dist/mcp/tools/run-transcript.js +70 -0
  324. package/dist/mcp/tools/runs.d.ts +0 -6
  325. package/dist/mcp/tools/runs.js +41 -14
  326. package/dist/mcp/tools/scheduling.js +3 -1
  327. package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
  328. package/dist/mcp/tools/secret-broker-compat.js +23 -0
  329. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
  330. package/dist/mcp/tools/secret-elicitation-form.js +205 -10
  331. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  332. package/dist/mcp/tools/secret-elicitation-server.js +10 -54
  333. package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
  334. package/dist/mcp/tools/secret-elicitation.js +110 -12
  335. package/dist/mcp/tools/secrets.js +186 -9
  336. package/dist/mcp/tools/stop-run.d.ts +2 -0
  337. package/dist/mcp/tools/stop-run.js +82 -0
  338. package/dist/mcp/tools/subagents.js +2 -2
  339. package/dist/mcp/tools/tools.d.ts +2 -2
  340. package/dist/mcp/tools/tools.js +47 -11
  341. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  342. package/dist/mcp/transport/stdio-link-host.js +67 -0
  343. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  344. package/dist/mcp/transport/streamable-http.js +41 -1
  345. package/dist/native-worker/composition.d.ts +23 -0
  346. package/dist/native-worker/composition.js +77 -0
  347. package/dist/native-worker/docker-isolation.d.ts +65 -0
  348. package/dist/native-worker/docker-isolation.js +183 -0
  349. package/dist/native-worker/docker-launcher.d.ts +110 -0
  350. package/dist/native-worker/docker-launcher.js +297 -0
  351. package/dist/native-worker/gateway-server.d.ts +77 -0
  352. package/dist/native-worker/gateway-server.js +412 -0
  353. package/dist/native-worker/gateway.d.ts +70 -0
  354. package/dist/native-worker/gateway.js +263 -0
  355. package/dist/native-worker/http-server.d.ts +24 -0
  356. package/dist/native-worker/http-server.js +113 -0
  357. package/dist/native-worker/http-transport.d.ts +17 -0
  358. package/dist/native-worker/http-transport.js +88 -0
  359. package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
  360. package/dist/native-worker/kubernetes-isolation.js +218 -0
  361. package/dist/native-worker/kubernetes-launcher.d.ts +106 -0
  362. package/dist/native-worker/kubernetes-launcher.js +375 -0
  363. package/dist/native-worker/launch.d.ts +62 -0
  364. package/dist/native-worker/launch.js +49 -0
  365. package/dist/native-worker/ledger.d.ts +125 -0
  366. package/dist/native-worker/ledger.js +245 -0
  367. package/dist/native-worker/loopback.d.ts +12 -0
  368. package/dist/native-worker/loopback.js +44 -0
  369. package/dist/native-worker/main.d.ts +8 -0
  370. package/dist/native-worker/main.js +85 -0
  371. package/dist/native-worker/protocol.d.ts +296 -0
  372. package/dist/native-worker/protocol.js +246 -0
  373. package/dist/native-worker/sandbox-executor.d.ts +83 -0
  374. package/dist/native-worker/sandbox-executor.js +284 -0
  375. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  376. package/dist/native-worker/stderr-redaction.js +237 -0
  377. package/dist/native-worker/stdio.d.ts +29 -0
  378. package/dist/native-worker/stdio.js +189 -0
  379. package/dist/native-worker/warm-delivery.d.ts +16 -0
  380. package/dist/native-worker/warm-delivery.js +33 -0
  381. package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
  382. package/dist/native-worker/warm-pool-ledger.js +73 -0
  383. package/dist/native-worker/warm-pool.d.ts +107 -0
  384. package/dist/native-worker/warm-pool.js +283 -0
  385. package/dist/native-worker/worker.d.ts +17 -0
  386. package/dist/native-worker/worker.js +141 -0
  387. package/dist/observability/metrics.js +6 -1
  388. package/dist/providers/auth/authorization-server.d.ts +3 -0
  389. package/dist/providers/auth/index.js +2 -0
  390. package/dist/providers/auth/self-hosted.d.ts +14 -2
  391. package/dist/providers/auth/self-hosted.js +54 -4
  392. package/dist/providers/chat/fake.d.ts +46 -0
  393. package/dist/providers/chat/fake.js +39 -0
  394. package/dist/providers/chat/index.d.ts +4 -0
  395. package/dist/providers/chat/index.js +8 -0
  396. package/dist/providers/chat/slack.d.ts +37 -0
  397. package/dist/providers/chat/slack.js +105 -0
  398. package/dist/providers/chat/types.d.ts +42 -0
  399. package/dist/providers/chat/types.js +19 -0
  400. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  401. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  402. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  403. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  404. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  405. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  406. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  407. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  408. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  409. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  410. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  411. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  412. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  413. package/dist/providers/coding-proxy/hold.js +86 -0
  414. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  415. package/dist/providers/coding-proxy/interrupted.js +104 -0
  416. package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
  417. package/dist/providers/coding-proxy/memory-ledger.js +84 -8
  418. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  419. package/dist/providers/coding-proxy/metering.js +27 -4
  420. package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
  421. package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
  422. package/dist/providers/coding-proxy/proxy.d.ts +14 -1
  423. package/dist/providers/coding-proxy/proxy.js +166 -14
  424. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  425. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  426. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  427. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  428. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  429. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  430. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  431. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  432. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  433. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  434. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  435. package/dist/providers/coding-proxy/registry/service.js +579 -112
  436. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  437. package/dist/providers/coding-proxy/registry/store.js +54 -1
  438. package/dist/providers/coding-proxy/runtime.d.ts +4 -0
  439. package/dist/providers/coding-proxy/runtime.js +78 -16
  440. package/dist/providers/coding-proxy/server.d.ts +6 -1
  441. package/dist/providers/coding-proxy/server.js +45 -1
  442. package/dist/providers/coding-proxy/types.d.ts +65 -1
  443. package/dist/providers/datastore/types.d.ts +5 -0
  444. package/dist/providers/engine/types.d.ts +36 -2
  445. package/dist/providers/engine/types.js +39 -0
  446. package/dist/providers/executor/composition.d.ts +31 -1
  447. package/dist/providers/executor/composition.js +81 -8
  448. package/dist/providers/executor/container.d.ts +385 -9
  449. package/dist/providers/executor/container.js +1234 -99
  450. package/dist/providers/executor/dbos-status.d.ts +31 -0
  451. package/dist/providers/executor/dbos-status.js +64 -0
  452. package/dist/providers/executor/dbos.d.ts +91 -0
  453. package/dist/providers/executor/dbos.js +319 -26
  454. package/dist/providers/executor/deferred.d.ts +44 -0
  455. package/dist/providers/executor/deferred.js +100 -0
  456. package/dist/providers/executor/in-process.d.ts +9 -1
  457. package/dist/providers/executor/in-process.js +14 -4
  458. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  459. package/dist/providers/executor/linked-issue-reader.js +30 -0
  460. package/dist/providers/executor/routing.d.ts +39 -10
  461. package/dist/providers/executor/routing.js +77 -32
  462. package/dist/providers/executor/types.d.ts +25 -0
  463. package/dist/providers/index.d.ts +2 -1
  464. package/dist/providers/issue-tracker/types.d.ts +17 -0
  465. package/dist/providers/issue-tracker/types.js +39 -1
  466. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  467. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  468. package/dist/providers/jobs/docker-isolation.d.ts +8 -0
  469. package/dist/providers/jobs/docker-isolation.js +17 -0
  470. package/dist/providers/jobs/docker.d.ts +1 -0
  471. package/dist/providers/jobs/docker.js +29 -4
  472. package/dist/providers/jobs/fake-kubernetes-api.d.ts +23 -2
  473. package/dist/providers/jobs/fake-kubernetes-api.js +45 -1
  474. package/dist/providers/jobs/kubernetes-api.d.ts +25 -1
  475. package/dist/providers/jobs/kubernetes-api.js +17 -0
  476. package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
  477. package/dist/providers/jobs/kubernetes-client.js +61 -3
  478. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
  479. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
  480. package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
  481. package/dist/providers/jobs/kubernetes-isolation.js +23 -1
  482. package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
  483. package/dist/providers/jobs/kubernetes-platform.js +38 -1
  484. package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
  485. package/dist/providers/jobs/kubernetes-preflight.js +4 -2
  486. package/dist/providers/jobs/kubernetes.d.ts +42 -2
  487. package/dist/providers/jobs/kubernetes.js +178 -19
  488. package/dist/providers/jobs/metadata-probes.d.ts +11 -0
  489. package/dist/providers/jobs/metadata-probes.js +13 -0
  490. package/dist/providers/jobs/types.d.ts +42 -0
  491. package/dist/providers/jobs/types.js +13 -1
  492. package/dist/providers/llm/anthropic.js +5 -1
  493. package/dist/providers/llm/bedrock.d.ts +0 -12
  494. package/dist/providers/llm/bedrock.js +4 -0
  495. package/dist/providers/llm/claude-messages.d.ts +3 -1
  496. package/dist/providers/llm/claude-messages.js +4 -1
  497. package/dist/providers/llm/claude-provider.d.ts +2 -2
  498. package/dist/providers/llm/claude-provider.js +2 -2
  499. package/dist/providers/llm/openai.d.ts +2 -2
  500. package/dist/providers/llm/openai.js +6 -2
  501. package/dist/providers/llm/routing.d.ts +2 -2
  502. package/dist/providers/llm/routing.js +2 -2
  503. package/dist/providers/llm/types.d.ts +12 -2
  504. package/dist/providers/review-host/github-events.d.ts +9 -1
  505. package/dist/providers/review-host/github-events.js +34 -12
  506. package/dist/providers/review-host/github.d.ts +39 -2
  507. package/dist/providers/review-host/github.js +274 -29
  508. package/dist/providers/review-host/local.d.ts +8 -4
  509. package/dist/providers/review-host/local.js +49 -31
  510. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  511. package/dist/providers/review-host/patch-pages.js +176 -0
  512. package/dist/providers/review-host/review-format.d.ts +19 -1
  513. package/dist/providers/review-host/review-format.js +38 -7
  514. package/dist/providers/review-host/types.d.ts +157 -2
  515. package/dist/providers/review-host/types.js +8 -0
  516. package/dist/providers/storage/gcs.d.ts +63 -0
  517. package/dist/providers/storage/gcs.js +69 -0
  518. package/dist/providers/storage/index.d.ts +15 -0
  519. package/dist/providers/storage/index.js +14 -0
  520. package/dist/providers/storage/local.d.ts +24 -0
  521. package/dist/providers/storage/local.js +92 -0
  522. package/dist/providers/storage/meter.d.ts +14 -0
  523. package/dist/providers/storage/meter.js +34 -0
  524. package/dist/providers/storage/s3.d.ts +41 -0
  525. package/dist/providers/storage/s3.js +107 -0
  526. package/dist/providers/storage/types.d.ts +37 -3
  527. package/dist/providers/storage/types.js +21 -4
  528. package/dist/providers/vcs/git.d.ts +33 -2
  529. package/dist/providers/vcs/git.js +324 -22
  530. package/dist/providers/vcs/github-remote.d.ts +26 -3
  531. package/dist/providers/vcs/github-remote.js +124 -14
  532. package/dist/providers/vcs/github.d.ts +246 -12
  533. package/dist/providers/vcs/github.js +521 -61
  534. package/dist/providers/vcs/index.js +8 -1
  535. package/dist/providers/vcs/pr-description.d.ts +127 -0
  536. package/dist/providers/vcs/pr-description.js +270 -0
  537. package/dist/providers/vcs/remote.d.ts +33 -1
  538. package/dist/providers/vcs/routing.d.ts +4 -2
  539. package/dist/providers/vcs/routing.js +6 -0
  540. package/dist/providers/vcs/types.d.ts +80 -3
  541. package/dist/quickstart/coding-seed.d.ts +21 -3
  542. package/dist/quickstart/coding-seed.js +283 -3
  543. package/dist/quickstart/images.d.ts +2 -0
  544. package/dist/quickstart/images.js +7 -1
  545. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  546. package/dist/quickstart/reviewer-prompt.js +6 -6
  547. package/dist/quickstart-images.json +1 -1
  548. package/dist/sandbox/brokered-fetch.d.ts +23 -0
  549. package/dist/sandbox/brokered-fetch.js +37 -0
  550. package/dist/sandbox/generated/zod.bundle.js +62 -1
  551. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  552. package/dist/sandbox/host-functions.d.ts +35 -0
  553. package/dist/sandbox/host-functions.js +150 -91
  554. package/dist/sandbox/prelude.js +7 -1
  555. package/dist/sandbox/run-in-sandbox.d.ts +19 -0
  556. package/dist/sandbox/run-in-sandbox.js +28 -10
  557. package/dist/sandbox/safe-fetch.d.ts +2 -0
  558. package/dist/sandbox/safe-fetch.js +3 -1
  559. package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
  560. package/dist/sandbox/secret-broker-sigv4.js +49 -0
  561. package/dist/sandbox/secret-broker.d.ts +34 -0
  562. package/dist/sandbox/secret-broker.js +161 -0
  563. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  564. package/dist/sandbox/user-tool.d.ts +14 -0
  565. package/dist/sandbox/user-tool.js +32 -0
  566. package/dist/sandbox/zod-params.d.ts +37 -5
  567. package/dist/sandbox/zod-params.js +181 -26
  568. package/dist/serve.js +25 -0
  569. package/dist/viewer/api-schema.d.ts +372 -2454
  570. package/dist/viewer/api-schema.js +29 -0
  571. package/dist/viewer/build-schemas.js +10 -3
  572. package/dist/viewer/event-bus.d.ts +6 -0
  573. package/dist/viewer/event-bus.js +16 -7
  574. package/dist/viewer/graph.d.ts +5 -2
  575. package/dist/viewer/graph.js +7 -2
  576. package/dist/viewer/http.d.ts +0 -1
  577. package/dist/viewer/http.js +2 -2
  578. package/dist/viewer/infra.js +25 -2
  579. package/dist/viewer/limits.d.ts +4 -0
  580. package/dist/viewer/limits.js +4 -0
  581. package/dist/viewer/openapi.d.ts +15 -0
  582. package/dist/viewer/openapi.js +170 -0
  583. package/dist/wardby-bin.js +10 -0
  584. package/docs/README.md +7 -0
  585. package/docs/agent-recipes.md +114 -27
  586. package/docs/architecture-runtime.md +16 -1
  587. package/docs/code-review-agents.md +689 -45
  588. package/docs/coding-agent-setup.md +602 -12
  589. package/docs/coding-packages.md +1037 -92
  590. package/docs/coding-services.md +30 -13
  591. package/docs/coding-worker-byo-images.md +218 -6
  592. package/docs/coding-worker-isolation.md +173 -44
  593. package/docs/getting-started-gke.md +332 -129
  594. package/docs/getting-started-identity-provider.md +31 -11
  595. package/docs/getting-started.md +14 -4
  596. package/docs/jira-agents.md +22 -9
  597. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  598. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  599. package/docs/knowledge/delegation-admission-slots.md +52 -0
  600. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  601. package/docs/knowledge/import-rename-target.md +52 -0
  602. package/docs/knowledge/index.md +57 -0
  603. package/docs/knowledge/log.md +9 -0
  604. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  605. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  606. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  607. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  608. package/docs/knowledge/overview-cli.md +74 -0
  609. package/docs/knowledge/overview-coding-proxy.md +72 -0
  610. package/docs/knowledge/overview-coding.md +72 -0
  611. package/docs/knowledge/overview-config.md +60 -0
  612. package/docs/knowledge/overview-core.md +72 -0
  613. package/docs/knowledge/overview-deploy.md +83 -0
  614. package/docs/knowledge/overview-mcp.md +61 -0
  615. package/docs/knowledge/overview-prisma.md +72 -0
  616. package/docs/knowledge/overview-providers.md +89 -0
  617. package/docs/knowledge/overview-sandbox.md +83 -0
  618. package/docs/knowledge/overview-surfaces.md +83 -0
  619. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  620. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  621. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  622. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  623. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  624. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  625. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  626. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  627. package/docs/knowledge/warm-input-publication.md +30 -0
  628. package/docs/knowledge/workspace-staging-failure.md +54 -0
  629. package/docs/knowledge.md +54 -14
  630. package/docs/native-sandbox.md +731 -0
  631. package/docs/observability.md +4 -0
  632. package/docs/release-verification.md +9 -0
  633. package/docs/security-deployment.md +146 -14
  634. package/docs/slack-notifications.md +268 -0
  635. package/docs/tool-secrets.md +284 -0
  636. package/docs/viewer-api.md +46 -5
  637. package/docs/viewer-api.openapi.yml +1404 -0
  638. package/help/admin-viewer.md +29 -3
  639. package/help/agent-recipes.md +27 -0
  640. package/help/architecture-agent.md +11 -6
  641. package/help/brokered-secrets.md +79 -0
  642. package/help/build-claude-code-image.md +131 -0
  643. package/help/build-worker-image.md +6 -7
  644. package/help/builder-agent.md +19 -6
  645. package/help/code-review-agents.md +243 -10
  646. package/help/coding-packages.md +156 -6
  647. package/help/cost-attribution.md +9 -5
  648. package/help/creating-agents.md +14 -1
  649. package/help/dependency-cache.md +143 -0
  650. package/help/deploy-gke.md +23 -9
  651. package/help/deployment-targets.md +25 -14
  652. package/help/errors/budget-exhausted.md +187 -0
  653. package/help/errors/budget-group-exhausted.md +5 -1
  654. package/help/errors/coding-provider-not-configured.md +2 -2
  655. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  656. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  657. package/help/errors/continuation-closed.md +9 -12
  658. package/help/errors/database-auth-invalid.md +28 -0
  659. package/help/errors/delegation-conflict.md +24 -0
  660. package/help/errors/file-list-truncated.md +45 -0
  661. package/help/errors/full-read-required.md +49 -0
  662. package/help/errors/github-account-not-allowed.md +29 -0
  663. package/help/errors/graph-incomplete.md +43 -0
  664. package/help/errors/graph-limit.md +43 -0
  665. package/help/errors/low-power-disabled.md +29 -0
  666. package/help/errors/low-power-scale-forbidden.md +35 -0
  667. package/help/errors/low-power-wake-timeout.md +30 -0
  668. package/help/errors/merge-conflict.md +49 -0
  669. package/help/errors/mobile-disabled.md +31 -0
  670. package/help/errors/native-sandbox-capacity.md +22 -0
  671. package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
  672. package/help/errors/native-sandbox-docker-failed.md +20 -0
  673. package/help/errors/native-sandbox-gateway-error.md +20 -0
  674. package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
  675. package/help/errors/native-sandbox-image-not-pinned.md +19 -0
  676. package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
  677. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  678. package/help/errors/native-sandbox-network-unenforced.md +22 -0
  679. package/help/errors/native-sandbox-requires-catalog.md +31 -0
  680. package/help/errors/native-sandbox-unavailable.md +19 -0
  681. package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
  682. package/help/errors/native-sandbox-worker-exited.md +21 -0
  683. package/help/errors/native-sandbox-worker-lost.md +20 -0
  684. package/help/errors/native-sandbox-worker-unready.md +22 -0
  685. package/help/errors/package-not-allowed-pending.md +52 -0
  686. package/help/errors/package-not-allowed.md +51 -0
  687. package/help/errors/package-refusals.md +43 -0
  688. package/help/errors/patch-cursor-malformed.md +31 -0
  689. package/help/errors/run-lost.md +39 -0
  690. package/help/errors/run-transcript-download.md +44 -0
  691. package/help/errors/secret-broker-body-invalid.md +26 -0
  692. package/help/errors/secret-broker-changed.md +20 -0
  693. package/help/errors/secret-broker-config-invalid.md +30 -0
  694. package/help/errors/secret-broker-conflict.md +27 -0
  695. package/help/errors/secret-broker-destination-denied.md +28 -0
  696. package/help/errors/secret-broker-value-invalid.md +28 -0
  697. package/help/errors/secret-brokered.md +24 -0
  698. package/help/errors/secret-in-value.md +69 -0
  699. package/help/errors/secret-not-brokered.md +25 -0
  700. package/help/errors/slack-auth-failed.md +48 -0
  701. package/help/errors/slack-channel-unreachable.md +39 -0
  702. package/help/errors/slack-not-configured.md +33 -0
  703. package/help/errors/target-merge.md +40 -0
  704. package/help/fix-merge-conflicts.md +73 -0
  705. package/help/getting-started.md +4 -5
  706. package/help/github-app-setup.md +132 -0
  707. package/help/github.md +40 -1
  708. package/help/identity-and-access.md +7 -1
  709. package/help/jira.md +23 -6
  710. package/help/knowledge.md +16 -7
  711. package/help/local-repositories.md +3 -4
  712. package/help/low-power-mode.md +131 -0
  713. package/help/merge-order-check.md +122 -0
  714. package/help/mobile-app.md +54 -0
  715. package/help/native-capabilities.md +29 -1
  716. package/help/native-sandbox.md +150 -0
  717. package/help/observability.md +8 -0
  718. package/help/operating-agents.md +5 -0
  719. package/help/package-audit-mode.md +91 -0
  720. package/help/related-pull-requests.md +80 -16
  721. package/help/repo-instructions-and-skills.md +91 -0
  722. package/help/resume-runs-locally.md +131 -0
  723. package/help/review-fix-rounds.md +43 -1
  724. package/help/sharing-agents.md +59 -0
  725. package/help/slack-notifications.md +76 -0
  726. package/help/status-comments.md +31 -0
  727. package/help/stop-run.md +58 -0
  728. package/help/troubleshooting/budgets.md +28 -0
  729. package/help/troubleshooting/coding-workers.md +99 -7
  730. package/package.json +27 -13
  731. package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
  732. package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
  733. package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
  734. package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
  735. package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
  736. package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
  737. package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
  738. package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
  739. package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
  740. package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
  741. package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
  742. package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
  743. package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
  744. package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
  745. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  746. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  747. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  748. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  749. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  750. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  751. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  752. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  753. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  754. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  755. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  756. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  757. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  758. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  759. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  760. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  761. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  762. package/prisma/schema.prisma +631 -146
  763. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -0,0 +1,85 @@
1
+ import type { DependencyCacheSessionState } from "../registry/store.js";
2
+ /**
3
+ * The value every snapshot row stores in its `policyHash` column, and the only
4
+ * value lookups match. The column and its unique index predate dropping the
5
+ * agent's package policy from the key (see key.ts for why), so they stay
6
+ * unchanged; rows written before carry a real policy hash, never match again,
7
+ * and age out through eviction.
8
+ */
9
+ export declare const POLICY_ANY = "any";
10
+ /** The parts every snapshot of one project shares, whatever its lockfile. */
11
+ export interface SnapshotScope {
12
+ ecosystem: string;
13
+ repository: string;
14
+ projectPath: string;
15
+ workerImage: string;
16
+ }
17
+ export interface SnapshotIdentity extends SnapshotScope {
18
+ lockHash: string;
19
+ }
20
+ export interface NewSnapshot extends SnapshotIdentity {
21
+ blobKey: string;
22
+ sha256: string;
23
+ sizeBytes: number;
24
+ archiveScanVersion: number | null;
25
+ archiveEntries: number | null;
26
+ unpackedBytes: number | null;
27
+ createdByRunId: string;
28
+ }
29
+ export interface SnapshotRow extends SnapshotIdentity {
30
+ id: string;
31
+ blobKey: string;
32
+ sha256: string;
33
+ sizeBytes: number;
34
+ archiveScanVersion: number | null;
35
+ archiveEntries: number | null;
36
+ unpackedBytes: number | null;
37
+ createdAt: Date;
38
+ lastUsedAt: Date;
39
+ createdByRunId: string | null;
40
+ }
41
+ /** What eviction needs of every snapshot. */
42
+ export type EvictionRow = Pick<SnapshotRow, "id" | "repository" | "blobKey" | "sizeBytes" | "createdAt" | "lastUsedAt">;
43
+ /** DependencySnapshot rows and the session fields the cache reads (Postgres in production). */
44
+ export interface DependencyCacheStore {
45
+ session(runId: string): Promise<DependencyCacheSessionState | null>;
46
+ /** Sets the session's sealedAt unless it is already set. */
47
+ seal(runId: string, now: Date): Promise<void>;
48
+ /** Like `seal`, but only for a run whose agent has the cache on (a model request's seal, ModelRequestSeal). */
49
+ sealForModelRequest(runId: string, now: Date): Promise<void>;
50
+ findByIdentity(identity: SnapshotIdentity): Promise<SnapshotRow | null>;
51
+ /** The most recent snapshot in the scope whose lockHash differs (ties broken by id), or null. */
52
+ findNearest(scope: SnapshotScope, excludeLockHash: string): Promise<SnapshotRow | null>;
53
+ /** Whether the run already created a snapshot for this project. */
54
+ hasUploaded(runId: string, ecosystem: string, projectPath: string): Promise<boolean>;
55
+ /** "exists" when a snapshot with the same identity (or blob key) is already stored. */
56
+ insert(snapshot: NewSnapshot): Promise<"inserted" | "exists">;
57
+ touch(id: string, now: Date): Promise<void>;
58
+ delete(id: string): Promise<void>;
59
+ /** Deletes the row only while it still points at `blobKey` (a re-upload may have replaced it); true when deleted. */
60
+ deleteIfBlob(id: string, blobKey: string): Promise<boolean>;
61
+ listForEviction(): Promise<EvictionRow[]>;
62
+ /** Runs `work` while holding the cluster-wide eviction lock; returns false (without running it) when another holder has it. */
63
+ withEvictionLock(work: () => Promise<void>): Promise<boolean>;
64
+ }
65
+ /** In-memory adapter for tests. `sessions` may be shared with a MemoryRegistryStore's `cacheSessions`. */
66
+ export declare class MemoryDependencyCacheStore implements DependencyCacheStore {
67
+ readonly sessions: Map<string, DependencyCacheSessionState>;
68
+ readonly rows: SnapshotRow[];
69
+ private evicting;
70
+ /** Runs whose agent has the cache off (sealForModelRequest leaves them alone). */
71
+ readonly cacheOff: Set<string>;
72
+ constructor(sessions?: Map<string, DependencyCacheSessionState>);
73
+ session(runId: string): Promise<DependencyCacheSessionState | null>;
74
+ seal(runId: string, now: Date): Promise<void>;
75
+ sealForModelRequest(runId: string, now: Date): Promise<void>;
76
+ findByIdentity(identity: SnapshotIdentity): Promise<SnapshotRow | null>;
77
+ findNearest(scope: SnapshotScope, excludeLockHash: string): Promise<SnapshotRow | null>;
78
+ hasUploaded(runId: string, ecosystem: string, projectPath: string): Promise<boolean>;
79
+ insert(snapshot: NewSnapshot): Promise<"inserted" | "exists">;
80
+ touch(id: string, now: Date): Promise<void>;
81
+ delete(id: string): Promise<void>;
82
+ deleteIfBlob(id: string, blobKey: string): Promise<boolean>;
83
+ listForEviction(): Promise<EvictionRow[]>;
84
+ withEvictionLock(work: () => Promise<void>): Promise<boolean>;
85
+ }
@@ -0,0 +1,95 @@
1
+ import { randomUUID } from "node:crypto";
2
+ /**
3
+ * The value every snapshot row stores in its `policyHash` column, and the only
4
+ * value lookups match. The column and its unique index predate dropping the
5
+ * agent's package policy from the key (see key.ts for why), so they stay
6
+ * unchanged; rows written before carry a real policy hash, never match again,
7
+ * and age out through eviction.
8
+ */
9
+ export const POLICY_ANY = "any";
10
+ const sameScope = (row, scope) => row.ecosystem === scope.ecosystem &&
11
+ row.repository === scope.repository &&
12
+ row.projectPath === scope.projectPath &&
13
+ row.workerImage === scope.workerImage;
14
+ /** In-memory adapter for tests. `sessions` may be shared with a MemoryRegistryStore's `cacheSessions`. */
15
+ export class MemoryDependencyCacheStore {
16
+ sessions;
17
+ rows = [];
18
+ evicting = false;
19
+ /** Runs whose agent has the cache off (sealForModelRequest leaves them alone). */
20
+ cacheOff = new Set();
21
+ constructor(sessions = new Map()) {
22
+ this.sessions = sessions;
23
+ }
24
+ async session(runId) {
25
+ const session = this.sessions.get(runId);
26
+ return session ? { ...session, lockHashes: [...session.lockHashes] } : null;
27
+ }
28
+ async seal(runId, now) {
29
+ const session = this.sessions.get(runId);
30
+ if (session && !session.sealedAt)
31
+ session.sealedAt = now;
32
+ }
33
+ async sealForModelRequest(runId, now) {
34
+ if (!this.cacheOff.has(runId))
35
+ await this.seal(runId, now);
36
+ }
37
+ async findByIdentity(identity) {
38
+ return this.rows.find((row) => sameScope(row, identity) && row.lockHash === identity.lockHash) ?? null;
39
+ }
40
+ async findNearest(scope, excludeLockHash) {
41
+ const candidates = this.rows
42
+ .filter((row) => sameScope(row, scope) && row.lockHash !== excludeLockHash)
43
+ .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime() || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0));
44
+ return candidates[0] ?? null;
45
+ }
46
+ async hasUploaded(runId, ecosystem, projectPath) {
47
+ return this.rows.some((row) => row.createdByRunId === runId && row.ecosystem === ecosystem && row.projectPath === projectPath);
48
+ }
49
+ async insert(snapshot) {
50
+ if ((await this.findByIdentity(snapshot)) || this.rows.some((row) => row.blobKey === snapshot.blobKey))
51
+ return "exists";
52
+ const now = new Date();
53
+ this.rows.push({ ...snapshot, id: `c${randomUUID().replaceAll("-", "")}`, createdAt: now, lastUsedAt: now });
54
+ return "inserted";
55
+ }
56
+ async touch(id, now) {
57
+ const row = this.rows.find((candidate) => candidate.id === id);
58
+ if (row)
59
+ row.lastUsedAt = now;
60
+ }
61
+ async delete(id) {
62
+ const index = this.rows.findIndex((row) => row.id === id);
63
+ if (index >= 0)
64
+ this.rows.splice(index, 1);
65
+ }
66
+ async deleteIfBlob(id, blobKey) {
67
+ const index = this.rows.findIndex((row) => row.id === id && row.blobKey === blobKey);
68
+ if (index < 0)
69
+ return false;
70
+ this.rows.splice(index, 1);
71
+ return true;
72
+ }
73
+ async listForEviction() {
74
+ return this.rows.map(({ id, repository, blobKey, sizeBytes, createdAt, lastUsedAt }) => ({
75
+ id,
76
+ repository,
77
+ blobKey,
78
+ sizeBytes,
79
+ createdAt,
80
+ lastUsedAt,
81
+ }));
82
+ }
83
+ async withEvictionLock(work) {
84
+ if (this.evicting)
85
+ return false;
86
+ this.evicting = true;
87
+ try {
88
+ await work();
89
+ return true;
90
+ }
91
+ finally {
92
+ this.evicting = false;
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,32 @@
1
+ import type { ModelPricing } from "../llm/pricing-core.js";
2
+ import type { PreviousReply, ProxyProtocol, ReservationBasis } from "./types.js";
3
+ /**
4
+ * Anthropic's prompt cache lives 5 minutes from when a request is processed, not from when its reply
5
+ * finishes: a previous request sent longer ago than this says nothing about the cache.
6
+ */
7
+ export declare const CACHE_WINDOW_MS: number;
8
+ export declare const MIN_CACHED_SHARE = 0.5;
9
+ export type HoldFallback = "no_previous" | "model_changed" | "previous_estimated" | "previous_not_completed" | "no_request_bytes" | "cache_expired" | "body_shrank" | "low_cache_share";
10
+ export interface HoldEstimate {
11
+ holdUsd: number;
12
+ ceilingUsd: number;
13
+ basis: ReservationBasis;
14
+ fallback?: HoldFallback;
15
+ cachedTokens?: number;
16
+ uncachedTokens?: number;
17
+ }
18
+ /**
19
+ * What identifies one conversation within a run (Claude Code runs several: the main one and its
20
+ * sub-agents). Anthropic: the first message without cache markers (the system prompt carries a
21
+ * per-version billing line). OpenAI: prompt_cache_key, else instructions + the first input item.
22
+ */
23
+ export declare function conversationKey(protocol: ProxyProtocol, body: Record<string, unknown>): string | null;
24
+ export declare function estimateHold(input: {
25
+ protocol: ProxyProtocol;
26
+ model: string;
27
+ bodyBytes: number;
28
+ maxOutputTokens: number;
29
+ pricing: ModelPricing;
30
+ previous: PreviousReply | null;
31
+ now: Date;
32
+ }): HoldEstimate;
@@ -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)