@wardby/cli 0.7.0 → 0.8.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 (304) hide show
  1. package/.env.example +5 -5
  2. package/README.md +6 -1
  3. package/deploy/local/docker-compose.quickstart-coding.yml +6 -0
  4. package/dist/claude-coding-worker/driver.d.ts +12 -0
  5. package/dist/claude-coding-worker/driver.js +29 -7
  6. package/dist/claude-coding-worker/main.js +5 -1
  7. package/dist/claude-coding-worker/sdk.js +17 -1
  8. package/dist/claude-plugin/command.d.ts +61 -0
  9. package/dist/claude-plugin/command.js +376 -0
  10. package/dist/cli-help.d.ts +1 -1
  11. package/dist/cli-help.js +2 -1
  12. package/dist/cli.js +47 -3
  13. package/dist/coding/code-host.d.ts +16 -0
  14. package/dist/coding/code-host.js +60 -0
  15. package/dist/coding/mcp-token.d.ts +12 -0
  16. package/dist/coding/mcp-token.js +26 -0
  17. package/dist/coding/protocol.js +2 -0
  18. package/dist/coding/redact.js +6 -1
  19. package/dist/coding/transcript/recorder.d.ts +5 -4
  20. package/dist/coding/transcript/recorder.js +1 -1
  21. package/dist/coding-worker/debug-trace.d.ts +3 -1
  22. package/dist/coding-worker/debug-trace.js +4 -2
  23. package/dist/coding-worker/driver.js +8 -1
  24. package/dist/coding-worker/main.js +5 -1
  25. package/dist/coding-worker/mcp-config.d.ts +27 -0
  26. package/dist/coding-worker/mcp-config.js +32 -0
  27. package/dist/coding-worker/sdk.d.ts +36 -0
  28. package/dist/coding-worker/sdk.js +28 -1
  29. package/dist/coding-worker/types.d.ts +4 -0
  30. package/dist/config/mcp-call-limit.d.ts +8 -0
  31. package/dist/config/mcp-call-limit.js +18 -0
  32. package/dist/config/mcp-servers.d.ts +8 -0
  33. package/dist/config/mcp-servers.js +12 -0
  34. package/dist/config/test-simulators.d.ts +10 -0
  35. package/dist/config/test-simulators.js +28 -0
  36. package/dist/config/tool-timeout.d.ts +1 -0
  37. package/dist/config/tool-timeout.js +18 -0
  38. package/dist/core/coding-mcp.d.ts +36 -0
  39. package/dist/core/coding-mcp.js +253 -0
  40. package/dist/core/coding-repository.d.ts +46 -0
  41. package/dist/core/coding-repository.js +92 -0
  42. package/dist/core/delegation-slots.d.ts +27 -0
  43. package/dist/core/delegation-slots.js +44 -0
  44. package/dist/core/dispatch.d.ts +6 -2
  45. package/dist/core/dispatch.js +36 -11
  46. package/dist/core/error-code.js +1 -0
  47. package/dist/core/grants.d.ts +28 -3
  48. package/dist/core/grants.js +46 -4
  49. package/dist/core/host-events.js +7 -3
  50. package/dist/core/host-status.js +2 -2
  51. package/dist/core/issue-status.js +4 -3
  52. package/dist/core/mark-ready.d.ts +1 -1
  53. package/dist/core/mark-ready.js +1 -1
  54. package/dist/core/mcp-client/client.d.ts +47 -0
  55. package/dist/core/mcp-client/client.js +141 -0
  56. package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
  57. package/dist/core/mcp-client/jsonrpc.js +54 -0
  58. package/dist/core/mcp-client/results.d.ts +13 -0
  59. package/dist/core/mcp-client/results.js +42 -0
  60. package/dist/core/mcp-servers.d.ts +90 -0
  61. package/dist/core/mcp-servers.js +230 -0
  62. package/dist/core/mcp-tools.d.ts +108 -0
  63. package/dist/core/mcp-tools.js +287 -0
  64. package/dist/core/merge-order-check.js +38 -19
  65. package/dist/core/notification-dispatcher.js +2 -1
  66. package/dist/core/related-pull-requests.js +26 -10
  67. package/dist/core/review-fix.js +2 -2
  68. package/dist/core/review-host-tools.js +3 -1
  69. package/dist/core/runner.d.ts +66 -16
  70. package/dist/core/runner.js +281 -73
  71. package/dist/core/secret-broker-config.d.ts +2 -0
  72. package/dist/core/secret-broker-config.js +1 -1
  73. package/dist/core/secret-guard.d.ts +5 -2
  74. package/dist/core/secret-guard.js +22 -7
  75. package/dist/core/secrets.d.ts +11 -1
  76. package/dist/core/secrets.js +27 -1
  77. package/dist/core/serializable-retry.d.ts +18 -0
  78. package/dist/core/serializable-retry.js +43 -0
  79. package/dist/core/tool-admin.d.ts +5 -1
  80. package/dist/core/tool-admin.js +7 -2
  81. package/dist/core/tool-names.d.ts +13 -0
  82. package/dist/core/tool-names.js +20 -0
  83. package/dist/core/webhooks.d.ts +4 -0
  84. package/dist/core/webhooks.js +68 -49
  85. package/dist/core/workflow-run-events.js +2 -1
  86. package/dist/generated/prisma/browser.d.ts +31 -0
  87. package/dist/generated/prisma/client.d.ts +31 -0
  88. package/dist/generated/prisma/commonInputTypes.d.ts +50 -50
  89. package/dist/generated/prisma/internal/class.d.ts +66 -0
  90. package/dist/generated/prisma/internal/class.js +4 -4
  91. package/dist/generated/prisma/internal/prismaNamespace.d.ts +530 -1
  92. package/dist/generated/prisma/internal/prismaNamespace.js +75 -2
  93. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +79 -0
  94. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +75 -2
  95. package/dist/generated/prisma/models/Agent.d.ts +271 -0
  96. package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
  97. package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
  98. package/dist/generated/prisma/models/AgentRepository.d.ts +40 -1
  99. package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
  100. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +0 -7
  101. package/dist/generated/prisma/models/CodingProxySession.d.ts +119 -2
  102. package/dist/generated/prisma/models/CodingRun.d.ts +76 -1
  103. package/dist/generated/prisma/models/HostProvider.d.ts +2176 -0
  104. package/dist/generated/prisma/models/HostProvider.js +1 -0
  105. package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
  106. package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
  107. package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
  108. package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
  109. package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
  110. package/dist/generated/prisma/models/HostProviderTrustedAccount.js +1 -0
  111. package/dist/generated/prisma/models/McpServer.d.ts +1500 -0
  112. package/dist/generated/prisma/models/McpServer.js +1 -0
  113. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
  114. package/dist/generated/prisma/models/Principal.d.ts +167 -0
  115. package/dist/generated/prisma/models/ResourceGrant.d.ts +1 -1
  116. package/dist/generated/prisma/models/Secret.d.ts +387 -0
  117. package/dist/generated/prisma/models/Tool.d.ts +223 -1
  118. package/dist/generated/prisma/models.d.ts +6 -0
  119. package/dist/help/search.js +12 -3
  120. package/dist/help-index.json +719 -47
  121. package/dist/import/create.js +16 -1
  122. package/dist/import/neutral-schema.d.ts +1 -0
  123. package/dist/import/neutral-schema.js +2 -0
  124. package/dist/mcp/auth/grants-cli.d.ts +6 -4
  125. package/dist/mcp/auth/grants-cli.js +42 -3
  126. package/dist/mcp/auth/resource-server.d.ts +3 -1
  127. package/dist/mcp/auth/resource-server.js +17 -2
  128. package/dist/mcp/context.d.ts +3 -0
  129. package/dist/mcp/index.js +11 -0
  130. package/dist/mcp/tools/agents.js +100 -15
  131. package/dist/mcp/tools/grants.js +66 -28
  132. package/dist/mcp/tools/host-providers.d.ts +2 -0
  133. package/dist/mcp/tools/host-providers.js +215 -0
  134. package/dist/mcp/tools/mcp-servers.d.ts +26 -0
  135. package/dist/mcp/tools/mcp-servers.js +481 -0
  136. package/dist/mcp/tools/repositories.js +50 -10
  137. package/dist/mcp/tools/runs.js +178 -18
  138. package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
  139. package/dist/mcp/tools/secret-elicitation.js +25 -2
  140. package/dist/mcp/tools/secrets.js +38 -4
  141. package/dist/mcp/tools/tools.d.ts +6 -4
  142. package/dist/mcp/tools/tools.js +40 -8
  143. package/dist/mcp/tools/trigger.js +28 -6
  144. package/dist/mcp/transport/http-limits.d.ts +2 -0
  145. package/dist/mcp/transport/http-limits.js +6 -2
  146. package/dist/mcp/webhooks/ingress.js +10 -0
  147. package/dist/native-worker/gateway-server.d.ts +14 -0
  148. package/dist/native-worker/gateway-server.js +28 -7
  149. package/dist/native-worker/gateway.d.ts +2 -0
  150. package/dist/native-worker/gateway.js +5 -1
  151. package/dist/native-worker/http-server.d.ts +4 -0
  152. package/dist/native-worker/http-server.js +51 -0
  153. package/dist/native-worker/ledger.d.ts +6 -2
  154. package/dist/native-worker/ledger.js +5 -4
  155. package/dist/native-worker/protocol.d.ts +1 -0
  156. package/dist/native-worker/protocol.js +4 -1
  157. package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
  158. package/dist/providers/coding-proxy/capability-hash.js +5 -0
  159. package/dist/providers/coding-proxy/mcp-route.d.ts +34 -0
  160. package/dist/providers/coding-proxy/mcp-route.js +166 -0
  161. package/dist/providers/coding-proxy/memory-ledger.d.ts +2 -0
  162. package/dist/providers/coding-proxy/memory-ledger.js +15 -0
  163. package/dist/providers/coding-proxy/prisma-ledger.d.ts +1 -0
  164. package/dist/providers/coding-proxy/prisma-ledger.js +30 -2
  165. package/dist/providers/coding-proxy/proxy.d.ts +7 -1
  166. package/dist/providers/coding-proxy/proxy.js +134 -34
  167. package/dist/providers/coding-proxy/runtime.d.ts +6 -0
  168. package/dist/providers/coding-proxy/runtime.js +32 -1
  169. package/dist/providers/coding-proxy/server.d.ts +3 -0
  170. package/dist/providers/coding-proxy/server.js +10 -0
  171. package/dist/providers/coding-proxy/types.d.ts +13 -0
  172. package/dist/providers/executor/composition.js +5 -0
  173. package/dist/providers/executor/container.d.ts +33 -1
  174. package/dist/providers/executor/container.js +76 -7
  175. package/dist/providers/host-tools/invoke.d.ts +37 -0
  176. package/dist/providers/host-tools/invoke.js +117 -0
  177. package/dist/providers/host-tools/operations.d.ts +65 -0
  178. package/dist/providers/host-tools/operations.js +149 -0
  179. package/dist/providers/host-tools/registry.d.ts +79 -0
  180. package/dist/providers/host-tools/registry.js +362 -0
  181. package/dist/providers/host-tools/request-guard.d.ts +17 -0
  182. package/dist/providers/host-tools/request-guard.js +99 -0
  183. package/dist/providers/host-tools/self-test.d.ts +64 -0
  184. package/dist/providers/host-tools/self-test.js +142 -0
  185. package/dist/providers/jobs/docker-isolation.d.ts +2 -2
  186. package/dist/providers/jobs/docker-isolation.js +30 -8
  187. package/dist/providers/jobs/docker.d.ts +8 -0
  188. package/dist/providers/jobs/docker.js +33 -9
  189. package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
  190. package/dist/providers/jobs/kubernetes-isolation.js +15 -2
  191. package/dist/providers/jobs/kubernetes.d.ts +5 -0
  192. package/dist/providers/jobs/kubernetes.js +6 -1
  193. package/dist/providers/jobs/types.d.ts +6 -0
  194. package/dist/providers/review-host/types.d.ts +6 -4
  195. package/dist/providers/review-host/types.js +1 -1
  196. package/dist/providers/vcs/git.d.ts +6 -2
  197. package/dist/providers/vcs/git.js +15 -4
  198. package/dist/providers/vcs/github.d.ts +2 -71
  199. package/dist/providers/vcs/github.js +8 -11
  200. package/dist/providers/vcs/index.d.ts +1 -1
  201. package/dist/providers/vcs/index.js +1 -1
  202. package/dist/providers/vcs/remote.d.ts +4 -0
  203. package/dist/providers/vcs/remote.js +7 -1
  204. package/dist/providers/vcs/routing.d.ts +12 -6
  205. package/dist/providers/vcs/routing.js +21 -6
  206. package/dist/providers/vcs/types.d.ts +71 -3
  207. package/dist/quickstart/index.d.ts +5 -0
  208. package/dist/quickstart/index.js +21 -0
  209. package/dist/quickstart-images.json +1 -1
  210. package/dist/sandbox/eval-core.d.ts +12 -2
  211. package/dist/sandbox/eval-core.js +20 -4
  212. package/dist/sandbox/host-functions.d.ts +4 -0
  213. package/dist/sandbox/host-functions.js +7 -2
  214. package/dist/sandbox/limits.d.ts +4 -1
  215. package/dist/sandbox/limits.js +4 -1
  216. package/dist/sandbox/run-in-sandbox.d.ts +6 -0
  217. package/dist/sandbox/run-in-sandbox.js +14 -2
  218. package/dist/sandbox/safe-fetch.d.ts +2 -0
  219. package/dist/sandbox/safe-fetch.js +1 -1
  220. package/dist/sandbox/secret-broker.d.ts +1 -0
  221. package/dist/sandbox/secret-broker.js +1 -1
  222. package/dist/sandbox/tool-timeout.d.ts +32 -0
  223. package/dist/sandbox/tool-timeout.js +52 -0
  224. package/dist/sandbox/user-tool.d.ts +8 -1
  225. package/dist/sandbox/user-tool.js +9 -3
  226. package/dist/viewer/graph.js +2 -1
  227. package/dist/wardby-bin.js +5 -0
  228. package/docs/README.md +11 -1
  229. package/docs/agent-recipes.md +37 -4
  230. package/docs/architecture-runtime.md +1 -1
  231. package/docs/claude-code-plugin.md +164 -0
  232. package/docs/code-review-agents.md +6 -0
  233. package/docs/coding-agent-setup.md +77 -1
  234. package/docs/coding-worker-byo-images.md +4 -2
  235. package/docs/coding-worker-isolation.md +78 -7
  236. package/docs/debugging-agent-runs.md +242 -0
  237. package/docs/getting-started-gke.md +5 -4
  238. package/docs/getting-started-identity-provider.md +43 -37
  239. package/docs/getting-started.md +8 -0
  240. package/docs/host-providers.md +294 -0
  241. package/docs/mcp-servers.md +254 -0
  242. package/docs/native-sandbox.md +25 -9
  243. package/docs/security-deployment.md +110 -31
  244. package/docs/tool-secrets.md +3 -0
  245. package/docs/viewer-api.md +6 -0
  246. package/docs/viewer-api.openapi.yml +1 -1
  247. package/help/admin-viewer.md +4 -0
  248. package/help/agent-recipes.md +33 -2
  249. package/help/brokered-secrets.md +3 -0
  250. package/help/build-claude-code-image.md +1 -1
  251. package/help/claude-code-run-pane.md +40 -0
  252. package/help/errors/coding-mcp-pins-unavailable.md +35 -0
  253. package/help/errors/database-auth-invalid.md +1 -1
  254. package/help/errors/host-provider-error.md +40 -0
  255. package/help/errors/host-tool-failed.md +36 -0
  256. package/help/errors/mcp-call-limit.md +22 -0
  257. package/help/errors/mcp-call-timeout.md +22 -0
  258. package/help/errors/mcp-server-auth-failed.md +22 -0
  259. package/help/errors/mcp-server-credentials-unavailable.md +45 -0
  260. package/help/errors/mcp-server-error.md +28 -0
  261. package/help/errors/mcp-server-unreachable.md +22 -0
  262. package/help/errors/mcp-servers-off.md +21 -0
  263. package/help/errors/mcp-tool-not-allowed.md +26 -0
  264. package/help/errors/mcp-tool-removed.md +22 -0
  265. package/help/errors/mcp-unavailable.md +25 -0
  266. package/help/errors/native-sandbox-capacity.md +1 -1
  267. package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
  268. package/help/errors/native-sandbox-docker-failed.md +1 -1
  269. package/help/errors/native-sandbox-gateway-error.md +1 -1
  270. package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
  271. package/help/errors/native-sandbox-image-not-pinned.md +1 -1
  272. package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
  273. package/help/errors/native-sandbox-network-unenforced.md +1 -1
  274. package/help/errors/native-sandbox-requires-catalog.md +1 -1
  275. package/help/errors/native-sandbox-unavailable.md +1 -1
  276. package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
  277. package/help/errors/native-sandbox-worker-exited.md +1 -1
  278. package/help/errors/native-sandbox-worker-lost.md +1 -1
  279. package/help/errors/native-sandbox-worker-unready.md +1 -1
  280. package/help/errors/repository-not-listed.md +36 -0
  281. package/help/errors/repository-required.md +36 -0
  282. package/help/errors/tool-timeout.md +38 -0
  283. package/help/host-providers.md +40 -0
  284. package/help/identity-and-access.md +4 -1
  285. package/help/mcp-servers.md +73 -0
  286. package/help/mcp.md +7 -2
  287. package/help/native-capabilities.md +27 -1
  288. package/help/native-sandbox.md +1 -1
  289. package/help/operating-agents.md +16 -0
  290. package/help/related-pull-requests.md +7 -3
  291. package/help/repo-instructions-and-skills.md +3 -1
  292. package/help/resume-runs-locally.md +3 -0
  293. package/help/stop-run.md +1 -1
  294. package/help/troubleshooting/coding-workers.md +9 -1
  295. package/help/troubleshooting/debugging-agent-runs.md +29 -0
  296. package/package.json +2 -1
  297. package/prisma/migrations/20261102000000_host_providers/migration.sql +56 -0
  298. package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
  299. package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
  300. package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
  301. package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
  302. package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
  303. package/prisma/schema.prisma +159 -14
  304. package/scripts/git-askpass.sh +1 -1
