@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,187 @@
1
+ import { loadProviderConfig, loadMcpConfig, loadAuthConfig } from "../config/providers.js";
2
+ import { prisma } from "../core/db.js";
3
+ import { NativeEngine } from "../core/engine-native.js";
4
+ import { resolveLlmRegistrations, RoutingLlmProvider } from "../providers/llm/index.js";
5
+ import { PostgresDatastore } from "../providers/datastore/index.js";
6
+ import { PostgresAgentMemory } from "../providers/memory/index.js";
7
+ import { buildConfiguredExecutor, buildExecutor } from "../providers/executor/index.js";
8
+ import { buildSecretCipher } from "../providers/secrets/index.js";
9
+ import { buildAuthProvider } from "../providers/auth/index.js";
10
+ import { buildMcpServer } from "./server.js";
11
+ import { countUnattendedSchedules, unattendedSchedulesWarning } from "./unattended-schedules.js";
12
+ import { runStdioServer } from "./transport/stdio.js";
13
+ import { startHttpServer } from "./transport/streamable-http.js";
14
+ import { resolvePrincipal } from "./auth/principal.js";
15
+ import { SCOPES_SUPPORTED } from "./auth/resource-server.js";
16
+ import { canonicalUrl } from "./transport/http-limits.js";
17
+ import { registerAgentTools } from "./tools/agents.js";
18
+ import { registerBudgetGroupTools } from "./tools/budget-groups.js";
19
+ import { registerModelTools } from "./tools/models.js";
20
+ import { registerTriggerTool } from "./tools/trigger.js";
21
+ import { registerToolAuthoringTools } from "./tools/tools.js";
22
+ import { registerSchedulingTools } from "./tools/scheduling.js";
23
+ import { registerRunTools } from "./tools/runs.js";
24
+ import { registerDatastoreTools } from "./tools/datastore.js";
25
+ import { registerSubAgentTools } from "./tools/subagents.js";
26
+ import { registerMemoryTools } from "./tools/memory.js";
27
+ import { registerSecretsTools } from "./tools/secrets.js";
28
+ import { registerWebhookTools } from "./tools/webhooks.js";
29
+ import { createStdioSecretElicitationHost } from "./tools/secret-elicitation-server.js";
30
+ import { SECRET_ELICITATION_PATH } from "./tools/secret-elicitation-form.js";
31
+ import { logger } from "../core/logger.js";
32
+ const mcpLog = logger.child({ module: "mcp-index" });
33
+ const SELF_HOSTED_CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // hourly
34
+ /** Says out loud at startup when enabled schedules exist that nothing in this process will fire (see ./unattended-schedules.ts). */
35
+ async function warnIfNothingWillFireSchedules() {
36
+ try {
37
+ const message = unattendedSchedulesWarning(await countUnattendedSchedules(prisma));
38
+ if (message)
39
+ mcpLog.warn(message);
40
+ }
41
+ catch (err) {
42
+ // Advisory only - never let it stop the server coming up.
43
+ mcpLog.debug({ err }, "could not check for unattended schedules");
44
+ }
45
+ }
46
+ /** Placeholder identifier for stdio, which has no HTTP endpoint to name. Never surfaced: stdio's fixed context always holds every scope, so no scope challenge is ever built against it. */
47
+ const STDIO_PLACEHOLDER_URI = "urn:wardby:local-stdio";
48
+ /** Registers the full Phase 4 tool surface — every module, in one place. */
49
+ export function registerAllTools(mcp, opts) {
50
+ registerAgentTools(mcp);
51
+ registerBudgetGroupTools(mcp);
52
+ registerModelTools(mcp);
53
+ registerTriggerTool(mcp);
54
+ registerToolAuthoringTools(mcp);
55
+ registerSchedulingTools(mcp);
56
+ registerRunTools(mcp);
57
+ registerDatastoreTools(mcp);
58
+ registerSubAgentTools(mcp);
59
+ registerMemoryTools(mcp);
60
+ registerSecretsTools(mcp, {
61
+ buildElicitationUrl: opts.secretElicitationUrl,
62
+ protocolElicitation: opts.secretElicitationProtocol,
63
+ });
64
+ registerWebhookTools(mcp);
65
+ }
66
+ /** Builds the real provider set (LLM/engine/datastore/secrets/executor) — shared by both transports. */
67
+ export function buildMcpProviders() {
68
+ const providerConfig = loadProviderConfig();
69
+ const llmResult = resolveLlmRegistrations();
70
+ if (llmResult.kind !== "registrations") {
71
+ throw new Error("No LLM credentials present. Set OPENAI_API_KEY, ANTHROPIC_API_KEY, and/or BEDROCK_REGION (or AWS_REGION).");
72
+ }
73
+ const llm = new RoutingLlmProvider(llmResult.registrations);
74
+ const engine = new NativeEngine();
75
+ const secrets = buildSecretCipher(providerConfig);
76
+ const datastore = new PostgresDatastore(prisma, secrets);
77
+ const memory = new PostgresAgentMemory(prisma);
78
+ // `nativeProviders` is passed by reference into buildExecutor, and native
79
+ // runs it drives read `this.providers.executor` at call time (not at
80
+ // construction time) — so patching `.executor` on afterward, once the
81
+ // full RoutingExecutor exists, is enough for a native run's own
82
+ // delegate_to_<boundName> dispatch to reach a coding-kind sub-agent
83
+ // through the same composed executor everything else uses. There's no
84
+ // way to hand the native executor a reference to its own wrapping
85
+ // RoutingExecutor before that wrapper is constructed.
86
+ const nativeProviders = { llm, engine, datastore, secrets, memory };
87
+ const nativeExecutor = buildExecutor(providerConfig, nativeProviders, prisma);
88
+ const executor = buildConfiguredExecutor({ native: nativeExecutor, db: prisma, providerConfig });
89
+ nativeProviders.executor = executor;
90
+ return { providers: { llm, engine, datastore, secrets, executor, memory } };
91
+ }
92
+ /** Awaits `promise` (if any), logging and swallowing a rejection instead of propagating it. */
93
+ async function closeQuietly(promise, what) {
94
+ try {
95
+ await promise;
96
+ }
97
+ catch (err) {
98
+ mcpLog.warn({ err }, `${what} failed during MCP shutdown`);
99
+ }
100
+ }
101
+ /** The real CLI entry point: `wardby mcp`. Reads config from the environment, starts stdio or HTTP per MCP_TRANSPORT. */
102
+ export async function startMcp(options = {}) {
103
+ const mcpConfig = loadMcpConfig();
104
+ const providers = options.providers ?? buildMcpProviders().providers;
105
+ await providers.executor.launch?.();
106
+ if (!options.schedulerAttached)
107
+ await warnIfNothingWillFireSchedules();
108
+ if (mcpConfig.transport === "stdio") {
109
+ const mcp = buildMcpServer({ providers, db: prisma, config: { canonicalUri: STDIO_PLACEHOLDER_URI } });
110
+ const secretElicitationHost = createStdioSecretElicitationHost({
111
+ verify: (token) => mcp.verifyRequestState(token),
112
+ secrets: providers.secrets,
113
+ db: prisma,
114
+ });
115
+ registerAllTools(mcp, {
116
+ secretElicitationUrl: (token) => secretElicitationHost.urlFor(token),
117
+ secretElicitationProtocol: mcpConfig.secretElicitationProtocol,
118
+ });
119
+ // stdio never carries per-call AuthInfo — one fixed, fully-trusted
120
+ // local identity for the whole connection, per the design's own
121
+ // "stdio local mode: no token; the operator is trusted."
122
+ const principal = await resolvePrincipal(mcpConfig.localPrincipal, prisma);
123
+ mcp.setFixedContext({
124
+ principal,
125
+ scopes: new Set(SCOPES_SUPPORTED),
126
+ canonicalUri: STDIO_PLACEHOLDER_URI,
127
+ providers,
128
+ db: prisma,
129
+ clientSupportsTasks: false,
130
+ // Placeholder — server.ts's resolveCtx overwrites this with the
131
+ // current call's real mcpReq on every dispatch.
132
+ mcpReq: { requestState: () => undefined },
133
+ });
134
+ const stdio = runStdioServer(mcp);
135
+ return {
136
+ close: async () => {
137
+ await closeQuietly(stdio.close(), "stdio transport close");
138
+ await closeQuietly(providers.executor.close?.(), "executor close");
139
+ },
140
+ };
141
+ }
142
+ if (!mcpConfig.canonicalUri) {
143
+ throw new Error("MCP_CANONICAL_URI is required when MCP_TRANSPORT=http.");
144
+ }
145
+ if (!mcpConfig.httpBind) {
146
+ throw new Error("MCP_HTTP_BIND is required when MCP_TRANSPORT=http.");
147
+ }
148
+ const providerConfig = loadProviderConfig();
149
+ const authConfig = loadAuthConfig();
150
+ if (!authConfig.audience || canonicalUrl(mcpConfig.canonicalUri).href !== canonicalUrl(authConfig.audience).href) {
151
+ throw new Error("MCP_CANONICAL_URI and AUTH_AUDIENCE must be identical normalized URLs.");
152
+ }
153
+ const authProviderKind = providerConfig.auth === "self-hosted" ? "self-hosted" : "delegating";
154
+ const authProvider = buildAuthProvider(providerConfig.auth, authConfig, prisma);
155
+ const selfHosted = authProviderKind === "self-hosted" ? authProvider : undefined;
156
+ const mcp = buildMcpServer({ providers, db: prisma, config: { canonicalUri: mcpConfig.canonicalUri } });
157
+ const httpOrigin = canonicalUrl(mcpConfig.canonicalUri).origin;
158
+ registerAllTools(mcp, {
159
+ secretElicitationUrl: (token) => Promise.resolve(`${httpOrigin}${SECRET_ELICITATION_PATH}?t=${encodeURIComponent(token)}`),
160
+ secretElicitationProtocol: mcpConfig.secretElicitationProtocol,
161
+ });
162
+ const http = await startHttpServer({
163
+ mcp,
164
+ config: {
165
+ canonicalUri: canonicalUrl(mcpConfig.canonicalUri).href,
166
+ httpBind: mcpConfig.httpBind,
167
+ authProviderKind,
168
+ authorizationServer: authConfig.issuer,
169
+ allowedOrigins: mcpConfig.allowedOrigins,
170
+ },
171
+ auth: { authProvider, db: prisma, providers },
172
+ selfHosted,
173
+ });
174
+ const cleanupTimer = selfHosted
175
+ ? setInterval(() => {
176
+ selfHosted.cleanup().catch((err) => mcpLog.warn({ err }, "self-hosted auth cleanup failed"));
177
+ }, SELF_HOSTED_CLEANUP_INTERVAL_MS)
178
+ : undefined;
179
+ return {
180
+ close: async () => {
181
+ if (cleanupTimer)
182
+ clearInterval(cleanupTimer);
183
+ await closeQuietly(http.close(), "HTTP transport close");
184
+ await closeQuietly(providers.executor.close?.(), "executor close");
185
+ },
186
+ };
187
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * JSON-RPC 2.0 envelope types, re-exported from the real MCP SDK rather than
3
+ * hand-rolled: @modelcontextprotocol/server already implements the
4
+ * 2026-07-28 wire format (including the stateless per-request `_meta`
5
+ * envelope), and hand-rolling a second, subtly-incompatible copy would be
6
+ * pure risk for no benefit.
7
+ */
8
+ export type { JSONRPCMessage, JSONRPCRequest, JSONRPCNotification } from "@modelcontextprotocol/server";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The MCP server core: wraps @modelcontextprotocol/server's McpServer with
3
+ * wardby's own ToolSpec contract (scope-gated, McpRequestContext-aware).
4
+ *
5
+ * Architecture note (adapted from the plan during implementation): the SDK
6
+ * already provides correct, spec-compliant serving entries —
7
+ * `createMcpHandler` (HTTP, Task 7) and `serveStdio` (stdio, below) — both
8
+ * of which construct a fresh McpServer per request/connection from a cheap,
9
+ * side-effect-free `McpServerFactory`. Hand-rolling message dispatch
10
+ * ourselves (an earlier draft of this file did exactly that) turned out to
11
+ * require re-deriving the 2026-07-28 stateless per-request `_meta` envelope
12
+ * by hand — fragile and exactly the kind of protocol-fidelity risk the real
13
+ * SDK exists to remove. This file instead accumulates ToolSpecs and exposes
14
+ * an `McpServerFactory`; the transports (this file's `runStdioServer` /
15
+ * Task 7's HTTP transport) call it exactly the way the SDK expects.
16
+ *
17
+ * Auth threading: per-tool-call caller identity travels as the SDK's own
18
+ * `AuthInfo.extra.principal` (an in-process object reference, never
19
+ * serialized — see the official `scoped-tools` example, which enforces
20
+ * scope the same way, inside each tool handler via `ctx.http?.authInfo`).
21
+ * stdio has no per-call AuthInfo at all (serveStdio never sets it), so
22
+ * `setFixedContext` supplies one fixed LOCAL_PRINCIPAL identity for the
23
+ * whole connection.
24
+ */
25
+ import { type McpServerFactory, type InputRequiredResult } from "@modelcontextprotocol/server";
26
+ import type { PrismaClient } from "@prisma/client";
27
+ import type { McpRequestContext, McpProviders } from "./context.js";
28
+ export interface ToolSpec<Args = Record<string, unknown>> {
29
+ name: string;
30
+ description?: string;
31
+ /** Scope(s) required to call this tool — checked before the handler ever runs. */
32
+ scope: string | string[];
33
+ /**
34
+ * A plain JSON Schema object (matching this codebase's existing
35
+ * JSON-Schema-first tool convention — see src/sandbox/deriveJsonSchema).
36
+ * Converted via the SDK's own `fromJsonSchema()` rather than accepted as
37
+ * a zod raw shape: `McpServer.registerTool`'s zod-shape overload requires
38
+ * REAL zod v4, and `@modelcontextprotocol/server` bundles its own nested
39
+ * zod@4.5.4 copy — any zod v4 wardby itself installs (even the exact
40
+ * same version) is a structurally-incompatible separate module instance.
41
+ * JSON Schema has no such identity problem.
42
+ */
43
+ inputSchema?: Record<string, unknown>;
44
+ handler: (args: Args, ctx: McpRequestContext) => Promise<{
45
+ content: {
46
+ type: "text";
47
+ text: string;
48
+ }[];
49
+ structuredContent?: unknown;
50
+ } | InputRequiredResult>;
51
+ }
52
+ export interface McpServerConfig {
53
+ canonicalUri: string;
54
+ }
55
+ export interface BuildMcpServerOptions {
56
+ providers: McpProviders;
57
+ db: PrismaClient;
58
+ config: McpServerConfig;
59
+ /** Testability hook for REQUEST_STATE_KEY — defaults to process.env, matching buildSecretCipher's convention. */
60
+ env?: NodeJS.ProcessEnv;
61
+ }
62
+ export interface DiscoverResultLike {
63
+ capabilities: {
64
+ extensions?: Record<string, unknown>;
65
+ [key: string]: unknown;
66
+ };
67
+ }
68
+ export interface WardbyMcpServer {
69
+ registerTool<Args = Record<string, unknown>>(spec: ToolSpec<Args>): void;
70
+ /**
71
+ * Registers a custom JSON-RPC method (e.g. the Tasks extension's
72
+ * tasks/get, tasks/cancel, tasks/update — there is no npm runtime package
73
+ * for the extension, see Task 6's ledger note, so these are hand-wired
74
+ * the same way this SDK itself expects any custom method to be added:
75
+ * `Server.setRequestHandler`). Scope is enforced BEFORE the handler runs,
76
+ * exactly like registerTool — a custom method is not exempt from the
77
+ * scope gate just because it isn't a tool.
78
+ */
79
+ registerRequestHandler(method: string, scope: string | string[], handler: (params: unknown, ctx: McpRequestContext) => Promise<unknown>): void;
80
+ /** Passed directly to createMcpHandler (Task 7) / serveStdio (below). */
81
+ factory: McpServerFactory;
82
+ /** Local capability introspection without a protocol round-trip. */
83
+ discover(): Promise<DiscoverResultLike>;
84
+ /** stdio only: the one fixed identity every call in this connection resolves to. */
85
+ setFixedContext(ctx: McpRequestContext | undefined): void;
86
+ /**
87
+ * Seals `payload` into the opaque `requestState` string a multi-round-trip
88
+ * tool hands back via `inputRequired({ requestState })`. Backed by one
89
+ * HMAC codec created for the life of this `WardbyMcpServer` (stable across
90
+ * every `factory()` call, so state minted on one call verifies on a
91
+ * later one) — see the module doc for why the key never needs to be
92
+ * shared beyond this process.
93
+ */
94
+ mintRequestState<T>(payload: T): Promise<string>;
95
+ /**
96
+ * Verifies a `requestState`-shaped token OUTSIDE the normal MCP request
97
+ * path — used by the secret-elicitation browser form (stdio's ephemeral
98
+ * local server, or the HTTP transport's mounted route), which receives
99
+ * the token via a URL query param rather than the protocol's own
100
+ * `requestState` field. Throws on a malformed, tampered, or expired
101
+ * token. Uses the same codec as `mintRequestState`/the SDK's own
102
+ * `ServerOptions.requestState.verify` hook, so a token is valid on
103
+ * either path interchangeably.
104
+ */
105
+ verifyRequestState<T>(token: string): Promise<T>;
106
+ }
107
+ export declare function buildMcpServer(opts: BuildMcpServerOptions): WardbyMcpServer;
@@ -0,0 +1,203 @@
1
+ /**
2
+ * The MCP server core: wraps @modelcontextprotocol/server's McpServer with
3
+ * wardby's own ToolSpec contract (scope-gated, McpRequestContext-aware).
4
+ *
5
+ * Architecture note (adapted from the plan during implementation): the SDK
6
+ * already provides correct, spec-compliant serving entries —
7
+ * `createMcpHandler` (HTTP, Task 7) and `serveStdio` (stdio, below) — both
8
+ * of which construct a fresh McpServer per request/connection from a cheap,
9
+ * side-effect-free `McpServerFactory`. Hand-rolling message dispatch
10
+ * ourselves (an earlier draft of this file did exactly that) turned out to
11
+ * require re-deriving the 2026-07-28 stateless per-request `_meta` envelope
12
+ * by hand — fragile and exactly the kind of protocol-fidelity risk the real
13
+ * SDK exists to remove. This file instead accumulates ToolSpecs and exposes
14
+ * an `McpServerFactory`; the transports (this file's `runStdioServer` /
15
+ * Task 7's HTTP transport) call it exactly the way the SDK expects.
16
+ *
17
+ * Auth threading: per-tool-call caller identity travels as the SDK's own
18
+ * `AuthInfo.extra.principal` (an in-process object reference, never
19
+ * serialized — see the official `scoped-tools` example, which enforces
20
+ * scope the same way, inside each tool handler via `ctx.http?.authInfo`).
21
+ * stdio has no per-call AuthInfo at all (serveStdio never sets it), so
22
+ * `setFixedContext` supplies one fixed LOCAL_PRINCIPAL identity for the
23
+ * whole connection.
24
+ */
25
+ import { McpServer, fromJsonSchema, createRequestStateCodec, CLIENT_CAPABILITIES_META_KEY, } from "@modelcontextprotocol/server";
26
+ import { randomBytes } from "node:crypto";
27
+ import { requireScope } from "./auth/resource-server.js";
28
+ import { McpError } from "./errors.js";
29
+ import { TASKS_EXTENSION_ID, clientSupportsTasks } from "./capabilities.js";
30
+ import { visibleToPrincipal } from "./auth/ownership.js";
31
+ import { logger } from "../core/logger.js";
32
+ const REQUEST_STATE_KEY_BYTES = 32;
33
+ /**
34
+ * REQUEST_STATE_KEY (hex, 32 bytes) shares the requestState HMAC key across
35
+ * instances — see the requestStateCodec construction below. Unset falls back
36
+ * to a fresh random key, which is correct for stdio and single-instance HTTP
37
+ * and is NOT an error: only a multi-instance HTTP deployment needs this set.
38
+ */
39
+ function loadRequestStateKey(env) {
40
+ const hex = env.REQUEST_STATE_KEY;
41
+ if (!hex)
42
+ return randomBytes(REQUEST_STATE_KEY_BYTES);
43
+ const key = Buffer.from(hex, "hex");
44
+ if (key.length !== REQUEST_STATE_KEY_BYTES) {
45
+ throw new Error(`REQUEST_STATE_KEY must be ${REQUEST_STATE_KEY_BYTES} bytes of hex (${REQUEST_STATE_KEY_BYTES * 2} hex chars); got ${key.length} bytes.`);
46
+ }
47
+ return key;
48
+ }
49
+ /**
50
+ * Shown to every connecting client at session start (Claude Code and other
51
+ * compliant clients surface this directly to the calling assistant) — the
52
+ * main discovery channel for "you can run a wardby agent's prompt
53
+ * yourself, right now, instead of only via its schedule/trigger." Paired
54
+ * with the per-agent MCP prompts registered below, which are the concrete,
55
+ * one-call way to actually do it.
56
+ */
57
+ const SERVER_INSTRUCTIONS = 'wardby hosts reusable LLM agents (a system prompt, model, budget, and attached tools) that normally run on a schedule or webhook trigger. Every agent\'s full system prompt is available via list_agents/get_agent ("systemPrompt" field), and agents you can see are also registered as MCP prompts by name — you can adopt an agent\'s instructions and run them yourself, in this session, right now. This is a good way to shift work like code review left: e.g., before committing, run the "systemPrompt" of a code-review agent against your own working tree using your own tools, rather than waiting for a separately triggered run. Where a pulled prompt names a wardby-specific sandboxed tool, use your own equivalent tool for the same purpose instead.';
58
+ /** The MCP prompt body for one Agent — the message a client injects when a user invokes it (e.g. as a slash command). */
59
+ function agentPromptText(agent) {
60
+ return [
61
+ `You are adopting the instructions of wardby agent "${agent.name}" (model "${agent.model}") to run directly in this session, instead of waiting for its schedule/trigger.`,
62
+ "Follow the instructions below as this conversation's operating instructions. Where they name a specific wardby tool that isn't available here, use your own equivalent tool for the same purpose instead.",
63
+ "---",
64
+ agent.systemPrompt,
65
+ ].join("\n\n");
66
+ }
67
+ export function buildMcpServer(opts) {
68
+ const specs = [];
69
+ const requestHandlers = [];
70
+ let fixedContext;
71
+ // No `bind` callback, so `ctx` is never read by mint()/verify() (confirmed
72
+ // against the codec's implementation) — safe to call verifyRequestState()
73
+ // from outside a real MCP request (the secret-elicitation browser form).
74
+ //
75
+ // REQUEST_STATE_KEY, when set, lets a token minted by one process verify
76
+ // on another — required for the secret-elicitation round trip (mint,
77
+ // browser-form POST, polling retry) to work under a multi-instance HTTP
78
+ // deployment, where those three legs can land on three different
79
+ // processes (see secret-elicitation.ts's matching Postgres-backed outcome
80
+ // store). stdio and single-instance HTTP need no configuration: with the
81
+ // env var unset, a fresh random key per process is fine, since nothing
82
+ // outside this same running server ever needs to verify a token it minted.
83
+ const requestStateCodec = createRequestStateCodec({
84
+ key: loadRequestStateKey(opts.env ?? process.env),
85
+ ttlSeconds: 600,
86
+ });
87
+ function mcpReqOf(sdkCtx) {
88
+ return {
89
+ inputResponses: sdkCtx.mcpReq?.inputResponses,
90
+ requestState: sdkCtx.mcpReq?.requestState ?? (() => undefined),
91
+ };
92
+ }
93
+ function resolveCtx(sdkCtx) {
94
+ const authInfo = sdkCtx.http?.authInfo;
95
+ const extra = authInfo?.extra;
96
+ if (extra?.principal) {
97
+ return {
98
+ principal: extra.principal,
99
+ scopes: new Set(authInfo.scopes),
100
+ canonicalUri: opts.config.canonicalUri,
101
+ providers: opts.providers,
102
+ db: opts.db,
103
+ mcpReq: mcpReqOf(sdkCtx),
104
+ clientSupportsTasks: clientSupportsTasks(
105
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- ESLint's type-checked view of `envelope` disagrees with the real tsc build; the cast is load-bearing there.
106
+ sdkCtx.mcpReq?.envelope?.[CLIENT_CAPABILITIES_META_KEY]),
107
+ };
108
+ }
109
+ if (fixedContext)
110
+ return { ...fixedContext, mcpReq: mcpReqOf(sdkCtx) };
111
+ throw new McpError(401, "No authenticated context available for this call.");
112
+ }
113
+ function registerTool(spec) {
114
+ specs.push(spec);
115
+ }
116
+ function registerRequestHandler(method, scope, handler) {
117
+ requestHandlers.push({ method, scope: Array.isArray(scope) ? scope : [scope], handler });
118
+ }
119
+ const factory = async () => {
120
+ const mcpServer = new McpServer({ name: "wardby", version: "0.0.0" }, {
121
+ requestState: { verify: (state, ctx) => requestStateCodec.verify(state, ctx) },
122
+ instructions: SERVER_INSTRUCTIONS,
123
+ });
124
+ mcpServer.server.registerCapabilities({ extensions: { [TASKS_EXTENSION_ID]: {} } });
125
+ for (const spec of specs) {
126
+ const requiredScopes = Array.isArray(spec.scope) ? spec.scope : [spec.scope];
127
+ mcpServer.registerTool(spec.name, {
128
+ description: spec.description,
129
+ inputSchema: spec.inputSchema ? fromJsonSchema(spec.inputSchema) : undefined,
130
+ }, async (args, sdkCtx) => {
131
+ const ctx = resolveCtx(sdkCtx);
132
+ requireScope(ctx, opts.config.canonicalUri, ...requiredScopes);
133
+ return spec.handler(args, ctx);
134
+ });
135
+ }
136
+ // Non-spec (extension) methods need a { params, result } schema bundle
137
+ // — setRequestHandler only resolves schemas from the method name for
138
+ // spec methods (see docs/advanced/custom-methods.md). A permissive
139
+ // passthrough JSON Schema on both sides keeps this generic: real
140
+ // validation of taskId/etc. happens inside each handler, not here.
141
+ const PERMISSIVE_SCHEMA = fromJsonSchema({ type: "object", additionalProperties: true });
142
+ for (const { method, scope, handler } of requestHandlers) {
143
+ mcpServer.server.setRequestHandler(method, { params: PERMISSIVE_SCHEMA }, async (params, sdkCtx) => {
144
+ const ctx = resolveCtx(sdkCtx);
145
+ requireScope(ctx, opts.config.canonicalUri, ...scope);
146
+ return (await handler(params, ctx));
147
+ });
148
+ }
149
+ // One MCP prompt per Agent this connection can see, so a client that
150
+ // supports the prompts UI (e.g. a slash-command picker) can run a
151
+ // wardby agent directly — the concrete half of the "shift left"
152
+ // discovery story SERVER_INSTRUCTIONS introduces. Identity isn't
153
+ // reliably known yet for an HTTP connection at this point (resolveCtx
154
+ // resolves it per-dispatch from the SDK's own per-call ServerContext,
155
+ // not at factory time) — stdio's fixedContext IS set by now
156
+ // (mcp/index.ts calls setFixedContext before serveStdio ever invokes
157
+ // this factory), so stdio sees every agent it owns plus public ones;
158
+ // HTTP conservatively falls back to public-only until this factory can
159
+ // see request-scoped identity. A DB hiccup here must not break tool
160
+ // registration — this is a discoverability nicety, not core function.
161
+ try {
162
+ const where = fixedContext ? visibleToPrincipal(fixedContext.principal.id) : { ownerId: null };
163
+ const agents = await opts.db.agent.findMany({ where });
164
+ for (const agent of agents) {
165
+ mcpServer.registerPrompt(agent.name, {
166
+ title: agent.name,
167
+ description: `Run wardby agent "${agent.name}" (model ${agent.model}) directly in this session, instead of via its schedule/trigger.`,
168
+ }, () => ({
169
+ messages: [{ role: "user", content: { type: "text", text: agentPromptText(agent) } }],
170
+ }));
171
+ }
172
+ }
173
+ catch (err) {
174
+ logger.warn({ err }, "failed to register agent prompts — continuing without them");
175
+ }
176
+ return mcpServer;
177
+ };
178
+ async function discover() {
179
+ const probe = (await factory({ era: "modern" }));
180
+ return { capabilities: probe.server.getCapabilities() };
181
+ }
182
+ function setFixedContext(ctx) {
183
+ fixedContext = ctx;
184
+ }
185
+ function mintRequestState(payload) {
186
+ return requestStateCodec.mint(payload);
187
+ }
188
+ function verifyRequestState(token) {
189
+ // `ctx` is unused by verify() when no `bind` is configured (see the
190
+ // codec construction above) — this cast stands in for the real
191
+ // ServerContext an MCP request would supply.
192
+ return requestStateCodec.verify(token, {});
193
+ }
194
+ return {
195
+ registerTool,
196
+ registerRequestHandler,
197
+ factory,
198
+ discover,
199
+ setFixedContext,
200
+ mintRequestState,
201
+ verifyRequestState,
202
+ };
203
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Task manager: maps a Run's lifecycle onto the MCP Tasks extension
3
+ * (io.modelcontextprotocol/tasks, schema 2026-07-28 — field names verified
4
+ * against the extension's own reference TypeScript, not guessed). A "run"
5
+ * task's live status/result is always DERIVED from Run.status on read —
6
+ * the persisted Task row's own `status` column is the task's independent
7
+ * lifecycle stamp, mutated only by createRunTask (-> working) and
8
+ * cancelTask (-> cancelled, a terminal task-level state that intentionally
9
+ * doesn't unwind even if the underlying run later finishes on its own —
10
+ * cancellation is cooperative and eventually consistent, per the
11
+ * extension's own spec language).
12
+ */
13
+ import type { PrismaClient, Task } from "@prisma/client";
14
+ export type TaskStatus = "working" | "input_required" | "completed" | "failed" | "cancelled";
15
+ export interface JsonRpcErrorObject {
16
+ code: number;
17
+ message: string;
18
+ data?: unknown;
19
+ }
20
+ interface TaskFields {
21
+ taskId: string;
22
+ status: TaskStatus;
23
+ statusMessage?: string;
24
+ createdAt: string;
25
+ lastUpdatedAt: string;
26
+ ttlMs: number | null;
27
+ pollIntervalMs?: number;
28
+ }
29
+ export type CreateTaskResult = TaskFields & {
30
+ resultType: "task";
31
+ };
32
+ export type GetTaskResult = (TaskFields & {
33
+ resultType: "complete";
34
+ status: "working";
35
+ }) | (TaskFields & {
36
+ resultType: "complete";
37
+ status: "input_required";
38
+ inputRequests: Record<string, unknown>;
39
+ }) | (TaskFields & {
40
+ resultType: "complete";
41
+ status: "completed";
42
+ result: Record<string, unknown>;
43
+ }) | (TaskFields & {
44
+ resultType: "complete";
45
+ status: "failed";
46
+ error: JsonRpcErrorObject;
47
+ }) | (TaskFields & {
48
+ resultType: "complete";
49
+ status: "cancelled";
50
+ });
51
+ export declare function createTaskResult(row: Task, ttlMs: number): CreateTaskResult;
52
+ /** Starts a run-backed task: persists the Task row BEFORE returning, so a client's first tasks/get always finds it. */
53
+ export declare function createRunTask(runId: string, principalId: string, db: PrismaClient, ttlMs: number): Promise<CreateTaskResult>;
54
+ /** Reads a task's current state, deriving a run task's status from the live Run.status. */
55
+ export declare function getTask(taskId: string, db: PrismaClient): Promise<GetTaskResult>;
56
+ /**
57
+ * Cooperatively stops a task's underlying run (best-effort — cancellation
58
+ * is eventually consistent). A no-op when the run has already reached a
59
+ * terminal status on its own; the stop hook is never called for a run
60
+ * that's already finished.
61
+ */
62
+ export declare function cancelTask(taskId: string, db: PrismaClient, stopRun: (runId: string) => Promise<void>): Promise<void>;
63
+ export {};