@wardby/cli 0.1.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 (412) hide show
  1. package/.env.example +131 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +2 -0
  4. package/README.md +282 -0
  5. package/bin/wardby.js +3 -0
  6. package/deploy/local/docker-compose.yml +19 -0
  7. package/dist/claude-coding-worker/driver.d.ts +70 -0
  8. package/dist/claude-coding-worker/driver.js +128 -0
  9. package/dist/claude-coding-worker/main.d.ts +2 -0
  10. package/dist/claude-coding-worker/main.js +41 -0
  11. package/dist/claude-coding-worker/sdk.d.ts +4 -0
  12. package/dist/claude-coding-worker/sdk.js +43 -0
  13. package/dist/claude-coding-worker/tool-relay.d.ts +1 -0
  14. package/dist/claude-coding-worker/tool-relay.js +9 -0
  15. package/dist/cli-help.d.ts +1 -0
  16. package/dist/cli-help.js +20 -0
  17. package/dist/cli.d.ts +18 -0
  18. package/dist/cli.js +629 -0
  19. package/dist/coding/observability.d.ts +59 -0
  20. package/dist/coding/observability.js +77 -0
  21. package/dist/coding/profile.d.ts +88 -0
  22. package/dist/coding/profile.js +137 -0
  23. package/dist/coding/protocol.d.ts +345 -0
  24. package/dist/coding/protocol.js +445 -0
  25. package/dist/coding/provider.d.ts +4 -0
  26. package/dist/coding/provider.js +18 -0
  27. package/dist/coding-proxy/main.d.ts +1 -0
  28. package/dist/coding-proxy/main.js +51 -0
  29. package/dist/coding-worker/artifact.d.ts +16 -0
  30. package/dist/coding-worker/artifact.js +37 -0
  31. package/dist/coding-worker/driver.d.ts +46 -0
  32. package/dist/coding-worker/driver.js +158 -0
  33. package/dist/coding-worker/errors.d.ts +1 -0
  34. package/dist/coding-worker/errors.js +23 -0
  35. package/dist/coding-worker/isolation-probe.d.ts +1 -0
  36. package/dist/coding-worker/isolation-probe.js +146 -0
  37. package/dist/coding-worker/keeper.d.ts +4 -0
  38. package/dist/coding-worker/keeper.js +29 -0
  39. package/dist/coding-worker/main.d.ts +2 -0
  40. package/dist/coding-worker/main.js +43 -0
  41. package/dist/coding-worker/sdk.d.ts +26 -0
  42. package/dist/coding-worker/sdk.js +28 -0
  43. package/dist/coding-worker/types.d.ts +64 -0
  44. package/dist/coding-worker/types.js +1 -0
  45. package/dist/config/providers.d.ts +158 -0
  46. package/dist/config/providers.js +162 -0
  47. package/dist/core/budget-groups.d.ts +72 -0
  48. package/dist/core/budget-groups.js +149 -0
  49. package/dist/core/budget.d.ts +63 -0
  50. package/dist/core/budget.js +69 -0
  51. package/dist/core/coding-queue.d.ts +32 -0
  52. package/dist/core/coding-queue.js +54 -0
  53. package/dist/core/cron.d.ts +31 -0
  54. package/dist/core/cron.js +43 -0
  55. package/dist/core/datastores.d.ts +41 -0
  56. package/dist/core/datastores.js +105 -0
  57. package/dist/core/db.d.ts +2 -0
  58. package/dist/core/db.js +2 -0
  59. package/dist/core/dispatch.d.ts +81 -0
  60. package/dist/core/dispatch.js +184 -0
  61. package/dist/core/engine-native.d.ts +29 -0
  62. package/dist/core/engine-native.js +259 -0
  63. package/dist/core/http-runtime.d.ts +7 -0
  64. package/dist/core/http-runtime.js +101 -0
  65. package/dist/core/lease.d.ts +13 -0
  66. package/dist/core/lease.js +22 -0
  67. package/dist/core/logger.d.ts +13 -0
  68. package/dist/core/logger.js +45 -0
  69. package/dist/core/memory-tools.d.ts +11 -0
  70. package/dist/core/memory-tools.js +122 -0
  71. package/dist/core/reconciler.d.ts +45 -0
  72. package/dist/core/reconciler.js +152 -0
  73. package/dist/core/runner.d.ts +87 -0
  74. package/dist/core/runner.js +529 -0
  75. package/dist/core/scheduler.d.ts +47 -0
  76. package/dist/core/scheduler.js +121 -0
  77. package/dist/core/secrets.d.ts +46 -0
  78. package/dist/core/secrets.js +100 -0
  79. package/dist/core/subagent-memory-tools.d.ts +18 -0
  80. package/dist/core/subagent-memory-tools.js +121 -0
  81. package/dist/core/timing.d.ts +7 -0
  82. package/dist/core/timing.js +7 -0
  83. package/dist/core/webhooks.d.ts +23 -0
  84. package/dist/core/webhooks.js +113 -0
  85. package/dist/env.d.ts +11 -0
  86. package/dist/env.js +13 -0
  87. package/dist/import/budgets.d.ts +16 -0
  88. package/dist/import/budgets.js +21 -0
  89. package/dist/import/bundle.d.ts +16 -0
  90. package/dist/import/bundle.js +61 -0
  91. package/dist/import/cli-args.d.ts +2 -0
  92. package/dist/import/cli-args.js +44 -0
  93. package/dist/import/create.d.ts +34 -0
  94. package/dist/import/create.js +363 -0
  95. package/dist/import/index.d.ts +25 -0
  96. package/dist/import/index.js +130 -0
  97. package/dist/import/model-gate.d.ts +1 -0
  98. package/dist/import/model-gate.js +3 -0
  99. package/dist/import/neutral-schema.d.ts +369 -0
  100. package/dist/import/neutral-schema.js +109 -0
  101. package/dist/import/preflight.d.ts +41 -0
  102. package/dist/import/preflight.js +71 -0
  103. package/dist/import/report.d.ts +5 -0
  104. package/dist/import/report.js +98 -0
  105. package/dist/import/tool-scan.d.ts +8 -0
  106. package/dist/import/tool-scan.js +20 -0
  107. package/dist/mcp/auth/ownership.d.ts +113 -0
  108. package/dist/mcp/auth/ownership.js +87 -0
  109. package/dist/mcp/auth/principal.d.ts +9 -0
  110. package/dist/mcp/auth/principal.js +9 -0
  111. package/dist/mcp/auth/resource-server.d.ts +47 -0
  112. package/dist/mcp/auth/resource-server.js +82 -0
  113. package/dist/mcp/auth/self-hosted/browser.d.ts +3 -0
  114. package/dist/mcp/auth/self-hosted/browser.js +273 -0
  115. package/dist/mcp/auth/self-hosted/cli.d.ts +2 -0
  116. package/dist/mcp/auth/self-hosted/cli.js +39 -0
  117. package/dist/mcp/auth/self-hosted/credentials.d.ts +58 -0
  118. package/dist/mcp/auth/self-hosted/credentials.js +106 -0
  119. package/dist/mcp/auth/self-hosted/rate-limit.d.ts +13 -0
  120. package/dist/mcp/auth/self-hosted/rate-limit.js +20 -0
  121. package/dist/mcp/auth/self-hosted/session.d.ts +36 -0
  122. package/dist/mcp/auth/self-hosted/session.js +110 -0
  123. package/dist/mcp/capabilities.d.ts +11 -0
  124. package/dist/mcp/capabilities.js +10 -0
  125. package/dist/mcp/context.d.ts +46 -0
  126. package/dist/mcp/context.js +1 -0
  127. package/dist/mcp/errors.d.ts +13 -0
  128. package/dist/mcp/errors.js +22 -0
  129. package/dist/mcp/index.d.ts +32 -0
  130. package/dist/mcp/index.js +187 -0
  131. package/dist/mcp/jsonrpc.d.ts +8 -0
  132. package/dist/mcp/jsonrpc.js +1 -0
  133. package/dist/mcp/server.d.ts +107 -0
  134. package/dist/mcp/server.js +203 -0
  135. package/dist/mcp/tasks/manager.d.ts +63 -0
  136. package/dist/mcp/tasks/manager.js +103 -0
  137. package/dist/mcp/tools/agents.d.ts +2 -0
  138. package/dist/mcp/tools/agents.js +375 -0
  139. package/dist/mcp/tools/budget-groups.d.ts +2 -0
  140. package/dist/mcp/tools/budget-groups.js +136 -0
  141. package/dist/mcp/tools/datastore.d.ts +2 -0
  142. package/dist/mcp/tools/datastore.js +217 -0
  143. package/dist/mcp/tools/memory.d.ts +3 -0
  144. package/dist/mcp/tools/memory.js +60 -0
  145. package/dist/mcp/tools/models.d.ts +8 -0
  146. package/dist/mcp/tools/models.js +15 -0
  147. package/dist/mcp/tools/runs.d.ts +2 -0
  148. package/dist/mcp/tools/runs.js +61 -0
  149. package/dist/mcp/tools/scheduling.d.ts +2 -0
  150. package/dist/mcp/tools/scheduling.js +48 -0
  151. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -0
  152. package/dist/mcp/tools/secret-elicitation-form.js +93 -0
  153. package/dist/mcp/tools/secret-elicitation-server.d.ts +5 -0
  154. package/dist/mcp/tools/secret-elicitation-server.js +57 -0
  155. package/dist/mcp/tools/secret-elicitation.d.ts +38 -0
  156. package/dist/mcp/tools/secret-elicitation.js +52 -0
  157. package/dist/mcp/tools/secrets.d.ts +13 -0
  158. package/dist/mcp/tools/secrets.js +124 -0
  159. package/dist/mcp/tools/subagents.d.ts +2 -0
  160. package/dist/mcp/tools/subagents.js +133 -0
  161. package/dist/mcp/tools/text-result.d.ts +6 -0
  162. package/dist/mcp/tools/text-result.js +3 -0
  163. package/dist/mcp/tools/tools.d.ts +2 -0
  164. package/dist/mcp/tools/tools.js +211 -0
  165. package/dist/mcp/tools/trigger.d.ts +2 -0
  166. package/dist/mcp/tools/trigger.js +120 -0
  167. package/dist/mcp/tools/webhooks.d.ts +2 -0
  168. package/dist/mcp/tools/webhooks.js +34 -0
  169. package/dist/mcp/transport/http-limits.d.ts +17 -0
  170. package/dist/mcp/transport/http-limits.js +92 -0
  171. package/dist/mcp/transport/stdio.d.ts +23 -0
  172. package/dist/mcp/transport/stdio.js +6 -0
  173. package/dist/mcp/transport/streamable-http.d.ts +34 -0
  174. package/dist/mcp/transport/streamable-http.js +158 -0
  175. package/dist/mcp/unattended-schedules.d.ts +15 -0
  176. package/dist/mcp/unattended-schedules.js +21 -0
  177. package/dist/mcp/webhooks/ingress.d.ts +17 -0
  178. package/dist/mcp/webhooks/ingress.js +33 -0
  179. package/dist/observability/config.d.ts +6 -0
  180. package/dist/observability/config.js +20 -0
  181. package/dist/observability/metrics-server.d.ts +11 -0
  182. package/dist/observability/metrics-server.js +47 -0
  183. package/dist/observability/metrics.d.ts +36 -0
  184. package/dist/observability/metrics.js +158 -0
  185. package/dist/providers/auth/authorization-server.d.ts +41 -0
  186. package/dist/providers/auth/authorization-server.js +1 -0
  187. package/dist/providers/auth/delegating.d.ts +44 -0
  188. package/dist/providers/auth/delegating.js +105 -0
  189. package/dist/providers/auth/index.d.ts +11 -0
  190. package/dist/providers/auth/index.js +20 -0
  191. package/dist/providers/auth/release-gate.d.ts +1 -0
  192. package/dist/providers/auth/release-gate.js +4 -0
  193. package/dist/providers/auth/self-hosted.d.ts +78 -0
  194. package/dist/providers/auth/self-hosted.js +377 -0
  195. package/dist/providers/auth/subject.d.ts +1 -0
  196. package/dist/providers/auth/subject.js +6 -0
  197. package/dist/providers/auth/types.d.ts +63 -0
  198. package/dist/providers/auth/types.js +22 -0
  199. package/dist/providers/coding-proxy/deny-port.d.ts +5 -0
  200. package/dist/providers/coding-proxy/deny-port.js +45 -0
  201. package/dist/providers/coding-proxy/environment-credentials.d.ts +7 -0
  202. package/dist/providers/coding-proxy/environment-credentials.js +16 -0
  203. package/dist/providers/coding-proxy/index.d.ts +7 -0
  204. package/dist/providers/coding-proxy/index.js +7 -0
  205. package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -0
  206. package/dist/providers/coding-proxy/memory-ledger.js +103 -0
  207. package/dist/providers/coding-proxy/metering.d.ts +20 -0
  208. package/dist/providers/coding-proxy/metering.js +161 -0
  209. package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -0
  210. package/dist/providers/coding-proxy/prisma-ledger.js +213 -0
  211. package/dist/providers/coding-proxy/proxy.d.ts +75 -0
  212. package/dist/providers/coding-proxy/proxy.js +721 -0
  213. package/dist/providers/coding-proxy/runtime.d.ts +18 -0
  214. package/dist/providers/coding-proxy/runtime.js +39 -0
  215. package/dist/providers/coding-proxy/secure-fetch.d.ts +9 -0
  216. package/dist/providers/coding-proxy/secure-fetch.js +72 -0
  217. package/dist/providers/coding-proxy/server.d.ts +17 -0
  218. package/dist/providers/coding-proxy/server.js +139 -0
  219. package/dist/providers/coding-proxy/types.d.ts +99 -0
  220. package/dist/providers/coding-proxy/types.js +1 -0
  221. package/dist/providers/datastore/index.d.ts +2 -0
  222. package/dist/providers/datastore/index.js +2 -0
  223. package/dist/providers/datastore/postgres.d.ts +20 -0
  224. package/dist/providers/datastore/postgres.js +130 -0
  225. package/dist/providers/datastore/scoped.d.ts +10 -0
  226. package/dist/providers/datastore/scoped.js +46 -0
  227. package/dist/providers/datastore/types.d.ts +31 -0
  228. package/dist/providers/datastore/types.js +7 -0
  229. package/dist/providers/email/types.d.ts +46 -0
  230. package/dist/providers/email/types.js +8 -0
  231. package/dist/providers/engine/index.d.ts +1 -0
  232. package/dist/providers/engine/index.js +1 -0
  233. package/dist/providers/engine/types.d.ts +67 -0
  234. package/dist/providers/engine/types.js +16 -0
  235. package/dist/providers/executor/build.d.ts +6 -0
  236. package/dist/providers/executor/build.js +15 -0
  237. package/dist/providers/executor/composition.d.ts +14 -0
  238. package/dist/providers/executor/composition.js +123 -0
  239. package/dist/providers/executor/container.d.ts +184 -0
  240. package/dist/providers/executor/container.js +936 -0
  241. package/dist/providers/executor/dbos-status.d.ts +50 -0
  242. package/dist/providers/executor/dbos-status.js +64 -0
  243. package/dist/providers/executor/dbos.d.ts +53 -0
  244. package/dist/providers/executor/dbos.js +269 -0
  245. package/dist/providers/executor/in-process.d.ts +18 -0
  246. package/dist/providers/executor/in-process.js +38 -0
  247. package/dist/providers/executor/index.d.ts +8 -0
  248. package/dist/providers/executor/index.js +8 -0
  249. package/dist/providers/executor/routing.d.ts +48 -0
  250. package/dist/providers/executor/routing.js +70 -0
  251. package/dist/providers/executor/types.d.ts +55 -0
  252. package/dist/providers/executor/types.js +1 -0
  253. package/dist/providers/index.d.ts +43 -0
  254. package/dist/providers/index.js +18 -0
  255. package/dist/providers/jobs/docker-isolation.d.ts +166 -0
  256. package/dist/providers/jobs/docker-isolation.js +724 -0
  257. package/dist/providers/jobs/docker.d.ts +127 -0
  258. package/dist/providers/jobs/docker.js +1027 -0
  259. package/dist/providers/jobs/fake-kubernetes-api.d.ts +98 -0
  260. package/dist/providers/jobs/fake-kubernetes-api.js +142 -0
  261. package/dist/providers/jobs/fake.d.ts +23 -0
  262. package/dist/providers/jobs/fake.js +132 -0
  263. package/dist/providers/jobs/kubernetes-api.d.ts +60 -0
  264. package/dist/providers/jobs/kubernetes-api.js +20 -0
  265. package/dist/providers/jobs/kubernetes-client.d.ts +36 -0
  266. package/dist/providers/jobs/kubernetes-client.js +171 -0
  267. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +49 -0
  268. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +141 -0
  269. package/dist/providers/jobs/kubernetes-isolation.d.ts +147 -0
  270. package/dist/providers/jobs/kubernetes-isolation.js +607 -0
  271. package/dist/providers/jobs/kubernetes-platform.d.ts +177 -0
  272. package/dist/providers/jobs/kubernetes-platform.js +280 -0
  273. package/dist/providers/jobs/kubernetes-preflight.d.ts +59 -0
  274. package/dist/providers/jobs/kubernetes-preflight.js +339 -0
  275. package/dist/providers/jobs/kubernetes-witness.d.ts +10 -0
  276. package/dist/providers/jobs/kubernetes-witness.js +193 -0
  277. package/dist/providers/jobs/kubernetes.d.ts +127 -0
  278. package/dist/providers/jobs/kubernetes.js +874 -0
  279. package/dist/providers/jobs/safe-extract.d.ts +9 -0
  280. package/dist/providers/jobs/safe-extract.js +325 -0
  281. package/dist/providers/jobs/types.d.ts +78 -0
  282. package/dist/providers/jobs/types.js +6 -0
  283. package/dist/providers/jobs/workspace-swap.d.ts +2 -0
  284. package/dist/providers/jobs/workspace-swap.js +47 -0
  285. package/dist/providers/llm/anthropic.d.ts +13 -0
  286. package/dist/providers/llm/anthropic.js +21 -0
  287. package/dist/providers/llm/bedrock.d.ts +19 -0
  288. package/dist/providers/llm/bedrock.js +33 -0
  289. package/dist/providers/llm/claude-messages.d.ts +106 -0
  290. package/dist/providers/llm/claude-messages.js +157 -0
  291. package/dist/providers/llm/claude-provider.d.ts +40 -0
  292. package/dist/providers/llm/claude-provider.js +31 -0
  293. package/dist/providers/llm/index.d.ts +10 -0
  294. package/dist/providers/llm/index.js +10 -0
  295. package/dist/providers/llm/openai.d.ts +23 -0
  296. package/dist/providers/llm/openai.js +156 -0
  297. package/dist/providers/llm/pricing-anthropic.d.ts +4 -0
  298. package/dist/providers/llm/pricing-anthropic.js +30 -0
  299. package/dist/providers/llm/pricing-bedrock-claude.d.ts +12 -0
  300. package/dist/providers/llm/pricing-bedrock-claude.js +37 -0
  301. package/dist/providers/llm/pricing-core.d.ts +26 -0
  302. package/dist/providers/llm/pricing-core.js +17 -0
  303. package/dist/providers/llm/pricing.d.ts +30 -0
  304. package/dist/providers/llm/pricing.js +74 -0
  305. package/dist/providers/llm/registration.d.ts +8 -0
  306. package/dist/providers/llm/registration.js +39 -0
  307. package/dist/providers/llm/routing.d.ts +25 -0
  308. package/dist/providers/llm/routing.js +32 -0
  309. package/dist/providers/llm/types.d.ts +85 -0
  310. package/dist/providers/llm/types.js +12 -0
  311. package/dist/providers/memory/index.d.ts +2 -0
  312. package/dist/providers/memory/index.js +2 -0
  313. package/dist/providers/memory/postgres.d.ts +20 -0
  314. package/dist/providers/memory/postgres.js +72 -0
  315. package/dist/providers/memory/types.d.ts +32 -0
  316. package/dist/providers/memory/types.js +17 -0
  317. package/dist/providers/secrets/app-key.d.ts +8 -0
  318. package/dist/providers/secrets/app-key.js +50 -0
  319. package/dist/providers/secrets/index.d.ts +10 -0
  320. package/dist/providers/secrets/index.js +13 -0
  321. package/dist/providers/secrets/transfer-envelope.d.ts +12 -0
  322. package/dist/providers/secrets/transfer-envelope.js +35 -0
  323. package/dist/providers/secrets/types.d.ts +18 -0
  324. package/dist/providers/secrets/types.js +12 -0
  325. package/dist/providers/storage/types.d.ts +18 -0
  326. package/dist/providers/storage/types.js +7 -0
  327. package/dist/providers/vcs/git.d.ts +105 -0
  328. package/dist/providers/vcs/git.js +710 -0
  329. package/dist/providers/vcs/github.d.ts +105 -0
  330. package/dist/providers/vcs/github.js +394 -0
  331. package/dist/providers/vcs/index.d.ts +6 -0
  332. package/dist/providers/vcs/index.js +26 -0
  333. package/dist/providers/vcs/types.d.ts +118 -0
  334. package/dist/providers/vcs/types.js +1 -0
  335. package/dist/sandbox/bounded-json.d.ts +2 -0
  336. package/dist/sandbox/bounded-json.js +36 -0
  337. package/dist/sandbox/bridge.d.ts +15 -0
  338. package/dist/sandbox/bridge.js +78 -0
  339. package/dist/sandbox/eval-core.d.ts +37 -0
  340. package/dist/sandbox/eval-core.js +159 -0
  341. package/dist/sandbox/fetch-policy.d.ts +24 -0
  342. package/dist/sandbox/fetch-policy.js +96 -0
  343. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +5 -0
  344. package/dist/sandbox/generated/zod.bundle.js +1 -0
  345. package/dist/sandbox/host-functions.d.ts +29 -0
  346. package/dist/sandbox/host-functions.js +168 -0
  347. package/dist/sandbox/limits.d.ts +39 -0
  348. package/dist/sandbox/limits.js +39 -0
  349. package/dist/sandbox/parser-worker/__fixtures__/crash.d.ts +1 -0
  350. package/dist/sandbox/parser-worker/__fixtures__/crash.js +6 -0
  351. package/dist/sandbox/parser-worker/__fixtures__/echo.d.ts +1 -0
  352. package/dist/sandbox/parser-worker/__fixtures__/echo.js +5 -0
  353. package/dist/sandbox/parser-worker/__fixtures__/reject.d.ts +1 -0
  354. package/dist/sandbox/parser-worker/__fixtures__/reject.js +5 -0
  355. package/dist/sandbox/parser-worker/__fixtures__/spin-forever.d.ts +1 -0
  356. package/dist/sandbox/parser-worker/__fixtures__/spin-forever.js +11 -0
  357. package/dist/sandbox/parser-worker/pool.d.ts +13 -0
  358. package/dist/sandbox/parser-worker/pool.js +111 -0
  359. package/dist/sandbox/parser-worker/worker.d.ts +14 -0
  360. package/dist/sandbox/parser-worker/worker.js +63 -0
  361. package/dist/sandbox/pii-redaction.d.ts +1 -0
  362. package/dist/sandbox/pii-redaction.js +29 -0
  363. package/dist/sandbox/prelude.d.ts +26 -0
  364. package/dist/sandbox/prelude.js +408 -0
  365. package/dist/sandbox/quickjs-module.d.ts +13 -0
  366. package/dist/sandbox/quickjs-module.js +19 -0
  367. package/dist/sandbox/run-in-sandbox.d.ts +34 -0
  368. package/dist/sandbox/run-in-sandbox.js +53 -0
  369. package/dist/sandbox/safe-fetch.d.ts +26 -0
  370. package/dist/sandbox/safe-fetch.js +140 -0
  371. package/dist/sandbox/tool-capabilities.d.ts +66 -0
  372. package/dist/sandbox/tool-capabilities.js +103 -0
  373. package/dist/sandbox/zod-params.d.ts +22 -0
  374. package/dist/sandbox/zod-params.js +60 -0
  375. package/dist/serve.d.ts +14 -0
  376. package/dist/serve.js +54 -0
  377. package/dist/wardby-bin.d.ts +2 -0
  378. package/dist/wardby-bin.js +20 -0
  379. package/package.json +123 -0
  380. package/prisma/migrations/20260905000000_init/migration.sql +34 -0
  381. package/prisma/migrations/20260905010000_scheduler_durability/migration.sql +31 -0
  382. package/prisma/migrations/20260905020000_tools_multiturn/migration.sql +47 -0
  383. package/prisma/migrations/20260905030000_cache_tool_json_schema/migration.sql +13 -0
  384. package/prisma/migrations/20260906000000_mcp_phase4/migration.sql +115 -0
  385. package/prisma/migrations/20260906010000_run_final_text/migration.sql +7 -0
  386. package/prisma/migrations/20260906020000_run_turns/migration.sql +6 -0
  387. package/prisma/migrations/20260906030000_task_principal_id/migration.sql +5 -0
  388. package/prisma/migrations/20260906040000_secure_self_hosted_oauth/migration.sql +67 -0
  389. package/prisma/migrations/20260906050000_phase5_coding_agents/migration.sql +52 -0
  390. package/prisma/migrations/20260906060000_tool_capability_scoping/migration.sql +22 -0
  391. package/prisma/migrations/20260906070000_datastore_pii_flag/migration.sql +6 -0
  392. package/prisma/migrations/20260906080000_secret_elicitation_outcomes/migration.sql +13 -0
  393. package/prisma/migrations/20260907010000_coding_proxy_ledger/migration.sql +57 -0
  394. package/prisma/migrations/20260907020000_budget_groups/migration.sql +24 -0
  395. package/prisma/migrations/20260907030000_coding_webhook_task_override/migration.sql +4 -0
  396. package/prisma/migrations/20260908010000_run_execution_backend/migration.sql +2 -0
  397. package/prisma/migrations/20260908020000_coding_run_audit_metadata/migration.sql +7 -0
  398. package/prisma/migrations/20260910010000_agent_secret_bound_name/migration.sql +16 -0
  399. package/prisma/migrations/20260911010000_coding_worker_toolchains/migration.sql +5 -0
  400. package/prisma/migrations/20260912010000_coding_provider_contract/migration.sql +24 -0
  401. package/prisma/migrations/20260912020000_coding_proxy_protocol/migration.sql +10 -0
  402. package/prisma/migrations/20260912030000_agent_memory/migration.sql +18 -0
  403. package/prisma/migrations/20260912040000_named_shared_datastores/migration.sql +68 -0
  404. package/prisma/migrations/20260913000000_run_trigger_webhook/migration.sql +2 -0
  405. package/prisma/migrations/20260913010000_agent_sub_agent/migration.sql +32 -0
  406. package/prisma/migrations/20260913020000_run_task_override/migration.sql +5 -0
  407. package/prisma/migrations/20260913030000_coding_run_root/migration.sql +11 -0
  408. package/prisma/migrations/20260922010000_coding_run_queued_at/migration.sql +8 -0
  409. package/prisma/migrations/20260922020000_coding_workspace_disk/migration.sql +8 -0
  410. package/prisma/migrations/migration_lock.toml +3 -0
  411. package/prisma/schema.prisma +723 -0
  412. package/scripts/git-askpass.sh +11 -0
