@wardby/cli 0.2.0 → 0.3.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 (491) hide show
  1. package/.env.example +34 -4
  2. package/README.md +183 -71
  3. package/dist/claude-coding-worker/driver.d.ts +7 -1
  4. package/dist/claude-coding-worker/driver.js +31 -2
  5. package/dist/claude-coding-worker/main.js +5 -2
  6. package/dist/claude-coding-worker/tool-socket.d.ts +9 -0
  7. package/dist/claude-coding-worker/tool-socket.js +26 -0
  8. package/dist/cli-help.d.ts +1 -1
  9. package/dist/cli-help.js +13 -4
  10. package/dist/cli.d.ts +1 -1
  11. package/dist/cli.js +219 -29
  12. package/dist/coding/collect-exclude.d.ts +25 -0
  13. package/dist/coding/collect-exclude.js +76 -0
  14. package/dist/coding/profile.d.ts +67 -22
  15. package/dist/coding/profile.js +58 -25
  16. package/dist/coding/protected-path-wording.d.ts +24 -0
  17. package/dist/coding/protected-path-wording.js +55 -0
  18. package/dist/coding/protected-paths.d.ts +31 -0
  19. package/dist/coding/protected-paths.js +48 -0
  20. package/dist/coding/protocol.d.ts +99 -3
  21. package/dist/coding/protocol.js +155 -4
  22. package/dist/coding/registry/adapters.d.ts +2 -0
  23. package/dist/coding/registry/adapters.js +9 -0
  24. package/dist/coding/registry/allowlist.d.ts +9 -0
  25. package/dist/coding/registry/allowlist.js +28 -0
  26. package/dist/coding/registry/json-scan.d.ts +55 -0
  27. package/dist/coding/registry/json-scan.js +191 -0
  28. package/dist/coding/registry/lockfiles.d.ts +6 -0
  29. package/dist/coding/registry/lockfiles.js +89 -0
  30. package/dist/coding/registry/npm-lockfile.d.ts +9 -0
  31. package/dist/coding/registry/npm-lockfile.js +73 -0
  32. package/dist/coding/registry/npm-plan.d.ts +29 -0
  33. package/dist/coding/registry/npm-plan.js +289 -0
  34. package/dist/coding/registry/npm.d.ts +7 -0
  35. package/dist/coding/registry/npm.js +252 -0
  36. package/dist/coding/registry/pypi.d.ts +4 -0
  37. package/dist/coding/registry/pypi.js +210 -0
  38. package/dist/coding/registry/report.d.ts +37 -0
  39. package/dist/coding/registry/report.js +31 -0
  40. package/dist/coding/registry/token.d.ts +4 -0
  41. package/dist/coding/registry/token.js +7 -0
  42. package/dist/coding/registry/types.d.ts +286 -0
  43. package/dist/coding/registry/types.js +19 -0
  44. package/dist/coding/registry/worker-config.d.ts +14 -0
  45. package/dist/coding/registry/worker-config.js +31 -0
  46. package/dist/coding/services/builtins.d.ts +22 -0
  47. package/dist/coding/services/builtins.js +85 -0
  48. package/dist/coding/services/catalog.d.ts +443 -0
  49. package/dist/coding/services/catalog.js +159 -0
  50. package/dist/coding/services/declaration.d.ts +11 -0
  51. package/dist/coding/services/declaration.js +114 -0
  52. package/dist/coding/services/note.d.ts +8 -0
  53. package/dist/coding/services/note.js +15 -0
  54. package/dist/coding/services/resolve.d.ts +25 -0
  55. package/dist/coding/services/resolve.js +50 -0
  56. package/dist/coding/services/wording.d.ts +25 -0
  57. package/dist/coding/services/wording.js +70 -0
  58. package/dist/coding-proxy/main.js +24 -4
  59. package/dist/coding-worker/artifact.d.ts +18 -0
  60. package/dist/coding-worker/artifact.js +48 -6
  61. package/dist/coding-worker/debug-trace.d.ts +37 -0
  62. package/dist/coding-worker/debug-trace.js +117 -0
  63. package/dist/coding-worker/driver.d.ts +14 -1
  64. package/dist/coding-worker/driver.js +106 -14
  65. package/dist/coding-worker/errors.d.ts +7 -0
  66. package/dist/coding-worker/errors.js +26 -0
  67. package/dist/coding-worker/main.js +13 -4
  68. package/dist/coding-worker/sdk.d.ts +2 -2
  69. package/dist/coding-worker/sdk.js +7 -2
  70. package/dist/coding-worker/types.d.ts +3 -0
  71. package/dist/config/providers.d.ts +41 -0
  72. package/dist/config/providers.js +66 -0
  73. package/dist/core/budget-groups.d.ts +109 -6
  74. package/dist/core/budget-groups.js +125 -19
  75. package/dist/core/budget-wording.d.ts +22 -0
  76. package/dist/core/budget-wording.js +55 -0
  77. package/dist/core/coding-queue.d.ts +1 -1
  78. package/dist/core/datastores.d.ts +1 -1
  79. package/dist/core/datastores.js +18 -2
  80. package/dist/core/db.d.ts +40 -2
  81. package/dist/core/db.js +75 -2
  82. package/dist/core/dispatch.d.ts +49 -7
  83. package/dist/core/dispatch.js +290 -45
  84. package/dist/core/engine-native.js +27 -10
  85. package/dist/core/grants.d.ts +86 -0
  86. package/dist/core/grants.js +126 -0
  87. package/dist/core/host-events.d.ts +49 -0
  88. package/dist/core/host-events.js +257 -0
  89. package/dist/core/host-identity-links.d.ts +54 -0
  90. package/dist/core/host-identity-links.js +189 -0
  91. package/dist/core/host-status.d.ts +61 -0
  92. package/dist/core/host-status.js +211 -0
  93. package/dist/core/http-runtime.js +3 -4
  94. package/dist/core/in-flight-runs.d.ts +8 -0
  95. package/dist/core/in-flight-runs.js +56 -0
  96. package/dist/core/lease.d.ts +1 -1
  97. package/dist/core/private-directory.d.ts +20 -0
  98. package/dist/core/private-directory.js +36 -0
  99. package/dist/core/provider-wording.d.ts +12 -0
  100. package/dist/core/provider-wording.js +44 -0
  101. package/dist/core/reconciler.d.ts +39 -3
  102. package/dist/core/reconciler.js +86 -2
  103. package/dist/core/repo-access.d.ts +99 -0
  104. package/dist/core/repo-access.js +136 -0
  105. package/dist/core/review-host-checks.d.ts +11 -0
  106. package/dist/core/review-host-checks.js +41 -0
  107. package/dist/core/review-host-tools.d.ts +47 -0
  108. package/dist/core/review-host-tools.js +347 -0
  109. package/dist/core/run-heartbeat.d.ts +27 -0
  110. package/dist/core/run-heartbeat.js +54 -0
  111. package/dist/core/runner.d.ts +31 -9
  112. package/dist/core/runner.js +237 -40
  113. package/dist/core/scheduler.d.ts +1 -1
  114. package/dist/core/secrets.d.ts +12 -3
  115. package/dist/core/secrets.js +25 -6
  116. package/dist/core/subagent-memory-tools.d.ts +2 -2
  117. package/dist/core/subagent-memory-tools.js +16 -3
  118. package/dist/core/tool-admin.d.ts +81 -0
  119. package/dist/core/tool-admin.js +129 -0
  120. package/dist/core/tool-names.d.ts +42 -0
  121. package/dist/core/tool-names.js +64 -0
  122. package/dist/core/untrusted-content.d.ts +32 -0
  123. package/dist/core/untrusted-content.js +72 -0
  124. package/dist/core/webhooks.d.ts +9 -2
  125. package/dist/core/webhooks.js +23 -2
  126. package/dist/generated/prisma/browser.d.ts +328 -0
  127. package/dist/generated/prisma/browser.js +17 -0
  128. package/dist/generated/prisma/client.d.ts +347 -0
  129. package/dist/generated/prisma/client.js +34 -0
  130. package/dist/generated/prisma/commonInputTypes.d.ts +839 -0
  131. package/dist/generated/prisma/commonInputTypes.js +10 -0
  132. package/dist/generated/prisma/enums.d.ts +59 -0
  133. package/dist/generated/prisma/enums.js +59 -0
  134. package/dist/generated/prisma/internal/class.d.ts +605 -0
  135. package/dist/generated/prisma/internal/class.js +49 -0
  136. package/dist/generated/prisma/internal/prismaNamespace.d.ts +4494 -0
  137. package/dist/generated/prisma/internal/prismaNamespace.js +628 -0
  138. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +635 -0
  139. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +599 -0
  140. package/dist/generated/prisma/models/Agent.d.ts +3560 -0
  141. package/dist/generated/prisma/models/Agent.js +1 -0
  142. package/dist/generated/prisma/models/AgentDatastore.d.ts +1210 -0
  143. package/dist/generated/prisma/models/AgentDatastore.js +1 -0
  144. package/dist/generated/prisma/models/AgentMemory.d.ts +986 -0
  145. package/dist/generated/prisma/models/AgentMemory.js +1 -0
  146. package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
  147. package/dist/generated/prisma/models/AgentRepository.js +1 -0
  148. package/dist/generated/prisma/models/AgentSecret.d.ts +1212 -0
  149. package/dist/generated/prisma/models/AgentSecret.js +1 -0
  150. package/dist/generated/prisma/models/AgentSubAgent.d.ts +1217 -0
  151. package/dist/generated/prisma/models/AgentSubAgent.js +1 -0
  152. package/dist/generated/prisma/models/AgentTool.d.ts +1403 -0
  153. package/dist/generated/prisma/models/AgentTool.js +1 -0
  154. package/dist/generated/prisma/models/AuthFormChallenge.d.ts +1298 -0
  155. package/dist/generated/prisma/models/AuthFormChallenge.js +1 -0
  156. package/dist/generated/prisma/models/AuthLoginKey.d.ts +1245 -0
  157. package/dist/generated/prisma/models/AuthLoginKey.js +1 -0
  158. package/dist/generated/prisma/models/AuthRateLimit.d.ts +979 -0
  159. package/dist/generated/prisma/models/AuthRateLimit.js +1 -0
  160. package/dist/generated/prisma/models/AuthSession.d.ts +1376 -0
  161. package/dist/generated/prisma/models/AuthSession.js +1 -0
  162. package/dist/generated/prisma/models/AuthUser.d.ts +1700 -0
  163. package/dist/generated/prisma/models/AuthUser.js +1 -0
  164. package/dist/generated/prisma/models/BudgetGroup.d.ts +1548 -0
  165. package/dist/generated/prisma/models/BudgetGroup.js +1 -0
  166. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +1681 -0
  167. package/dist/generated/prisma/models/CodingAgentProfile.js +1 -0
  168. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +1749 -0
  169. package/dist/generated/prisma/models/CodingProxyRequest.js +1 -0
  170. package/dist/generated/prisma/models/CodingProxySession.d.ts +1626 -0
  171. package/dist/generated/prisma/models/CodingProxySession.js +1 -0
  172. package/dist/generated/prisma/models/CodingRun.d.ts +3583 -0
  173. package/dist/generated/prisma/models/CodingRun.js +1 -0
  174. package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
  175. package/dist/generated/prisma/models/CodingService.js +1 -0
  176. package/dist/generated/prisma/models/Datastore.d.ts +1434 -0
  177. package/dist/generated/prisma/models/Datastore.js +1 -0
  178. package/dist/generated/prisma/models/DatastoreEntry.d.ts +1314 -0
  179. package/dist/generated/prisma/models/DatastoreEntry.js +1 -0
  180. package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
  181. package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
  182. package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
  183. package/dist/generated/prisma/models/HostIdentity.js +1 -0
  184. package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
  185. package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
  186. package/dist/generated/prisma/models/OAuthAuthorizationCode.d.ts +1526 -0
  187. package/dist/generated/prisma/models/OAuthAuthorizationCode.js +1 -0
  188. package/dist/generated/prisma/models/OAuthAuthorizationRequest.d.ts +1350 -0
  189. package/dist/generated/prisma/models/OAuthAuthorizationRequest.js +1 -0
  190. package/dist/generated/prisma/models/OAuthClient.d.ts +1289 -0
  191. package/dist/generated/prisma/models/OAuthClient.js +1 -0
  192. package/dist/generated/prisma/models/OAuthFamily.d.ts +1540 -0
  193. package/dist/generated/prisma/models/OAuthFamily.js +1 -0
  194. package/dist/generated/prisma/models/OAuthGrant.d.ts +1280 -0
  195. package/dist/generated/prisma/models/OAuthGrant.js +1 -0
  196. package/dist/generated/prisma/models/Principal.d.ts +2245 -0
  197. package/dist/generated/prisma/models/Principal.js +1 -0
  198. package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
  199. package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
  200. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
  201. package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
  202. package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
  203. package/dist/generated/prisma/models/RegistryFetch.js +1 -0
  204. package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
  205. package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
  206. package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
  207. package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
  208. package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
  209. package/dist/generated/prisma/models/ResourceGrant.js +1 -0
  210. package/dist/generated/prisma/models/Run.d.ts +2669 -0
  211. package/dist/generated/prisma/models/Run.js +1 -0
  212. package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
  213. package/dist/generated/prisma/models/RunHostCheck.js +1 -0
  214. package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
  215. package/dist/generated/prisma/models/RunHostStatus.js +1 -0
  216. package/dist/generated/prisma/models/SchedulerLease.d.ts +970 -0
  217. package/dist/generated/prisma/models/SchedulerLease.js +1 -0
  218. package/dist/generated/prisma/models/Secret.d.ts +1399 -0
  219. package/dist/generated/prisma/models/Secret.js +1 -0
  220. package/dist/generated/prisma/models/SecretElicitationOutcome.d.ts +973 -0
  221. package/dist/generated/prisma/models/SecretElicitationOutcome.js +1 -0
  222. package/dist/generated/prisma/models/Task.d.ts +1176 -0
  223. package/dist/generated/prisma/models/Task.js +1 -0
  224. package/dist/generated/prisma/models/Tool.d.ts +1490 -0
  225. package/dist/generated/prisma/models/Tool.js +1 -0
  226. package/dist/generated/prisma/models/Webhook.d.ts +1386 -0
  227. package/dist/generated/prisma/models/Webhook.js +1 -0
  228. package/dist/generated/prisma/models.d.ts +45 -0
  229. package/dist/generated/prisma/models.js +1 -0
  230. package/dist/help/build.d.ts +1 -0
  231. package/dist/help/build.js +9 -0
  232. package/dist/help/catalog.d.ts +24 -0
  233. package/dist/help/catalog.js +160 -0
  234. package/dist/help/cli.d.ts +2 -0
  235. package/dist/help/cli.js +65 -0
  236. package/dist/help/runtime.d.ts +3 -0
  237. package/dist/help/runtime.js +44 -0
  238. package/dist/help/search.d.ts +9 -0
  239. package/dist/help/search.js +104 -0
  240. package/dist/help-index.json +660 -0
  241. package/dist/import/cli-args.js +3 -2
  242. package/dist/import/create.d.ts +6 -1
  243. package/dist/import/create.js +68 -14
  244. package/dist/import/index.d.ts +1 -1
  245. package/dist/import/index.js +19 -9
  246. package/dist/import/neutral-schema.d.ts +11 -11
  247. package/dist/mcp/auth/access.d.ts +70 -0
  248. package/dist/mcp/auth/access.js +58 -0
  249. package/dist/mcp/auth/grants-cli.d.ts +149 -0
  250. package/dist/mcp/auth/grants-cli.js +518 -0
  251. package/dist/mcp/auth/host-account-cli.d.ts +2 -0
  252. package/dist/mcp/auth/host-account-cli.js +47 -0
  253. package/dist/mcp/auth/ownership.d.ts +37 -63
  254. package/dist/mcp/auth/ownership.js +19 -14
  255. package/dist/mcp/auth/principal.d.ts +1 -1
  256. package/dist/mcp/auth/repo-authorization.d.ts +22 -0
  257. package/dist/mcp/auth/repo-authorization.js +51 -0
  258. package/dist/mcp/auth/resource-server.d.ts +32 -3
  259. package/dist/mcp/auth/resource-server.js +84 -3
  260. package/dist/mcp/auth/self-hosted/browser.js +22 -8
  261. package/dist/mcp/auth/self-hosted/cli.d.ts +1 -1
  262. package/dist/mcp/auth/self-hosted/cli.js +47 -13
  263. package/dist/mcp/auth/self-hosted/credentials.d.ts +21 -3
  264. package/dist/mcp/auth/self-hosted/credentials.js +62 -4
  265. package/dist/mcp/auth/self-hosted/rate-limit.d.ts +1 -1
  266. package/dist/mcp/auth/self-hosted/session.d.ts +3 -2
  267. package/dist/mcp/context.d.ts +28 -2
  268. package/dist/mcp/errors.d.ts +25 -6
  269. package/dist/mcp/errors.js +98 -0
  270. package/dist/mcp/host-events/github-ingress.d.ts +36 -0
  271. package/dist/mcp/host-events/github-ingress.js +92 -0
  272. package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
  273. package/dist/mcp/host-events/github-user-callback.js +50 -0
  274. package/dist/mcp/index.d.ts +8 -1
  275. package/dist/mcp/index.js +106 -16
  276. package/dist/mcp/server.d.ts +1 -1
  277. package/dist/mcp/server.js +27 -9
  278. package/dist/mcp/shared/page-style.d.ts +16 -0
  279. package/dist/mcp/shared/page-style.js +129 -0
  280. package/dist/mcp/tasks/manager.d.ts +1 -1
  281. package/dist/mcp/tools/agents.js +447 -49
  282. package/dist/mcp/tools/budget-groups.js +3 -3
  283. package/dist/mcp/tools/datastore.js +23 -16
  284. package/dist/mcp/tools/grants.d.ts +2 -0
  285. package/dist/mcp/tools/grants.js +239 -0
  286. package/dist/mcp/tools/help.d.ts +5 -0
  287. package/dist/mcp/tools/help.js +67 -0
  288. package/dist/mcp/tools/host-accounts.d.ts +2 -0
  289. package/dist/mcp/tools/host-accounts.js +114 -0
  290. package/dist/mcp/tools/memory.d.ts +7 -1
  291. package/dist/mcp/tools/memory.js +5 -5
  292. package/dist/mcp/tools/repositories.d.ts +2 -0
  293. package/dist/mcp/tools/repositories.js +181 -0
  294. package/dist/mcp/tools/runs.d.ts +6 -0
  295. package/dist/mcp/tools/runs.js +60 -6
  296. package/dist/mcp/tools/scheduling.js +4 -7
  297. package/dist/mcp/tools/secret-elicitation-form.d.ts +1 -1
  298. package/dist/mcp/tools/secret-elicitation-form.js +10 -28
  299. package/dist/mcp/tools/secret-elicitation.d.ts +1 -1
  300. package/dist/mcp/tools/secrets.js +18 -6
  301. package/dist/mcp/tools/services.d.ts +2 -0
  302. package/dist/mcp/tools/services.js +222 -0
  303. package/dist/mcp/tools/subagents.js +53 -17
  304. package/dist/mcp/tools/tools.d.ts +41 -0
  305. package/dist/mcp/tools/tools.js +202 -41
  306. package/dist/mcp/tools/trigger.js +36 -6
  307. package/dist/mcp/tools/webhooks.js +15 -4
  308. package/dist/mcp/transport/streamable-http.d.ts +11 -1
  309. package/dist/mcp/transport/streamable-http.js +32 -2
  310. package/dist/mcp/unattended-schedules.d.ts +1 -1
  311. package/dist/mcp/webhooks/ingress.d.ts +1 -1
  312. package/dist/providers/auth/delegating.d.ts +19 -0
  313. package/dist/providers/auth/delegating.js +71 -0
  314. package/dist/providers/auth/index.d.ts +3 -1
  315. package/dist/providers/auth/index.js +11 -0
  316. package/dist/providers/auth/self-hosted.d.ts +4 -3
  317. package/dist/providers/auth/self-hosted.js +16 -4
  318. package/dist/providers/auth/types.d.ts +6 -0
  319. package/dist/providers/coding-proxy/memory-ledger.d.ts +3 -0
  320. package/dist/providers/coding-proxy/memory-ledger.js +21 -2
  321. package/dist/providers/coding-proxy/metering.d.ts +4 -0
  322. package/dist/providers/coding-proxy/metering.js +28 -2
  323. package/dist/providers/coding-proxy/prisma-ledger.d.ts +18 -1
  324. package/dist/providers/coding-proxy/prisma-ledger.js +50 -5
  325. package/dist/providers/coding-proxy/proxy.d.ts +13 -0
  326. package/dist/providers/coding-proxy/proxy.js +479 -18
  327. package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
  328. package/dist/providers/coding-proxy/registry/audit.js +380 -0
  329. package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
  330. package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
  331. package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
  332. package/dist/providers/coding-proxy/registry/plan.js +304 -0
  333. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
  334. package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
  335. package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
  336. package/dist/providers/coding-proxy/registry/service.js +1137 -0
  337. package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
  338. package/dist/providers/coding-proxy/registry/store.js +70 -0
  339. package/dist/providers/coding-proxy/runtime.d.ts +18 -1
  340. package/dist/providers/coding-proxy/runtime.js +63 -0
  341. package/dist/providers/coding-proxy/secure-fetch.js +0 -1
  342. package/dist/providers/coding-proxy/server.d.ts +11 -0
  343. package/dist/providers/coding-proxy/server.js +163 -0
  344. package/dist/providers/coding-proxy/types.d.ts +15 -0
  345. package/dist/providers/datastore/postgres.d.ts +1 -1
  346. package/dist/providers/engine/types.d.ts +10 -0
  347. package/dist/providers/executor/build.d.ts +3 -3
  348. package/dist/providers/executor/composition.d.ts +4 -1
  349. package/dist/providers/executor/composition.js +19 -0
  350. package/dist/providers/executor/container.d.ts +106 -4
  351. package/dist/providers/executor/container.js +305 -22
  352. package/dist/providers/executor/dbos.d.ts +3 -4
  353. package/dist/providers/executor/in-process.d.ts +2 -3
  354. package/dist/providers/executor/routing.d.ts +7 -0
  355. package/dist/providers/executor/routing.js +13 -0
  356. package/dist/providers/executor/types.d.ts +22 -0
  357. package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
  358. package/dist/providers/jobs/claude-tool-setup.js +50 -0
  359. package/dist/providers/jobs/collect-prune.d.ts +7 -0
  360. package/dist/providers/jobs/collect-prune.js +27 -0
  361. package/dist/providers/jobs/docker-isolation.d.ts +48 -3
  362. package/dist/providers/jobs/docker-isolation.js +213 -22
  363. package/dist/providers/jobs/docker-services.d.ts +35 -0
  364. package/dist/providers/jobs/docker-services.js +191 -0
  365. package/dist/providers/jobs/docker.d.ts +60 -2
  366. package/dist/providers/jobs/docker.js +313 -50
  367. package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
  368. package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
  369. package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
  370. package/dist/providers/jobs/kubernetes-isolation.js +238 -57
  371. package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
  372. package/dist/providers/jobs/kubernetes-platform.js +11 -5
  373. package/dist/providers/jobs/kubernetes-preflight.js +3 -0
  374. package/dist/providers/jobs/kubernetes.d.ts +21 -2
  375. package/dist/providers/jobs/kubernetes.js +117 -31
  376. package/dist/providers/jobs/types.d.ts +20 -0
  377. package/dist/providers/llm/anthropic.js +6 -2
  378. package/dist/providers/llm/bedrock.js +2 -1
  379. package/dist/providers/llm/claude-messages.d.ts +5 -1
  380. package/dist/providers/llm/claude-messages.js +1 -0
  381. package/dist/providers/llm/claude-provider.d.ts +3 -1
  382. package/dist/providers/llm/claude-provider.js +5 -1
  383. package/dist/providers/llm/index.d.ts +1 -1
  384. package/dist/providers/llm/index.js +1 -1
  385. package/dist/providers/llm/pricing-anthropic.d.ts +10 -0
  386. package/dist/providers/llm/pricing-anthropic.js +32 -14
  387. package/dist/providers/llm/pricing-bedrock-claude.d.ts +8 -0
  388. package/dist/providers/llm/pricing-bedrock-claude.js +9 -0
  389. package/dist/providers/llm/routing.d.ts +10 -1
  390. package/dist/providers/llm/routing.js +18 -0
  391. package/dist/providers/llm/types.d.ts +12 -0
  392. package/dist/providers/llm/types.js +8 -1
  393. package/dist/providers/memory/postgres.d.ts +1 -1
  394. package/dist/providers/review-host/diff-lines.d.ts +16 -0
  395. package/dist/providers/review-host/diff-lines.js +59 -0
  396. package/dist/providers/review-host/github-events.d.ts +6 -0
  397. package/dist/providers/review-host/github-events.js +180 -0
  398. package/dist/providers/review-host/github-user-auth.d.ts +38 -0
  399. package/dist/providers/review-host/github-user-auth.js +128 -0
  400. package/dist/providers/review-host/github.d.ts +57 -0
  401. package/dist/providers/review-host/github.js +567 -0
  402. package/dist/providers/review-host/index.d.ts +12 -0
  403. package/dist/providers/review-host/index.js +30 -0
  404. package/dist/providers/review-host/review-format.d.ts +19 -0
  405. package/dist/providers/review-host/review-format.js +59 -0
  406. package/dist/providers/review-host/types.d.ts +284 -0
  407. package/dist/providers/review-host/types.js +24 -0
  408. package/dist/providers/vcs/git.d.ts +16 -6
  409. package/dist/providers/vcs/git.js +79 -14
  410. package/dist/providers/vcs/github.d.ts +74 -3
  411. package/dist/providers/vcs/github.js +195 -15
  412. package/dist/providers/vcs/types.d.ts +42 -4
  413. package/dist/quickstart/index.js +34 -32
  414. package/dist/quickstart/migrate.d.ts +23 -0
  415. package/dist/quickstart/migrate.js +125 -0
  416. package/dist/sandbox/fetch-policy.d.ts +20 -2
  417. package/dist/sandbox/fetch-policy.js +64 -3
  418. package/dist/sandbox/host-functions.d.ts +9 -1
  419. package/dist/sandbox/host-functions.js +12 -5
  420. package/dist/serve.js +1 -1
  421. package/dist/wardby-bin.js +6 -0
  422. package/docs/README.md +30 -0
  423. package/docs/architecture-runtime.md +90 -0
  424. package/docs/assets/brand/wardby-icon-512.png +0 -0
  425. package/docs/assets/brand/wardby-icon.svg +16 -0
  426. package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
  427. package/docs/assets/brand/wardby-mascot.png +0 -0
  428. package/docs/assets/brand/wardby-mascot.svg +5 -0
  429. package/docs/assets/wardby-workflow.svg +106 -0
  430. package/docs/code-review-agents.md +481 -0
  431. package/docs/coding-agent-setup.md +172 -0
  432. package/docs/coding-packages.md +455 -0
  433. package/docs/coding-services.md +300 -0
  434. package/docs/coding-worker-byo-images.md +98 -0
  435. package/docs/coding-worker-isolation.md +1061 -0
  436. package/docs/getting-started-gke.md +615 -0
  437. package/docs/getting-started-identity-provider.md +308 -0
  438. package/docs/getting-started.md +133 -0
  439. package/docs/observability.md +53 -0
  440. package/docs/release-verification.md +66 -0
  441. package/docs/security-deployment.md +657 -0
  442. package/help/code-review-agents.md +31 -0
  443. package/help/coding-packages.md +31 -0
  444. package/help/coding-services.md +71 -0
  445. package/help/creating-agents.md +68 -0
  446. package/help/deploy-gke.md +39 -0
  447. package/help/deployment-targets.md +39 -0
  448. package/help/errors/budget-group-exhausted.md +25 -0
  449. package/help/errors/docker-isolation-unsupported.md +26 -0
  450. package/help/errors/protected-path.md +45 -0
  451. package/help/errors/repo-access.md +27 -0
  452. package/help/errors/service-declaration-invalid.md +27 -0
  453. package/help/errors/service-declaration-unavailable.md +25 -0
  454. package/help/errors/service-launcher-unsupported.md +30 -0
  455. package/help/errors/service-not-allowed.md +27 -0
  456. package/help/errors/service-unknown.md +23 -0
  457. package/help/errors/service-unready.md +49 -0
  458. package/help/getting-started.md +31 -0
  459. package/help/github.md +30 -0
  460. package/help/identity-and-access.md +39 -0
  461. package/help/mcp.md +30 -0
  462. package/help/native-capabilities.md +30 -0
  463. package/help/observability.md +41 -0
  464. package/help/operating-agents.md +30 -0
  465. package/help/security.md +27 -0
  466. package/help/troubleshooting/budgets.md +26 -0
  467. package/help/troubleshooting/coding-workers.md +47 -0
  468. package/help/troubleshooting/repository-access.md +27 -0
  469. package/package.json +30 -11
  470. package/prisma/migrate.config.mjs +20 -0
  471. package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
  472. package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
  473. package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
  474. package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
  475. package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
  476. package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
  477. package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
  478. package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
  479. package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
  480. package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
  481. package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
  482. package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
  483. package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
  484. package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
  485. package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
  486. package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
  487. package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
  488. package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
  489. package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
  490. package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
  491. package/prisma/schema.prisma +417 -23
