@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,377 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { SignJWT, jwtVerify } from "jose";
3
+ import { z } from "zod";
4
+ import { NotSupportedError } from "./types.js";
5
+ import { requireSubject } from "./subject.js";
6
+ import { SCOPES_SUPPORTED } from "../../mcp/auth/resource-server.js";
7
+ import { canonicalUrl } from "../../mcp/transport/http-limits.js";
8
+ import { Credentials, DAY, decodeKey, lockUser } from "../../mcp/auth/self-hosted/credentials.js";
9
+ import { Sessions } from "../../mcp/auth/self-hosted/session.js";
10
+ function validRedirect(value) {
11
+ try {
12
+ const u = new URL(value);
13
+ return (!value.includes("#") &&
14
+ !u.username &&
15
+ !u.password &&
16
+ (u.protocol === "https:" || (u.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(u.hostname))));
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ const registration = z
23
+ .object({
24
+ redirectUris: z.array(z.string().min(1).max(2048).refine(validRedirect)).min(1).max(10),
25
+ clientName: z.string().max(100).optional(),
26
+ grantTypes: z
27
+ .array(z.enum(["authorization_code", "refresh_token"]))
28
+ .min(1)
29
+ .max(2)
30
+ .default(["authorization_code", "refresh_token"]),
31
+ tokenEndpointAuthMethod: z.literal("none").default("none"),
32
+ })
33
+ .strict();
34
+ const authorization = z
35
+ .object({
36
+ clientId: z.string().max(100),
37
+ redirectUri: z.string().max(2048),
38
+ codeChallenge: z.string().regex(/^[A-Za-z0-9_-]{43}$/),
39
+ codeChallengeMethod: z.literal("S256"),
40
+ scope: z.string().max(512),
41
+ resource: z.string().max(2048),
42
+ state: z.string().max(1024).optional(),
43
+ })
44
+ .strict();
45
+ export class SelfHostedAuthProvider {
46
+ db;
47
+ credentials;
48
+ sessions;
49
+ config;
50
+ key;
51
+ constructor(config, db) {
52
+ this.db = db;
53
+ this.config = { ...config, canonicalUri: canonicalUrl(config.canonicalUri).href };
54
+ this.key = decodeKey(config.signingKey, "AUTH_SIGNING_KEY");
55
+ const credentialKey = decodeKey(config.credentialHashKey, "AUTH_CREDENTIAL_HASH_KEY");
56
+ if (this.key.equals(credentialKey))
57
+ throw new Error("Signing and credential hash keys must be distinct.");
58
+ if (!Number.isInteger(config.maxClients ?? 1000) || (config.maxClients ?? 1000) < 1)
59
+ throw new Error("Invalid OAuth client limit.");
60
+ this.credentials = new Credentials(config.credentialHashKey);
61
+ this.sessions = new Sessions(db, this.credentials);
62
+ }
63
+ asMetadata() {
64
+ const base = new URL(this.config.canonicalUri).origin;
65
+ return {
66
+ issuer: this.config.canonicalUri,
67
+ authorization_endpoint: base + "/authorize",
68
+ token_endpoint: base + "/token",
69
+ registration_endpoint: base + "/register",
70
+ revocation_endpoint: base + "/revoke",
71
+ response_types_supported: ["code"],
72
+ grant_types_supported: ["authorization_code", "refresh_token"],
73
+ code_challenge_methods_supported: ["S256"],
74
+ token_endpoint_auth_methods_supported: ["none"],
75
+ revocation_endpoint_auth_methods_supported: ["none"],
76
+ scopes_supported: SCOPES_SUPPORTED,
77
+ authorization_response_iss_parameter_supported: true,
78
+ };
79
+ }
80
+ async registerClient(params) {
81
+ const p = registration.parse(params);
82
+ return this.db.$transaction(async (tx) => {
83
+ await tx.$queryRawUnsafe("SELECT 1 AS locked FROM pg_advisory_xact_lock(7412901)");
84
+ if ((await tx.oAuthClient.count()) >= (this.config.maxClients ?? 1000))
85
+ throw new Error("Client capacity reached.");
86
+ const clientId = randomUUID();
87
+ await tx.oAuthClient.create({
88
+ data: {
89
+ clientId,
90
+ metadata: {
91
+ redirect_uris: p.redirectUris,
92
+ grant_types: p.grantTypes,
93
+ client_name: p.clientName ?? "Unnamed client",
94
+ token_endpoint_auth_method: "none",
95
+ },
96
+ },
97
+ });
98
+ return { clientId };
99
+ });
100
+ }
101
+ async handleAuthorize(input) {
102
+ const p = authorization.parse(input);
103
+ if (p.resource !== this.config.canonicalUri)
104
+ throw new Error("Invalid resource.");
105
+ const client = await this.db.oAuthClient.findUnique({ where: { clientId: p.clientId } });
106
+ const metadata = client?.metadata;
107
+ if (!metadata?.redirect_uris?.includes(p.redirectUri) || !metadata.grant_types?.includes("authorization_code"))
108
+ throw new Error("Invalid client or redirect.");
109
+ const scope = [...new Set(p.scope.split(/\s+/).filter((s) => SCOPES_SUPPORTED.includes(s)))].join(" ");
110
+ const request = await this.db.oAuthAuthorizationRequest.create({
111
+ data: {
112
+ clientId: p.clientId,
113
+ redirectUri: p.redirectUri,
114
+ resource: p.resource,
115
+ requestedScope: scope,
116
+ codeChallenge: p.codeChallenge,
117
+ state: p.state,
118
+ expiresAt: new Date(Date.now() + 600_000),
119
+ },
120
+ });
121
+ return { interactionId: request.id };
122
+ }
123
+ async consentPage(sessionToken, interactionId) {
124
+ const session = await this.sessions.get(sessionToken);
125
+ const interaction = await this.db.oAuthAuthorizationRequest.findUnique({
126
+ where: { id: interactionId },
127
+ include: { client: true },
128
+ });
129
+ if (!interaction || interaction.consumedAt || interaction.expiresAt.getTime() <= Date.now())
130
+ throw new Error("Invalid interaction.");
131
+ const challenge = await this.sessions.challenge("consent", session.sessionId, interactionId);
132
+ return { interaction, challenge };
133
+ }
134
+ async consent(sessionToken, interactionId, challenge, approve) {
135
+ const first = await this.sessions.get(sessionToken);
136
+ return this.db.$transaction(async (tx) => {
137
+ await lockUser(tx, first.userId);
138
+ const session = await this.sessions.get(sessionToken, tx);
139
+ await this.sessions.consumeChallenge(tx, challenge, "consent", session.sessionId, interactionId);
140
+ const interaction = await tx.oAuthAuthorizationRequest.findUnique({ where: { id: interactionId } });
141
+ if (!interaction)
142
+ throw new Error("Invalid interaction.");
143
+ const used = await tx.oAuthAuthorizationRequest.updateMany({
144
+ where: { id: interactionId, consumedAt: null, expiresAt: { gt: new Date() } },
145
+ data: { consumedAt: new Date() },
146
+ });
147
+ if (used.count !== 1)
148
+ throw new Error("Invalid interaction.");
149
+ const redirect = new URL(interaction.redirectUri);
150
+ redirect.searchParams.set("iss", this.config.canonicalUri);
151
+ if (interaction.state !== null)
152
+ redirect.searchParams.set("state", interaction.state);
153
+ if (!approve)
154
+ redirect.searchParams.set("error", "access_denied");
155
+ else {
156
+ const code = this.credentials.create("rva");
157
+ await tx.oAuthAuthorizationCode.create({
158
+ data: {
159
+ codeId: code.id,
160
+ secretHash: code.hash,
161
+ clientId: interaction.clientId,
162
+ userId: session.userId,
163
+ redirectUri: interaction.redirectUri,
164
+ resource: interaction.resource,
165
+ scope: interaction.requestedScope,
166
+ codeChallenge: interaction.codeChallenge,
167
+ expiresAt: new Date(Date.now() + 60_000),
168
+ },
169
+ });
170
+ redirect.searchParams.set("code", code.token);
171
+ }
172
+ return redirect.href;
173
+ });
174
+ }
175
+ async handleToken(params) {
176
+ if (params.resource !== undefined && !this.withinCanonical(params.resource))
177
+ throw new Error("Invalid grant: resource does not match the canonical URI.");
178
+ if (params.grantType === "authorization_code")
179
+ return this.exchange(params);
180
+ if (params.grantType === "refresh_token")
181
+ return this.rotate(params);
182
+ throw new Error("Unsupported grant.");
183
+ }
184
+ /**
185
+ * Whether a token request's `resource` names this server: the canonical URI
186
+ * itself, or a URL beneath it. The MCP SDK sends the metadata's canonical
187
+ * URI when it has it, but falls back to the MCP endpoint URL (e.g. `/mcp`
188
+ * under a root canonical URI) on refresh - rejecting that logged every
189
+ * Claude Code session out after one access-token lifetime. The issued
190
+ * token's audience still comes from the grant (code.resource /
191
+ * family.resource), never from this parameter.
192
+ */
193
+ withinCanonical(resource) {
194
+ let url;
195
+ try {
196
+ url = new URL(resource);
197
+ }
198
+ catch {
199
+ return false;
200
+ }
201
+ const canonical = new URL(this.config.canonicalUri);
202
+ if (url.origin !== canonical.origin || url.search || url.hash)
203
+ return false;
204
+ const base = canonical.pathname.endsWith("/") ? canonical.pathname : canonical.pathname + "/";
205
+ return url.pathname === canonical.pathname || url.pathname.startsWith(base);
206
+ }
207
+ async exchange(p) {
208
+ const id = this.credentials.id(p.code, "rva");
209
+ const code = id ? await this.db.oAuthAuthorizationCode.findUnique({ where: { codeId: id } }) : null;
210
+ if (!code || !this.credentials.matches(p.code, code.secretHash))
211
+ throw new Error("Invalid grant: unknown code.");
212
+ if (code.clientId !== p.clientId)
213
+ throw new Error("Invalid grant: client_id does not match the code.");
214
+ if (code.redirectUri !== p.redirectUri)
215
+ throw new Error("Invalid grant: redirect_uri does not match the code.");
216
+ if (code.resource !== this.config.canonicalUri)
217
+ throw new Error("Invalid grant: code resource mismatch.");
218
+ if (!/^[A-Za-z0-9._~-]{43,128}$/.test(p.codeVerifier) ||
219
+ createHash("sha256").update(p.codeVerifier).digest("base64url") !== code.codeChallenge)
220
+ throw new Error("Invalid grant: PKCE verifier mismatch.");
221
+ return this.db.$transaction(async (tx) => {
222
+ const user = await lockUser(tx, code.userId);
223
+ const consumed = await tx.oAuthAuthorizationCode.updateMany({
224
+ where: { codeId: code.codeId, consumedAt: null, expiresAt: { gt: new Date() } },
225
+ data: { consumedAt: new Date() },
226
+ });
227
+ if (consumed.count !== 1)
228
+ throw new Error("Invalid grant: code expired or already used.");
229
+ const family = await tx.oAuthFamily.create({
230
+ data: {
231
+ id: randomUUID(),
232
+ clientId: code.clientId,
233
+ userId: code.userId,
234
+ scope: code.scope,
235
+ resource: code.resource,
236
+ expiresAt: new Date(Date.now() + 30 * DAY),
237
+ },
238
+ });
239
+ return this.issue(tx, family, user.principal.subject);
240
+ });
241
+ }
242
+ async rotate(p) {
243
+ const id = this.credentials.id(p.refreshToken, "rvr");
244
+ const initial = id ? await this.db.oAuthGrant.findUnique({ where: { id }, include: { family: true } }) : null;
245
+ if (!initial || !this.credentials.matches(p.refreshToken, initial.refreshTokenHash))
246
+ throw new Error("Invalid grant: unknown refresh token.");
247
+ if (initial.family.clientId !== p.clientId)
248
+ throw new Error("Invalid grant: client_id does not match the refresh token.");
249
+ const result = await this.db.$transaction(async (tx) => {
250
+ const user = await lockUser(tx, initial.family.userId);
251
+ await tx.$queryRawUnsafe('SELECT "id" FROM "OAuthFamily" WHERE "id" = $1 FOR UPDATE', initial.familyId);
252
+ const grant = await tx.oAuthGrant.findUnique({
253
+ where: { id: initial.id },
254
+ include: { family: { include: { client: true } } },
255
+ });
256
+ // Failures return a reason instead of throwing so the reuse revocation
257
+ // below COMMITs; the caller throws after the transaction.
258
+ if (!grant || grant.revokedAt || grant.family.revokedAt)
259
+ return "refresh token revoked";
260
+ if (grant.family.expiresAt.getTime() <= Date.now() || grant.expiresAt.getTime() <= Date.now())
261
+ return "refresh token expired";
262
+ if (!grant.family.client.metadata.grant_types?.includes("refresh_token"))
263
+ return "client not registered for refresh_token";
264
+ if (grant.consumedAt) {
265
+ await this.revokeFamily(tx, grant.familyId);
266
+ return "refresh token reused; family revoked";
267
+ }
268
+ const result = await this.issue(tx, grant.family, user.principal.subject);
269
+ await tx.oAuthGrant.update({
270
+ where: { id: grant.id },
271
+ data: { consumedAt: new Date(), replacedById: this.credentials.id(result.refreshToken, "rvr") },
272
+ });
273
+ return result;
274
+ });
275
+ if (typeof result === "string")
276
+ throw new Error(`Invalid grant: ${result}.`);
277
+ return result;
278
+ }
279
+ async issue(tx, family, subject) {
280
+ const refresh = this.credentials.create("rvr");
281
+ await tx.oAuthGrant.create({
282
+ data: { id: refresh.id, familyId: family.id, refreshTokenHash: refresh.hash, expiresAt: family.expiresAt },
283
+ });
284
+ const accessToken = await new SignJWT({
285
+ scope: family.scope,
286
+ client_id: family.clientId,
287
+ fid: family.id,
288
+ uid: family.userId,
289
+ ver: 2,
290
+ })
291
+ .setProtectedHeader({ alg: "HS256", typ: "at+jwt" })
292
+ .setIssuer(this.config.canonicalUri)
293
+ .setAudience(family.resource)
294
+ .setSubject(requireSubject(subject))
295
+ .setIssuedAt()
296
+ .setExpirationTime("10m")
297
+ .setJti(randomUUID())
298
+ .sign(this.key);
299
+ return { accessToken, tokenType: "Bearer", expiresIn: 600, refreshToken: refresh.token, scope: family.scope };
300
+ }
301
+ async revokeFamily(tx, id) {
302
+ await tx.oAuthFamily.update({ where: { id }, data: { revokedAt: new Date() } });
303
+ await tx.oAuthGrant.updateMany({ where: { familyId: id }, data: { revokedAt: new Date() } });
304
+ }
305
+ async revoke(token, clientId) {
306
+ const id = this.credentials.id(token, "rvr");
307
+ const grant = id ? await this.db.oAuthGrant.findUnique({ where: { id }, include: { family: true } }) : null;
308
+ if (!grant || !this.credentials.matches(token, grant.refreshTokenHash) || grant.family.clientId !== clientId)
309
+ return;
310
+ await this.db.$transaction(async (tx) => {
311
+ await tx.$queryRawUnsafe('SELECT "id" FROM "AuthUser" WHERE "id" = $1 FOR UPDATE', grant.family.userId);
312
+ await this.revokeFamily(tx, grant.familyId);
313
+ });
314
+ }
315
+ async verifyBearer(token) {
316
+ const { payload } = await jwtVerify(token, this.key, {
317
+ algorithms: ["HS256"],
318
+ typ: "at+jwt",
319
+ issuer: this.config.canonicalUri,
320
+ audience: this.config.canonicalUri,
321
+ requiredClaims: ["sub", "iss", "aud", "iat", "exp", "jti", "client_id", "fid", "uid", "ver"],
322
+ });
323
+ const subject = requireSubject(payload.sub);
324
+ if (payload.ver !== 2 ||
325
+ typeof payload.fid !== "string" ||
326
+ typeof payload.uid !== "string" ||
327
+ typeof payload.client_id !== "string")
328
+ throw new Error("Invalid token.");
329
+ const family = await this.db.oAuthFamily.findUnique({
330
+ where: { id: payload.fid },
331
+ include: { user: { include: { principal: true } } },
332
+ });
333
+ if (!family ||
334
+ family.revokedAt ||
335
+ family.expiresAt.getTime() <= Date.now() ||
336
+ family.user.status !== "enabled" ||
337
+ family.userId !== payload.uid ||
338
+ family.user.principal.subject !== subject ||
339
+ family.clientId !== payload.client_id ||
340
+ payload.scope !== family.scope)
341
+ throw new Error("Invalid token.");
342
+ return { subject, scopes: family.scope.split(/\s+/).filter(Boolean), roles: [] };
343
+ }
344
+ async cleanup() {
345
+ const now = new Date();
346
+ // Retain consumed grants until absolute family expiry for reuse detection.
347
+ await this.db.oAuthFamily.deleteMany({ where: { expiresAt: { lt: now } } });
348
+ await this.db.oAuthAuthorizationCode.deleteMany({ where: { expiresAt: { lt: now } } });
349
+ await this.db.oAuthAuthorizationRequest.deleteMany({ where: { expiresAt: { lt: now } } });
350
+ await this.db.authFormChallenge.deleteMany({ where: { expiresAt: { lt: now } } });
351
+ await this.db.authSession.deleteMany({ where: { expiresAt: { lt: now } } });
352
+ await this.db.authRateLimit.deleteMany({ where: { expiresAt: { lt: now } } });
353
+ // /register has no auth in front of it once Cloud Run allows
354
+ // unauthenticated invocation (required for self-hosted OAuth to serve
355
+ // real clients at all), and maxClients is a hard global cap - so
356
+ // unthrottled registrations could permanently exhaust it. A client
357
+ // that never completes a single token exchange within a week is
358
+ // abandoned or spam, never a real client still mid-flow (authorization
359
+ // requests expire in 10 minutes, codes in 60 seconds).
360
+ await this.db.oAuthClient.deleteMany({
361
+ where: { createdAt: { lt: new Date(now.getTime() - 7 * DAY) }, families: { none: {} } },
362
+ });
363
+ }
364
+ async profile(token) {
365
+ const v = await this.verifyBearer(token);
366
+ return { subject: v.subject, roles: [] };
367
+ }
368
+ authorizeUrl() {
369
+ throw new NotSupportedError("Use browser authorization.");
370
+ }
371
+ async exchangeCode() {
372
+ throw new NotSupportedError("Use the token endpoint.");
373
+ }
374
+ async refresh() {
375
+ throw new NotSupportedError("Use the token endpoint.");
376
+ }
377
+ }
@@ -0,0 +1 @@
1
+ export declare function requireSubject(value: unknown): string;
@@ -0,0 +1,6 @@
1
+ export function requireSubject(value) {
2
+ if (typeof value !== "string" || !value.trim() || Buffer.byteLength(value, "utf8") > 512) {
3
+ throw new Error("Invalid token subject.");
4
+ }
5
+ return value;
6
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Auth seam — OAuth 2.1 resource-server identity and scope extraction.
3
+ *
4
+ * Default adapter: DelegatingAuthProvider (resource-server-only; an external
5
+ * IdP is the authorization server). Native adapter: SelfHostedAuthProvider
6
+ * (wardby additionally runs the AS role: PKCE /authorize+/token, its own
7
+ * signed tokens).
8
+ */
9
+ /**
10
+ * The interactive-login identity shape (returned by `profile(idToken)`).
11
+ * Identity only — no scopes here. Scopes are a per-token authorization
12
+ * grant, not a property of who someone is: the same subject can present
13
+ * two different tokens carrying two different scope sets, so a scope
14
+ * field on an identity type would conflate a grant with an identity the
15
+ * moment more than one token exists for the same subject.
16
+ */
17
+ export interface AuthProfile {
18
+ subject: string;
19
+ email?: string;
20
+ name?: string;
21
+ /** Application roles resolved from the provider's token claims. */
22
+ roles: string[];
23
+ }
24
+ /**
25
+ * The result of validating a bearer access token (returned by
26
+ * `verifyBearer`). Distinct from `AuthProfile` precisely because it DOES
27
+ * carry scopes — this is per-token, not per-identity.
28
+ */
29
+ export interface VerifiedToken {
30
+ subject: string;
31
+ /** OAuth scopes granted to this specific token. */
32
+ scopes: string[];
33
+ email?: string;
34
+ roles?: string[];
35
+ }
36
+ export interface AuthTokens {
37
+ idToken: string;
38
+ accessToken: string;
39
+ refreshToken?: string;
40
+ }
41
+ export interface AuthProvider {
42
+ authorizeUrl(state: string, redirectUri: string): string;
43
+ exchangeCode(code: string, redirectUri: string): Promise<AuthTokens>;
44
+ refresh(refreshToken: string): Promise<AuthTokens>;
45
+ /** Validate the id token and map its claims to a profile with roles. */
46
+ profile(idToken: string): Promise<AuthProfile>;
47
+ /**
48
+ * Validate a bearer access token (signature, audience, expiry, issuer)
49
+ * and map its claims to a verified-token result. This is what the MCP
50
+ * resource-server middleware calls on every authenticated request — both
51
+ * adapters implement it so the middleware never needs to know which is
52
+ * active.
53
+ */
54
+ verifyBearer(token: string): Promise<VerifiedToken>;
55
+ }
56
+ /** Thrown by verifyBearer when a token's audience doesn't match the configured canonical URI. */
57
+ export declare class AudienceError extends Error {
58
+ constructor(message: string);
59
+ }
60
+ /** Thrown by authorizeUrl/exchangeCode/refresh on an adapter that doesn't run those flows itself. */
61
+ export declare class NotSupportedError extends Error {
62
+ constructor(message: string);
63
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Auth seam — OAuth 2.1 resource-server identity and scope extraction.
3
+ *
4
+ * Default adapter: DelegatingAuthProvider (resource-server-only; an external
5
+ * IdP is the authorization server). Native adapter: SelfHostedAuthProvider
6
+ * (wardby additionally runs the AS role: PKCE /authorize+/token, its own
7
+ * signed tokens).
8
+ */
9
+ /** Thrown by verifyBearer when a token's audience doesn't match the configured canonical URI. */
10
+ export class AudienceError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "AudienceError";
14
+ }
15
+ }
16
+ /** Thrown by authorizeUrl/exchangeCode/refresh on an adapter that doesn't run those flows itself. */
17
+ export class NotSupportedError extends Error {
18
+ constructor(message) {
19
+ super(message);
20
+ this.name = "NotSupportedError";
21
+ }
22
+ }
@@ -0,0 +1,5 @@
1
+ export interface DenyPortListenerHandle {
2
+ port: number;
3
+ close(): Promise<void>;
4
+ }
5
+ export declare function startDenyPortListener(host: string, port: number): Promise<DenyPortListenerHandle>;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The coding proxy's second listener: the *deny port*.
3
+ *
4
+ * It exists only to be unreachable. No run's NetworkPolicy ever permits a
5
+ * coding-run pod to reach it, so a run pod that can connect to the proxy on
6
+ * CODING_PROXY_PORT but not on CODING_PROXY_DENY_PORT has proven its policy is
7
+ * programmed and port-scoped — something no accident can produce, and the one
8
+ * witness a cluster without kube-dns (GKE Autopilot, where Cloud DNS is the
9
+ * only provider) still has.
10
+ *
11
+ * It must therefore serve nothing at all: the socket is never read
12
+ * (`pauseOnConnect`), nothing is ever written to it, and it is destroyed the
13
+ * moment it is accepted. There is no protocol here to attack and no credential
14
+ * to leak — only the fact that the TCP handshake completed.
15
+ */
16
+ import { createServer } from "node:net";
17
+ import { logger } from "../../core/logger.js";
18
+ const denyLog = logger.child({ module: "coding-proxy-deny-port" });
19
+ export async function startDenyPortListener(host, port) {
20
+ const server = createServer({ pauseOnConnect: true }, (socket) => socket.destroy());
21
+ await new Promise((resolve, reject) => {
22
+ // Startup-only: removed the moment listen() succeeds, below, and replaced with a permanent
23
+ // handler — an 'error' event on a net.Server with no listener at all crashes the process.
24
+ const onStartupError = (error) => reject(error);
25
+ server.once("error", onStartupError);
26
+ server.listen(port, host, () => {
27
+ server.removeListener("error", onStartupError);
28
+ resolve();
29
+ });
30
+ });
31
+ const address = server.address();
32
+ const resolvedPort = typeof address === "object" && address ? address.port : port;
33
+ // A later accept-level failure (EMFILE, ENFILE, ECONNABORTED, ...) must not crash the process
34
+ // and must not vanish silently either. These are server-level errors, not connection-level
35
+ // ones, so there is no peer to name here — only the error itself and the listener's own port.
36
+ server.on("error", (error) => {
37
+ denyLog.error({ err: error, port: resolvedPort }, "deny-port listener error");
38
+ });
39
+ return {
40
+ port: resolvedPort,
41
+ close: () => new Promise((resolve, reject) => {
42
+ server.close((error) => (error ? reject(error) : resolve()));
43
+ }),
44
+ };
45
+ }
@@ -0,0 +1,7 @@
1
+ import type { CredentialResolver } from "./types.js";
2
+ /** Resolves credential references only from the trusted proxy process environment. */
3
+ export declare class EnvironmentCredentialResolver implements CredentialResolver {
4
+ private readonly env;
5
+ constructor(env?: NodeJS.ProcessEnv);
6
+ resolve(reference: string): Promise<string>;
7
+ }
@@ -0,0 +1,16 @@
1
+ /** Resolves credential references only from the trusted proxy process environment. */
2
+ export class EnvironmentCredentialResolver {
3
+ env;
4
+ constructor(env = process.env) {
5
+ this.env = env;
6
+ }
7
+ async resolve(reference) {
8
+ const match = /^env:([A-Z][A-Z0-9_]{0,127})$/.exec(reference);
9
+ if (!match)
10
+ throw new Error("coding_credential_reference_invalid");
11
+ const value = this.env[match[1]];
12
+ if (!value)
13
+ throw new Error("coding_credential_unavailable");
14
+ return value;
15
+ }
16
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./metering.js";
2
+ export * from "./memory-ledger.js";
3
+ export * from "./prisma-ledger.js";
4
+ export * from "./proxy.js";
5
+ export * from "./server.js";
6
+ export * from "./secure-fetch.js";
7
+ export * from "./types.js";
@@ -0,0 +1,7 @@
1
+ export * from "./metering.js";
2
+ export * from "./memory-ledger.js";
3
+ export * from "./prisma-ledger.js";
4
+ export * from "./proxy.js";
5
+ export * from "./server.js";
6
+ export * from "./secure-fetch.js";
7
+ export * from "./types.js";
@@ -0,0 +1,17 @@
1
+ import type { CreateProxySessionInput, ProxyLedger, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
2
+ /** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
3
+ export declare class MemoryProxyLedger implements ProxyLedger {
4
+ private readonly sessions;
5
+ private readonly sessionByCapability;
6
+ private readonly requests;
7
+ private readonly requestBySessionKey;
8
+ createSession(input: CreateProxySessionInput): Promise<void>;
9
+ findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
10
+ reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
11
+ complete(requestId: string, usage: ProxyUsage, actualCostUsd: number, upstreamStatus: number): Promise<ProxyRequest>;
12
+ release(requestId: string, upstreamStatus: number): Promise<void>;
13
+ markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
14
+ cancelSession(sessionId: string): Promise<void>;
15
+ getRequest(requestId: string): Promise<ProxyRequest | null>;
16
+ private requiredRequest;
17
+ }