@@ -0,0 +1,103 @@
1
+ function cloneSession(session) {
2
+ return { ...session, allowedModels: [...session.allowedModels], deadlineAt: new Date(session.deadlineAt) };
3
+ }
4
+ function cloneRequest(request) {
5
+ return {
6
+ ...request,
7
+ pricing: { ...request.pricing },
8
+ usage: request.usage ? { ...request.usage } : undefined,
9
+ };
10
+ }
11
+ /** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
12
+ export class MemoryProxyLedger {
13
+ sessions = new Map();
14
+ sessionByCapability = new Map();
15
+ requests = new Map();
16
+ requestBySessionKey = new Map();
17
+ async createSession(input) {
18
+ if ([...this.sessions.values()].some((session) => session.runId === input.runId)) {
19
+ throw new Error("proxy_session_exists");
20
+ }
21
+ if (this.sessionByCapability.has(input.capabilityHash))
22
+ throw new Error("proxy_capability_collision");
23
+ const session = { ...input, allowedModels: [...input.allowedModels], status: "active" };
24
+ this.sessions.set(session.id, session);
25
+ this.sessionByCapability.set(session.capabilityHash, session.id);
26
+ }
27
+ async findSessionByCapabilityHash(capabilityHash) {
28
+ const id = this.sessionByCapability.get(capabilityHash);
29
+ const session = id ? this.sessions.get(id) : undefined;
30
+ return session ? cloneSession(session) : null;
31
+ }
32
+ async reserve(input) {
33
+ const session = this.sessions.get(input.sessionId);
34
+ if (!session || session.status === "cancelled")
35
+ return { outcome: "inactive", reason: "cancelled" };
36
+ if (input.now.getTime() >= session.deadlineAt.getTime())
37
+ return { outcome: "inactive", reason: "expired" };
38
+ const lookupKey = `${input.sessionId}\0${input.requestKey}`;
39
+ const existingId = this.requestBySessionKey.get(lookupKey);
40
+ if (existingId)
41
+ return { outcome: "duplicate", request: cloneRequest(this.requests.get(existingId)) };
42
+ let committedOrHeld = 0;
43
+ for (const request of this.requests.values()) {
44
+ if (request.sessionId !== input.sessionId)
45
+ continue;
46
+ if (request.status === "completed")
47
+ committedOrHeld += request.actualCostUsd;
48
+ if (request.status === "reserved" || request.status === "uncertain")
49
+ committedOrHeld += request.reservationUsd;
50
+ }
51
+ if (committedOrHeld + input.reservationUsd >= session.budgetUsd)
52
+ return { outcome: "budget_exhausted" };
53
+ const request = { ...input, pricing: { ...input.pricing }, status: "reserved" };
54
+ this.requests.set(request.id, request);
55
+ this.requestBySessionKey.set(lookupKey, request.id);
56
+ return { outcome: "reserved", request: cloneRequest(request) };
57
+ }
58
+ async complete(requestId, usage, actualCostUsd, upstreamStatus) {
59
+ const request = this.requiredRequest(requestId);
60
+ if (request.status === "completed") {
61
+ if (request.actualCostUsd !== actualCostUsd || JSON.stringify(request.usage) !== JSON.stringify(usage)) {
62
+ throw new Error("proxy_completion_conflict");
63
+ }
64
+ return cloneRequest(request);
65
+ }
66
+ if (request.status === "released")
67
+ throw new Error("proxy_request_released");
68
+ request.status = "completed";
69
+ request.actualCostUsd = actualCostUsd;
70
+ request.usage = { ...usage };
71
+ request.upstreamStatus = upstreamStatus;
72
+ return cloneRequest(request);
73
+ }
74
+ async release(requestId, upstreamStatus) {
75
+ const request = this.requiredRequest(requestId);
76
+ if (request.status === "completed" || request.status === "uncertain")
77
+ return;
78
+ request.status = "released";
79
+ request.upstreamStatus = upstreamStatus;
80
+ }
81
+ async markUncertain(requestId, upstreamStatus) {
82
+ const request = this.requiredRequest(requestId);
83
+ if (request.status !== "reserved")
84
+ return;
85
+ request.status = "uncertain";
86
+ request.upstreamStatus = upstreamStatus;
87
+ }
88
+ async cancelSession(sessionId) {
89
+ const session = this.sessions.get(sessionId);
90
+ if (session)
91
+ session.status = "cancelled";
92
+ }
93
+ async getRequest(requestId) {
94
+ const request = this.requests.get(requestId);
95
+ return request ? cloneRequest(request) : null;
96
+ }
97
+ requiredRequest(requestId) {
98
+ const request = this.requests.get(requestId);
99
+ if (!request)
100
+ throw new Error("unknown_proxy_request");
101
+ return request;
102
+ }
103
+ }
@@ -0,0 +1,20 @@
1
+ import { type ModelPricing } from "../llm/pricing.js";
2
+ import type { PricingSnapshot, ProxyUsage } from "./types.js";
3
+ export declare function parseAuthoritativeUsage(value: unknown): ProxyUsage;
4
+ export declare function parseAnthropicAuthoritativeUsage(value: unknown): ProxyUsage;
5
+ export declare function actualCostUsd(usage: ProxyUsage, pricing: ModelPricing): number;
6
+ export declare function estimateReservationUsd(bodyBytes: number, maxOutputTokens: number, pricing: ModelPricing): number;
7
+ export declare function fingerprintRequest(body: string): string;
8
+ export interface TerminalUsage {
9
+ terminal: boolean;
10
+ usage?: ProxyUsage;
11
+ }
12
+ export declare function terminalUsageFromSseFrame(frame: string): TerminalUsage;
13
+ /** Accumulates Anthropic's split input/output usage until message_stop. */
14
+ export declare class AnthropicSseUsageTracker {
15
+ private startUsage?;
16
+ private outputTokens?;
17
+ private stopped;
18
+ consume(frame: string): TerminalUsage;
19
+ }
20
+ export declare function pricingSnapshot(version: string, pricing: ModelPricing): PricingSnapshot;
@@ -0,0 +1,161 @@
1
+ import { createHash } from "node:crypto";
2
+ import { computeCost } from "../llm/pricing.js";
3
+ const MAX_SAFE_TOKENS = 2_000_000_000;
4
+ function tokenCount(value, name) {
5
+ if (!Number.isSafeInteger(value) || value < 0 || value > MAX_SAFE_TOKENS) {
6
+ throw new Error(`invalid_authoritative_usage:${name}`);
7
+ }
8
+ return value;
9
+ }
10
+ export function parseAuthoritativeUsage(value) {
11
+ if (!value || typeof value !== "object" || Array.isArray(value))
12
+ throw new Error("invalid_authoritative_usage");
13
+ const usage = value;
14
+ const inputDetails = usage.input_tokens_details && typeof usage.input_tokens_details === "object"
15
+ ? usage.input_tokens_details
16
+ : {};
17
+ const outputDetails = usage.output_tokens_details && typeof usage.output_tokens_details === "object"
18
+ ? usage.output_tokens_details
19
+ : {};
20
+ const parsed = {
21
+ inputTokens: tokenCount(usage.input_tokens, "input_tokens"),
22
+ outputTokens: tokenCount(usage.output_tokens, "output_tokens"),
23
+ cachedInputTokens: tokenCount(inputDetails.cached_tokens ?? 0, "cached_tokens"),
24
+ cacheWriteTokens: tokenCount(inputDetails.cache_write_tokens ?? 0, "cache_write_tokens"),
25
+ reasoningTokens: tokenCount(outputDetails.reasoning_tokens ?? 0, "reasoning_tokens"),
26
+ };
27
+ if (parsed.cachedInputTokens > parsed.inputTokens || parsed.reasoningTokens > parsed.outputTokens) {
28
+ throw new Error("invalid_authoritative_usage:details_exceed_total");
29
+ }
30
+ return parsed;
31
+ }
32
+ export function parseAnthropicAuthoritativeUsage(value) {
33
+ if (!value || typeof value !== "object" || Array.isArray(value))
34
+ throw new Error("invalid_authoritative_usage");
35
+ const usage = value;
36
+ const cachedInputTokens = tokenCount(usage.cache_read_input_tokens ?? 0, "cache_read_input_tokens");
37
+ return {
38
+ inputTokens: tokenCount(usage.input_tokens, "input_tokens") + cachedInputTokens,
39
+ outputTokens: tokenCount(usage.output_tokens, "output_tokens"),
40
+ cachedInputTokens,
41
+ cacheWriteTokens: tokenCount(usage.cache_creation_input_tokens ?? 0, "cache_creation_input_tokens"),
42
+ reasoningTokens: 0,
43
+ };
44
+ }
45
+ export function actualCostUsd(usage, pricing) {
46
+ return computeCost(pricing, usage);
47
+ }
48
+ export function estimateReservationUsd(bodyBytes, maxOutputTokens, pricing) {
49
+ if (!Number.isSafeInteger(bodyBytes) || bodyBytes < 1)
50
+ throw new Error("invalid_request_size");
51
+ if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens < 1)
52
+ throw new Error("invalid_max_output_tokens");
53
+ const cacheWriteRate = pricing.cacheWritePerMTok ?? pricing.inputPerMTok;
54
+ return (bodyBytes * (pricing.inputPerMTok + cacheWriteRate) + maxOutputTokens * pricing.outputPerMTok) / 1_000_000;
55
+ }
56
+ export function fingerprintRequest(body) {
57
+ return createHash("sha256").update(body).digest("base64url");
58
+ }
59
+ export function terminalUsageFromSseFrame(frame) {
60
+ const data = frame
61
+ .split("\n")
62
+ .filter((line) => line.startsWith("data:"))
63
+ .map((line) => line.slice(5).trimStart())
64
+ .join("\n");
65
+ if (!data || data === "[DONE]")
66
+ return { terminal: false };
67
+ let event;
68
+ try {
69
+ event = JSON.parse(data);
70
+ }
71
+ catch {
72
+ throw new Error("invalid_upstream_sse");
73
+ }
74
+ if (!event || typeof event !== "object")
75
+ return { terminal: false };
76
+ const record = event;
77
+ if (record.type !== "response.completed" && record.type !== "response.failed")
78
+ return { terminal: false };
79
+ const response = record.response;
80
+ if (!response || typeof response !== "object")
81
+ throw new Error("invalid_upstream_terminal_event");
82
+ const usage = response.usage;
83
+ return { terminal: true, usage: usage == null ? undefined : parseAuthoritativeUsage(usage) };
84
+ }
85
+ function sseEvent(frame) {
86
+ const lines = frame.split("\n");
87
+ const name = lines
88
+ .find((line) => line.startsWith("event:"))
89
+ ?.slice(6)
90
+ .trim();
91
+ const data = lines
92
+ .filter((line) => line.startsWith("data:"))
93
+ .map((line) => line.slice(5).trimStart())
94
+ .join("\n");
95
+ if (!data || data === "[DONE]")
96
+ return { name };
97
+ let value;
98
+ try {
99
+ value = JSON.parse(data);
100
+ }
101
+ catch {
102
+ throw new Error("invalid_upstream_sse");
103
+ }
104
+ if (!value || typeof value !== "object" || Array.isArray(value))
105
+ throw new Error("invalid_upstream_sse");
106
+ const record = value;
107
+ if (typeof record.type !== "string" || (name && name !== record.type))
108
+ throw new Error("invalid_upstream_sse");
109
+ return { name, value: record };
110
+ }
111
+ /** Accumulates Anthropic's split input/output usage until message_stop. */
112
+ export class AnthropicSseUsageTracker {
113
+ startUsage;
114
+ outputTokens;
115
+ stopped = false;
116
+ consume(frame) {
117
+ const { value } = sseEvent(frame);
118
+ if (!value)
119
+ return { terminal: false };
120
+ switch (value.type) {
121
+ case "message_start": {
122
+ if (this.startUsage || !value.message || typeof value.message !== "object") {
123
+ throw new Error("invalid_upstream_sse");
124
+ }
125
+ const usage = value.message.usage;
126
+ if (!usage || typeof usage !== "object" || Array.isArray(usage))
127
+ throw new Error("invalid_upstream_sse");
128
+ const record = usage;
129
+ tokenCount(record.input_tokens, "input_tokens");
130
+ tokenCount(record.cache_read_input_tokens ?? 0, "cache_read_input_tokens");
131
+ tokenCount(record.cache_creation_input_tokens ?? 0, "cache_creation_input_tokens");
132
+ this.startUsage = record;
133
+ if (record.output_tokens !== undefined)
134
+ this.outputTokens = tokenCount(record.output_tokens, "output_tokens");
135
+ return { terminal: false };
136
+ }
137
+ case "message_delta": {
138
+ const usage = value.usage;
139
+ if (!usage || typeof usage !== "object" || Array.isArray(usage))
140
+ throw new Error("invalid_upstream_sse");
141
+ this.outputTokens = tokenCount(usage.output_tokens, "output_tokens");
142
+ return { terminal: false };
143
+ }
144
+ case "message_stop": {
145
+ if (this.stopped || !this.startUsage || this.outputTokens === undefined) {
146
+ return { terminal: true };
147
+ }
148
+ this.stopped = true;
149
+ return {
150
+ terminal: true,
151
+ usage: parseAnthropicAuthoritativeUsage({ ...this.startUsage, output_tokens: this.outputTokens }),
152
+ };
153
+ }
154
+ default:
155
+ return { terminal: false };
156
+ }
157
+ }
158
+ }
159
+ export function pricingSnapshot(version, pricing) {
160
+ return { version, ...pricing };
161
+ }
@@ -0,0 +1,15 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ import type { CreateProxySessionInput, ProxyLedger, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
3
+ export type PrismaProxyLedgerDb = Pick<PrismaClient, "$transaction" | "$queryRaw" | "$executeRaw">;
4
+ export declare class PrismaProxyLedger implements ProxyLedger {
5
+ private readonly db;
6
+ constructor(db: PrismaProxyLedgerDb);
7
+ createSession(input: CreateProxySessionInput): Promise<void>;
8
+ findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
9
+ reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
10
+ complete(requestId: string, usage: ProxyUsage, actualCostUsd: number, upstreamStatus: number): Promise<ProxyRequest>;
11
+ release(requestId: string, upstreamStatus: number): Promise<void>;
12
+ markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
13
+ cancelSession(sessionId: string): Promise<void>;
14
+ getRequest(requestId: string): Promise<ProxyRequest | null>;
15
+ }
@@ -0,0 +1,213 @@
1
+ function sessionFromRow(row) {
2
+ if (!Array.isArray(row.allowedModels) || !row.allowedModels.every((model) => typeof model === "string")) {
3
+ throw new Error("invalid_proxy_session_models");
4
+ }
5
+ if (row.protocol !== "openai-responses" && row.protocol !== "anthropic-messages") {
6
+ throw new Error("invalid_proxy_session_protocol");
7
+ }
8
+ return {
9
+ id: row.id,
10
+ runId: row.runId,
11
+ capabilityHash: row.capabilityHash,
12
+ credentialRef: row.credentialRef,
13
+ protocol: row.protocol,
14
+ allowedModels: row.allowedModels,
15
+ deadlineAt: row.deadlineAt,
16
+ budgetUsd: Number(row.budgetUsd),
17
+ status: row.status,
18
+ };
19
+ }
20
+ function requestFromRow(row) {
21
+ const pricing = row.pricingSnapshot;
22
+ const hasUsage = row.inputTokens !== null && row.outputTokens !== null;
23
+ return {
24
+ id: row.id,
25
+ sessionId: row.sessionId,
26
+ requestKey: row.requestKey,
27
+ requestFingerprint: row.requestFingerprint,
28
+ model: row.model,
29
+ status: row.status,
30
+ reservationUsd: Number(row.reservationUsd),
31
+ actualCostUsd: row.actualCostUsd === null ? undefined : Number(row.actualCostUsd),
32
+ pricing: { ...pricing, version: row.pricingVersion },
33
+ usage: hasUsage
34
+ ? {
35
+ inputTokens: row.inputTokens,
36
+ outputTokens: row.outputTokens,
37
+ cachedInputTokens: row.cachedInputTokens ?? 0,
38
+ cacheWriteTokens: row.cacheWriteTokens ?? 0,
39
+ reasoningTokens: row.reasoningTokens ?? 0,
40
+ }
41
+ : undefined,
42
+ upstreamStatus: row.upstreamStatus ?? undefined,
43
+ };
44
+ }
45
+ async function requestById(db, id) {
46
+ const rows = await db.$queryRaw `
47
+ SELECT "id", "sessionId", "requestKey", "requestFingerprint", "model", "status",
48
+ "reservationUsd", "actualCostUsd", "pricingVersion", "pricingSnapshot",
49
+ "inputTokens", "outputTokens", "cachedInputTokens", "cacheWriteTokens",
50
+ "reasoningTokens", "upstreamStatus"
51
+ FROM "CodingProxyRequest" WHERE "id" = ${id}
52
+ `;
53
+ return rows[0] ? requestFromRow(rows[0]) : null;
54
+ }
55
+ export class PrismaProxyLedger {
56
+ db;
57
+ constructor(db) {
58
+ this.db = db;
59
+ }
60
+ async createSession(input) {
61
+ const models = JSON.stringify(input.allowedModels);
62
+ await this.db.$executeRaw `
63
+ INSERT INTO "CodingProxySession"
64
+ ("id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt",
65
+ "budgetUsd", "status", "createdAt", "updatedAt")
66
+ VALUES
67
+ (${input.id}, ${input.runId}, ${input.capabilityHash}, ${input.credentialRef}, ${input.protocol}, ${models}::jsonb,
68
+ ${input.deadlineAt}, ${input.budgetUsd}, 'active', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
69
+ `;
70
+ }
71
+ async findSessionByCapabilityHash(capabilityHash) {
72
+ const rows = await this.db.$queryRaw `
73
+ SELECT "id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt", "budgetUsd", "status"
74
+ FROM "CodingProxySession" WHERE "capabilityHash" = ${capabilityHash}
75
+ `;
76
+ return rows[0] ? sessionFromRow(rows[0]) : null;
77
+ }
78
+ async reserve(input) {
79
+ return this.db.$transaction(async (tx) => {
80
+ const sessions = await tx.$queryRaw `
81
+ SELECT "id", "runId", "capabilityHash", "credentialRef", "protocol", "allowedModels", "deadlineAt", "budgetUsd", "status"
82
+ FROM "CodingProxySession" WHERE "id" = ${input.sessionId} FOR UPDATE
83
+ `;
84
+ const row = sessions[0];
85
+ if (!row || row.status !== "active")
86
+ return { outcome: "inactive", reason: "cancelled" };
87
+ if (input.now.getTime() >= row.deadlineAt.getTime())
88
+ return { outcome: "inactive", reason: "expired" };
89
+ const duplicate = await tx.$queryRaw `
90
+ SELECT "id", "sessionId", "requestKey", "requestFingerprint", "model", "status",
91
+ "reservationUsd", "actualCostUsd", "pricingVersion", "pricingSnapshot",
92
+ "inputTokens", "outputTokens", "cachedInputTokens", "cacheWriteTokens",
93
+ "reasoningTokens", "upstreamStatus"
94
+ FROM "CodingProxyRequest"
95
+ WHERE "sessionId" = ${input.sessionId} AND "requestKey" = ${input.requestKey}
96
+ `;
97
+ if (duplicate[0])
98
+ return { outcome: "duplicate", request: requestFromRow(duplicate[0]) };
99
+ const totals = await tx.$queryRaw `
100
+ SELECT COALESCE(SUM(
101
+ CASE
102
+ WHEN "status" = 'completed' THEN "actualCostUsd"
103
+ WHEN "status" IN ('reserved', 'uncertain') THEN "reservationUsd"
104
+ ELSE 0
105
+ END
106
+ ), 0) AS "held"
107
+ FROM "CodingProxyRequest" WHERE "sessionId" = ${input.sessionId}
108
+ `;
109
+ if (Number(totals[0]?.held ?? 0) + input.reservationUsd >= Number(row.budgetUsd)) {
110
+ return { outcome: "budget_exhausted" };
111
+ }
112
+ const pricing = JSON.stringify({
113
+ encoding: input.pricing.encoding,
114
+ inputPerMTok: input.pricing.inputPerMTok,
115
+ outputPerMTok: input.pricing.outputPerMTok,
116
+ cachedInputPerMTok: input.pricing.cachedInputPerMTok,
117
+ cacheWritePerMTok: input.pricing.cacheWritePerMTok,
118
+ });
119
+ await tx.$executeRaw `
120
+ INSERT INTO "CodingProxyRequest"
121
+ ("id", "sessionId", "requestKey", "requestFingerprint", "model", "status",
122
+ "reservationUsd", "pricingVersion", "pricingSnapshot", "createdAt", "updatedAt")
123
+ VALUES
124
+ (${input.id}, ${input.sessionId}, ${input.requestKey}, ${input.requestFingerprint}, ${input.model},
125
+ 'reserved', ${input.reservationUsd}, ${input.pricing.version}, ${pricing}::jsonb,
126
+ CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
127
+ `;
128
+ const request = await requestById(tx, input.id);
129
+ if (!request)
130
+ throw new Error("proxy_reservation_not_persisted");
131
+ return { outcome: "reserved", request };
132
+ });
133
+ }
134
+ async complete(requestId, usage, actualCostUsd, upstreamStatus) {
135
+ return this.db.$transaction(async (tx) => {
136
+ const initial = await requestById(tx, requestId);
137
+ if (!initial)
138
+ throw new Error("unknown_proxy_request");
139
+ await tx.$queryRaw `
140
+ SELECT "id" FROM "CodingProxySession" WHERE "id" = ${initial.sessionId} FOR UPDATE
141
+ `;
142
+ const locked = await tx.$queryRaw `
143
+ SELECT "id", "sessionId", "requestKey", "requestFingerprint", "model", "status",
144
+ "reservationUsd", "actualCostUsd", "pricingVersion", "pricingSnapshot",
145
+ "inputTokens", "outputTokens", "cachedInputTokens", "cacheWriteTokens",
146
+ "reasoningTokens", "upstreamStatus"
147
+ FROM "CodingProxyRequest" WHERE "id" = ${requestId} FOR UPDATE
148
+ `;
149
+ const prior = locked[0] ? requestFromRow(locked[0]) : null;
150
+ if (!prior)
151
+ throw new Error("unknown_proxy_request");
152
+ if (prior.status === "released")
153
+ throw new Error("proxy_request_released");
154
+ if (prior.status === "completed") {
155
+ if (Math.abs((prior.actualCostUsd ?? -1) - actualCostUsd) > 1e-12 ||
156
+ JSON.stringify(prior.usage) !== JSON.stringify(usage)) {
157
+ throw new Error("proxy_completion_conflict");
158
+ }
159
+ return prior;
160
+ }
161
+ await tx.$executeRaw `
162
+ UPDATE "CodingProxyRequest"
163
+ SET "status" = 'completed', "actualCostUsd" = ${actualCostUsd},
164
+ "inputTokens" = ${usage.inputTokens}, "outputTokens" = ${usage.outputTokens},
165
+ "cachedInputTokens" = ${usage.cachedInputTokens}, "cacheWriteTokens" = ${usage.cacheWriteTokens},
166
+ "reasoningTokens" = ${usage.reasoningTokens}, "upstreamStatus" = ${upstreamStatus},
167
+ "completedAt" = CURRENT_TIMESTAMP, "updatedAt" = CURRENT_TIMESTAMP
168
+ WHERE "id" = ${requestId} AND "status" IN ('reserved', 'uncertain')
169
+ `;
170
+ await tx.$executeRaw `
171
+ UPDATE "Run" AS r
172
+ SET "tokensIn" = totals."tokensIn", "tokensOut" = totals."tokensOut", "costUsd" = totals."costUsd"
173
+ FROM (
174
+ SELECT s."runId", COALESCE(SUM(q."inputTokens"), 0)::integer AS "tokensIn",
175
+ COALESCE(SUM(q."outputTokens"), 0)::integer AS "tokensOut",
176
+ COALESCE(SUM(q."actualCostUsd"), 0) AS "costUsd"
177
+ FROM "CodingProxySession" s
178
+ JOIN "CodingProxyRequest" q ON q."sessionId" = s."id" AND q."status" = 'completed'
179
+ WHERE s."id" = ${prior.sessionId}
180
+ GROUP BY s."runId"
181
+ ) AS totals
182
+ WHERE r."id" = totals."runId"
183
+ `;
184
+ const request = await requestById(tx, requestId);
185
+ if (!request)
186
+ throw new Error("proxy_completion_not_persisted");
187
+ return request;
188
+ });
189
+ }
190
+ async release(requestId, upstreamStatus) {
191
+ await this.db.$executeRaw `
192
+ UPDATE "CodingProxyRequest"
193
+ SET "status" = 'released', "upstreamStatus" = ${upstreamStatus}, "updatedAt" = CURRENT_TIMESTAMP
194
+ WHERE "id" = ${requestId} AND "status" = 'reserved'
195
+ `;
196
+ }
197
+ async markUncertain(requestId, upstreamStatus) {
198
+ await this.db.$executeRaw `
199
+ UPDATE "CodingProxyRequest"
200
+ SET "status" = 'uncertain', "upstreamStatus" = ${upstreamStatus ?? null}, "updatedAt" = CURRENT_TIMESTAMP
201
+ WHERE "id" = ${requestId} AND "status" = 'reserved'
202
+ `;
203
+ }
204
+ async cancelSession(sessionId) {
205
+ await this.db.$executeRaw `
206
+ UPDATE "CodingProxySession" SET "status" = 'cancelled', "updatedAt" = CURRENT_TIMESTAMP
207
+ WHERE "id" = ${sessionId} AND "status" = 'active'
208
+ `;
209
+ }
210
+ getRequest(requestId) {
211
+ return requestById(this.db, requestId);
212
+ }
213
+ }
@@ -0,0 +1,75 @@
1
+ import { type ModelPricing } from "../llm/pricing.js";
2
+ import type { CredentialResolver, ProxyAuditSink, ProxyLedger, ProxyProtocol } from "./types.js";
3
+ export declare const PROXY_MAX_BODY_BYTES: number;
4
+ export declare const PROXY_MAX_OUTPUT_TOKENS = 1000000;
5
+ export declare const PROXY_DEFAULT_MAX_OUTPUT_TOKENS = 4096;
6
+ export declare const CLAUDE_CODE_ANTHROPIC_BETAS: readonly ["claude-code-20250219", "context-management-2025-06-27", "effort-2025-11-24", "interleaved-thinking-2025-05-14", "mid-conversation-system-2026-04-07", "prompt-caching-scope-2026-01-05", "thinking-token-count-2026-05-13"];
7
+ export declare class CodingProxyError extends Error {
8
+ readonly status: number;
9
+ readonly code: string;
10
+ constructor(status: number, code: string);
11
+ }
12
+ export interface ProxyResponseSink {
13
+ start(status: number, headers: Record<string, string>): void;
14
+ write(chunk: Uint8Array): void | Promise<void>;
15
+ end(): void;
16
+ destroy(): void;
17
+ }
18
+ export interface ExecuteProxyRequest {
19
+ bearer: string;
20
+ protocol: ProxyProtocol;
21
+ rawBody: string;
22
+ requestKey?: string;
23
+ anthropicBeta?: string;
24
+ }
25
+ export interface CreateCodingProxySession {
26
+ runId: string;
27
+ credentialRef: string;
28
+ protocol: ProxyProtocol;
29
+ allowedModels: string[];
30
+ deadlineAt: Date;
31
+ budgetUsd: number;
32
+ }
33
+ export interface CreatedCodingProxySession {
34
+ id: string;
35
+ runId: string;
36
+ capability: string;
37
+ protocol: ProxyProtocol;
38
+ allowedModels: string[];
39
+ deadlineAt: Date;
40
+ budgetUsd: number;
41
+ }
42
+ export interface CodingProxyOptions {
43
+ ledger: ProxyLedger;
44
+ credentials: CredentialResolver;
45
+ upstreamUrl?: string;
46
+ anthropicUpstreamUrl?: string;
47
+ upstreamAllowedHosts?: string[];
48
+ fetch?: typeof globalThis.fetch;
49
+ now?: () => Date;
50
+ audit?: ProxyAuditSink;
51
+ pricing?: (model: string, protocol: ProxyProtocol) => ModelPricing;
52
+ pricingVersion?: string;
53
+ }
54
+ export declare class CodingProxy {
55
+ private readonly ledger;
56
+ private readonly credentials;
57
+ private readonly upstreamUrls;
58
+ private readonly fetchImpl;
59
+ private readonly now;
60
+ private readonly audit;
61
+ private readonly getPricing;
62
+ private readonly priceVersion;
63
+ private readonly activeRequests;
64
+ constructor(options: CodingProxyOptions);
65
+ createSession(input: CreateCodingProxySession): Promise<CreatedCodingProxySession>;
66
+ cancelSession(sessionId: string): Promise<void>;
67
+ execute(input: ExecuteProxyRequest, sink: ProxyResponseSink): Promise<void>;
68
+ private authenticate;
69
+ private trackActive;
70
+ private handleDuplicate;
71
+ private complete;
72
+ private forwardJson;
73
+ private forwardStream;
74
+ private markUncertain;
75
+ }