@@ -1,4 +1,4 @@
1
- import { CODING_CODE_PROVIDER, normalizeGitHubRepository } from "../coding/protocol.js";
1
+ import { codeProviderOf, normalizeHostedRepository, pullRequestWebUrl } from "../coding/code-host.js";
2
2
  import { logger } from "./logger.js";
3
3
  import { maybeMarkReady } from "./mark-ready.js";
4
4
  import { collectRelatedPullRequests, runTreeRoot } from "./related-pull-requests.js";
@@ -31,18 +31,31 @@ export function mergeOrderVerdict(self, set) {
31
31
  return { status: "in_progress", waitingFor };
32
32
  return { status: "success", dependencies };
33
33
  }
34
- const prUrl = (repository, number) => `https://github.com/${repository}/pull/${number}`;
35
- /** `repository#number` as a link: never a title or any other free text from the host. */
36
- const prLink = (m) => `[${m.repository}#${m.number}](${prUrl(m.repository, m.number)})`;
34
+ /** `repository#number`, as a link when the host has one: never a title or any other free text from the host. */
35
+ const prLink = (m) => {
36
+ const label = `${m.repository}#${m.number}`;
37
+ const url = pullRequestWebUrl(codeProviderOf(m.repository), m.repository, m.number);
38
+ return url ? `[${label}](${url})` : label;
39
+ };
37
40
  const keyOf = (repository, number) => `${repository}#${number}`;