@@ -0,0 +1,181 @@
1
+ /**
2
+ * AgentRepository CRUD — which repositories on which code-review host a
3
+ * native agent may act on, and which host events trigger it. Linking needs
4
+ * more than owning the agent: the owner's own linked GitHub account must have
5
+ * the link's access on the repository (write for a write link, read for a
6
+ * read link), or a wardby admin must approve it explicitly (adminOverride).
7
+ * The authorization is stamped on the link and re-checked whenever the link
8
+ * is used (core/repo-access.ts). A repository is an owner binding (resource-
9
+ * sharing grants spec §3.4.3): link/unlink are the agent owner's alone (or
10
+ * an admin's explicit approval), whatever grants others hold on the agent,
11
+ * and owner-less agents can't be linked.
12
+ * See docs/private/2026-09-26-repo-access-authorization-spec-and-plan.md.
13
+ */
14
+ import { Prisma } from "#prisma";
15
+ import { normalizeGitHubRepository } from "../../coding/protocol.js";
16
+ import { requireAgentAccess, requireBindingOwner } from "../auth/access.js";
17
+ import { authorizeRepositoryForSet } from "../auth/repo-authorization.js";
18
+ import { requireScope } from "../auth/resource-server.js";
19
+ import { McpError } from "../errors.js";
20
+ import { textResult } from "./text-result.js";
21
+ const PROVIDERS = ["github"];
22
+ const TRIGGERS = ["pull_request", "mention"];
23
+ const CHECK_NAME = /^[A-Za-z0-9][A-Za-z0-9 ._/()-]{0,99}$/;
24
+ function normalizeRepository(provider, repository) {
25
+ try {
26
+ if (provider === "github")
27
+ return normalizeGitHubRepository(repository);
28
+ }
29
+ catch {
30
+ // fall through
31
+ }
32
+ throw new McpError(400, `invalid repository "${repository}" for provider ${provider}`);
33
+ }
34
+ async function assertNoConflicts(tx, args) {
35
+ if (args.triggers.length === 0 && args.checkName === null)
36
+ return;
37
+ const others = await tx.agentRepository.findMany({
38
+ where: { provider: args.provider, repository: args.repository, NOT: { agentId: args.agentId } },
39
+ });
40
+ if (args.triggers.includes("mention") && others.some((o) => o.triggers.includes("mention"))) {
41
+ throw new McpError(409, `Another agent already handles @-mentions on ${args.repository}.`);
42
+ }
43
+ // Against every other link, whatever its triggers: a check name identifies
44
+ // one agent's verdict on the repository (also a unique index).
45
+ if (args.checkName !== null && others.some((o) => o.checkName === args.checkName)) {
46
+ throw checkNameTaken(args.checkName, args.repository);
47
+ }
48
+ }
49
+ function checkNameTaken(checkName, repository) {
50
+ return new McpError(409, `Another agent already uses check name "${checkName}" on ${repository}.`);
51
+ }
52
+ export function registerRepositoryTools(mcp) {
53
+ mcp.registerTool({
54
+ name: "link_repository",
55
+ scope: "agents:write",
56
+ description: "Links a native agent you own to a repository on a code-review host, with its access, event triggers, and checkName. " +
57
+ "Your linked GitHub account (link_host_account) must have write access to the repository for a write link, or read for a " +
58
+ "read link; a wardby admin may instead approve it with adminOverride. checkName is only allowed (and required) with the " +
59
+ "pull_request trigger, and is unique per repository. Re-linking an already-linked repository replaces its access, " +
60
+ "triggers, and checkName (an omitted field is cleared, not kept) and re-checks access — always send the full desired state.",
61
+ inputSchema: {
62
+ type: "object",
63
+ additionalProperties: false,
64
+ properties: {
65
+ agentId: { type: "string" },
66
+ provider: { type: "string", enum: [...PROVIDERS] },
67
+ repository: { type: "string", minLength: 1, maxLength: 300 },
68
+ access: { type: "string", enum: ["read", "write"] },
69
+ triggers: { type: "array", items: { type: "string", enum: [...TRIGGERS] }, uniqueItems: true },
70
+ checkName: { type: "string", minLength: 1, maxLength: 100 },
71
+ adminOverride: {
72
+ type: "boolean",
73
+ description: "Admins only (agents:admin with the admin role): approve this link without checking GitHub access, recorded as an admin approval. Allowed on any agent that has an owner, not only the admin's own.",
74
+ },
75
+ },
76
+ required: ["agentId", "repository", "access"],
77
+ },
78
+ handler: async (args, ctx) => {
79
+ // An admin approving a repository explicitly may do it on any agent
80
+ // (the role already allows reassigning any agent with make_owner);
81
+ // everyone else, admins included, links only agents they own.
82
+ let agent;
83
+ if (args.adminOverride === true) {
84
+ requireScope(ctx, ctx.canonicalUri, "agents:admin");
85
+ agent = await ctx.db.agent.findUnique({ where: { id: args.agentId } });
86
+ if (!agent)
87
+ throw new McpError(404, `Agent "${args.agentId}" not found.`);
88
+ }
89
+ else {
90
+ agent = (await requireAgentAccess(ctx, args.agentId, "read")).agent;
91
+ requireBindingOwner(ctx, agent);
92
+ }
93
+ if (agent.kind !== "native") {
94
+ throw new McpError(400, "Repository links are for native agents only; coding agents use codingProfile.repository.");
95
+ }
96
+ const provider = args.provider ?? "github";
97
+ const repository = normalizeRepository(provider, args.repository);
98
+ const triggers = [...new Set(args.triggers ?? [])];
99
+ if (triggers.length > 0 && args.access !== "write")
100
+ throw new McpError(400, "Event triggers need write access.");
101
+ const checkName = args.checkName ?? null;
102
+ if (triggers.includes("pull_request") && !checkName) {
103
+ throw new McpError(400, "checkName is required with the pull_request trigger.");
104
+ }
105
+ if (checkName !== null && !triggers.includes("pull_request")) {
106
+ throw new McpError(400, "checkName needs the pull_request trigger (a check is only published for a dispatched PR).");
107
+ }
108
+ if (checkName !== null && !CHECK_NAME.test(checkName))
109
+ throw new McpError(400, "invalid checkName");
110
+ // The host call happens before, and outside, the serializable transaction.
111
+ const authorization = await authorizeRepositoryForSet(ctx, {
112
+ ownerId: agent.ownerId,
113
+ provider,
114
+ repository,
115
+ kind: args.access,
116
+ adminOverride: args.adminOverride === true,
117
+ });
118
+ let link;
119
+ try {
120
+ link = await ctx.db.$transaction(async (tx) => {
121
+ await assertNoConflicts(tx, { agentId: args.agentId, provider, repository, triggers, checkName });
122
+ const fields = { access: args.access, triggers, checkName, ...authorization };
123
+ return tx.agentRepository.upsert({
124
+ where: { agentId_provider_repository: { agentId: args.agentId, provider, repository } },
125
+ create: { agentId: args.agentId, provider, repository, ...fields },
126
+ update: fields,
127
+ });
128
+ }, { isolationLevel: "Serializable" });
129
+ }
130
+ catch (err) {
131
+ if (checkName !== null && err instanceof Prisma.PrismaClientKnownRequestError && err.code === "P2002") {
132
+ throw checkNameTaken(checkName, repository);
133
+ }
134
+ throw err;
135
+ }
136
+ return textResult({ linked: true, link });
137
+ },
138
+ });
139
+ mcp.registerTool({
140
+ name: "unlink_repository",
141
+ scope: "agents:write",
142
+ inputSchema: {
143
+ type: "object",
144
+ additionalProperties: false,
145
+ properties: {
146
+ agentId: { type: "string" },
147
+ provider: { type: "string", enum: [...PROVIDERS] },
148
+ repository: { type: "string", minLength: 1, maxLength: 300 },
149
+ },
150
+ required: ["agentId", "repository"],
151
+ },
152
+ handler: async (args, ctx) => {
153
+ const { agent } = await requireAgentAccess(ctx, args.agentId, "read");
154
+ requireBindingOwner(ctx, agent);
155
+ const provider = args.provider ?? "github";
156
+ const repository = normalizeRepository(provider, args.repository);
157
+ const { count } = await ctx.db.agentRepository.deleteMany({
158
+ where: { agentId: args.agentId, provider, repository },
159
+ });
160
+ return textResult({ unlinked: count > 0 });
161
+ },
162
+ });
163
+ mcp.registerTool({
164
+ name: "list_repositories",
165
+ scope: "agents:read",
166
+ inputSchema: {
167
+ type: "object",
168
+ additionalProperties: false,
169
+ properties: { agentId: { type: "string" } },
170
+ required: ["agentId"],
171
+ },
172
+ handler: async (args, ctx) => {
173
+ await requireAgentAccess(ctx, args.agentId, "read");
174
+ const links = await ctx.db.agentRepository.findMany({
175
+ where: { agentId: args.agentId },
176
+ orderBy: { createdAt: "asc" },
177
+ });
178
+ return textResult({ repositories: links });
179
+ },
180
+ });
181
+ }
@@ -1,2 +1,8 @@
1
1
  import type { WardbyMcpServer } from "../server.js";
