@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
package/dist/cli.js ADDED
@@ -0,0 +1,629 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Minimal CLI.
4
+ *
5
+ * wardby agent create --name <n> --model <m> --prompt <p> --budget <usd> [--schedule "<cron>"] [--timezone <tz>] [--memory-enabled]
6
+ * wardby agent list
7
+ * wardby agent schedule <name> --cron "<expr>" [--timezone <tz>] [--disable]
8
+ * wardby run <name>
9
+ * wardby runs [--agent <name>] [--limit N] [--status <s>]
10
+ * wardby scheduler [--scope default]
11
+ * wardby mcp (MCP_TRANSPORT=stdio|http selects the transport; authoring/
12
+ * control is MCP-first from here — this floor keeps working
13
+ * before/without an MCP client)
14
+ * wardby serve [--scope default] (everything: mcp + scheduler + reconciler; the
15
+ * image's default command, and what a
16
+ * single-container deployment should run)
17
+ */
18
+ import "./env.js";
19
+ import { readFileSync } from "node:fs";
20
+ import { execFile as execFileCallback } from "node:child_process";
21
+ import { parseArgs } from "node:util";
22
+ import { promisify } from "node:util";
23
+ import { loadCodingConcurrencyConfig, loadContainerExecutorConfig, loadKubernetesJobConfig, loadProviderConfig, } from "./config/providers.js";
24
+ import { drainCodingQueue } from "./core/coding-queue.js";
25
+ import { isImmutableDockerImage } from "./providers/jobs/docker-isolation.js";
26
+ import { ClientNodeKubernetesApi } from "./providers/jobs/kubernetes-client.js";
27
+ import { describePreflightFailure, kubernetesPreflight } from "./providers/jobs/kubernetes-preflight.js";
28
+ import { RoutingLlmProvider, resolveLlmRegistrations } from "./providers/llm/index.js";
29
+ import { buildConfiguredExecutor, buildExecutor } from "./providers/executor/index.js";
30
+ import { PostgresDatastore } from "./providers/datastore/index.js";
31
+ import { PostgresAgentMemory } from "./providers/memory/index.js";
32
+ import { buildSecretCipher } from "./providers/secrets/index.js";
33
+ import { prisma } from "./core/db.js";
34
+ import { runAgent } from "./core/runner.js";
35
+ import { validateCronExpression } from "./core/cron.js";
36
+ import { startScheduler } from "./core/scheduler.js";
37
+ import { startReconciler } from "./core/reconciler.js";
38
+ import { NativeEngine } from "./core/engine-native.js";
39
+ import { logger } from "./core/logger.js";
40
+ import { deriveJsonSchema } from "./sandbox/zod-params.js";
41
+ import { ToolCapabilitiesPatchSchema } from "./sandbox/tool-capabilities.js";
42
+ import { startMcp } from "./mcp/index.js";
43
+ import { startServe } from "./serve.js";
44
+ import { authCommand } from "./mcp/auth/self-hosted/cli.js";
45
+ import { parseImportArgs } from "./import/cli-args.js";
46
+ import { runImport } from "./import/index.js";
47
+ import { CLI_USAGE } from "./cli-help.js";
48
+ const cliLog = logger.child({ module: "cli" });
49
+ const RUN_STATUSES = [
50
+ "pending",
51
+ "running",
52
+ "succeeded",
53
+ "failed",
54
+ "refused",
55
+ "lost",
56
+ "budget_exhausted",
57
+ "cancelled",
58
+ ];
59
+ const execFile = promisify(execFileCallback);
60
+ function fail(message) {
61
+ console.error(`error: ${message}`);
62
+ process.exit(1);
63
+ }
64
+ function buildLlmProvider() {
65
+ const result = resolveLlmRegistrations();
66
+ if (result.kind === "no-credentials") {
67
+ fail("No LLM credentials present. Set OPENAI_API_KEY, ANTHROPIC_API_KEY, and/or BEDROCK_REGION (or AWS_REGION).");
68
+ }
69
+ return new RoutingLlmProvider(result.registrations);
70
+ }
71
+ function buildEngine() {
72
+ const config = loadProviderConfig();
73
+ if (config.engine !== "native") {
74
+ fail(`ENGINE "${config.engine}" has no adapter yet (only "native").`);
75
+ }
76
+ return new NativeEngine();
77
+ }
78
+ function buildDatastore(cipher) {
79
+ const config = loadProviderConfig();
80
+ if (config.datastore !== "postgres") {
81
+ fail(`DATASTORE "${String(config.datastore)}" has no adapter yet (only "postgres").`);
82
+ }
83
+ return new PostgresDatastore(prisma, cipher);
84
+ }
85
+ function buildMemory() {
86
+ return new PostgresAgentMemory(prisma);
87
+ }
88
+ function buildSecrets() {
89
+ const config = loadProviderConfig();
90
+ try {
91
+ return buildSecretCipher(config);
92
+ }
93
+ catch (err) {
94
+ fail(err instanceof Error ? err.message : String(err));
95
+ }
96
+ }
97
+ async function agentCreate(args) {
98
+ const { values } = parseArgs({
99
+ args,
100
+ options: {
101
+ name: { type: "string" },
102
+ model: { type: "string" },
103
+ prompt: { type: "string" },
104
+ budget: { type: "string" },
105
+ schedule: { type: "string" },
106
+ timezone: { type: "string" },
107
+ "max-turns": { type: "string" },
108
+ "memory-enabled": { type: "boolean" },
109
+ },
110
+ });
111
+ if (!values.name || !values.model || !values.prompt || !values.budget) {
112
+ fail("agent create requires --name, --model, --prompt, and --budget.");
113
+ }
114
+ const budgetUsd = Number(values.budget);
115
+ if (!Number.isFinite(budgetUsd) || budgetUsd <= 0) {
116
+ fail(`--budget must be a positive number, got "${values.budget}".`);
117
+ }
118
+ const maxTurns = values["max-turns"] ? Number(values["max-turns"]) : 10;
119
+ if (!Number.isInteger(maxTurns) || maxTurns <= 0) {
120
+ fail(`--max-turns must be a positive integer, got "${values["max-turns"]}".`);
121
+ }
122
+ const timezone = values.timezone ?? "UTC";
123
+ if (values.schedule) {
124
+ try {
125
+ validateCronExpression(values.schedule, timezone);
126
+ }
127
+ catch (err) {
128
+ fail(`invalid --schedule/--timezone: ${err instanceof Error ? err.message : String(err)}`);
129
+ }
130
+ }
131
+ const agent = await prisma.agent.create({
132
+ data: {
133
+ name: values.name,
134
+ model: values.model,
135
+ systemPrompt: values.prompt,
136
+ budgetUsd,
137
+ schedule: values.schedule ?? null,
138
+ timezone,
139
+ maxTurns,
140
+ memoryEnabled: values["memory-enabled"] ?? false,
141
+ },
142
+ });
143
+ console.log(agent.id);
144
+ }
145
+ async function toolCreate(args) {
146
+ const { values } = parseArgs({
147
+ args,
148
+ options: {
149
+ name: { type: "string" },
150
+ description: { type: "string" },
151
+ params: { type: "string" },
152
+ code: { type: "string" },
153
+ },
154
+ });
155
+ if (!values.name || !values.description || !values.params || !values.code) {
156
+ fail("tool create requires --name, --description, --params <file>, and --code <file>.");
157
+ }
158
+ let paramsZod;
159
+ let code;
160
+ try {
161
+ paramsZod = readFileSync(values.params, "utf8");
162
+ }
163
+ catch (err) {
164
+ fail(`could not read --params file "${values.params}": ${err instanceof Error ? err.message : String(err)}`);
165
+ }
166
+ try {
167
+ code = readFileSync(values.code, "utf8");
168
+ }
169
+ catch (err) {
170
+ fail(`could not read --code file "${values.code}": ${err instanceof Error ? err.message : String(err)}`);
171
+ }
172
+ // Fails at registration, not at call time: a malformed schema never gets
173
+ // persisted. The derived schema is cached on the row (no "update tool"
174
+ // path exists, so it can never go stale) rather than re-derived per run.
175
+ const schemaResult = await deriveJsonSchema(paramsZod);
176
+ if (!schemaResult.ok) {
177
+ fail(`invalid --params schema: ${schemaResult.errorMessage}`);
178
+ }
179
+ const tool = await prisma.tool.create({
180
+ data: {
181
+ name: values.name,
182
+ description: values.description,
183
+ paramsZod: paramsZod,
184
+ jsonSchema: schemaResult.value,
185
+ code: code,
186
+ },
187
+ });
188
+ console.log(tool.id);
189
+ }
190
+ async function toolAttach(args, detach) {
191
+ const { values, positionals } = parseArgs({
192
+ args,
193
+ allowPositionals: true,
194
+ options: {
195
+ "allow-secret": { type: "string", multiple: true },
196
+ "allow-datastore-prefix": { type: "string", multiple: true },
197
+ "allow-host": { type: "string", multiple: true },
198
+ // "<boundName>:<prefix>" — repeatable, one prefix per flag; grouped
199
+ // below into { [boundName]: prefix[] }, mirroring how
200
+ // allow-datastore-prefix maps to the agent's own private store.
201
+ "allow-shared-datastore-prefix": { type: "string", multiple: true },
202
+ },
203
+ });
204
+ const [toolName, agentName] = positionals;
205
+ if (!toolName || !agentName) {
206
+ fail(`tool ${detach ? "detach" : "attach"} requires <tool-name> <agent-name>.`);
207
+ }
208
+ const tool = await prisma.tool.findUnique({ where: { name: toolName } });
209
+ if (!tool)
210
+ fail(`unknown tool "${toolName}".`);
211
+ const agent = await prisma.agent.findUnique({ where: { name: agentName } });
212
+ if (!agent)
213
+ fail(`unknown agent "${agentName}".`);
214
+ if (detach) {
215
+ await prisma.agentTool.deleteMany({ where: { agentId: agent.id, toolId: tool.id } });
216
+ console.log(`detached "${toolName}" from "${agentName}".`);
217
+ return;
218
+ }
219
+ let allowedSharedDatastorePrefixes;
220
+ if (values["allow-shared-datastore-prefix"]) {
221
+ allowedSharedDatastorePrefixes = {};
222
+ for (const entry of values["allow-shared-datastore-prefix"]) {
223
+ const sep = entry.indexOf(":");
224
+ if (sep < 0) {
225
+ fail(`invalid --allow-shared-datastore-prefix "${entry}" — expected "<boundName>:<prefix>".`);
226
+ }
227
+ const boundName = entry.slice(0, sep);
228
+ const prefix = entry.slice(sep + 1);
229
+ (allowedSharedDatastorePrefixes[boundName] ??= []).push(prefix);
230
+ }
231
+ }
232
+ const patch = ToolCapabilitiesPatchSchema.safeParse({
233
+ allowedSecrets: values["allow-secret"],
234
+ allowedDatastorePrefixes: values["allow-datastore-prefix"],
235
+ allowedHosts: values["allow-host"],
236
+ allowedSharedDatastorePrefixes,
237
+ });
238
+ if (!patch.success) {
239
+ fail(`invalid tool capabilities: ${patch.error.issues.map((i) => i.message).join("; ")}`);
240
+ }
241
+ await prisma.agentTool.upsert({
242
+ where: { agentId_toolId: { agentId: agent.id, toolId: tool.id } },
243
+ create: {
244
+ agentId: agent.id,
245
+ toolId: tool.id,
246
+ allowedSecrets: patch.data.allowedSecrets ?? [],
247
+ allowedDatastorePrefixes: patch.data.allowedDatastorePrefixes ?? [],
248
+ allowedHosts: patch.data.allowedHosts ?? [],
249
+ allowedSharedDatastorePrefixes: patch.data.allowedSharedDatastorePrefixes ?? {},
250
+ },
251
+ update: {
252
+ ...(patch.data.allowedSecrets !== undefined ? { allowedSecrets: patch.data.allowedSecrets } : {}),
253
+ ...(patch.data.allowedDatastorePrefixes !== undefined
254
+ ? { allowedDatastorePrefixes: patch.data.allowedDatastorePrefixes }
255
+ : {}),
256
+ ...(patch.data.allowedHosts !== undefined ? { allowedHosts: patch.data.allowedHosts } : {}),
257
+ ...(patch.data.allowedSharedDatastorePrefixes !== undefined
258
+ ? { allowedSharedDatastorePrefixes: patch.data.allowedSharedDatastorePrefixes }
259
+ : {}),
260
+ },
261
+ });
262
+ console.log(`attached "${toolName}" to "${agentName}".`);
263
+ }
264
+ async function toolList(args) {
265
+ const { values } = parseArgs({ args, options: { agent: { type: "string" } } });
266
+ if (values.agent) {
267
+ const agent = await prisma.agent.findUnique({ where: { name: values.agent } });
268
+ if (!agent)
269
+ fail(`unknown agent "${values.agent}".`);
270
+ const attached = await prisma.agentTool.findMany({ where: { agentId: agent.id }, include: { tool: true } });
271
+ if (attached.length === 0) {
272
+ console.log(`no tools attached to "${values.agent}".`);
273
+ return;
274
+ }
275
+ for (const a of attached)
276
+ console.log(`${a.tool.name} ${a.tool.description}`);
277
+ return;
278
+ }
279
+ const tools = await prisma.tool.findMany({ orderBy: { name: "asc" } });
280
+ if (tools.length === 0) {
281
+ console.log("no tools registered.");
282
+ return;
283
+ }
284
+ for (const t of tools)
285
+ console.log(`${t.name} ${t.description}`);
286
+ }
287
+ async function agentSchedule(args) {
288
+ const [name, ...rest] = args;
289
+ if (!name) {
290
+ fail('agent schedule requires an agent name: wardby agent schedule <name> --cron "<expr>"');
291
+ }
292
+ const { values } = parseArgs({
293
+ args: rest,
294
+ options: {
295
+ cron: { type: "string" },
296
+ timezone: { type: "string" },
297
+ disable: { type: "boolean" },
298
+ },
299
+ });
300
+ const agent = await prisma.agent.findUnique({ where: { name: name } });
301
+ if (!agent) {
302
+ fail(`unknown agent "${name}".`);
303
+ }
304
+ if (values.disable) {
305
+ await prisma.agent.update({ where: { name: name }, data: { scheduleEnabled: false } });
306
+ console.log(`schedule disabled for "${name}".`);
307
+ return;
308
+ }
309
+ const timezone = values.timezone ?? agent.timezone;
310
+ const schedule = values.cron ?? agent.schedule;
311
+ if (!schedule) {
312
+ fail("no --cron given and the agent has no existing schedule to re-enable.");
313
+ }
314
+ try {
315
+ validateCronExpression(schedule, timezone);
316
+ }
317
+ catch (err) {
318
+ fail(`invalid --cron/--timezone: ${err instanceof Error ? err.message : String(err)}`);
319
+ }
320
+ await prisma.agent.update({
321
+ where: { name: name },
322
+ data: { schedule, timezone, scheduleEnabled: true },
323
+ });
324
+ console.log(`schedule set for "${name}": "${schedule}" (${timezone}).`);
325
+ }
326
+ async function agentList() {
327
+ const agents = await prisma.agent.findMany({ orderBy: { name: "asc" } });
328
+ if (agents.length === 0) {
329
+ console.log("no agents registered.");
330
+ return;
331
+ }
332
+ for (const agent of agents) {
333
+ const schedule = agent.schedule
334
+ ? `${agent.scheduleEnabled ? "enabled" : "disabled"}: ${agent.schedule} (${agent.timezone})`
335
+ : "manual";
336
+ console.log(`${agent.name} ${agent.kind.padEnd(6)} ${agent.model} ` +
337
+ `$${Number(agent.budgetUsd).toFixed(4)} ${agent.maxTurns} turns memory ${agent.memoryEnabled ? "on" : "off"} ${schedule}`);
338
+ }
339
+ }
340
+ async function run(name) {
341
+ if (!name) {
342
+ fail("run requires an agent name: wardby run <name>");
343
+ }
344
+ const agent = await prisma.agent.findUnique({ where: { name } });
345
+ if (!agent)
346
+ fail(`unknown agent "${name}".`);
347
+ if (agent.kind === "coding") {
348
+ fail("Coding agents are MCP-first: use trigger_agent so task input and ownership are recorded safely.");
349
+ }
350
+ const llm = buildLlmProvider();
351
+ const engine = buildEngine();
352
+ const secrets = buildSecrets();
353
+ const datastore = buildDatastore(secrets);
354
+ const memory = buildMemory();
355
+ let run;
356
+ try {
357
+ run = await runAgent(name, { llm, engine, datastore, secrets, memory }, prisma, (delta) => {
358
+ process.stdout.write(delta);
359
+ });
360
+ }
361
+ catch (err) {
362
+ fail(err instanceof Error ? err.message : String(err));
363
+ }
364
+ process.stdout.write("\n");
365
+ const completedAgent = await prisma.agent.findUnique({ where: { id: run.agentId } });
366
+ const budgetUsd = completedAgent ? Number(completedAgent.budgetUsd) : NaN;
367
+ if (run.status === "succeeded" || run.status === "budget_exhausted") {
368
+ const marker = run.status === "succeeded" ? "✓" : "◐";
369
+ console.log(`${marker} run ${run.id} (${run.status}) — ${run.tokensIn} in / ${run.tokensOut} out — ` +
370
+ `$${Number(run.costUsd).toFixed(6)} (budget $${budgetUsd.toFixed(4)})`);
371
+ if (run.status === "budget_exhausted")
372
+ process.exitCode = 1;
373
+ }
374
+ else {
375
+ console.error(`✗ run ${run.id} — ${run.status}: ${run.error ?? "unknown error"}`);
376
+ process.exitCode = 1;
377
+ }
378
+ }
379
+ function noopExecutor() {
380
+ return { async start() { }, async stop() { } };
381
+ }
382
+ async function codingOps(args) {
383
+ const [operation, ...rest] = args;
384
+ const config = loadProviderConfig();
385
+ if (config.jobs !== "docker" && config.jobs !== "kubernetes") {
386
+ fail("coding operations require JOB_LAUNCHER=docker or kubernetes.");
387
+ }
388
+ const container = loadContainerExecutorConfig();
389
+ if (config.jobs === "kubernetes") {
390
+ if (!container.workerImage)
391
+ fail("CODING_WORKER_IMAGE is required when JOB_LAUNCHER=kubernetes.");
392
+ }
393
+ else if (!container.workerImage || !container.proxyContainer) {
394
+ fail("CODING_WORKER_IMAGE and CODING_PROXY_CONTAINER are required when JOB_LAUNCHER=docker.");
395
+ }
396
+ if (operation === "preflight" && config.jobs === "kubernetes") {
397
+ const kubernetes = loadKubernetesJobConfig();
398
+ let checks;
399
+ try {
400
+ const api = new ClientNodeKubernetesApi({ context: kubernetes.context });
401
+ checks = await kubernetesPreflight({
402
+ api,
403
+ config: kubernetes,
404
+ workerImage: container.workerImage,
405
+ maxDiskMb: container.maxDiskMb,
406
+ timeoutMs: kubernetes.preflightTimeoutMs,
407
+ });
408
+ }
409
+ catch (error) {
410
+ fail(`coding preflight failed: ${describePreflightFailure(error)}`);
411
+ }
412
+ console.log(`coding preflight passed (${checks.join(", ")}) for ${container.workerImage}`);
413
+ return;
414
+ }
415
+ if (operation === "preflight") {
416
+ if (!isImmutableDockerImage(container.workerImage)) {
417
+ fail("CODING_WORKER_IMAGE must use an immutable repository digest or local image ID.");
418
+ }
419
+ try {
420
+ await execFile("docker", ["image", "inspect", container.workerImage], { maxBuffer: 1024 * 1024 });
421
+ }
422
+ catch {
423
+ fail(`Docker cannot inspect coding worker image "${container.workerImage}".`);
424
+ }
425
+ console.log(`coding preflight passed for ${container.workerImage}`);
426
+ return;
427
+ }
428
+ if (operation === "cleanup") {
429
+ const { values } = parseArgs({ args: rest, options: { "run-id": { type: "string" } } });
430
+ if (!values["run-id"])
431
+ fail("coding cleanup requires --run-id <id>.");
432
+ const executor = buildConfiguredExecutor({ native: noopExecutor(), db: prisma });
433
+ await executor.stop(values["run-id"], "operator cleanup");
434
+ console.log(`coding cleanup requested for run ${values["run-id"]}`);
435
+ return;
436
+ }
437
+ fail("coding requires preflight or cleanup --run-id <id>.");
438
+ }
439
+ async function listRuns(args) {
440
+ const { values } = parseArgs({
441
+ args,
442
+ options: {
443
+ agent: { type: "string" },
444
+ limit: { type: "string" },
445
+ status: { type: "string" },
446
+ },
447
+ });
448
+ const limit = values.limit ? Number(values.limit) : 20;
449
+ if (!Number.isInteger(limit) || limit <= 0) {
450
+ fail(`--limit must be a positive integer, got "${values.limit}".`);
451
+ }
452
+ if (values.status && !RUN_STATUSES.includes(values.status)) {
453
+ fail(`--status must be one of ${RUN_STATUSES.join(", ")}, got "${values.status}".`);
454
+ }
455
+ let agentId;
456
+ if (values.agent) {
457
+ const agent = await prisma.agent.findUnique({ where: { name: values.agent } });
458
+ if (!agent) {
459
+ fail(`unknown agent "${values.agent}".`);
460
+ }
461
+ agentId = agent.id;
462
+ }
463
+ const runs = await prisma.run.findMany({
464
+ where: {
465
+ ...(agentId ? { agentId } : {}),
466
+ ...(values.status ? { status: values.status } : {}),
467
+ },
468
+ include: { agent: true },
469
+ orderBy: { startedAt: "desc" },
470
+ take: limit,
471
+ });
472
+ if (runs.length === 0) {
473
+ console.log("no runs found.");
474
+ return;
475
+ }
476
+ for (const r of runs) {
477
+ const finished = r.finishedAt ? r.finishedAt.toISOString() : "-";
478
+ console.log(`${r.id} ${r.agent.name.padEnd(20)} ${r.trigger.padEnd(9)} ${r.status.padEnd(9)} ` +
479
+ `${String(r.tokensIn).padStart(6)} in / ${String(r.tokensOut).padStart(6)} out ` +
480
+ `$${Number(r.costUsd).toFixed(6)} started ${r.startedAt.toISOString()} finished ${finished}`);
481
+ }
482
+ }
483
+ async function scheduler(args) {
484
+ const { values } = parseArgs({ args, options: { scope: { type: "string" } } });
485
+ const scope = values.scope ?? "default";
486
+ // Parsed before anything starts, so a malformed CODING_MAX_CONCURRENT or
487
+ // CODING_QUEUE_TIMEOUT_SEC fails fast.
488
+ const concurrency = loadCodingConcurrencyConfig();
489
+ const config = loadProviderConfig();
490
+ const llm = buildLlmProvider();
491
+ const engine = buildEngine();
492
+ const secrets = buildSecrets();
493
+ const datastore = buildDatastore(secrets);
494
+ const memory = buildMemory();
495
+ const nativeExecutor = buildExecutor(config, { llm, engine, datastore, secrets, memory }, prisma);
496
+ const executor = buildConfiguredExecutor({ native: nativeExecutor, db: prisma, providerConfig: config });
497
+ await executor.launch?.();
498
+ const reconciler = startReconciler({ db: prisma, executor });
499
+ const sched = startScheduler({
500
+ executor,
501
+ db: prisma,
502
+ scope,
503
+ onLeaderTick: async () => {
504
+ await drainCodingQueue({ db: prisma, executor, ...concurrency });
505
+ },
506
+ });
507
+ console.log(`wardby scheduler started (scope "${scope}"). Press Ctrl+C to stop.`);
508
+ await new Promise((resolve) => {
509
+ const shutdown = () => {
510
+ console.log("\nwardby scheduler shutting down...");
511
+ sched.stop();
512
+ reconciler.stop();
513
+ void Promise.resolve(executor.close?.())
514
+ .catch((err) => cliLog.warn({ err }, "executor close failed during scheduler shutdown"))
515
+ .finally(resolve);
516
+ };
517
+ process.once("SIGINT", shutdown);
518
+ process.once("SIGTERM", shutdown);
519
+ });
520
+ }
521
+ async function mcp() {
522
+ const handle = await startMcp();
523
+ // startMcp() resolves once the transport is up (bound/listening), not
524
+ // when it stops — block here the same way `scheduler` does, so main()'s
525
+ // `finally { prisma.$disconnect() }` doesn't tear the connection down
526
+ // out from under a server that's still supposed to be running.
527
+ //
528
+ // stderr, not stdout: in stdio mode stdout IS the JSON-RPC protocol
529
+ // stream (unlike `scheduler`, which owns no such stream), so a stray
530
+ // console.log here would corrupt every stdio-connected client.
531
+ console.error("wardby mcp started. Press Ctrl+C to stop.");
532
+ await new Promise((resolve) => {
533
+ const shutdown = () => {
534
+ console.error("\nwardby mcp shutting down...");
535
+ void Promise.resolve(handle.close())
536
+ .catch((err) => cliLog.warn({ err }, "mcp handle close failed during shutdown"))
537
+ .finally(resolve);
538
+ };
539
+ process.once("SIGINT", shutdown);
540
+ process.once("SIGTERM", shutdown);
541
+ });
542
+ }
543
+ async function serve(args) {
544
+ const { values } = parseArgs({ args, options: { scope: { type: "string" } } });
545
+ const handle = await startServe({ scope: values.scope });
546
+ // stderr, like `mcp`: stdout must stay clean in case a future transport
547
+ // multiplexes it, and this keeps the two commands' output consistent.
548
+ console.error(`wardby serve started (scope "${values.scope ?? "default"}"). Press Ctrl+C to stop.`);
549
+ await new Promise((resolve) => {
550
+ const shutdown = () => {
551
+ console.error("\nwardby serve shutting down...");
552
+ void handle
553
+ .close()
554
+ .catch((err) => cliLog.warn({ err }, "serve close failed during shutdown"))
555
+ .finally(resolve);
556
+ };
557
+ process.once("SIGINT", shutdown);
558
+ process.once("SIGTERM", shutdown);
559
+ });
560
+ }
561
+ async function importCommand(rest) {
562
+ const opts = parseImportArgs(rest);
563
+ const { report, result } = await runImport({ ...opts, db: prisma, env: process.env });
564
+ console.log(report);
565
+ if (result) {
566
+ for (const w of result.webhookSecrets)
567
+ console.log(`webhook secret (${w.agentName}): ${w.secret}`);
568
+ }
569
+ }
570
+ async function main() {
571
+ const [command, ...rest] = process.argv.slice(2);
572
+ try {
573
+ if (command === "auth") {
574
+ await authCommand(rest, prisma, process.env.AUTH_CREDENTIAL_HASH_KEY ?? "");
575
+ }
576
+ else if (command === "agent" && rest[0] === "create") {
577
+ await agentCreate(rest.slice(1));
578
+ }
579
+ else if (command === "agent" && rest[0] === "list") {
580
+ await agentList();
581
+ }
582
+ else if (command === "agent" && rest[0] === "schedule") {
583
+ await agentSchedule(rest.slice(1));
584
+ }
585
+ else if (command === "tool" && rest[0] === "create") {
586
+ await toolCreate(rest.slice(1));
587
+ }
588
+ else if (command === "tool" && rest[0] === "attach") {
589
+ await toolAttach(rest.slice(1), false);
590
+ }
591
+ else if (command === "tool" && rest[0] === "detach") {
592
+ await toolAttach(rest.slice(1), true);
593
+ }
594
+ else if (command === "tool" && rest[0] === "list") {
595
+ await toolList(rest.slice(1));
596
+ }
597
+ else if (command === "run") {
598
+ await run(rest[0]);
599
+ }
600
+ else if (command === "runs") {
601
+ await listRuns(rest);
602
+ }
603
+ else if (command === "coding") {
604
+ await codingOps(rest);
605
+ }
606
+ else if (command === "scheduler") {
607
+ await scheduler(rest);
608
+ }
609
+ else if (command === "mcp") {
610
+ await mcp();
611
+ }
612
+ else if (command === "serve") {
613
+ await serve(rest);
614
+ }
615
+ else if (command === "import") {
616
+ await importCommand(rest);
617
+ }
618
+ else {
619
+ fail(CLI_USAGE);
620
+ }
621
+ }
622
+ finally {
623
+ await prisma.$disconnect();
624
+ }
625
+ }
626
+ main().catch((err) => {
627
+ console.error(err instanceof Error ? err.message : String(err));
628
+ process.exit(1);
629
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Metadata-only lifecycle telemetry for coding runs. Keep untrusted task and
3
+ * repository data out of this boundary so log retention cannot become source
4
+ * retention by accident.
5
+ */
6
+ export type CodingLifecycleStage = "queued" | "prepared" | "launched" | "running" | "budget_cutoff" | "stopping" | "collected" | "pull_request_opened" | "pull_request_updated" | "terminal" | "cleanup";
7
+ export interface CodingLifecycleEvent {
8
+ stage: CodingLifecycleStage;
9
+ runId: string;
10
+ /** Opaque launcher handle, never a container command line or environment. */
11
+ jobId?: string;
12
+ outcome?: "succeeded" | "failed" | "refused" | "lost" | "budget_exhausted" | "cancelled";
13
+ failureCategory?: string;
14
+ diagnosticId?: string;
15
+ durationMs?: number;
16
+ budgetReservedUsd?: number;
17
+ budgetActualUsd?: number;
18
+ cleanupSucceeded?: boolean;
19
+ /** Enumerated execution metadata only; never a model request or source field. */
20
+ workerProvider?: "codex" | "claude-code";
21
+ proxyProtocol?: "openai-responses" | "anthropic-messages";
22
+ }
23
+ export interface CodingRunObserver {
24
+ emit(event: CodingLifecycleEvent): void;
25
+ }
26
+ export interface CodingMetricsSnapshot {
27
+ stages: Record<CodingLifecycleStage, number>;
28
+ terminalOutcomes: Record<string, number>;
29
+ activeJobs: number;
30
+ cleanupFailures: number;
31
+ budgetReservedUsd: number;
32
+ budgetActualUsd: number;
33
+ runtimeMsTotal: number;
34
+ }
35
+ /** A small exporter-neutral aggregate that monitoring adapters can scrape or forward. */
36
+ export declare class CodingMetrics implements CodingRunObserver {
37
+ private readonly stages;
38
+ private readonly terminalOutcomes;
39
+ private activeJobs;
40
+ private cleanupFailures;
41
+ private budgetReservedUsd;
42
+ private budgetActualUsd;
43
+ private runtimeMsTotal;
44
+ emit(event: CodingLifecycleEvent): void;
45
+ snapshot(): CodingMetricsSnapshot;
46
+ }
47
+ export declare class PinoCodingRunObserver implements CodingRunObserver {
48
+ private readonly metrics;
49
+ constructor(metrics?: CodingMetrics);
50
+ emit(event: CodingLifecycleEvent): void;
51
+ snapshot(): CodingMetricsSnapshot;
52
+ }
53
+ /** Default application observer. Production log infrastructure owns retention. */
54
+ export declare const codingRunObserver: PinoCodingRunObserver;
55
+ export declare class InMemoryCodingRunObserver implements CodingRunObserver {
56
+ readonly events: CodingLifecycleEvent[];
57
+ readonly metrics: CodingMetrics;
58
+ emit(event: CodingLifecycleEvent): void;
59
+ }