38
41
  function safeRepository(value) {
39
42
  try {
40
- return normalizeGitHubRepository(value);
43
+ return normalizeHostedRepository(value);
41
44
  }
42
45
  catch {
43
46
  return undefined;
44
47
  }
45
48
  }
49
+ const canPostCheck = (host) => host?.upsertNamedCheck !== undefined && host.pullRequestOrigin !== undefined;
50
+ /** The host that can post this repository's merge order check, if any. */
51
+ function checkHost(hosts, repository) {
52
+ const host = hosts?.[codeProviderOf(repository)];
53
+ return canPostCheck(host) ? host : undefined;
54
+ }
55
+ /** Whether any configured host can post the check; none means nothing to read or sync. */
56
+ function anyCheckHost(hosts) {
57
+ return Object.values(hosts ?? {}).some(canPostCheck);
58
+ }
46
59
  function originState(origin) {
47
60
  if (origin.merged)
48
61
  return "merged";
@@ -109,8 +122,7 @@ export function mergeOrderCheckInput(self, verdict, steps, headSha, leadRunning
109
122
  */
110
123
  export async function syncMergeOrderChecks(deps, seedRunId, opts = {}) {
111
124
  const log = deps.log ?? moduleLog;
112
- const host = deps.hosts?.[CODING_CODE_PROVIDER];
113
- if (!host?.upsertNamedCheck || !host.pullRequestOrigin)
125
+ if (!anyCheckHost(deps.hosts))
114
126
  return;
115
127
  try {
116
128
  const group = await collectRelatedPullRequests(deps.db, seedRunId);
@@ -154,9 +166,15 @@ export async function syncMergeOrderChecks(deps, seedRunId, opts = {}) {
154
166
  continue;
155
167
  }
156
168
  try {
157
- const origin = reused && key === keyOf(reused, opts.origin.number)
158
- ? await opts.origin.read()
159
- : await host.pullRequestOrigin(pr.repository, pr.number);
169
+ let origin;
170
+ // Reading only needs the read: a host that can't post checks still reports its pull requests.
171
+ const memberHost = deps.hosts?.[codeProviderOf(pr.repository)];
172
+ if (reused && key === keyOf(reused, opts.origin.number))
173
+ origin = await opts.origin.read();
174
+ else if (memberHost?.pullRequestOrigin)
175
+ origin = await memberHost.pullRequestOrigin(pr.repository, pr.number);
176
+ else
177
+ throw new Error("no_host_for_repository");
160
178
  let headSha;
161
179
  if (origin.markerRunId) {
162
180
  const opener = await deps.db.codingRun.findUnique({
@@ -186,9 +204,12 @@ export async function syncMergeOrderChecks(deps, seedRunId, opts = {}) {
186
204
  const verdict = mergeOrderVerdict(self, set);
187
205
  if (verdict.status === "skip")
188
206
  continue;
207
+ const selfHost = checkHost(deps.hosts, self.repository);
208
+ if (!selfHost)
209
+ continue;
189
210
  const input = mergeOrderCheckInput(self, verdict, steps, target.headSha, leadRunning);
190
211
  try {
191
- await host.upsertNamedCheck(self.repository, input);
212
+ await selfHost.upsertNamedCheck(self.repository, input);
192
213
  log.info({ seedRunId, repository: self.repository, number: self.number, status: verdict.status }, "merge order check posted");
193
214
  }
194
215
  catch (err) {
@@ -197,7 +218,7 @@ export async function syncMergeOrderChecks(deps, seedRunId, opts = {}) {
197
218
  }
198
219
  if (input.status === "completed" && input.conclusion === "success") {
199
220
  // The last earlier step merged: the pull request may now be ready for review (#287).
200
- await maybeMarkReady({ db: deps.db, hosts: deps.hosts, log: deps.log }, self.repository, self.number);
221
+ await maybeMarkReady({ db: deps.db, hosts: deps.hosts, log: deps.log }, self.repository, self.number, codeProviderOf(self.repository));
201
222
  }
202
223
  }
203
224
  }
@@ -212,8 +233,7 @@ export async function syncMergeOrderChecks(deps, seedRunId, opts = {}) {
212
233
  export async function syncMergeOrderChecksAfterRun(deps, run) {
213
234
  if (run.parentRunId !== null)
214
235
  return;
215
- const host = deps.hosts?.[CODING_CODE_PROVIDER];
216
- if (!host?.upsertNamedCheck || !host.pullRequestOrigin)
236
+ if (!anyCheckHost(deps.hosts))
217
237
  return;
218
238
  try {
219
239
  if (!(await deps.db.run.findFirst({ where: { parentRunId: run.id }, select: { id: true } })))
@@ -250,12 +270,12 @@ async function orderedSeeds(db, repository, number) {
250
270
  */
251
271
  export async function syncMergeOrderChecksForPullRequest(deps, pr, opts = {}) {
252
272
  const log = deps.log ?? moduleLog;
253
- const host = deps.hosts?.[CODING_CODE_PROVIDER];
254
- if (!host?.upsertNamedCheck || !host.pullRequestOrigin)
255
- return;
256
273
  const repository = safeRepository(pr.repository);
257
274
  if (!repository || !Number.isSafeInteger(pr.number) || pr.number <= 0)
258
275
  return;
276
+ // This pull request's own host need not post checks: its siblings' checks may depend on it.
277
+ if (!anyCheckHost(deps.hosts))
278
+ return;
259
279
  let roots;
260
280
  try {
261
281
  roots = [];
@@ -297,8 +317,7 @@ export function resetMergeOrderSweepForTests() {
297
317
  */
298
318
  export async function sweepMergeOrderChecks(deps, now = new Date()) {
299
319
  const log = deps.log ?? moduleLog;
300
- const host = deps.hosts?.[CODING_CODE_PROVIDER];
301
- if (!host?.upsertNamedCheck || !host.pullRequestOrigin)
320
+ if (!anyCheckHost(deps.hosts))
302
321
  return 0;
303
322
  if (now.getTime() - lastSweepAt < MERGE_ORDER_SWEEP_INTERVAL_MS)
304
323
  return 0;
@@ -34,6 +34,7 @@
34
34
  */
35
35
  import { Prisma } from "#prisma";
36
36
  import { ChatError, } from "../providers/chat/types.js";
37
+ import { pullRequestWebUrl } from "../coding/code-host.js";
37
38
  import { tryAcquireLease } from "./lease.js";
38
39
  import { logger } from "./logger.js";
39
40
  import { broadcasts, nextStatus, renderEvent, renderParent, senderName, } from "./notification-templates.js";
@@ -82,7 +83,7 @@ async function subjectOf(db, d) {
82
83
  return { label: ev.workItemKey, title: item?.title ?? null, url: item?.url ?? null };
83
84
  }
84
85
  if (ev.repository && ev.prNumber != null) {
85
- const url = ev.codeProvider === "github" ? `https://github.com/${ev.repository}/pull/${ev.prNumber}` : null;
86
+ const url = pullRequestWebUrl(ev.codeProvider ?? "", ev.repository, ev.prNumber);
86
87
  return { label: `${ev.repository}#${ev.prNumber}`, title: null, url };
87
88
  }
88
89
  if (ev.runId)
@@ -23,7 +23,7 @@
23
23
  * brings every later follow-up tree that continued one of its pull requests.
24
24
  */
25
25
  import { Prisma } from "#prisma";
26
- import { CODING_CODE_PROVIDER, normalizeGitHubRepository } from "../coding/protocol.js";
26
+ import { codeProviderOf, normalizeHostedRepository, pullRequestWebUrl } from "../coding/code-host.js";
27
27
  import { issueReference, } from "../providers/issue-tracker/types.js";
28
28
  import { renderRelatedSection } from "../providers/vcs/github.js";
29
29
  import { pullRequestOutcome } from "./host-status.js";
@@ -91,7 +91,7 @@ export async function runTreeRoot(db, markerRunId, repository) {
91
91
  }
92
92
  function safeRepository(value) {
93
93
  try {
94
- return normalizeGitHubRepository(value);
94
+ return normalizeHostedRepository(value);
95
95
  }
96
96
  catch {
97
97
  return undefined;
@@ -222,7 +222,8 @@ onlyIssueKey) {
222
222
  if (issueFilter.size > 0) {
223
223
  const recorded = await db.issuePullRequest.findMany({
224
224
  where: {
225
- codeProvider: CODING_CODE_PROVIDER,
225
+ // A local repository has no pull requests to record: everything here is on a code host.
226
+ codeProvider: { not: "local" },
226
227
  OR: [...issueFilter.values()].map((i) => ({ issueProvider: i.provider, issueKey: i.key })),
227
228
  },
228
229
  select: { repository: true, number: true, createdAt: true, openedByRunId: true, state: true },
@@ -269,6 +270,7 @@ onlyIssueKey) {
269
270
  ...(roots.size > 0 ? { roots: [...roots].map(([id, root]) => ({ id, ...root })) } : {}),
270
271
  };
271
272
  }
273
+ const canEditRelatedSection = (host) => host?.replaceRelatedSection !== undefined && host.pullRequestOrigin !== undefined;
272
274
  function issueFor(group, trackers) {
273
275
  if (!group.issue)
274
276
  return undefined;
@@ -283,8 +285,12 @@ function issueFor(group, trackers) {
283
285
  * deployment recorded in that repository, are edited.
284
286
  */
285
287
  export async function updateRelatedPullRequests(db, run, hosts, trackers) {
286
- const host = hosts?.[CODING_CODE_PROVIDER];
287
- if (!host?.replaceRelatedSection || !host.pullRequestOrigin)
288
+ // A request's pull requests may span hosts: each is read and written through its own.
289
+ const editorFor = (repository) => {
290
+ const host = hosts?.[codeProviderOf(repository)];
291
+ return canEditRelatedSection(host) ? host : undefined;
292
+ };
293
+ if (!Object.values(hosts ?? {}).some(canEditRelatedSection))
288
294
  return;
289
295
  try {
290
296
  // A run that delegated nothing has no request set of its own.
@@ -306,6 +312,10 @@ export async function updateRelatedPullRequests(db, run, hosts, trackers) {
306
312
  continue;
307
313
  }
308
314
  try {
315
+ // Reading only needs the read: a host that can't edit the section still reports its pull requests.
316
+ const host = hosts?.[codeProviderOf(pr.repository)];
317
+ if (!host?.pullRequestOrigin)
318
+ throw new Error("no_host_for_repository");
309
319
  const origin = await host.pullRequestOrigin(pr.repository, pr.number);
310
320
  const state = origin.merged
311
321
  ? "merged"
@@ -358,6 +368,9 @@ export async function updateRelatedPullRequests(db, run, hosts, trackers) {
358
368
  });
359
369
  if (!block)
360
370
  continue;
371
+ const host = editorFor(target.repository);
372
+ if (!host)
373
+ continue;
361
374
  try {
362
375
  const outcome = await host.replaceRelatedSection(target.repository, target.number, {
363
376
  expectedMarkerRunId: target.markerRunId,
@@ -381,7 +394,7 @@ const SAFE_RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
381
394
  export const SIBLING_GUIDANCE = "Continue the pull request you were asked about, and a listed open one only when the change requires it. " +
382
395
  "Never open a new pull request in a repository that already has an open pull request listed here. Merged or " +
383
396
  "closed pull requests are not listed: a change there needs a new pull request.";
384
- const HINT_REPOSITORY = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
397
+ const HINT_REPOSITORY = /^(?:[a-z][a-z0-9-]{1,30}:)?[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
385
398
  /**
386
399
  * The continuation hint for a ticket (a GitHub or Jira issue) that already has
387
400
  * open wardby pull requests: one sentence per pull request (up to
@@ -396,9 +409,12 @@ export function openPullRequestHints(prs) {
396
409
  Number.isSafeInteger(p.number) &&
397
410
  p.number > 0)
398
411
  .slice(0, MAX_SIBLING_HINTS)
399
- .map((p) => `This issue already has an open pull request wardby opened: ${p.repository}#${p.number} ` +
400
- `(https://github.com/${p.repository}/pull/${p.number}). ` +
401
- `To revise it, delegate with continuePriorRun set to exactly "${p.openedByRunId}".`);
412
+ .map((p) => {
413
+ const url = pullRequestWebUrl(codeProviderOf(p.repository), p.repository, p.number);
414
+ return (`This issue already has an open pull request wardby opened: ${p.repository}#${p.number}` +
415
+ `${url ? ` (${url})` : ""}. ` +
416
+ `To revise it, delegate with continuePriorRun set to exactly "${p.openedByRunId}".`);
417
+ });
402
418
  return lines.length > 0 ? [...lines, SIBLING_GUIDANCE].join("\n\n") : "";
403
419
  }
404
420
  /**
@@ -436,7 +452,7 @@ export async function openSiblings(db, seedRunId, exclude) {
436
452
  export async function openSiblingsForIssue(db, issue) {
437
453
  try {
438
454
  const newest = await db.issuePullRequest.findMany({
439
- where: { issueProvider: issue.provider, issueKey: issue.key, codeProvider: CODING_CODE_PROVIDER },
455
+ where: { issueProvider: issue.provider, issueKey: issue.key, codeProvider: { not: "local" } },
440
456
  orderBy: { createdAt: "desc" },
441
457
  take: 1,
442
458
  select: { openedByRunId: true },
@@ -182,7 +182,7 @@ export async function startReviewFixAfterReview(runId, deps) {
182
182
  const check = await deps.db.runHostCheck.findUnique({ where: { runId } });
183
183
  if (!check || check.verdict !== "CHANGES_REQUESTED" || check.prNumber === null || !check.reviewBody)
184
184
  return;
185
- if (check.provider !== "github")
185
+ if (check.provider === "local")
186
186
  return;
187
187
  const result = await startReviewFixRound({
188
188
  provider: check.provider,
@@ -256,7 +256,7 @@ async function reReview(runId, deps) {
256
256
  if (root.parentRunId)
257
257
  return skip("not_fix_round");
258
258
  const status = root.hostStatus;
259
- if (!status || status.provider !== "github")
259
+ if (!status || status.provider === "local")
260
260
  return skip("not_fix_round");
261
261
  const provider = status.provider;
262
262
  const { repository, number: prNumber } = status;
@@ -14,6 +14,7 @@ import { MAX_PATCH_CURSOR_CHARS } from "../providers/review-host/patch-pages.js"
14
14
  import { escapeHtmlComments } from "../providers/review-host/review-format.js";
15
15
  import { REVIEW_HOST_PROVIDERS, PatchCursorError, ReviewHostError, } from "../providers/review-host/types.js";
16
16
  import { isLocalRepository, normalizeGitHubRepository, normalizeLocalRepository } from "../coding/protocol.js";
17
+ import { codeProviderOf, normalizeHostedRepository } from "../coding/code-host.js";
17
18
  import { ciForAgent } from "./ci-context.js";
18
19
  import { logger } from "./logger.js";
19
20
  import { collectRelatedPullRequests } from "./related-pull-requests.js";
@@ -221,11 +222,12 @@ function normalizeFor(provider, value) {
221
222
  return normalizeGitHubRepository(value);
222
223
  if (provider === "local")
223
224
  return normalizeLocalRepository(value);
225
+ const repository = normalizeHostedRepository(value);
226
+ return codeProviderOf(repository) === provider ? repository : null;
224
227
  }
225
228
  catch {
226
229
  return null;
227
230
  }
228
- return null;
229
231
  }
230
232
  export function resolveLink(links, repositoryArg) {
231
233
  const raw = repositoryArg.trim();
@@ -36,6 +36,42 @@ import { ReviewReadLedger } from "./review-reads.js";
36
36
  import { type RepoAccessGate } from "./repo-access.js";
37
37
  import { type BudgetEventView } from "./budget-events.js";
38
38
  export declare const runnerLog: import("pino").Logger<never, boolean>;
39
+ /**
40
+ * Sub-agent dispatch uses one synthetic tool per declared child, named by the
41
+ * boundName it's attached
42
+ * under. The parent's tool call blocks until the child run reaches a
43
+ * terminal state, and its result comes back as this tool call's result.
44
+ * A run delegates at most maxDelegationsPerRun times (default one: a
45
+ * classifier deciding plan-vs-implement commits to exactly one child) and to
46
+ * each child at most once. With Agent.parallelDelegations, the delegate_to_*
47
+ * calls of one turn run at the same time (NativeEngine.runToolCalls); their
48
+ * admission (the checks below plus the child row) is still one at a time,
49
+ * through the run's delegation gate, and a child refused for budget while a
50
+ * sibling runs waits for that sibling to finish (delegation-siblings.ts).
51
+ *
52
+ * Two execution paths depending on the child's `kind`:
53
+ * - `native`: calls `executeRun` directly, bypassing any `Executor` — the
54
+ * created Run row is never marked `executionManaged`, so the reconciler
55
+ * leaves it alone even if it runs long, the same way an attended
56
+ * `wardby run` foreground execution does. Fast, in-process, no durability
57
+ * machinery needed for a native turn loop.
58
+ * - `coding`: a coding-kind child needs a real Docker container (Codex),
59
+ * which `executeRun` explicitly refuses to drive itself. Goes through
60
+ * `dispatchRun` (the same persistence path webhooks/trigger_agent use)
61
+ * with `awaitExecution: true`, so the already-existing `RoutingExecutor`
62
+ * sends it to the container backend and this call blocks until it's
63
+ * terminal — reusing proven infrastructure rather than re-implementing
64
+ * container dispatch. Marked `executionManaged: true` here (unlike the
65
+ * native path) since a long-running container crash mid-dispatch is
66
+ * exactly the case the reconciler exists for. Under the coding
67
+ * concurrency cap `Executor.start` can resolve with the child merely
68
+ * queued (still pending), so the call then polls the child row until it
69
+ * is terminal — see `waitForCodingChild`.
70
+ *
71
+ * The `delegate_to_` prefix lives in core/tool-names.ts, which reserves it
72
+ * so no user tool can be created under a name this dispatch would shadow.
73
+ */
74
+ export declare function delegateToolDef(boundName: string, parallel: boolean, repositories?: readonly string[]): LoadedTool;
39
75
  declare const DelegateArgs: z.ZodObject<{
40
76
  task: z.ZodString;
41
77
  datastoreRef: z.ZodOptional<z.ZodObject<{
@@ -45,6 +81,7 @@ declare const DelegateArgs: z.ZodObject<{
45
81
  grantParentMemoryKeys: z.ZodOptional<z.ZodArray<z.ZodString>>;
46
82
  continuePriorRun: z.ZodOptional<z.ZodString>;
47
83
  mergeOrder: z.ZodOptional<z.ZodNumber>;
84
+ repository: z.ZodOptional<z.ZodString>;
48
85
  }, z.core.$strict>;
49
86
  /** A delegate_to_* call's arguments, or the tool result refusing them. */
50
87
  export declare function parseDelegateArgs(argsJson: string): {
@@ -52,18 +89,6 @@ export declare function parseDelegateArgs(argsJson: string): {
52
89
  } | {
53
90
  refusal: string;
54
91
  };
55
- /**
56
- * At most `limit` dispatches per run (default one: a classifier deciding plan-vs-implement
57
- * commits to exactly one child), and never the same child twice, so a retry can't leave two
58
- * children racing on the same task. A delegation waiting for budget holds its place.
59
- */
60
- export declare function delegationLimitRefusal(input: {
61
- priorChildAgentIds: readonly string[];
62
- waitingChildAgentIds: readonly string[];
63
- childAgentId: string;
64
- boundName: string;
65
- limit: number;
66
- }): string | null;
67
92
  declare const DELEGATION_CHILD_SELECT: {
68
93
  readonly id: true;
69
94
  readonly kind: true;
@@ -75,6 +100,8 @@ declare const DELEGATION_CHILD_SELECT: {
75
100
  readonly select: {
76
101
  readonly allowWebhookTaskOverride: true;
77
102
  readonly timeoutSec: true;
103
+ readonly repository: true;
104
+ readonly baseRef: true;
78
105
  };
79
106
  };
80
107
  };
@@ -105,7 +132,7 @@ export declare function nativeChildResult(run: Pick<Run, "status" | "finalText"
105
132
  * also satisfies `dispatch.ts`'s `DispatchDb`, needed for dispatching a
106
133
  * coding-kind sub-agent from inside a running native turn loop.
107
134
  */
108
- export type RunnerDb = Pick<PrismaClient, "agent" | "run" | "agentTool" | "agentSecret" | "agentDatastore" | "budgetGroup" | "agentSubAgent" | "resourceGrant" | "codingRun" | "registryFetch" | "registryAuditRecord" | "task" | "webhook" | "$transaction" | "$queryRaw" | "agentRepository" | "runModelUsage" | "runHostCheck" | "runBudgetEvent" | "runHostStatus" | "hostIdentity" | "agentIssueProject" | "issuePullRequest" | "runIssueStatus" | "issueFingerprint" | "workItem" | "deferredReview" | "runAttribution">;
135
+ export type RunnerDb = Pick<PrismaClient, "agent" | "run" | "agentTool" | "agentSecret" | "agentMcpServer" | "secret" | "agentDatastore" | "budgetGroup" | "agentSubAgent" | "resourceGrant" | "codingRun" | "registryFetch" | "registryAuditRecord" | "task" | "webhook" | "$transaction" | "$queryRaw" | "agentRepository" | "runModelUsage" | "runHostCheck" | "runBudgetEvent" | "runHostStatus" | "hostIdentity" | "agentIssueProject" | "issuePullRequest" | "runIssueStatus" | "issueFingerprint" | "workItem" | "deferredReview" | "runAttribution">;
109
136
  /** The providers a native run needs; `executor`, `reviewHosts` and `issueTrackers` are optional capabilities. */
110
137
  export type NativeRunProviders = Pick<ProviderRegistry, "llm" | "engine" | "datastore" | "secrets" | "memory"> & {
111
138
  executor?: ProviderRegistry["executor"];
@@ -262,8 +289,6 @@ export interface LoadNativeRunOptions {
262
289
  * order diverges from the record.
263
290
  */
264
291
  export declare function loadNativeRun(options: LoadNativeRunOptions): Promise<{
265
- repositoryLinks: RepositoryLink[];
266
- issueProjectLinks: IssueProjectLink[];
267
292
  agent: {
268
293
  untrustedContext?: string | undefined;
269
294
  effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
@@ -275,6 +300,7 @@ export declare function loadNativeRun(options: LoadNativeRunOptions): Promise<{
275
300
  tools: LoadedTool[];
276
301
  toolsByName: {
277
302
  [k: string]: {
303
+ timeoutMs?: number | undefined;
278
304
  code: string;
279
305
  paramsZod: string;
280
306
  allowedSecrets: string[];
@@ -283,6 +309,9 @@ export declare function loadNativeRun(options: LoadNativeRunOptions): Promise<{
283
309
  allowedSharedDatastorePrefixes: Record<string, string[]>;
284
310
  };
285
311
  };
312
+ mcpTools?: import("./mcp-tools.js").McpToolPin[] | undefined;
313
+ repositoryLinks: RepositoryLink[];
314
+ issueProjectLinks: IssueProjectLink[];
286
315
  parallelDelegations?: boolean | undefined;
287
316
  maxDelegationsPerRun?: number | undefined;
288
317
  agentId: string;
@@ -311,6 +340,8 @@ export interface NativeRunToolsOptions {
311
340
  issueTrackers: IssueTrackerRegistry | undefined;
312
341
  /** What earlier requests of this run read (a sandbox run's gateway restores it per request); fresh otherwise. */
313
342
  reviewReads?: ReviewReadLedger;
343
+ /** A sandboxed run's session deadline (the gateway's); an MCP tool call never runs past it. */
344
+ deadlineAt?: Date;
314
345
  }
315
346
  /** An attached user tool as the load step pinned it: its code, schema, and consented capabilities. */
316
347
  export type LoadedUserTool = LoadedNativeRun["toolsByName"][string];
@@ -336,6 +367,7 @@ export declare function readRedactionValues(accessor: SecretsAccessor, names: re
336
367
  */
337
368
  export declare function createNativeRunTools(options: NativeRunToolsOptions): {
338
369
  toolsByName: Map<string, {
370
+ timeoutMs?: number | undefined;
339
371
  code: string;
340
372
  paramsZod: string;
341
373
  allowedSecrets: string[];
@@ -348,6 +380,13 @@ export declare function createNativeRunTools(options: NativeRunToolsOptions): {
348
380
  readableSecretValues: (name: string) => Promise<string[]>;
349
381
  runUserTool: (name: string, argsJson: string) => Promise<string>;
350
382
  runSandboxTool: (name: string, argsJson: string, callId?: string) => Promise<string>;
383
+ toolTimeoutMs: (name: string) => number | undefined;
384
+ watchStop: () => {
385
+ signal: AbortSignal;
386
+ done: () => void;
387
+ };
388
+ /** Every secret value of the agent's attached MCP servers (never handed to a worker; redaction only). */
389
+ mcpSecretValues: () => Promise<string[]>;
351
390
  };
352
391
  /**
353
392
  * Live progress for observers (MCP get_run, the viewer). Absolute totals, so a DBOS replay
@@ -374,6 +413,17 @@ export declare function finishNativeRun(ctx: NativeRunFinishContext, model: stri
374
413
  export declare function failNativeRun(ctx: NativeRunFinishContext, err: unknown): Promise<Run>;
375
414
  /** The terminal write for a run that cannot continue (it ends `lost` with `reason`), then the same settle path. */
376
415
  export declare function loseNativeRun(ctx: NativeRunFinishContext, reason: string): Promise<Run>;
416
+ /** How often a user tool call in progress checks whether its run was stopped. */
417
+ export declare const TOOL_STOP_POLL_MS = 2000;
418
+ /**
419
+ * Aborts `signal` once the run is no longer drivable (stop_run, a cancelled task, a parent's
420
+ * stop). Polls every `intervalMs`, starting one interval in, so a quick call reads nothing; a
421
+ * failed read changes nothing and the next tick reads again. `done()` stops the polling.
422
+ */
423
+ export declare function watchRunStop(db: RunnerDb, runId: string, intervalMs?: number): {
424
+ signal: AbortSignal;
425
+ done: () => void;
426
+ };
377
427
  /** Where a run stands for the native gateway: still drivable, cancelled (its task), or otherwise ended. */
378
428
  export declare function runDrivability(db: RunnerDb, runId: string): Promise<RunDrivability>;
379
429
  /**
@@ -383,7 +433,7 @@ export declare function runDrivability(db: RunnerDb, runId: string): Promise<Run
383
433
  */
384
434
  export declare function sandboxWorkerInput(runId: string, loaded: LoadedNativeRun, tools: Pick<ReturnType<typeof createNativeRunTools>, "builtinHandler" | "toolsByName">): WorkerInput;
385
435
  /** What the durable delegation needs from the gateway ledger (src/native-worker/ledger.ts). */
386
- export type DelegationLedger = Pick<PrismaGatewayLedger, "claim" | "recordResult" | "setDelegation" | "delegation" | "waitingChildAgentIds">;
436
+ export type DelegationLedger = Pick<PrismaGatewayLedger, "claim" | "recordResult" | "setDelegation" | "delegation" | "waitingDelegations">;
387
437
  export interface DurableDelegationContext {
388
438
  runId: string;
389
439
  existingRun: Run;