@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,140 @@
1
+ import { request as httpRequest } from "node:http";
2
+ import { request as httpsRequest } from "node:https";
3
+ import { Writable } from "node:stream";
4
+ import { pipeline } from "node:stream/promises";
5
+ import { createGunzip, createInflate, createBrotliDecompress } from "node:zlib";
6
+ import { resolveDestination } from "./fetch-policy.js";
7
+ import { BRIDGE_INPUT_BYTES, FETCH_RESPONSE_BYTES, FETCH_TIMEOUT_MS, MAX_REDIRECTS } from "./limits.js";
8
+ export function pinnedLookup(destination) {
9
+ return (_, options, callback) => {
10
+ if (options?.all)
11
+ callback(null, [{ address: destination.address, family: destination.family }]);
12
+ else
13
+ callback(null, destination.address, destination.family);
14
+ };
15
+ }
16
+ export function requestPinned(destination, init, signal) {
17
+ return new Promise((resolve, reject) => {
18
+ // The URL preserves Host and TLS SNI. Only the vetted address reaches the socket.
19
+ const request = (destination.url.protocol === "https:" ? httpsRequest : httpRequest)(destination.url, {
20
+ method: init.method,
21
+ headers: init.headers,
22
+ lookup: pinnedLookup(destination),
23
+ family: destination.family,
24
+ agent: false,
25
+ signal,
26
+ maxHeaderSize: 16 * 1024,
27
+ }, resolve);
28
+ request.once("error", reject);
29
+ request.end(init.body);
30
+ });
31
+ }
32
+ async function untilAbort(promise, signal) {
33
+ signal.throwIfAborted();
34
+ return new Promise((resolve, reject) => {
35
+ const abort = () => reject(new Error("fetch_cancelled_or_timeout"));
36
+ signal.addEventListener("abort", abort, { once: true });
37
+ promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
38
+ });
39
+ }
40
+ export async function safeFetch(input, init = {}, options = {}) {
41
+ const abort = new AbortController();
42
+ const timer = setTimeout(() => abort.abort(new Error("fetch_timeout")), FETCH_TIMEOUT_MS);
43
+ const signal = options.signal ? AbortSignal.any([options.signal, abort.signal]) : abort.signal;
44
+ let url = input;
45
+ let method = init.method ?? "GET";
46
+ let body = init.body;
47
+ let headers = Object.fromEntries(Object.entries(init.headers ?? {}).map(([k, v]) => [k.toLowerCase(), v]));
48
+ let response;
49
+ try {
50
+ if (!/^(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS)$/.test(method))
51
+ throw new Error("fetch_method_invalid");
52
+ if (body !== undefined && (typeof body !== "string" || Buffer.byteLength(body) > BRIDGE_INPUT_BYTES))
53
+ throw new Error("fetch_body_limit");
54
+ if (Object.keys(headers).some((k) => ["host", "connection", "transfer-encoding", "content-length", "upgrade", "proxy-connection"].includes(k)))
55
+ throw new Error("fetch_header_invalid");
56
+ headers["accept-encoding"] = "identity";
57
+ for (let hop = 0;; hop++) {
58
+ signal.throwIfAborted();
59
+ const destination = await untilAbort(resolveDestination(url, options), signal);
60
+ signal.throwIfAborted();
61
+ response = await (options.connect ?? requestPinned)(destination, { method, headers, body }, signal);
62
+ const status = response.statusCode ?? 0;
63
+ if ([301, 302, 303, 307, 308].includes(status) && response.headers.location) {
64
+ response.destroy();
65
+ if (hop >= MAX_REDIRECTS)
66
+ throw new Error("fetch_redirect_limit");
67
+ const next = new URL(response.headers.location, destination.url);
68
+ if ((status === 303 && method !== "HEAD") || ((status === 301 || status === 302) && method === "POST")) {
69
+ method = "GET";
70
+ body = undefined;
71
+ delete headers["content-type"];
72
+ }
73
+ if (next.origin !== destination.url.origin) {
74
+ if (body)
75
+ throw new Error("fetch_cross_origin_body_blocked");
76
+ // Only non-credential headers survive; custom API-key headers must not leak either.
77
+ headers = Object.fromEntries(Object.entries(headers).filter(([key]) => ["accept", "accept-language", "content-type", "user-agent", "accept-encoding"].includes(key)));
78
+ }
79
+ url = next.href;
80
+ continue;
81
+ }
82
+ let encoded = 0;
83
+ response.on("data", (chunk) => {
84
+ encoded += chunk.length;
85
+ if (encoded > FETCH_RESPONSE_BYTES)
86
+ response.destroy(new Error("fetch_response_limit"));
87
+ });
88
+ const encoding = response.headers["content-encoding"];
89
+ const decoder = encoding === "gzip"
90
+ ? createGunzip()
91
+ : encoding === "deflate"
92
+ ? createInflate()
93
+ : encoding === "br"
94
+ ? createBrotliDecompress()
95
+ : undefined;
96
+ if (encoding && encoding !== "identity" && !decoder)
97
+ throw new Error("fetch_encoding_invalid");
98
+ const chunks = [];
99
+ let size = 0;
100
+ const sink = new Writable({
101
+ write(chunk, _, callback) {
102
+ size += chunk.length;
103
+ if (size > FETCH_RESPONSE_BYTES)
104
+ callback(new Error("fetch_response_limit"));
105
+ else {
106
+ chunks.push(chunk);
107
+ callback();
108
+ }
109
+ },
110
+ });
111
+ if (decoder)
112
+ await pipeline(response, decoder, sink, { signal });
113
+ else
114
+ await pipeline(response, sink, { signal });
115
+ const resultHeaders = Object.fromEntries(Object.entries(response.headers)
116
+ .filter(([key]) => !["content-encoding", "content-length", "set-cookie"].includes(key))
117
+ .map(([key, value]) => [key, Array.isArray(value) ? value.join(", ") : (value ?? "")]));
118
+ return {
119
+ ok: status >= 200 && status < 300,
120
+ status,
121
+ statusText: response.statusMessage ?? "",
122
+ url: destination.url.href,
123
+ headers: resultHeaders,
124
+ bodyBase64: Buffer.concat(chunks, size).toString("base64"),
125
+ };
126
+ }
127
+ }
128
+ catch (err) {
129
+ if (signal.aborted)
130
+ throw new Error("fetch_cancelled_or_timeout", { cause: err });
131
+ if (err instanceof Error && /^fetch_/.test(err.message))
132
+ throw err;
133
+ throw new Error("fetch_failed", { cause: err });
134
+ }
135
+ finally {
136
+ clearTimeout(timer);
137
+ response?.destroy();
138
+ abort.abort();
139
+ }
140
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Per-attachment capability scoping for sandboxed tools (OWASP LLM08 —
3
+ * Excessive Agency fix): which secrets, datastore key prefixes, and fetch
4
+ * hosts a tool may touch, declared once at `attach_tool` time and persisted
5
+ * as `Json` on `AgentTool`. Mirrors the coding-agent profile's own
6
+ * bounded-array + zod-schema convention (`src/coding/profile.ts`) rather
7
+ * than a native Postgres array column.
8
+ */
9
+ import { z } from "zod";
10
+ export declare const MAX_ALLOWED_SECRETS = 64;
11
+ export declare const MAX_ALLOWED_DATASTORE_PREFIXES = 64;
12
+ export declare const MAX_ALLOWED_HOSTS = 64;
13
+ export declare const MAX_ALLOWED_SHARED_DATASTORES = 16;
14
+ /** Element that lifts the fetch allowlist entirely for a tool (existing SSRF protection against private/link-local addresses still applies). */
15
+ export declare const FETCH_WILDCARD = "*";
16
+ /** Full capability set — used when creating a brand-new attachment (unset fields default to deny-all). */
17
+ export declare const ToolCapabilitiesSchema: z.ZodObject<{
18
+ allowedSecrets: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">, string[], string[]>>;
19
+ allowedDatastorePrefixes: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">, string[], string[]>>;
20
+ allowedHosts: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, "many">, string[], string[]>>;
21
+ allowedSharedDatastorePrefixes: z.ZodDefault<z.ZodEffects<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>, Record<string, string[]>, Record<string, string[]>>>;
22
+ }, "strict", z.ZodTypeAny, {
23
+ allowedSecrets: string[];
24
+ allowedDatastorePrefixes: string[];
25
+ allowedHosts: string[];
26
+ allowedSharedDatastorePrefixes: Record<string, string[]>;
27
+ }, {
28
+ allowedSecrets?: string[] | undefined;
29
+ allowedDatastorePrefixes?: string[] | undefined;
30
+ allowedHosts?: string[] | undefined;
31
+ allowedSharedDatastorePrefixes?: Record<string, string[]> | undefined;
32
+ }>;
33
+ /** Partial capability set — used when re-declaring capabilities on an attachment that already exists; an omitted field leaves that field untouched. */
34
+ export declare const ToolCapabilitiesPatchSchema: z.ZodObject<{
35
+ allowedSecrets: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">, string[], string[]>>;
36
+ allowedDatastorePrefixes: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">, string[], string[]>>;
37
+ allowedHosts: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, "many">, string[], string[]>>;
38
+ allowedSharedDatastorePrefixes: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>, Record<string, string[]>, Record<string, string[]>>>;
39
+ }, "strict", z.ZodTypeAny, {
40
+ allowedSecrets?: string[] | undefined;
41
+ allowedDatastorePrefixes?: string[] | undefined;
42
+ allowedHosts?: string[] | undefined;
43
+ allowedSharedDatastorePrefixes?: Record<string, string[]> | undefined;
44
+ }, {
45
+ allowedSecrets?: string[] | undefined;
46
+ allowedDatastorePrefixes?: string[] | undefined;
47
+ allowedHosts?: string[] | undefined;
48
+ allowedSharedDatastorePrefixes?: Record<string, string[]> | undefined;
49
+ }>;
50
+ export type ToolCapabilities = z.infer<typeof ToolCapabilitiesSchema>;
51
+ export type ToolCapabilitiesPatch = z.infer<typeof ToolCapabilitiesPatchSchema>;
52
+ /**
53
+ * Coerces a Prisma `Json` column back into a string[]. Only
54
+ * `ToolCapabilitiesSchema`-validated data is ever written to these columns,
55
+ * but a DB read is never trusted blindly — malformed/foreign data degrades
56
+ * to "no capability" rather than throwing mid-run.
57
+ */
58
+ export declare function asStringArray(value: unknown): string[];
59
+ /**
60
+ * Coerces a Prisma `Json` column back into a Record<string, string[]>. Only
61
+ * `ToolCapabilitiesSchema`-validated data is ever written to this column,
62
+ * but a DB read is never trusted blindly — malformed/foreign data degrades
63
+ * to "no capability" (missing key, or an empty array for a malformed value)
64
+ * rather than throwing mid-run.
65
+ */
66
+ export declare function asPrefixMap(value: unknown): Record<string, string[]>;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Per-attachment capability scoping for sandboxed tools (OWASP LLM08 —
3
+ * Excessive Agency fix): which secrets, datastore key prefixes, and fetch
4
+ * hosts a tool may touch, declared once at `attach_tool` time and persisted
5
+ * as `Json` on `AgentTool`. Mirrors the coding-agent profile's own
6
+ * bounded-array + zod-schema convention (`src/coding/profile.ts`) rather
7
+ * than a native Postgres array column.
8
+ */
9
+ import { z } from "zod";
10
+ import { normalizeHost } from "./fetch-policy.js";
11
+ export const MAX_ALLOWED_SECRETS = 64;
12
+ export const MAX_ALLOWED_DATASTORE_PREFIXES = 64;
13
+ export const MAX_ALLOWED_HOSTS = 64;
14
+ export const MAX_ALLOWED_SHARED_DATASTORES = 16;
15
+ const MAX_SECRET_NAME_BYTES = 1024;
16
+ const MAX_DATASTORE_PREFIX_BYTES = 1024;
17
+ /** Element that lifts the fetch allowlist entirely for a tool (existing SSRF protection against private/link-local addresses still applies). */
18
+ export const FETCH_WILDCARD = "*";
19
+ function byteLength(value) {
20
+ return Buffer.byteLength(value, "utf8");
21
+ }
22
+ function isValidHostToken(value) {
23
+ if (value === FETCH_WILDCARD)
24
+ return true;
25
+ try {
26
+ normalizeHost(value);
27
+ return true;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ const secretNameSchema = z
34
+ .string()
35
+ .refine((v) => byteLength(v) <= MAX_SECRET_NAME_BYTES, `must be at most ${MAX_SECRET_NAME_BYTES} UTF-8 bytes`);
36
+ const datastorePrefixSchema = z
37
+ .string()
38
+ .refine((v) => byteLength(v) <= MAX_DATASTORE_PREFIX_BYTES, `must be at most ${MAX_DATASTORE_PREFIX_BYTES} UTF-8 bytes`);
39
+ const fetchHostSchema = z
40
+ .string()
41
+ .refine(isValidHostToken, `must be "${FETCH_WILDCARD}" or a normalizable hostname`)
42
+ .transform((v) => (v === FETCH_WILDCARD ? FETCH_WILDCARD : normalizeHost(v)));
43
+ const sharedDatastorePrefixesSchema = z
44
+ .record(secretNameSchema, z.array(datastorePrefixSchema).max(MAX_ALLOWED_DATASTORE_PREFIXES))
45
+ .refine((v) => Object.keys(v).length <= MAX_ALLOWED_SHARED_DATASTORES, `at most ${MAX_ALLOWED_SHARED_DATASTORES} shared datastore bindings`);
46
+ const toolCapabilityFields = {
47
+ allowedSecrets: z
48
+ .array(secretNameSchema)
49
+ .max(MAX_ALLOWED_SECRETS)
50
+ .transform((v) => [...new Set(v)]),
51
+ allowedDatastorePrefixes: z
52
+ .array(datastorePrefixSchema)
53
+ .max(MAX_ALLOWED_DATASTORE_PREFIXES)
54
+ .transform((v) => [...new Set(v)]),
55
+ allowedHosts: z
56
+ .array(fetchHostSchema)
57
+ .max(MAX_ALLOWED_HOSTS)
58
+ .transform((v) => [...new Set(v)]),
59
+ allowedSharedDatastorePrefixes: sharedDatastorePrefixesSchema,
60
+ };
61
+ /** Full capability set — used when creating a brand-new attachment (unset fields default to deny-all). */
62
+ export const ToolCapabilitiesSchema = z
63
+ .object({
64
+ allowedSecrets: toolCapabilityFields.allowedSecrets.default([]),
65
+ allowedDatastorePrefixes: toolCapabilityFields.allowedDatastorePrefixes.default([]),
66
+ allowedHosts: toolCapabilityFields.allowedHosts.default([]),
67
+ allowedSharedDatastorePrefixes: toolCapabilityFields.allowedSharedDatastorePrefixes.default({}),
68
+ })
69
+ .strict();
70
+ /** Partial capability set — used when re-declaring capabilities on an attachment that already exists; an omitted field leaves that field untouched. */
71
+ export const ToolCapabilitiesPatchSchema = z
72
+ .object({
73
+ allowedSecrets: toolCapabilityFields.allowedSecrets.optional(),
74
+ allowedDatastorePrefixes: toolCapabilityFields.allowedDatastorePrefixes.optional(),
75
+ allowedHosts: toolCapabilityFields.allowedHosts.optional(),
76
+ allowedSharedDatastorePrefixes: toolCapabilityFields.allowedSharedDatastorePrefixes.optional(),
77
+ })
78
+ .strict();
79
+ /**
80
+ * Coerces a Prisma `Json` column back into a string[]. Only
81
+ * `ToolCapabilitiesSchema`-validated data is ever written to these columns,
82
+ * but a DB read is never trusted blindly — malformed/foreign data degrades
83
+ * to "no capability" rather than throwing mid-run.
84
+ */
85
+ export function asStringArray(value) {
86
+ return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
87
+ }
88
+ /**
89
+ * Coerces a Prisma `Json` column back into a Record<string, string[]>. Only
90
+ * `ToolCapabilitiesSchema`-validated data is ever written to this column,
91
+ * but a DB read is never trusted blindly — malformed/foreign data degrades
92
+ * to "no capability" (missing key, or an empty array for a malformed value)
93
+ * rather than throwing mid-run.
94
+ */
95
+ export function asPrefixMap(value) {
96
+ if (typeof value !== "object" || value === null || Array.isArray(value))
97
+ return {};
98
+ const out = {};
99
+ for (const [key, v] of Object.entries(value)) {
100
+ out[key] = asStringArray(v);
101
+ }
102
+ return out;
103
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Zod-in-sandbox: the tool author's Zod schema is *source text*, compiled
3
+ * and evaluated inside the QuickJS sandbox — never `new Function`/`eval` in
4
+ * the host process. Two operations, both reusing eval-core.ts's isolated
5
+ * eval (pure computation, no host I/O — `installExtras` is a no-op):
6
+ *
7
+ * - `deriveJsonSchema`: registration-time. Compiles the schema and derives
8
+ * its JSON Schema (via the vendored `zod-to-json-schema`) — what's sent
9
+ * to the model as the tool's `parameters`. A malformed schema fails here,
10
+ * not at call time.
11
+ * - `validateParams`: call-time. Compiles the same schema (again, inside
12
+ * the sandbox) and parses the model-supplied arguments against it.
13
+ * Zod's own validation error (a real thrown `ZodError`, whose `.message`
14
+ * is already a readable issue list) becomes the sandbox failure the
15
+ * engine feeds back to the model as a tool-result error — not a run
16
+ * failure.
17
+ */
18
+ import { type SandboxResult } from "./eval-core.js";
19
+ /** Registration-time: compiles the schema source and derives its JSON Schema. */
20
+ export declare function deriveJsonSchema(paramsZodSource: string): Promise<SandboxResult>;
21
+ /** Call-time: compiles the schema source and validates the model-supplied args against it. */
22
+ export declare function validateParams(paramsZodSource: string, rawArgs: unknown): Promise<SandboxResult>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Zod-in-sandbox: the tool author's Zod schema is *source text*, compiled
3
+ * and evaluated inside the QuickJS sandbox — never `new Function`/`eval` in
4
+ * the host process. Two operations, both reusing eval-core.ts's isolated
5
+ * eval (pure computation, no host I/O — `installExtras` is a no-op):
6
+ *
7
+ * - `deriveJsonSchema`: registration-time. Compiles the schema and derives
8
+ * its JSON Schema (via the vendored `zod-to-json-schema`) — what's sent
9
+ * to the model as the tool's `parameters`. A malformed schema fails here,
10
+ * not at call time.
11
+ * - `validateParams`: call-time. Compiles the same schema (again, inside
12
+ * the sandbox) and parses the model-supplied arguments against it.
13
+ * Zod's own validation error (a real thrown `ZodError`, whose `.message`
14
+ * is already a readable issue list) becomes the sandbox failure the
15
+ * engine feeds back to the model as a tool-result error — not a run
16
+ * failure.
17
+ */
18
+ import { readFileSync } from "node:fs";
19
+ import { fileURLToPath } from "node:url";
20
+ import path from "node:path";
21
+ import { evalToJson } from "./eval-core.js";
22
+ const GENERATED_DIR = fileURLToPath(new URL("./generated/", import.meta.url));
23
+ let vendorPreludeCache;
24
+ function getVendorPrelude() {
25
+ if (vendorPreludeCache)
26
+ return vendorPreludeCache;
27
+ let zodBundle;
28
+ let zodToJsonSchemaBundle;
29
+ try {
30
+ zodBundle = readFileSync(path.join(GENERATED_DIR, "zod.bundle.js"), "utf8");
31
+ zodToJsonSchemaBundle = readFileSync(path.join(GENERATED_DIR, "zod-to-json-schema.bundle.js"), "utf8");
32
+ }
33
+ catch (err) {
34
+ throw new Error(`Sandbox vendor bundles missing (run "npm run build:vendor" first): ${err instanceof Error ? err.message : String(err)}`, { cause: err });
35
+ }
36
+ vendorPreludeCache =
37
+ `${zodBundle}\n${zodToJsonSchemaBundle}\n` +
38
+ `const z = __zodModule.default.z;\n` +
39
+ `const zodToJsonSchema = __zodToJsonSchemaModule.default.zodToJsonSchema;\n`;
40
+ return vendorPreludeCache;
41
+ }
42
+ /** Registration-time: compiles the schema source and derives its JSON Schema. */
43
+ export async function deriveJsonSchema(paramsZodSource) {
44
+ const code = `${getVendorPrelude()}
45
+ (async () => {
46
+ const schema = (${paramsZodSource});
47
+ return JSON.stringify(zodToJsonSchema(schema));
48
+ })()`;
49
+ return evalToJson(code, undefined, () => { });
50
+ }
51
+ /** Call-time: compiles the schema source and validates the model-supplied args against it. */
52
+ export async function validateParams(paramsZodSource, rawArgs) {
53
+ const code = `${getVendorPrelude()}
54
+ (async () => {
55
+ const schema = (${paramsZodSource});
56
+ const args = ${JSON.stringify(rawArgs)};
57
+ return JSON.stringify(schema.parse(args));
58
+ })()`;
59
+ return evalToJson(code, undefined, () => { });
60
+ }
@@ -0,0 +1,14 @@
1
+ import type { McpProviders } from "./mcp/context.js";
2
+ export interface ServeOptions {
3
+ /** Scheduler lease scope; defaults to "default" like `wardby scheduler --scope`. */
4
+ scope?: string;
5
+ /** Pre-built providers (tests); built once via buildMcpProviders() when omitted. */
6
+ providers?: McpProviders;
7
+ }
8
+ export interface ServeHandle {
9
+ /** Stops accepting schedule claims, then reconciling, then closes HTTP and the executor. */
10
+ close(): Promise<void>;
11
+ /** Whether this process currently holds the scheduler lease. */
12
+ isLeader(): boolean;
13
+ }
14
+ export declare function startServe(options?: ServeOptions): Promise<ServeHandle>;
package/dist/serve.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `wardby serve`: the complete wardby process. Runs the MCP server, the
3
+ * scheduler, and the reconciler together on ONE provider set and ONE
4
+ * executor, which is what a single-container deployment (Cloud Run, a lone
5
+ * VM) needs - `wardby mcp` alone never fires a schedule.
6
+ *
7
+ * Why one executor: DbosExecutor is a per-process singleton and refuses to
8
+ * launch twice under different ids (providers/executor/dbos.ts), and its
9
+ * recovery decisions key on that id. Building providers once and sharing
10
+ * them is the whole trick; it also gives scheduled native runs the same
11
+ * `providers.executor` wiring MCP-triggered runs get, so sub-agent dispatch
12
+ * from a scheduled run works (it does not from `wardby scheduler`).
13
+ *
14
+ * Why the scheduler and reconciler can run in every replica: the scheduler
15
+ * elects one ticker via a Postgres lease and enforces at-most-once with row
16
+ * locks regardless (core/scheduler.ts); the reconciler is deliberately not
17
+ * lease-gated and is safe under concurrency (core/reconciler.ts).
18
+ */
19
+ import { loadCodingConcurrencyConfig, loadMcpConfig } from "./config/providers.js";
20
+ import { drainCodingQueue } from "./core/coding-queue.js";
21
+ import { prisma } from "./core/db.js";
22
+ import { startReconciler } from "./core/reconciler.js";
23
+ import { startScheduler } from "./core/scheduler.js";
24
+ import { buildMcpProviders, startMcp } from "./mcp/index.js";
25
+ export async function startServe(options = {}) {
26
+ const transport = loadMcpConfig().transport;
27
+ if (transport !== "http") {
28
+ throw new Error(`wardby serve requires MCP_TRANSPORT=http (got "${transport}"): in stdio mode stdout is the JSON-RPC wire ` +
29
+ `and a scheduler has no stdio client to serve. Use "wardby mcp" for stdio.`);
30
+ }
31
+ // Parsed before anything starts, so a malformed CODING_MAX_CONCURRENT or
32
+ // CODING_QUEUE_TIMEOUT_SEC fails fast instead of after HTTP is listening.
33
+ const concurrency = loadCodingConcurrencyConfig();
34
+ const providers = options.providers ?? buildMcpProviders().providers;
35
+ const mcp = await startMcp({ providers, schedulerAttached: true });
36
+ const reconciler = startReconciler({ executor: providers.executor });
37
+ const scheduler = startScheduler({
38
+ executor: providers.executor,
39
+ scope: options.scope,
40
+ onLeaderTick: async () => {
41
+ await drainCodingQueue({ db: prisma, executor: providers.executor, ...concurrency });
42
+ },
43
+ });
44
+ return {
45
+ isLeader: () => scheduler.isLeader(),
46
+ close: async () => {
47
+ // Order matters under a SIGTERM grace period: stop creating new runs,
48
+ // stop reaping, then let startMcp close HTTP and drain the executor.
49
+ scheduler.stop();
50
+ reconciler.stop();
51
+ await mcp.close();
52
+ },
53
+ };
54
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { CLI_USAGE } from "./cli-help.js";
4
+ function packageVersion() {
5
+ const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
6
+ if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
7
+ throw new Error("invalid_package_version");
8
+ }
9
+ return packageJson.version;
10
+ }
11
+ const command = process.argv[2];
12
+ if (command === undefined || command === "--help" || command === "-h") {
13
+ process.stdout.write(`${CLI_USAGE}\n`);
14
+ }
15
+ else if (command === "--version" || command === "-v") {
16
+ process.stdout.write(`${packageVersion()}\n`);
17
+ }
18
+ else {
19
+ await import("./cli.js");
20
+ }
package/package.json ADDED
@@ -0,0 +1,123 @@
1
+ {
2
+ "name": "@wardby/cli",
3
+ "version": "0.1.0",
4
+ "description": "Self-hosted control plane for budget-guarded AI agents.",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://github.com/wardby/wardby#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/wardby/wardby.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/wardby/wardby/issues"
13
+ },
14
+ "keywords": [
15
+ "ai-agents",
16
+ "mcp",
17
+ "self-hosted",
18
+ "agent-governance",
19
+ "budget-control"
20
+ ],
21
+ "type": "module",
22
+ "engines": {
23
+ "node": ">=24.0.0"
24
+ },
25
+ "bin": {
26
+ "wardby": "bin/wardby.js"
27
+ },
28
+ "files": [
29
+ ".env.example",
30
+ "NOTICE",
31
+ "bin/",
32
+ "deploy/local/docker-compose.yml",
33
+ "dist/",
34
+ "prisma/migrations/",
35
+ "prisma/schema.prisma",
36
+ "scripts/git-askpass.sh"
37
+ ],
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "typecheck": "tsc --noEmit",
43
+ "lint": "eslint .",
44
+ "lint:fix": "eslint . --fix",
45
+ "format": "prettier --write .",
46
+ "format:check": "prettier --check .",
47
+ "build:vendor": "node scripts/build-sandbox-vendor.mjs",
48
+ "build": "npm run build:vendor && tsc -p tsconfig.build.json",
49
+ "prepare": "npm run build:vendor",
50
+ "prepack": "npm run build",
51
+ "postinstall": "prisma generate --schema prisma/schema.prisma",
52
+ "cli": "tsx src/cli.ts",
53
+ "capture:autopilot": "tsx src/tools/capture-autopilot-dry-run.ts",
54
+ "test": "npm run build:vendor && vitest run",
55
+ "test:package": "node scripts/npm-package-acceptance.mjs",
56
+ "test:contract": "vitest run --config vitest.contract.config.ts",
57
+ "test:kubernetes": "WARDBY_KUBERNETES_TEST=1 vitest run src/providers/jobs/kubernetes.integration.test.ts",
58
+ "prisma:generate": "prisma generate",
59
+ "prisma:migrate": "prisma migrate deploy",
60
+ "db:up": "docker compose -f deploy/local/docker-compose.yml up -d",
61
+ "db:down": "docker compose -f deploy/local/docker-compose.yml down",
62
+ "coding:local:up": "docker compose --env-file .env.local -f deploy/local/docker-compose.yml -f deploy/local/docker-compose.phase5.yml up --build -d coding-proxy",
63
+ "coding:local:down": "docker compose --env-file .env.local -f deploy/local/docker-compose.yml -f deploy/local/docker-compose.phase5.yml down",
64
+ "observability:up": "docker compose --env-file .env.local -f deploy/local/docker-compose.yml -f deploy/local/docker-compose.phase5.yml -f deploy/observability/docker-compose.grafana.yml up --build -d",
65
+ "observability:smoke": "node scripts/grafana-smoke.mjs",
66
+ "observability:down": "docker compose --env-file .env.local -f deploy/local/docker-compose.yml -f deploy/local/docker-compose.phase5.yml -f deploy/observability/docker-compose.grafana.yml down",
67
+ "worker:image:local": "node scripts/build-local-coding-worker.mjs",
68
+ "test:phase5": "vitest run src/coding/observability.test.ts src/coding/profile.test.ts src/coding/protocol.test.ts src/providers/coding-proxy/proxy.test.ts src/providers/coding-proxy/secure-fetch.test.ts src/providers/coding-proxy/metering.test.ts src/providers/coding-proxy/runtime.test.ts src/providers/executor/container.test.ts src/providers/jobs/docker.test.ts src/providers/jobs/docker-isolation.test.ts src/providers/jobs/fake.test.ts src/providers/vcs/github.test.ts src/mcp/tools/trigger.test.ts src/core/webhooks.test.ts src/claude-coding-worker/driver.test.ts src/claude-coding-worker/sdk.test.ts src/claude-coding-worker/image-policy.test.ts src/claude-tool-runner/command.test.mjs src/claude-tool-runner/main.test.mjs src/claude-tool-runner/image-policy.test.ts",
69
+ "test:phase5:database": "vitest run src/coding/schema.database.test.ts src/providers/coding-proxy/prisma-ledger.database.test.ts src/providers/executor/container.database.test.ts src/core/coding-concurrency.database.test.ts src/core/scheduler.test.ts src/mcp/integration.test.ts",
70
+ "verify:phase5": "npm run typecheck && npm run test:phase5 && npm run build && npm run worker:image:policy",
71
+ "test:docker-isolation": "node scripts/docker-isolation-acceptance.mjs",
72
+ "test:docker-job": "node scripts/docker-job-acceptance.mjs",
73
+ "claude:images:local": "docker build -f src/claude-coding-worker/Dockerfile -t wardby-claude-coding-worker:phase5 . && docker build -f src/claude-tool-runner/Dockerfile -t wardby-claude-tool-runner:phase5 .",
74
+ "test:claude-compatibility": "docker build -f src/claude-coding-worker/Dockerfile.compatibility -t wardby-claude-compat:phase5 . && docker run --rm wardby-claude-compat:phase5",
75
+ "test:claude-docker": "node scripts/claude-docker-acceptance.mjs",
76
+ "test:production-boundary": "node scripts/production-boundary-policy.mjs",
77
+ "verify:claude-code": "npm run typecheck && npm run test:phase5 && npm run test:claude-compatibility && npm run claude:images:local && npm run test:claude-docker",
78
+ "worker:image:policy": "node scripts/coding-worker-image-policy.mjs"
79
+ },
80
+ "dependencies": {
81
+ "@anthropic-ai/bedrock-sdk": "^0.33.4",
82
+ "@anthropic-ai/sdk": "^0.124.0",
83
+ "@dbos-inc/dbos-sdk": "4.27.6",
84
+ "@kubernetes/client-node": "^2.0.0",
85
+ "@modelcontextprotocol/client": "^2.0.0",
86
+ "@modelcontextprotocol/node": "^2.0.0",
87
+ "@modelcontextprotocol/server": "^2.0.0",
88
+ "@prisma/client": "^6.19.3",
89
+ "@prometheus-io/client": "^0.16.1",
90
+ "croner": "^10.0.1",
91
+ "dotenv-flow": "^4.1.0",
92
+ "fast-xml-parser": "^5.11.1",
93
+ "gpt-tokenizer": "^2.5.0",
94
+ "jose": "^6.2.12",
95
+ "node-html-parser": "^9.0.3",
96
+ "openai": "^4.67.0",
97
+ "papaparse": "^5.7.0",
98
+ "pino": "^9.14.0",
99
+ "prisma": "^6.19.3",
100
+ "quickjs-emscripten": "^0.32.0",
101
+ "tar-stream": "^3.2.1",
102
+ "undici": "^8.7.0",
103
+ "zod": "^3.25.76",
104
+ "zod-to-json-schema": "^3.25.2"
105
+ },
106
+ "devDependencies": {
107
+ "@eslint/js": "^10.0.1",
108
+ "@openai/codex-sdk": "0.153.4",
109
+ "@types/node": "^24.0.0",
110
+ "@types/papaparse": "^5.5.2",
111
+ "@types/tar-stream": "^3.1.4",
112
+ "esbuild": "^0.28.2",
113
+ "eslint": "^10.10.0",
114
+ "eslint-config-prettier": "^10.1.8",
115
+ "globals": "^17.12.0",
116
+ "playwright": "^1.63.0",
117
+ "prettier": "^3.9.6",
118
+ "tsx": "^4.19.0",
119
+ "typescript": "^5.6.0",
120
+ "typescript-eslint": "^8.69.0",
121
+ "vitest": "^4.1.11"
122
+ }
123
+ }
@@ -0,0 +1,34 @@
1
+ -- Hand-written per CLEANROOM.md (never `db push`, never generated from
2
+ -- another project's migrations). Mirrors prisma/schema.prisma exactly.
3
+
4
+ CREATE TYPE "RunStatus" AS ENUM ('pending', 'running', 'succeeded', 'failed', 'refused');
5
+
6
+ CREATE TABLE "Agent" (
7
+ "id" TEXT NOT NULL,
8
+ "name" TEXT NOT NULL,
9
+ "systemPrompt" TEXT NOT NULL,
10
+ "model" TEXT NOT NULL,
11
+ "budgetUsd" DECIMAL(10,4) NOT NULL,
12
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+ "updatedAt" TIMESTAMP(3) NOT NULL,
14
+
15
+ CONSTRAINT "Agent_pkey" PRIMARY KEY ("id")
16
+ );
17
+
18
+ CREATE UNIQUE INDEX "Agent_name_key" ON "Agent"("name");
19
+
20
+ CREATE TABLE "Run" (
21
+ "id" TEXT NOT NULL,
22
+ "agentId" TEXT NOT NULL,
23
+ "status" "RunStatus" NOT NULL DEFAULT 'pending',
24
+ "tokensIn" INTEGER NOT NULL DEFAULT 0,
25
+ "tokensOut" INTEGER NOT NULL DEFAULT 0,
26
+ "costUsd" DECIMAL(10,6) NOT NULL DEFAULT 0,
27
+ "error" TEXT,
28
+ "startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
29
+ "finishedAt" TIMESTAMP(3),
30
+
31
+ CONSTRAINT "Run_pkey" PRIMARY KEY ("id")
32
+ );
33
+
34
+ ALTER TABLE "Run" ADD CONSTRAINT "Run_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE;