@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,9 @@
1
+ import type { Readable } from "node:stream";
2
+ export interface SafeExtractLimits {
3
+ maxBytes: number;
4
+ maxEntries: number;
5
+ }
6
+ export interface SafeExtractOptions {
7
+ signal?: AbortSignal;
8
+ }
9
+ export declare function safeExtract(source: Readable, root: string, limits: SafeExtractLimits, options?: SafeExtractOptions): Promise<void>;
@@ -0,0 +1,325 @@
1
+ import { chmod, lstat, mkdir, open, readlink, realpath, symlink as createSymlink } from "node:fs/promises";
2
+ import { dirname, isAbsolute, resolve, sep } from "node:path";
3
+ import tar from "tar-stream";
4
+ const MAX_SYMLINK_HOPS = 40;
5
+ function fail(code) {
6
+ throw new Error(code);
7
+ }
8
+ /** "./a/b" -> "a/b"; "./" -> "" (the root itself). Rejects anything that could leave the root. */
9
+ function normalize(name) {
10
+ if (name.includes("\0") || name.startsWith("/"))
11
+ fail("extract_path_invalid");
12
+ let path = name.replace(/^(\.\/)+/, "").replace(/\/+$/, "");
13
+ if (path === ".")
14
+ path = "";
15
+ if (path === "")
16
+ return "";
17
+ const segments = path.split("/");
18
+ if (segments.some((s) => s === "" || s === "." || s === ".."))
19
+ fail("extract_path_invalid");
20
+ return path;
21
+ }
22
+ function inside(root, target) {
23
+ return target === root || target.startsWith(`${root}${sep}`);
24
+ }
25
+ function executableMode(headerMode) {
26
+ return (headerMode ?? 0) & 0o111 ? 0o755 : 0o644;
27
+ }
28
+ /** Maps any error that escaped our own fixed extract_* codes to a path-free fallback. */
29
+ function mapError(err) {
30
+ if (err instanceof Error && /^extract_/.test(err.message))
31
+ return err;
32
+ const code = err?.code;
33
+ if (code === "EEXIST" || code === "ENOTDIR" || code === "ENOTEMPTY")
34
+ return new Error("extract_duplicate_entry");
35
+ return new Error("extract_io");
36
+ }
37
+ /** Lexically applies path components ("." skip, ".." pop, else append) — no filesystem access. */
38
+ function applyLexically(base, components) {
39
+ let current = base;
40
+ for (const component of components) {
41
+ if (component === "" || component === ".")
42
+ continue;
43
+ if (component === "..") {
44
+ current = dirname(current);
45
+ continue;
46
+ }
47
+ current = current === sep ? `${sep}${component}` : `${current}${sep}${component}`;
48
+ }
49
+ return current;
50
+ }
51
+ /**
52
+ * Resolves `components` starting from the already-real `startReal`, like realpath but tolerant of a
53
+ * dangling tail: once a component doesn't exist (or a non-final one isn't a directory), the rest is
54
+ * applied lexically instead of failing. Any symlink encountered along the way is followed for real
55
+ * (readlink + splice its target in front of what's left), which is what catches a chain of in-tree
56
+ * symlinks that composes into a physical escape even though each hop looks fine on its own.
57
+ */
58
+ async function resolveWalk(startReal, components) {
59
+ let current = startReal;
60
+ let remaining = components.slice();
61
+ let hops = 0;
62
+ while (remaining.length > 0) {
63
+ const component = remaining.shift();
64
+ if (component === "" || component === ".")
65
+ continue;
66
+ if (component === "..") {
67
+ current = dirname(current);
68
+ continue;
69
+ }
70
+ const candidate = current === sep ? `${sep}${component}` : `${current}${sep}${component}`;
71
+ let stats;
72
+ try {
73
+ stats = await lstat(candidate);
74
+ }
75
+ catch (err) {
76
+ const code = err.code;
77
+ if (code === "ENOENT" || code === "ENOTDIR") {
78
+ return applyLexically(current, [component, ...remaining]);
79
+ }
80
+ throw err;
81
+ }
82
+ if (stats.isSymbolicLink()) {
83
+ hops += 1;
84
+ if (hops > MAX_SYMLINK_HOPS)
85
+ fail("extract_symlink_escape");
86
+ const linkTarget = await readlink(candidate);
87
+ if (isAbsolute(linkTarget))
88
+ fail("extract_symlink_escape");
89
+ remaining = linkTarget.split("/").concat(remaining);
90
+ continue;
91
+ }
92
+ current = candidate;
93
+ }
94
+ return current;
95
+ }
96
+ export async function safeExtract(source, root, limits, options) {
97
+ const base = resolve(root);
98
+ const recordedSymlinks = new Map();
99
+ const seen = new Set();
100
+ let entries = 0;
101
+ let bytes = 0;
102
+ const extract = tar.extract();
103
+ let rejectFailed;
104
+ const failed = new Promise((_resolve, reject) => {
105
+ rejectFailed = reject;
106
+ });
107
+ failed.catch(() => undefined);
108
+ const onStreamError = (err) => rejectFailed(err);
109
+ extract.once("error", onStreamError);
110
+ source.once("error", onStreamError);
111
+ const signal = options?.signal;
112
+ const onAbort = () => rejectFailed(new Error("extract_aborted"));
113
+ if (signal) {
114
+ if (signal.aborted)
115
+ onAbort();
116
+ else
117
+ signal.addEventListener("abort", onAbort, { once: true });
118
+ }
119
+ function guard(operation) {
120
+ return Promise.race([operation, failed]);
121
+ }
122
+ // Created (and so subscribed to tar-stream's internal 'entry'/'close' events) before any `await`,
123
+ // including the realpath below: tar-stream's async iterator only delivers an entry to listeners that
124
+ // were attached before it was emitted, so creating this after an async gap can silently miss the very
125
+ // first entry and hang forever waiting for one that already came and went.
126
+ const extractIterator = extract[Symbol.asyncIterator]();
127
+ source.pipe(extract);
128
+ try {
129
+ const rootReal = await guard(realpath(base));
130
+ /**
131
+ * Creates (if needed) and verifies every directory named by `segments`, one component at a time,
132
+ * starting from `rootReal`, and returns the resulting real path. For each component: `lstat` it; if
133
+ * it doesn't exist, `mkdir` just that one component (non-recursive — its parent was already verified
134
+ * real by the previous iteration), re-`lstat`ing on a raced `EEXIST`. Then — whether it already
135
+ * existed or was just created — `lstat` it again: if that's a symlink, `extract_through_symlink`
136
+ * (this is what stops phase 2a from creating or `chmod`ing through a symlink an *earlier* entry in
137
+ * this same extraction created, including one that's only a case-insensitive alias of the component
138
+ * being resolved); if it exists but isn't a directory at all, `extract_duplicate_entry` (preserves
139
+ * the existing "file blocking a nested path" behavior). Only once a component is freshly confirmed by
140
+ * `lstat` to be a real, non-symlink directory does it get `chmod`'d to 0o755 — never by a path that
141
+ * was merely assumed to still be what an earlier check saw.
142
+ */
143
+ async function ensureDirectory(segments) {
144
+ let current = rootReal;
145
+ for (const component of segments) {
146
+ const child = current === sep ? `${sep}${component}` : `${current}${sep}${component}`;
147
+ let exists = true;
148
+ try {
149
+ await guard(lstat(child));
150
+ }
151
+ catch (err) {
152
+ if (err.code !== "ENOENT")
153
+ throw err;
154
+ exists = false;
155
+ }
156
+ if (!exists) {
157
+ try {
158
+ await guard(mkdir(child, { mode: 0o755 }));
159
+ }
160
+ catch (err) {
161
+ if (err.code !== "EEXIST")
162
+ throw err;
163
+ }
164
+ }
165
+ const stats = await guard(lstat(child));
166
+ if (stats.isSymbolicLink())
167
+ fail("extract_through_symlink");
168
+ if (!stats.isDirectory())
169
+ fail("extract_duplicate_entry");
170
+ await guard(chmod(child, 0o755));
171
+ current = child;
172
+ }
173
+ return current;
174
+ }
175
+ // Phase 1 (streaming): create directories and regular files; validate and record symlinks.
176
+ for (;;) {
177
+ const step = await guard(extractIterator.next());
178
+ if (step.done)
179
+ break;
180
+ const entry = step.value;
181
+ const { header } = entry;
182
+ entries += 1;
183
+ if (entries > limits.maxEntries) {
184
+ entry.resume();
185
+ fail("extract_entry_limit");
186
+ }
187
+ const path = normalize(header.name);
188
+ if (path === "") {
189
+ entry.resume();
190
+ continue;
191
+ }
192
+ const segments = path.split("/");
193
+ for (let i = 1; i < segments.length; i += 1) {
194
+ if (recordedSymlinks.has(segments.slice(0, i).join("/"))) {
195
+ entry.resume();
196
+ fail("extract_through_symlink");
197
+ }
198
+ }
199
+ if (seen.has(path)) {
200
+ entry.resume();
201
+ fail("extract_duplicate_entry");
202
+ }
203
+ seen.add(path);
204
+ const target = resolve(base, path);
205
+ if (!inside(base, target)) {
206
+ entry.resume();
207
+ fail("extract_path_invalid");
208
+ }
209
+ // Count every entry type's declared size before draining/consuming its body: a symlink (or any
210
+ // other type) can carry a body up to its declared size, and this must be rejected before we ever
211
+ // read a byte of it, not after.
212
+ const declaredSize = header.size ?? 0;
213
+ if (bytes + declaredSize > limits.maxBytes) {
214
+ entry.resume();
215
+ fail("extract_size_limit");
216
+ }
217
+ bytes += declaredSize;
218
+ switch (header.type) {
219
+ case "directory": {
220
+ entry.resume();
221
+ try {
222
+ await ensureDirectory(segments);
223
+ }
224
+ catch (err) {
225
+ throw mapError(err);
226
+ }
227
+ break;
228
+ }
229
+ case "file":
230
+ case "contiguous-file": {
231
+ if (entry.destroyed)
232
+ throw mapError(new Error("entry stream destroyed"));
233
+ let fh;
234
+ try {
235
+ const parentReal = await ensureDirectory(segments.slice(0, -1));
236
+ const fileTarget = resolve(parentReal, segments[segments.length - 1]);
237
+ const openPromise = open(fileTarget, "wx", 0o644);
238
+ try {
239
+ fh = await guard(openPromise);
240
+ }
241
+ catch (err) {
242
+ // If `failed` won the race, `open()` may still resolve later with a real handle that
243
+ // nothing else will ever close — close it then. Harmless (and a no-op) if `open()` itself
244
+ // is what rejected instead, since then it never produced a handle at all.
245
+ openPromise.then((handle) => handle.close().catch(() => undefined)).catch(() => undefined);
246
+ throw err;
247
+ }
248
+ }
249
+ catch (err) {
250
+ throw mapError(err);
251
+ }
252
+ try {
253
+ let streamed = 0;
254
+ const bodyIterator = entry[Symbol.asyncIterator]();
255
+ for (;;) {
256
+ const chunkStep = await guard(bodyIterator.next());
257
+ if (chunkStep.done)
258
+ break;
259
+ const chunk = chunkStep.value;
260
+ streamed += chunk.byteLength;
261
+ if (streamed > limits.maxBytes)
262
+ fail("extract_size_limit");
263
+ await guard(fh.write(chunk));
264
+ }
265
+ await guard(fh.chmod(executableMode(header.mode)));
266
+ }
267
+ finally {
268
+ await fh.close().catch(() => undefined);
269
+ }
270
+ break;
271
+ }
272
+ case "symlink": {
273
+ entry.resume();
274
+ const link = header.linkname ?? "";
275
+ if (link === "" || link.startsWith("/") || !inside(base, resolve(dirname(target), link))) {
276
+ fail("extract_symlink_escape");
277
+ }
278
+ recordedSymlinks.set(path, link);
279
+ break;
280
+ }
281
+ default:
282
+ entry.resume();
283
+ fail("extract_special_entry");
284
+ }
285
+ }
286
+ // Phase 2a: materialize every recorded symlink, now that the real tree is final. `ensureDirectory`
287
+ // rejects (extract_through_symlink) rather than create or chmod through a symlink an earlier
288
+ // iteration of this same loop created — including one that's merely a case-insensitive alias of the
289
+ // parent this symlink names — and a same-path collision with a phase-1-created path surfaces as
290
+ // EEXIST from `symlink()` itself, mapped to extract_duplicate_entry.
291
+ for (const [path, link] of recordedSymlinks) {
292
+ const segments = path.split("/");
293
+ try {
294
+ const parentReal = await ensureDirectory(segments.slice(0, -1));
295
+ const target = resolve(parentReal, segments[segments.length - 1]);
296
+ await guard(createSymlink(link, target));
297
+ }
298
+ catch (err) {
299
+ throw mapError(err);
300
+ }
301
+ }
302
+ // Phase 2b: validate every created symlink against the real filesystem. A lexical check can't see a
303
+ // chain of in-tree symlinks (e.g. s -> "..", t -> "s/..") whose composed, physically-resolved target
304
+ // lands outside root even though each link's own text looks contained.
305
+ for (const [path, link] of recordedSymlinks) {
306
+ const segments = path.split("/");
307
+ const parentReal = await guard(resolveWalk(rootReal, segments.slice(0, -1)));
308
+ const finalReal = await guard(resolveWalk(parentReal, link.split("/")));
309
+ if (!(finalReal === rootReal || finalReal.startsWith(`${rootReal}${sep}`))) {
310
+ fail("extract_symlink_escape");
311
+ }
312
+ }
313
+ }
314
+ catch (err) {
315
+ source.destroy();
316
+ extract.destroy();
317
+ throw mapError(err);
318
+ }
319
+ finally {
320
+ if (signal)
321
+ signal.removeEventListener("abort", onAbort);
322
+ extract.removeListener("error", onStreamError);
323
+ source.removeListener("error", onStreamError);
324
+ }
325
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Trusted control-plane contract for isolated coding jobs. User-controlled
3
+ * values are carried in a versioned input artifact, never expanded into an
4
+ * arbitrary environment map or shell command.
5
+ */
6
+ export interface JobResourceLimits {
7
+ cpus: number;
8
+ memoryMb: number;
9
+ pids: number;
10
+ diskMb: number;
11
+ }
12
+ export interface JobSpec {
13
+ kind: "coding-agent";
14
+ runId: string;
15
+ /** Omitted specs are legacy Codex jobs and retain the single-worker topology. */
16
+ provider?: "codex" | "claude-code";
17
+ image: string;
18
+ /** Required only for Claude's credential-free repository tool container. */
19
+ toolImage?: string;
20
+ inputArtifact: string;
21
+ timeoutSec: number;
22
+ limits: JobResourceLimits;
23
+ labels: Record<string, string>;
24
+ }
25
+ /** Opaque provider reference. Callers persist both fields exactly as given. */
26
+ export interface JobHandle {
27
+ backend: string;
28
+ id: string;
29
+ }
30
+ export type JobStatus = {
31
+ state: "pending" | "running";
32
+ } | {
33
+ state: "succeeded";
34
+ } | {
35
+ state: "failed";
36
+ reason?: string;
37
+ } | {
38
+ state: "stopped";
39
+ } | {
40
+ state: "lost";
41
+ };
42
+ export interface JobResult {
43
+ exitCode: number;
44
+ reason: "completed" | "failed" | "stopped" | "timed_out" | "lost";
45
+ resultArtifact?: string;
46
+ /** Fixed worker-owned failure code; never raw container output. */
47
+ diagnostic?: string;
48
+ }
49
+ /**
50
+ * Lifecycle invariants implemented by every launcher:
51
+ *
52
+ * - `launch` is idempotent by runId for an identical spec and rejects a
53
+ * different spec for the same runId.
54
+ * - pending may become running or terminal; running may become terminal;
55
+ * terminal states never change.
56
+ * - `collect` is repeatable for a terminal job until `remove` succeeds.
57
+ * - `stop` and `remove` are idempotent and best effort; removing an active
58
+ * job is rejected so cleanup cannot silently become an implicit stop.
59
+ * - no operation implicitly relaunches a missing, stopped, or removed job.
60
+ */
61
+ export interface JobLauncher {
62
+ /**
63
+ * The handle `launch(spec)` will return, when a backend can derive it from the spec alone with no
64
+ * side effects. Callers persist it *before* launching, so a crash mid-launch still leaves a handle
65
+ * to stop and remove the run's resources with. `launch` must return an equal handle. Backends that
66
+ * cannot know the handle in advance omit this, and callers persist only after `launch` returns.
67
+ */
68
+ plannedHandle?: (spec: JobSpec) => JobHandle | undefined;
69
+ launch: (spec: JobSpec) => Promise<JobHandle>;
70
+ status: (handle: JobHandle) => Promise<JobStatus>;
71
+ collect: (handle: JobHandle) => Promise<JobResult>;
72
+ stop: (handle: JobHandle, reason?: string) => Promise<void>;
73
+ remove: (handle: JobHandle) => Promise<void>;
74
+ }
75
+ /** A launcher that can safely copy a terminal worker workspace back to trusted storage. */
76
+ export interface WorkspaceJobLauncher extends JobLauncher {
77
+ materializeWorkspace: (handle: JobHandle, destination: string) => Promise<void>;
78
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Trusted control-plane contract for isolated coding jobs. User-controlled
3
+ * values are carried in a versioned input artifact, never expanded into an
4
+ * arbitrary environment map or shell command.
5
+ */
6
+ export {};
@@ -0,0 +1,2 @@
1
+ /** Fills a fresh staging directory next to `destination`, validates it, then atomically swaps it into place. */
2
+ export declare function replaceDirectoryFromStaging(destination: string, maxBytes: number, destinationInvalidError: string, fill: (staging: string) => Promise<void>): Promise<void>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Replaces a trusted workspace directory with a freshly filled copy, shared by
3
+ * the Docker and Kubernetes launchers. The copy is filled into a staging
4
+ * directory beside the destination, validated, and only then swapped into
5
+ * place by rename, with the original restored if the swap fails.
6
+ *
7
+ * A fill that rejects has, by definition, produced an untrusted tree (it may
8
+ * contain escaping symlinks): it is never walked, validated, or renamed — the
9
+ * staging directory is removed with `rm({ recursive, force })`, which unlinks
10
+ * symlinks rather than following them.
11
+ */
12
+ import { lstat, mkdtemp, realpath, rename, rm } from "node:fs/promises";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import { validateMaterializedWorkspace } from "./docker.js";
15
+ /** Fills a fresh staging directory next to `destination`, validates it, then atomically swaps it into place. */
16
+ export async function replaceDirectoryFromStaging(destination, maxBytes, destinationInvalidError, fill) {
17
+ const target = resolve(destination);
18
+ const parent = dirname(target);
19
+ const [parentReal, targetReal, targetStat] = await Promise.all([realpath(parent), realpath(target), lstat(target)]);
20
+ if (!targetStat.isDirectory() ||
21
+ targetStat.isSymbolicLink() ||
22
+ targetReal !== resolve(parentReal, target.slice(parent.length + 1))) {
23
+ throw new Error(destinationInvalidError);
24
+ }
25
+ const staging = await mkdtemp(join(parentReal, ".wardby-workspace-stage-"));
26
+ const backup = await mkdtemp(join(parentReal, ".wardby-workspace-backup-"));
27
+ await rm(backup, { recursive: true });
28
+ let targetMoved = false;
29
+ try {
30
+ await fill(staging);
31
+ await validateMaterializedWorkspace(staging, maxBytes);
32
+ await rename(targetReal, backup);
33
+ targetMoved = true;
34
+ await rename(staging, targetReal);
35
+ targetMoved = false;
36
+ await rm(backup, { recursive: true, force: true });
37
+ }
38
+ catch (error) {
39
+ if (targetMoved)
40
+ await rename(backup, targetReal).catch(() => undefined);
41
+ throw error;
42
+ }
43
+ finally {
44
+ await rm(staging, { recursive: true, force: true });
45
+ await rm(backup, { recursive: true, force: true });
46
+ }
47
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Direct Anthropic (Claude) adapter for the LlmProvider seam. `@anthropic-ai/sdk`
3
+ * is imported only here; all protocol/pricing-dispatch logic lives in the
4
+ * shared ClaudeLlmProvider base class (claude-provider.ts) — this file's only
5
+ * job is constructing the right client and pricing module.
6
+ */
7
+ import Anthropic from "@anthropic-ai/sdk";
8
+ import { ClaudeLlmProvider } from "./claude-provider.js";
9
+ export { anthropicSupportedModels } from "./pricing-anthropic.js";
10
+ export declare function anthropicCredentialsPresent(env?: NodeJS.ProcessEnv): boolean;
11
+ export declare class AnthropicLlmProvider extends ClaudeLlmProvider {
12
+ constructor(apiKey?: string, client?: Anthropic);
13
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Direct Anthropic (Claude) adapter for the LlmProvider seam. `@anthropic-ai/sdk`
3
+ * is imported only here; all protocol/pricing-dispatch logic lives in the
4
+ * shared ClaudeLlmProvider base class (claude-provider.ts) — this file's only
5
+ * job is constructing the right client and pricing module.
6
+ */
7
+ import Anthropic from "@anthropic-ai/sdk";
8
+ import { ClaudeLlmProvider } from "./claude-provider.js";
9
+ import { anthropicPriceUsd, getAnthropicPricing } from "./pricing-anthropic.js";
10
+ export { anthropicSupportedModels } from "./pricing-anthropic.js";
11
+ export function anthropicCredentialsPresent(env = process.env) {
12
+ return Boolean(env.ANTHROPIC_API_KEY);
13
+ }
14
+ export class AnthropicLlmProvider extends ClaudeLlmProvider {
15
+ constructor(apiKey = process.env.ANTHROPIC_API_KEY ?? "", client) {
16
+ if (!client && !apiKey) {
17
+ throw new Error("ANTHROPIC_API_KEY is not set — required by the Anthropic LlmProvider adapter.");
18
+ }
19
+ super(client ?? new Anthropic({ apiKey }), { getPricing: getAnthropicPricing, priceUsd: anthropicPriceUsd });
20
+ }
21
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Bedrock-Claude adapter for the LlmProvider seam. `@anthropic-ai/bedrock-sdk`
3
+ * is imported only here; all protocol/pricing-dispatch logic lives in the
4
+ * shared ClaudeLlmProvider base class (claude-provider.ts) — AnthropicBedrock
5
+ * exposes the identical .messages.stream() surface as @anthropic-ai/sdk, so
6
+ * this file's only job is constructing the right client and pricing module.
7
+ *
8
+ * Named BedrockClaudeLlmProvider, not BedrockLlmProvider: Bedrock hosts
9
+ * multiple model vendors, and this adapter only ever speaks the
10
+ * Anthropic-native protocol for Claude models. A future non-Claude Bedrock
11
+ * adapter gets its own name, not a rename of this one.
12
+ */
13
+ import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
14
+ import { ClaudeLlmProvider } from "./claude-provider.js";
15
+ export { bedrockClaudeSupportedModels } from "./pricing-bedrock-claude.js";
16
+ export declare function bedrockCredentialsPresent(env?: NodeJS.ProcessEnv): boolean;
17
+ export declare class BedrockClaudeLlmProvider extends ClaudeLlmProvider {
18
+ constructor(region?: string, client?: AnthropicBedrock);
19
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Bedrock-Claude adapter for the LlmProvider seam. `@anthropic-ai/bedrock-sdk`
3
+ * is imported only here; all protocol/pricing-dispatch logic lives in the
4
+ * shared ClaudeLlmProvider base class (claude-provider.ts) — AnthropicBedrock
5
+ * exposes the identical .messages.stream() surface as @anthropic-ai/sdk, so
6
+ * this file's only job is constructing the right client and pricing module.
7
+ *
8
+ * Named BedrockClaudeLlmProvider, not BedrockLlmProvider: Bedrock hosts
9
+ * multiple model vendors, and this adapter only ever speaks the
10
+ * Anthropic-native protocol for Claude models. A future non-Claude Bedrock
11
+ * adapter gets its own name, not a rename of this one.
12
+ */
13
+ import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
14
+ import { ClaudeLlmProvider } from "./claude-provider.js";
15
+ import { bedrockClaudePriceUsd, getBedrockClaudePricing } from "./pricing-bedrock-claude.js";
16
+ export { bedrockClaudeSupportedModels } from "./pricing-bedrock-claude.js";
17
+ export function bedrockCredentialsPresent(env = process.env) {
18
+ // A region is the one thing Bedrock always needs; AWS resolves actual
19
+ // credentials from the standard default chain (env keys, shared config,
20
+ // IAM role) — this only gates whether the adapter registers at all.
21
+ return Boolean(env.BEDROCK_REGION ?? env.AWS_REGION);
22
+ }
23
+ export class BedrockClaudeLlmProvider extends ClaudeLlmProvider {
24
+ constructor(region = process.env.BEDROCK_REGION ?? process.env.AWS_REGION ?? "", client) {
25
+ if (!client && !region) {
26
+ throw new Error("BEDROCK_REGION (or AWS_REGION) is required by the Bedrock Claude LlmProvider adapter.");
27
+ }
28
+ super(client ?? new AnthropicBedrock({ awsRegion: region }), {
29
+ getPricing: getBedrockClaudePricing,
30
+ priceUsd: bedrockClaudePriceUsd,
31
+ });
32
+ }
33
+ }
@@ -0,0 +1,106 @@
1
+ import type { LlmMessage, LlmRequest, LlmToolDef, LlmStreamEvent, LlmUsage } from "./types.js";
2
+ export interface CacheControl {
3
+ type: "ephemeral";
4
+ }
5
+ export interface ClaudeTextBlock {
6
+ type: "text";
7
+ text: string;
8
+ cache_control?: CacheControl;
9
+ }
10
+ export interface ClaudeToolUseBlock {
11
+ type: "tool_use";
12
+ id: string;
13
+ name: string;
14
+ input: unknown;
15
+ cache_control?: CacheControl;
16
+ }
17
+ export interface ClaudeToolResultBlock {
18
+ type: "tool_result";
19
+ tool_use_id: string;
20
+ content: string;
21
+ cache_control?: CacheControl;
22
+ }
23
+ export type ClaudeContentBlock = ClaudeTextBlock | ClaudeToolUseBlock | ClaudeToolResultBlock;
24
+ export interface ClaudeMessage {
25
+ role: "user" | "assistant";
26
+ content: ClaudeContentBlock[];
27
+ }
28
+ export interface ClaudeTool {
29
+ name: string;
30
+ description: string;
31
+ input_schema: Record<string, unknown>;
32
+ cache_control?: CacheControl;
33
+ }
34
+ export interface ClaudeRequest {
35
+ system?: ClaudeTextBlock[];
36
+ messages: ClaudeMessage[];
37
+ tools?: ClaudeTool[];
38
+ max_tokens: number;
39
+ }
40
+ /**
41
+ * Same shape sent to the API in `toClaudeRequest` — kept as one function so
42
+ * a pre-flight token estimate (AnthropicLlmProvider.countTokens) can never
43
+ * drift from what's actually serialized into the request. Mirrors the
44
+ * OpenAI adapter's `toOpenAiTools`, which guards against the same failure
45
+ * class: a duplicated tool-schema mapping once desynced the pre-flight
46
+ * estimate from the real request and broke the budget guardrail's turn-1
47
+ * refuse guarantee (measured 44-52% under-count).
48
+ */
49
+ export declare function toClaudeTools(tools: LlmToolDef[]): ClaudeTool[];
50
+ /**
51
+ * Raw (pre-inflation) offline token estimate shared by every Claude-protocol
52
+ * adapter. Each caller applies its own inflation constant on top.
53
+ */
54
+ export declare function estimateClaudeTokens(messages: LlmMessage[], tools?: LlmToolDef[]): number;
55
+ export declare function toClaudeRequest(req: LlmRequest, defaultMaxTokens: number): ClaudeRequest;
56
+ /**
57
+ * Two-breakpoint canonical caching. Anthropic's cache order is
58
+ * tools -> system -> messages, so a breakpoint on the last system block
59
+ * caches tools+system (static across the run). A rolling breakpoint on the
60
+ * last message's final block grows the conversation cache each turn.
61
+ * Sub-minimum prefixes (1024/2048 tokens) are silently un-cached by Anthropic.
62
+ */
63
+ export declare function withCacheBreakpoints(req: ClaudeRequest): ClaudeRequest;
64
+ interface ClaudeUsage {
65
+ input_tokens?: number;
66
+ cache_read_input_tokens?: number;
67
+ cache_creation_input_tokens?: number;
68
+ output_tokens?: number;
69
+ }
70
+ export type ClaudeStreamEvent = {
71
+ type: "message_start";
72
+ message: {
73
+ usage: ClaudeUsage;
74
+ };
75
+ } | {
76
+ type: "content_block_start";
77
+ index: number;
78
+ content_block: {
79
+ type: "text" | "tool_use";
80
+ id?: string;
81
+ name?: string;
82
+ };
83
+ } | {
84
+ type: "content_block_delta";
85
+ index: number;
86
+ delta: {
87
+ type: "text_delta";
88
+ text: string;
89
+ } | {
90
+ type: "input_json_delta";
91
+ partial_json: string;
92
+ };
93
+ } | {
94
+ type: "content_block_stop";
95
+ index: number;
96
+ } | {
97
+ type: "message_delta";
98
+ delta: {
99
+ stop_reason?: string;
100
+ };
101
+ usage?: ClaudeUsage;
102
+ } | {
103
+ type: "message_stop";
104
+ };
105
+ export declare function mapClaudeStream(events: AsyncIterable<ClaudeStreamEvent>, priceUsd: (usage: LlmUsage) => number): AsyncIterable<LlmStreamEvent>;
106
+ export {};