2
+ /**
3
+ * Run visibility (resource-sharing grants spec §3.5, A6): a run's output is
4
+ * the triggerer's and the agent owner's, never every reader's. The owner
5
+ * (and the stdio operator) sees every run; anyone else only runs with
6
+ * Run.triggeredById equal to themselves.
7
+ */
2
8
  export declare function registerRunTools(mcp: WardbyMcpServer): void;
@@ -1,7 +1,15 @@
1
1
  import { McpError } from "../errors.js";
2
- import { requireReadableAgent } from "../auth/ownership.js";
2
+ import { agentAccess, requireAgentAccess } from "../auth/access.js";
3
3
  import { publicCodingRunResult } from "../../coding/protocol.js";
4
+ import { countPlanRefusals, summarizeRegistryFetches } from "../../coding/registry/report.js";
5
+ import { storedServiceLabels } from "../../coding/services/catalog.js";
4
6
  import { textResult } from "./text-result.js";
7
+ /**
8
+ * Run visibility (resource-sharing grants spec §3.5, A6): a run's output is
9
+ * the triggerer's and the agent owner's, never every reader's. The owner
10
+ * (and the stdio operator) sees every run; anyone else only runs with
11
+ * Run.triggeredById equal to themselves.
12
+ */
5
13
  export function registerRunTools(mcp) {
6
14
  mcp.registerTool({
7
15
  name: "list_runs",
@@ -12,9 +20,13 @@ export function registerRunTools(mcp) {
12
20
  required: ["agentId"],
13
21
  },
14
22
  handler: async (args, ctx) => {
15
- await requireReadableAgent(ctx.db, args.agentId, ctx.principal.id);
23
+ const { access } = await requireAgentAccess(ctx, args.agentId, "read");
16
24
  const runs = await ctx.db.run.findMany({
17
- where: { agentId: args.agentId, ...(args.status ? { status: args.status } : {}) },
25
+ where: {
26
+ agentId: args.agentId,
27
+ ...(args.status ? { status: args.status } : {}),
28
+ ...(access === "owner" ? {} : { triggeredById: ctx.principal.id }),
29
+ },
18
30
  take: args.limit,
19
31
  orderBy: { startedAt: "desc" },
20
32
  });
@@ -40,21 +52,63 @@ export function registerRunTools(mcp) {
40
52
  inputSchema: { type: "object", properties: { runId: { type: "string" } }, required: ["runId"] },
41
53
  handler: async (args, ctx) => {
42
54
  const run = await ctx.db.run.findUnique({ where: { id: args.runId } });
55
+ const notFound = new McpError(404, `Run "${args.runId}" not found.`);
43
56
  if (!run)
44
- throw new McpError(404, `Run "${args.runId}" not found.`);
45
- await requireReadableAgent(ctx.db, run.agentId, ctx.principal.id);
57
+ throw notFound;
58
+ // Its triggerer keeps seeing it even after losing access to the agent;
59
+ // otherwise only the agent's owner. read on the agent is not enough.
60
+ if (run.triggeredById !== ctx.principal.id) {
61
+ const agent = await ctx.db.agent.findUnique({ where: { id: run.agentId } });
62
+ if (!agent || (await agentAccess(ctx, agent)) !== "owner")
63
+ throw notFound;
64
+ }
46
65
  const codingRun = await ctx.db.codingRun.findUnique({
47
66
  where: { runId: run.id },
48
- select: { result: true, queuedAt: true },
67
+ select: {
68
+ result: true,
69
+ queuedAt: true,
70
+ failureCategory: true,
71
+ diagnosticId: true,
72
+ debugTrace: true,
73
+ services: true,
74
+ },
49
75
  });
50
76
  const codingResult = publicCodingRunResult(codingRun?.result);
51
77
  // A pending coding run with queuedAt is waiting for a concurrency slot
52
78
  // (CODING_MAX_CONCURRENT), not stuck.
53
79
  const codingQueuedAt = run.status === "pending" && codingRun?.queuedAt ? codingRun.queuedAt.toISOString() : undefined;
80
+ // Packages served/refused only exist for coding runs; a non-coding run
81
+ // has no RegistryFetch rows at all, so skip the query entirely.
82
+ const registryFetches = codingRun
83
+ ? await ctx.db.registryFetch.findMany({ where: { runId: run.id }, orderBy: { createdAt: "asc" } })
84
+ : [];
85
+ const { packages, packageRefusals } = summarizeRegistryFetches(registryFetches);
86
+ // Lockfile verification (POST /registry/<ecosystem>/-/plan): exact
87
+ // versions approved for the run, and distinct entries it refused.
88
+ const packagePlan = codingRun
89
+ ? {
90
+ approved: await ctx.db.registryApprovedVersion.count({ where: { runId: run.id } }),
91
+ refused: countPlanRefusals(registryFetches),
92
+ }
93
+ : undefined;
94
+ // A failed coding run's error is only an opaque id; these two say which
95
+ // stage failed and are the key an operator searches the control-plane
96
+ // log for (the real reason is logged there, never persisted). Both are
97
+ // designed to be safe to show the agent's owner (schema.prisma).
98
+ const failureCategory = codingRun?.failureCategory ?? undefined;
99
+ const diagnosticId = codingRun?.diagnosticId ?? undefined;
100
+ // Which services the run started with ("postgres 16"); never their images or environments.
101
+ const services = codingRun ? storedServiceLabels(codingRun.services) : [];
54
102
  return textResult({
55
103
  ...run,
56
104
  ...(codingResult ? { codingResult } : {}),
105
+ ...(failureCategory ? { failureCategory } : {}),
106
+ ...(diagnosticId ? { diagnosticId } : {}),
57
107
  ...(codingQueuedAt ? { codingQueuedAt } : {}),
108
+ // An admin turned on the debug trace: the worker's full trace is in its pod log.
109
+ ...(codingRun?.debugTrace ? { debugTrace: true } : {}),
110
+ ...(services.length > 0 ? { services } : {}),
111
+ ...(codingRun ? { packages, packageRefusals, packagePlan } : {}),
58
112
  });
59
113
  },
60
114
  });
@@ -1,7 +1,7 @@
1
- import { Prisma } from "@prisma/client";
1
+ import { Prisma } from "#prisma";
2
2
  import { validateCronExpression } from "../../core/cron.js";
3
3
  import { McpError } from "../errors.js";
4
- import { assertCanMutate, requireOwnedAgent } from "../auth/ownership.js";
4
+ import { assertAgentAccess, requireAgentAccess } from "../auth/access.js";
5
5
  import { textResult } from "./text-result.js";
6
6
  export function registerSchedulingTools(mcp) {
7
7
  mcp.registerTool({
@@ -20,10 +20,7 @@ export function registerSchedulingTools(mcp) {
20
20
  throw new McpError(400, `Invalid schedule/timezone: ${err instanceof Error ? err.message : String(err)}`);
21
21
  }
22
22
  const agent = await ctx.db.$transaction(async (tx) => {
23
- const existing = await tx.agent.findUnique({ where: { id: args.agentId }, include: { codingProfile: true } });
24
- if (!existing)
25
- throw new McpError(404, `Agent "${args.agentId}" not found.`);
26
- assertCanMutate(existing.ownerId, ctx.principal.id, `Agent "${args.agentId}" is not owned by the caller.`);
23
+ const { agent: existing } = await assertAgentAccess(ctx, await tx.agent.findUnique({ where: { id: args.agentId }, include: { codingProfile: true } }), args.agentId, "write", tx);
27
24
  if (existing.kind === "coding" && !existing.codingProfile?.defaultTask) {
28
25
  throw new McpError(400, "A default task is required before enabling a coding-agent schedule.");
29
26
  }
@@ -40,7 +37,7 @@ export function registerSchedulingTools(mcp) {
40
37
  scope: "agents:write",
41
38
  inputSchema: { type: "object", properties: { agentId: { type: "string" } }, required: ["agentId"] },
42
39
  handler: async (args, ctx) => {
43
- await requireOwnedAgent(ctx.db, args.agentId, ctx.principal.id);
40
+ await requireAgentAccess(ctx, args.agentId, "write");
44
41
  const agent = await ctx.db.agent.update({ where: { id: args.agentId }, data: { scheduleEnabled: false } });
45
42
  return textResult(agent);
46
43
  },
@@ -6,7 +6,7 @@
6
6
  * CSP can forbid scripts outright rather than needing a nonce.
7
7
  */
8
8
  import type { IncomingMessage, ServerResponse } from "node:http";
9
- import type { PrismaClient } from "@prisma/client";
9
+ import type { PrismaClient } from "#prisma";
10
10
  import type { SecretCipher } from "../../providers/secrets/types.js";
11
11
  import { type SecretElicitationPayload } from "./secret-elicitation.js";
12
12
  /** The HTTP-transport route path this form is mounted at (see streamable-http.ts). */
@@ -1,43 +1,24 @@
1
1
  import { fulfillSecretElicitation } from "./secret-elicitation.js";
2
+ import { PAGE_STYLE } from "../shared/page-style.js";
2
3
  /** The HTTP-transport route path this form is mounted at (see streamable-http.ts). */
3
4
  export const SECRET_ELICITATION_PATH = "/elicit/secret";
4
5
  function escape(value) {
5
6
  return value.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
6
7
  }
7
- const STYLE = `
8
- :root { color-scheme: light dark; }
9
- * { box-sizing: border-box; }
10
- body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px;
11
- background: #f5f5f7; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
12
- .card { background: #fff; border-radius: 14px; box-shadow: 0 1px 3px rgba(0,0,0,.1), 0 8px 24px rgba(0,0,0,.08);
13
- padding: 36px; max-width: 480px; width: 100%; }
14
- h1 { margin: 0 0 10px; font-size: 21px; }
15
- p { margin: 0 0 24px; color: #555; font-size: 14px; line-height: 1.5; }
16
- p strong { color: #111; }
17
- input[type=password] { display: block; width: 100%; padding: 16px 18px; font-size: 17px; letter-spacing: .02em;
18
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; border: 1px solid #d1d1d6; border-radius: 10px;
19
- margin-bottom: 18px; }
20
- input[type=password]:focus { outline: none; border-color: #0071e3; box-shadow: 0 0 0 3px rgba(0,113,227,.15); }
21
- button { width: 100%; padding: 15px; font-size: 15px; font-weight: 600; color: #fff; background: #0071e3;
22
- border: none; border-radius: 10px; cursor: pointer; }
23
- button:hover { background: #0077ed; }
24
- @media (prefers-color-scheme: dark) {
25
- body { background: #1c1c1e; }
26
- .card { background: #2c2c2e; box-shadow: none; }
27
- h1 { color: #f5f5f7; }
28
- p { color: #a1a1a6; }
29
- p strong { color: #f5f5f7; }
30
- input[type=password] { background: #1c1c1e; border-color: #48484a; color: #f5f5f7; }
31
- }`;
32
8
  function html(res, status, body) {
33
9
  res.setHeader("content-security-policy", "default-src 'none'; script-src 'none'; style-src 'unsafe-inline'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'");
34
10
  res.setHeader("cache-control", "no-store");
35
11
  res.setHeader("x-content-type-options", "nosniff");
36
- res.setHeader("referrer-policy", "no-referrer");
12
+ // Not no-referrer: under it a browser sends `Origin: null` on this page's native
13
+ // form POST, even to the same origin, and the HTTP transport rejects that as
14
+ // invalid_origin. same-origin keeps the Origin and still sends nothing,
15
+ // token-bearing URL included, to any other site. (The login page solves the
16
+ // same problem with a fetch() instead; this page runs no script at all.)
17
+ res.setHeader("referrer-policy", "same-origin");
37
18
  res
38
19
  .writeHead(status, { "content-type": "text/html; charset=utf-8" })
39
20
  .end(`<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">` +
40
- `<title>wardby secret entry</title><style>${STYLE}</style><body><div class="card">${body}</div></body></html>`);
21
+ `<title>wardby secret entry</title><style>${PAGE_STYLE}</style><body><div class="card"><div class="kicker">wardby</div>${body}</div></body></html>`);
41
22
  }
42
23
  /** Handles one GET (render) or POST (submit) for the secret-entry form at the given token. */
43
24
  export async function handleSecretElicitationForm(method, token, readFormBody, res, deps) {
@@ -53,7 +34,8 @@ export async function handleSecretElicitationForm(method, token, readFormBody, r
53
34
  }
54
35
  if (method === "GET") {
55
36
  html(res, 200, `<h1>Enter secret value</h1><p>Name: <strong>${escape(payload.secretName)}</strong></p>` +
56
- `<form method="post"><input type="password" name="value" autocomplete="off" required autofocus placeholder="Paste the value here">` +
37
+ `<form method="post"><label>Secret value` +
38
+ `<input type="password" name="value" autocomplete="off" required autofocus placeholder="Paste the value here"></label>` +
57
39
  `<button type="submit">Save</button></form>`);
58
40
  return;
59
41
  }
@@ -15,7 +15,7 @@
15
15
  * Expiry is swept lazily on every read and write via a `deleteMany` rather
16
16
  * than a timer, so an idle process holds no interval.
17
17
  */
18
- import type { PrismaClient } from "@prisma/client";
18
+ import type { PrismaClient } from "#prisma";
19
19
  import { type SecretMetadata } from "../../core/secrets.js";
20
20
  import type { SecretCipher } from "../../providers/secrets/types.js";
21
21
  export interface SecretElicitationPayload {
@@ -6,7 +6,8 @@
6
6
  import { inputRequired, inputResponse } from "@modelcontextprotocol/server";
7
7
  import { createSecret, listSecrets, attachSecret, detachSecret, deleteSecret } from "../../core/secrets.js";
8
8
  import { McpError } from "../errors.js";
9
- import { requireOwnedAgent, requireOwnedSecret } from "../auth/ownership.js";
9
+ import { requireOwnedSecret } from "../auth/ownership.js";
10
+ import { requireAgentAccess, requireBindingOwner } from "../auth/access.js";
10
11
  import { getSecretElicitationOutcome } from "./secret-elicitation.js";
11
12
  import { textResult } from "./text-result.js";
12
13
  export function registerSecretsTools(mcp, opts) {
@@ -87,9 +88,15 @@ export function registerSecretsTools(mcp, opts) {
87
88
  required: ["agentId", "name"],
88
89
  },
89
90
  handler: async (args, ctx) => {
90
- await requireOwnedAgent(ctx.db, args.agentId, ctx.principal.id);
91
+ // Strictly the agent owner's own secret on the owner's own agent
92
+ // (A2/S2-2): a binding hands the value to every tool the owner lets
93
+ // read it. Not even the stdio operator crosses owners.
94
+ const { agent } = await requireAgentAccess(ctx, args.agentId, "read");
95
+ requireBindingOwner(ctx, agent);
96
+ const ownerId = agent.ownerId;
91
97
  try {
92
- await attachSecret(args.agentId, args.name, ctx.principal.id, ctx.db, args.alias ?? args.name);
98
+ // Resolved among the agent owner's secrets (== the caller here).
99
+ await attachSecret(args.agentId, args.name, ownerId, ctx.db, args.alias ?? args.name);
93
100
  }
94
101
  catch (err) {
95
102
  throw new McpError(404, err instanceof Error ? err.message : String(err));
@@ -100,15 +107,20 @@ export function registerSecretsTools(mcp, opts) {
100
107
  mcp.registerTool({
101
108
  name: "detach_secret",
102
109
  scope: "secrets:write",
110
+ description: "Detaches a secret from an agent. `name` is the alias it was attached under; the secret's own name also works when no attachment has that alias.",
103
111
  inputSchema: {
104
112
  type: "object",
105
113
  properties: { agentId: { type: "string" }, name: { type: "string" } },
106
114
  required: ["agentId", "name"],
107
115
  },
108
116
  handler: async (args, ctx) => {
109
- await requireOwnedAgent(ctx.db, args.agentId, ctx.principal.id);
110
- await detachSecret(args.agentId, args.name, ctx.db);
111
- return textResult({ detached: true });
117
+ const { agent } = await requireAgentAccess(ctx, args.agentId, "read");
118
+ requireBindingOwner(ctx, agent);
119
+ const count = await detachSecret(args.agentId, args.name, ctx.db);
120
+ if (count === 0) {
121
+ throw new McpError(404, `No secret is attached to agent "${args.agentId}" as "${args.name}".`);
122
+ }
123
+ return textResult({ detached: true, count });
112
124
  },
113
125
  });
114
126
  mcp.registerTool({
@@ -0,0 +1,2 @@
1
+ import type { WardbyMcpServer } from "../server.js";
2
+ export declare function registerServiceTools(mcp: WardbyMcpServer): void;