@wardby/cli 0.5.3 → 0.6.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 (370) hide show
  1. package/.env.example +33 -0
  2. package/README.md +25 -14
  3. package/dist/claude-coding-worker/context.d.ts +22 -0
  4. package/dist/claude-coding-worker/context.js +92 -0
  5. package/dist/claude-coding-worker/driver.d.ts +7 -1
  6. package/dist/claude-coding-worker/driver.js +38 -5
  7. package/dist/claude-coding-worker/sdk.js +13 -4
  8. package/dist/cli-help.d.ts +1 -1
  9. package/dist/cli-help.js +5 -2
  10. package/dist/cli-native-mode.d.ts +9 -0
  11. package/dist/cli-native-mode.js +20 -0
  12. package/dist/cli.d.ts +3 -1
  13. package/dist/cli.js +141 -5
  14. package/dist/coding/claude-context.d.ts +45 -0
  15. package/dist/coding/claude-context.js +434 -0
  16. package/dist/coding/profile.d.ts +12 -0
  17. package/dist/coding/profile.js +6 -0
  18. package/dist/coding/protocol.d.ts +104 -0
  19. package/dist/coding/protocol.js +87 -3
  20. package/dist/coding-worker/artifact.d.ts +8 -0
  21. package/dist/coding-worker/artifact.js +2 -2
  22. package/dist/coding-worker/driver.js +2 -0
  23. package/dist/coding-worker/sdk.d.ts +6 -0
  24. package/dist/coding-worker/sdk.js +1 -0
  25. package/dist/coding-worker/skills.d.ts +23 -0
  26. package/dist/coding-worker/skills.js +117 -0
  27. package/dist/coding-worker/types.d.ts +2 -0
  28. package/dist/config/github-allowed-accounts.d.ts +15 -0
  29. package/dist/config/github-allowed-accounts.js +36 -0
  30. package/dist/config/low-power.d.ts +12 -0
  31. package/dist/config/low-power.js +18 -0
  32. package/dist/config/mobile.d.ts +12 -0
  33. package/dist/config/mobile.js +18 -0
  34. package/dist/config/providers.d.ts +53 -0
  35. package/dist/config/providers.js +92 -6
  36. package/dist/core/db.d.ts +16 -6
  37. package/dist/core/db.js +12 -10
  38. package/dist/core/dispatch.d.ts +11 -0
  39. package/dist/core/dispatch.js +36 -1
  40. package/dist/core/engine-native.js +9 -5
  41. package/dist/core/host-events.d.ts +49 -3
  42. package/dist/core/host-events.js +289 -15
  43. package/dist/core/issue-bridge.js +42 -2
  44. package/dist/core/issue-events.js +12 -1
  45. package/dist/core/issue-status.js +14 -3
  46. package/dist/core/merge-order-check.d.ts +129 -0
  47. package/dist/core/merge-order-check.js +336 -0
  48. package/dist/core/notification-dispatcher.d.ts +70 -0
  49. package/dist/core/notification-dispatcher.js +368 -0
  50. package/dist/core/notification-templates.d.ts +25 -0
  51. package/dist/core/notification-templates.js +105 -0
  52. package/dist/core/notifications.d.ts +10 -0
  53. package/dist/core/notifications.js +38 -0
  54. package/dist/core/pg-auth.d.ts +22 -0
  55. package/dist/core/pg-auth.js +152 -0
  56. package/dist/core/power-composition.d.ts +16 -0
  57. package/dist/core/power-composition.js +37 -0
  58. package/dist/core/power-idle.d.ts +14 -0
  59. package/dist/core/power-idle.js +30 -0
  60. package/dist/core/power.d.ts +71 -0
  61. package/dist/core/power.js +202 -0
  62. package/dist/core/reconciler.d.ts +4 -2
  63. package/dist/core/reconciler.js +29 -5
  64. package/dist/core/related-pull-requests.d.ts +48 -4
  65. package/dist/core/related-pull-requests.js +113 -11
  66. package/dist/core/repo-access.d.ts +15 -0
  67. package/dist/core/repo-access.js +66 -0
  68. package/dist/core/review-fix.d.ts +37 -0
  69. package/dist/core/review-fix.js +207 -6
  70. package/dist/core/review-host-tools.d.ts +20 -0
  71. package/dist/core/review-host-tools.js +58 -2
  72. package/dist/core/runner.d.ts +336 -3
  73. package/dist/core/runner.js +894 -317
  74. package/dist/core/secret-broker-config.d.ts +103 -0
  75. package/dist/core/secret-broker-config.js +112 -0
  76. package/dist/core/secrets.d.ts +39 -4
  77. package/dist/core/secrets.js +148 -40
  78. package/dist/core/workflow-event-recorder.d.ts +14 -0
  79. package/dist/core/workflow-event-recorder.js +120 -0
  80. package/dist/core/workflow-events.d.ts +82 -0
  81. package/dist/core/workflow-events.js +44 -0
  82. package/dist/core/workflow-run-events.d.ts +16 -0
  83. package/dist/core/workflow-run-events.js +40 -0
  84. package/dist/generated/prisma/browser.d.ts +58 -0
  85. package/dist/generated/prisma/client.d.ts +58 -0
  86. package/dist/generated/prisma/commonInputTypes.d.ts +150 -0
  87. package/dist/generated/prisma/enums.d.ts +27 -0
  88. package/dist/generated/prisma/enums.js +23 -0
  89. package/dist/generated/prisma/internal/class.d.ts +88 -0
  90. package/dist/generated/prisma/internal/class.js +4 -4
  91. package/dist/generated/prisma/internal/prismaNamespace.d.ts +772 -1
  92. package/dist/generated/prisma/internal/prismaNamespace.js +135 -4
  93. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +139 -0
  94. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +135 -4
  95. package/dist/generated/prisma/models/Agent.d.ts +360 -1
  96. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +73 -1
  97. package/dist/generated/prisma/models/CodingRun.d.ts +205 -1
  98. package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
  99. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1675 -0
  100. package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
  101. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1517 -0
  102. package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
  103. package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
  104. package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
  105. package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
  106. package/dist/generated/prisma/models/NotificationChannel.js +1 -0
  107. package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
  108. package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
  109. package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
  110. package/dist/generated/prisma/models/NotificationThread.js +1 -0
  111. package/dist/generated/prisma/models/Run.d.ts +826 -1
  112. package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
  113. package/dist/generated/prisma/models/Secret.d.ts +37 -1
  114. package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
  115. package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
  116. package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
  117. package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
  118. package/dist/generated/prisma/models.d.ts +8 -0
  119. package/dist/help/build.js +4 -2
  120. package/dist/help/catalog.d.ts +1 -1
  121. package/dist/help/catalog.js +31 -6
  122. package/dist/help-index.json +1363 -176
  123. package/dist/import/create.js +17 -0
  124. package/dist/import/neutral-schema.d.ts +6 -2
  125. package/dist/import/neutral-schema.js +2 -0
  126. package/dist/mcp/auth/access.d.ts +1 -0
  127. package/dist/mcp/auth/repo-authorization.js +14 -0
  128. package/dist/mcp/auth/resource-server.d.ts +2 -1
  129. package/dist/mcp/auth/resource-server.js +7 -2
  130. package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
  131. package/dist/mcp/auth/self-hosted/browser.js +19 -6
  132. package/dist/mcp/context.d.ts +6 -0
  133. package/dist/mcp/host-events/github-ingress.d.ts +23 -1
  134. package/dist/mcp/host-events/github-ingress.js +68 -0
  135. package/dist/mcp/index.d.ts +13 -0
  136. package/dist/mcp/index.js +59 -10
  137. package/dist/mcp/tools/agents.js +82 -11
  138. package/dist/mcp/tools/notification-channels.d.ts +2 -0
  139. package/dist/mcp/tools/notification-channels.js +293 -0
  140. package/dist/mcp/tools/power.d.ts +2 -0
  141. package/dist/mcp/tools/power.js +77 -0
  142. package/dist/mcp/tools/runs.d.ts +0 -6
  143. package/dist/mcp/tools/runs.js +7 -2
  144. package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
  145. package/dist/mcp/tools/secret-broker-compat.js +23 -0
  146. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
  147. package/dist/mcp/tools/secret-elicitation-form.js +200 -10
  148. package/dist/mcp/tools/secret-elicitation-server.js +8 -1
  149. package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
  150. package/dist/mcp/tools/secret-elicitation.js +110 -12
  151. package/dist/mcp/tools/secrets.js +184 -7
  152. package/dist/mcp/tools/tools.d.ts +1 -1
  153. package/dist/mcp/tools/tools.js +22 -2
  154. package/dist/native-worker/composition.d.ts +23 -0
  155. package/dist/native-worker/composition.js +77 -0
  156. package/dist/native-worker/docker-isolation.d.ts +65 -0
  157. package/dist/native-worker/docker-isolation.js +183 -0
  158. package/dist/native-worker/docker-launcher.d.ts +74 -0
  159. package/dist/native-worker/docker-launcher.js +237 -0
  160. package/dist/native-worker/gateway-server.d.ts +39 -0
  161. package/dist/native-worker/gateway-server.js +315 -0
  162. package/dist/native-worker/gateway.d.ts +44 -0
  163. package/dist/native-worker/gateway.js +197 -0
  164. package/dist/native-worker/http-server.d.ts +22 -0
  165. package/dist/native-worker/http-server.js +109 -0
  166. package/dist/native-worker/http-transport.d.ts +17 -0
  167. package/dist/native-worker/http-transport.js +88 -0
  168. package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
  169. package/dist/native-worker/kubernetes-isolation.js +218 -0
  170. package/dist/native-worker/kubernetes-launcher.d.ts +102 -0
  171. package/dist/native-worker/kubernetes-launcher.js +335 -0
  172. package/dist/native-worker/launch.d.ts +45 -0
  173. package/dist/native-worker/launch.js +44 -0
  174. package/dist/native-worker/ledger.d.ts +109 -0
  175. package/dist/native-worker/ledger.js +192 -0
  176. package/dist/native-worker/loopback.d.ts +12 -0
  177. package/dist/native-worker/loopback.js +49 -0
  178. package/dist/native-worker/main.d.ts +7 -0
  179. package/dist/native-worker/main.js +74 -0
  180. package/dist/native-worker/protocol.d.ts +744 -0
  181. package/dist/native-worker/protocol.js +200 -0
  182. package/dist/native-worker/sandbox-executor.d.ts +68 -0
  183. package/dist/native-worker/sandbox-executor.js +210 -0
  184. package/dist/native-worker/stdio.d.ts +29 -0
  185. package/dist/native-worker/stdio.js +188 -0
  186. package/dist/native-worker/warm-delivery.d.ts +16 -0
  187. package/dist/native-worker/warm-delivery.js +33 -0
  188. package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
  189. package/dist/native-worker/warm-pool-ledger.js +73 -0
  190. package/dist/native-worker/warm-pool.d.ts +107 -0
  191. package/dist/native-worker/warm-pool.js +283 -0
  192. package/dist/native-worker/worker.d.ts +17 -0
  193. package/dist/native-worker/worker.js +115 -0
  194. package/dist/providers/auth/authorization-server.d.ts +3 -0
  195. package/dist/providers/auth/index.js +2 -0
  196. package/dist/providers/auth/self-hosted.d.ts +13 -1
  197. package/dist/providers/auth/self-hosted.js +54 -4
  198. package/dist/providers/chat/fake.d.ts +46 -0
  199. package/dist/providers/chat/fake.js +39 -0
  200. package/dist/providers/chat/index.d.ts +4 -0
  201. package/dist/providers/chat/index.js +8 -0
  202. package/dist/providers/chat/slack.d.ts +37 -0
  203. package/dist/providers/chat/slack.js +105 -0
  204. package/dist/providers/chat/types.d.ts +42 -0
  205. package/dist/providers/chat/types.js +19 -0
  206. package/dist/providers/engine/types.d.ts +19 -0
  207. package/dist/providers/engine/types.js +22 -0
  208. package/dist/providers/executor/composition.d.ts +24 -1
  209. package/dist/providers/executor/composition.js +39 -6
  210. package/dist/providers/executor/container.d.ts +24 -1
  211. package/dist/providers/executor/container.js +101 -11
  212. package/dist/providers/executor/dbos.d.ts +42 -0
  213. package/dist/providers/executor/dbos.js +118 -12
  214. package/dist/providers/executor/deferred.d.ts +56 -0
  215. package/dist/providers/executor/deferred.js +119 -0
  216. package/dist/providers/executor/routing.d.ts +37 -10
  217. package/dist/providers/executor/routing.js +73 -32
  218. package/dist/providers/executor/types.d.ts +12 -0
  219. package/dist/providers/jobs/docker.js +3 -3
  220. package/dist/providers/jobs/fake-kubernetes-api.d.ts +21 -2
  221. package/dist/providers/jobs/fake-kubernetes-api.js +42 -1
  222. package/dist/providers/jobs/kubernetes-api.d.ts +17 -1
  223. package/dist/providers/jobs/kubernetes-api.js +7 -0
  224. package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
  225. package/dist/providers/jobs/kubernetes-client.js +52 -3
  226. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
  227. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
  228. package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
  229. package/dist/providers/jobs/kubernetes-isolation.js +6 -0
  230. package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
  231. package/dist/providers/jobs/kubernetes-platform.js +38 -1
  232. package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
  233. package/dist/providers/jobs/kubernetes-preflight.js +4 -2
  234. package/dist/providers/jobs/kubernetes.d.ts +36 -1
  235. package/dist/providers/jobs/kubernetes.js +74 -4
  236. package/dist/providers/jobs/metadata-probes.d.ts +11 -0
  237. package/dist/providers/jobs/metadata-probes.js +13 -0
  238. package/dist/providers/jobs/types.d.ts +9 -0
  239. package/dist/providers/review-host/github.d.ts +11 -1
  240. package/dist/providers/review-host/github.js +50 -0
  241. package/dist/providers/review-host/types.d.ts +23 -0
  242. package/dist/providers/vcs/github.d.ts +32 -6
  243. package/dist/providers/vcs/github.js +74 -16
  244. package/dist/quickstart/coding-seed.d.ts +10 -3
  245. package/dist/quickstart/coding-seed.js +74 -3
  246. package/dist/quickstart/images.d.ts +2 -0
  247. package/dist/quickstart/images.js +7 -1
  248. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  249. package/dist/quickstart/reviewer-prompt.js +1 -1
  250. package/dist/quickstart-images.json +1 -1
  251. package/dist/sandbox/brokered-fetch.d.ts +23 -0
  252. package/dist/sandbox/brokered-fetch.js +37 -0
  253. package/dist/sandbox/host-functions.d.ts +34 -0
  254. package/dist/sandbox/host-functions.js +144 -80
  255. package/dist/sandbox/prelude.js +7 -1
  256. package/dist/sandbox/run-in-sandbox.d.ts +19 -0
  257. package/dist/sandbox/run-in-sandbox.js +28 -10
  258. package/dist/sandbox/safe-fetch.d.ts +2 -0
  259. package/dist/sandbox/safe-fetch.js +3 -1
  260. package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
  261. package/dist/sandbox/secret-broker-sigv4.js +49 -0
  262. package/dist/sandbox/secret-broker.d.ts +34 -0
  263. package/dist/sandbox/secret-broker.js +162 -0
  264. package/dist/sandbox/user-tool.d.ts +14 -0
  265. package/dist/sandbox/user-tool.js +32 -0
  266. package/dist/serve.js +18 -0
  267. package/dist/viewer/api-schema.d.ts +210 -14
  268. package/dist/viewer/api-schema.js +22 -0
  269. package/dist/viewer/build-schemas.js +4 -1
  270. package/dist/viewer/event-bus.d.ts +6 -0
  271. package/dist/viewer/event-bus.js +16 -7
  272. package/dist/viewer/graph.d.ts +5 -2
  273. package/dist/viewer/graph.js +7 -2
  274. package/dist/viewer/http.d.ts +0 -1
  275. package/dist/viewer/http.js +2 -2
  276. package/dist/viewer/infra.js +25 -2
  277. package/dist/viewer/limits.d.ts +4 -0
  278. package/dist/viewer/limits.js +4 -0
  279. package/dist/viewer/openapi.d.ts +15 -0
  280. package/dist/viewer/openapi.js +172 -0
  281. package/docs/README.md +7 -0
  282. package/docs/agent-recipes.md +57 -8
  283. package/docs/architecture-runtime.md +16 -1
  284. package/docs/code-review-agents.md +139 -5
  285. package/docs/coding-agent-setup.md +113 -5
  286. package/docs/coding-packages.md +4 -2
  287. package/docs/coding-services.md +3 -1
  288. package/docs/coding-worker-byo-images.md +198 -6
  289. package/docs/coding-worker-isolation.md +68 -14
  290. package/docs/getting-started-gke.md +225 -9
  291. package/docs/getting-started-identity-provider.md +21 -10
  292. package/docs/getting-started.md +5 -4
  293. package/docs/jira-agents.md +5 -1
  294. package/docs/native-sandbox.md +635 -0
  295. package/docs/release-verification.md +9 -0
  296. package/docs/security-deployment.md +113 -12
  297. package/docs/slack-notifications.md +252 -0
  298. package/docs/tool-secrets.md +252 -0
  299. package/docs/viewer-api.md +46 -5
  300. package/docs/viewer-api.openapi.yml +1404 -0
  301. package/help/admin-viewer.md +6 -2
  302. package/help/agent-recipes.md +27 -0
  303. package/help/architecture-agent.md +1 -1
  304. package/help/brokered-secrets.md +79 -0
  305. package/help/build-claude-code-image.md +131 -0
  306. package/help/build-worker-image.md +3 -6
  307. package/help/code-review-agents.md +68 -6
  308. package/help/deploy-gke.md +8 -1
  309. package/help/deployment-targets.md +25 -14
  310. package/help/errors/coding-provider-not-configured.md +2 -2
  311. package/help/errors/database-auth-invalid.md +28 -0
  312. package/help/errors/github-account-not-allowed.md +25 -0
  313. package/help/errors/low-power-disabled.md +29 -0
  314. package/help/errors/low-power-scale-forbidden.md +35 -0
  315. package/help/errors/low-power-wake-timeout.md +30 -0
  316. package/help/errors/mobile-disabled.md +31 -0
  317. package/help/errors/native-sandbox-capacity.md +22 -0
  318. package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
  319. package/help/errors/native-sandbox-docker-failed.md +20 -0
  320. package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
  321. package/help/errors/native-sandbox-image-not-pinned.md +19 -0
  322. package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
  323. package/help/errors/native-sandbox-network-unenforced.md +22 -0
  324. package/help/errors/native-sandbox-requires-catalog.md +31 -0
  325. package/help/errors/native-sandbox-unavailable.md +19 -0
  326. package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
  327. package/help/errors/native-sandbox-worker-exited.md +20 -0
  328. package/help/errors/native-sandbox-worker-lost.md +20 -0
  329. package/help/errors/native-sandbox-worker-unready.md +22 -0
  330. package/help/errors/secret-broker-body-invalid.md +26 -0
  331. package/help/errors/secret-broker-changed.md +20 -0
  332. package/help/errors/secret-broker-config-invalid.md +30 -0
  333. package/help/errors/secret-broker-conflict.md +27 -0
  334. package/help/errors/secret-broker-destination-denied.md +28 -0
  335. package/help/errors/secret-broker-value-invalid.md +28 -0
  336. package/help/errors/secret-brokered.md +24 -0
  337. package/help/errors/secret-not-brokered.md +25 -0
  338. package/help/errors/slack-auth-failed.md +48 -0
  339. package/help/errors/slack-channel-unreachable.md +39 -0
  340. package/help/errors/slack-not-configured.md +33 -0
  341. package/help/getting-started.md +4 -5
  342. package/help/github.md +18 -1
  343. package/help/identity-and-access.md +5 -1
  344. package/help/local-repositories.md +2 -3
  345. package/help/low-power-mode.md +125 -0
  346. package/help/merge-order-check.md +117 -0
  347. package/help/mobile-app.md +54 -0
  348. package/help/native-sandbox.md +136 -0
  349. package/help/observability.md +8 -0
  350. package/help/related-pull-requests.md +70 -9
  351. package/help/repo-instructions-and-skills.md +91 -0
  352. package/help/review-fix-rounds.md +10 -0
  353. package/help/slack-notifications.md +62 -0
  354. package/help/troubleshooting/coding-workers.md +21 -0
  355. package/package.json +11 -4
  356. package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
  357. package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
  358. package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
  359. package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
  360. package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
  361. package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
  362. package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
  363. package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
  364. package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
  365. package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
  366. package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
  367. package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
  368. package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
  369. package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
  370. package/prisma/schema.prisma +362 -91
@@ -1,8 +1,6 @@
1
1
  /** The graph snapshot read model behind GET /admin/api/graph (docs/viewer-api.md). */
2
2
  import type { Prisma, PrismaClient } from "#prisma";
3
3
  import type { GraphRun, GraphSnapshot } from "./api-schema.js";
4
- export declare const DEFAULT_GRAPH_LIMIT = 500;
5
- export declare const MAX_GRAPH_LIMIT = 2000;
6
4
  /** Accepts "15m" | "1h" | "6h" | "24h" | "7d" or an ISO-8601 timestamp; null defaults to 1h. Throws otherwise. */
7
5
  export declare function parseSince(value: string | null, now: Date): Date;
8
6
  declare const runInclude: {
@@ -23,6 +21,11 @@ declare const runInclude: {
23
21
  createdAt: "asc";
24
22
  };
25
23
  };
24
+ nativeWarmWorker: {
25
+ select: {
26
+ name: true;
27
+ };
28
+ };
26
29
  };
27
30
  type RunRow = Prisma.RunGetPayload<{
28
31
  include: typeof runInclude;
@@ -1,7 +1,5 @@
1
1
  import { periodStart } from "../core/budget-groups.js";
2
2
  import { publicCodingRunResult } from "../coding/protocol.js";
3
- export const DEFAULT_GRAPH_LIMIT = 500;
4
- export const MAX_GRAPH_LIMIT = 2000;
5
3
  const DEFAULT_SINCE_MS = 60 * 60 * 1000;
6
4
  const RELATIVE_SINCE_MS = {
7
5
  "15m": 15 * 60 * 1000,
@@ -30,6 +28,7 @@ const runInclude = {
30
28
  hostStatus: true,
31
29
  issueStatus: true,
32
30
  serviceStatuses: { orderBy: { createdAt: "asc" } },
31
+ nativeWarmWorker: { select: { name: true } },
33
32
  };
34
33
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
35
34
  /** Name and version of each service in a coding run's resolved services snapshot. */
@@ -151,6 +150,12 @@ export function toGraphRun(row, pullRequests, sites = {}) {
151
150
  agentKind: row.agent.kind,
152
151
  model: row.codingRun?.model ?? row.agent.model,
153
152
  codingProvider: row.codingRun?.provider ?? null,
153
+ nativeExecutionMode: row.nativeExecutionMode === "sandbox"
154
+ ? "sandbox"
155
+ : row.nativeExecutionMode === "control_plane"
156
+ ? "control-plane"
157
+ : null,
158
+ warmWorkerName: row.nativeWarmWorker?.name ?? null,
154
159
  status: row.status,
155
160
  trigger: triggerFor(row, sites),
156
161
  turns: row.turns,
@@ -12,7 +12,6 @@ import type { InfraInfo } from "./api-schema.js";
12
12
  import { type IssueSites } from "./graph.js";
13
13
  import type { ViewerEventBus } from "./event-bus.js";
14
14
  export declare const VIEWER_API_PREFIX = "/admin/api/";
15
- export declare const SSE_HEARTBEAT_MS = 15000;
16
15
  /** A stream whose unsent backlog exceeds this is ended; the client reconnects and resyncs. */
17
16
  export declare const SSE_MAX_BUFFERED_BYTES: number;
18
17
  export interface ViewerApiDeps {
@@ -1,9 +1,9 @@
1
1
  import { requireScope } from "../mcp/auth/resource-server.js";
2
2
  import { sendJson } from "../mcp/transport/streamable-http.js";
3
- import { DEFAULT_GRAPH_LIMIT, MAX_GRAPH_LIMIT, loadGraph, parseSince } from "./graph.js";
3
+ import { loadGraph, parseSince } from "./graph.js";
4
+ import { DEFAULT_GRAPH_LIMIT, MAX_GRAPH_LIMIT, SSE_HEARTBEAT_MS } from "./limits.js";
4
5
  import { loadRunDetail } from "./run-detail.js";
5
6
  export const VIEWER_API_PREFIX = "/admin/api/";
6
- export const SSE_HEARTBEAT_MS = 15_000;
7
7
  /** A stream whose unsent backlog exceeds this is ended; the client reconnects and resyncs. */
8
8
  export const SSE_MAX_BUFFERED_BYTES = 1024 * 1024;
9
9
  const RUN_ID = /^[A-Za-z0-9_-]{1,64}$/;
@@ -1,14 +1,17 @@
1
1
  /** The read model behind GET /admin/api/infra (docs/viewer-api.md): built once at startup, no cluster reads. */
2
- import { loadKubernetesJobConfig, loadProviderConfig } from "../config/providers.js";
2
+ import { loadKubernetesJobConfig, loadNativeSandboxConfig, loadProviderConfig } from "../config/providers.js";
3
+ import { NATIVE_RUN_COMPONENT_LABEL, NATIVE_RUN_SHA_LABEL, NATIVE_WARM_POOL_LABEL, NATIVE_WARM_TOKEN_LABEL, } from "../native-worker/kubernetes-isolation.js";
3
4
  import { RUN_COMPONENT_LABEL, RUN_MANAGED_BY_LABEL, RUN_SHA_CHARS, RUN_SHA_LABEL, } from "../providers/jobs/kubernetes-isolation.js";
4
5
  export function buildInfraInfo(env = process.env) {
5
6
  const raw = loadProviderConfig(env).jobs;
6
7
  const launcher = raw === "docker" || raw === "kubernetes" ? raw : "local";
8
+ const native = buildNativeInfo(env);
7
9
  if (launcher !== "kubernetes")
8
- return { launcher, kubernetes: null };
10
+ return { launcher, kubernetes: null, native };
9
11
  const k8s = loadKubernetesJobConfig(env);
10
12
  return {
11
13
  launcher,
14
+ native,
12
15
  kubernetes: {
13
16
  namespace: k8s.namespace,
14
17
  platform: k8s.platform,
@@ -21,3 +24,23 @@ export function buildInfraInfo(env = process.env) {
21
24
  },
22
25
  };
23
26
  }
27
+ /** Where sandbox-mode native agents run (NATIVE_SANDBOX_*); null when no sandbox launcher is configured. */
28
+ function buildNativeInfo(env) {
29
+ const config = loadNativeSandboxConfig(env);
30
+ if (!config)
31
+ return null;
32
+ return {
33
+ launcher: config.launcher,
34
+ warmPoolSize: config.warmPoolSize,
35
+ kubernetes: config.launcher === "kubernetes"
36
+ ? {
37
+ namespace: config.namespace,
38
+ runtimeClass: config.runtimeClassName ?? null,
39
+ runLabel: NATIVE_RUN_SHA_LABEL,
40
+ componentLabel: { ...NATIVE_RUN_COMPONENT_LABEL },
41
+ warmPoolLabel: { ...NATIVE_WARM_POOL_LABEL },
42
+ warmWorkerLabel: NATIVE_WARM_TOKEN_LABEL,
43
+ }
44
+ : null,
45
+ };
46
+ }
@@ -0,0 +1,4 @@
1
+ /** Viewer API constants shared by the server and the OpenAPI generator (no runtime imports). */
2
+ export declare const DEFAULT_GRAPH_LIMIT = 500;
3
+ export declare const MAX_GRAPH_LIMIT = 2000;
4
+ export declare const SSE_HEARTBEAT_MS = 15000;
@@ -0,0 +1,4 @@
1
+ /** Viewer API constants shared by the server and the OpenAPI generator (no runtime imports). */
2
+ export const DEFAULT_GRAPH_LIMIT = 500;
3
+ export const MAX_GRAPH_LIMIT = 2000;
4
+ export const SSE_HEARTBEAT_MS = 15_000;
@@ -0,0 +1,15 @@
1
+ export declare const OPENAPI_PATH: string;
2
+ type Json = Record<string, unknown>;
3
+ export interface ViewerRoute {
4
+ path: string;
5
+ operationId: string;
6
+ summary: string;
7
+ description: string;
8
+ parameters?: readonly Json[];
9
+ responses: Readonly<Record<string, Json>>;
10
+ }
11
+ export declare const VIEWER_ROUTES: readonly ViewerRoute[];
12
+ export declare function buildViewerOpenApi(version: string): Json;
13
+ export declare const HEADER = "# Generated by npm run build:viewer-schemas from src/viewer/api-schema.ts and src/viewer/openapi.ts. Do not edit.";
14
+ export declare function renderViewerOpenApi(version: string): string;
15
+ export {};
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Builds the published OpenAPI 3.1 document for the admin viewer API
3
+ * (docs/viewer-api.openapi.yml) from the zod schemas and a route table.
4
+ * Generated by `npm run build:viewer-schemas`; never edit the YAML by hand.
5
+ */
6
+ import { dirname, join } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { stringify } from "yaml";
9
+ import { zodToJsonSchema } from "zod-to-json-schema";
10
+ import { VIEWER_SCHEMAS } from "./api-schema.js";
11
+ import { DEFAULT_GRAPH_LIMIT, MAX_GRAPH_LIMIT, SSE_HEARTBEAT_MS } from "./limits.js";
12
+ export const OPENAPI_PATH = join(dirname(fileURLToPath(import.meta.url)), "../../docs/viewer-api.openapi.yml");
13
+ const AUTH_NOTE = "Requires a bearer token with the `admin:view` scope, held by a caller with the admin role.";
14
+ const ref = (name) => ({ $ref: `#/components/schemas/${name}` });
15
+ const errorBody = (codes, description) => {
16
+ const list = codes.split(", ");
17
+ return {
18
+ description,
19
+ content: {
20
+ "application/json": {
21
+ schema: { allOf: [ref("ViewerError"), { properties: { error: { enum: list } } }] },
22
+ },
23
+ },
24
+ "x-error-codes": list,
25
+ };
26
+ };
27
+ const wwwAuthenticate = { "WWW-Authenticate": { $ref: "#/components/headers/WWWAuthenticate" } };
28
+ export const VIEWER_ROUTES = [
29
+ {
30
+ path: "/admin/api/graph",
31
+ operationId: "getGraph",
32
+ summary: "Graph snapshot",
33
+ description: "Agents, runs, coding-run services and outcomes for a time window, as a graph.",
34
+ parameters: [
35
+ {
36
+ name: "since",
37
+ in: "query",
38
+ required: false,
39
+ description: "Window start: `15m`, `1h`, `6h`, `24h`, `7d`, or an ISO-8601 timestamp. Default `1h`.",
40
+ schema: { type: "string", default: "1h" },
41
+ },
42
+ {
43
+ name: "limit",
44
+ in: "query",
45
+ required: false,
46
+ description: `Maximum number of runs, 1 to ${MAX_GRAPH_LIMIT}. Default ${DEFAULT_GRAPH_LIMIT}.`,
47
+ schema: { type: "integer", minimum: 1, maximum: MAX_GRAPH_LIMIT, default: DEFAULT_GRAPH_LIMIT },
48
+ },
49
+ ],
50
+ responses: {
51
+ "200": {
52
+ description: "The graph snapshot.",
53
+ content: { "application/json": { schema: ref("graph-snapshot") } },
54
+ },
55
+ "400": errorBody("invalid_since, invalid_limit", "A query parameter is invalid."),
56
+ },
57
+ },
58
+ {
59
+ path: "/admin/api/runs/{id}",
60
+ operationId: "getRun",
61
+ summary: "Run detail",
62
+ description: "Full detail for one run, including final text.",
63
+ parameters: [{ name: "id", in: "path", required: true, description: "Run id.", schema: { type: "string" } }],
64
+ responses: {
65
+ "200": { description: "The run.", content: { "application/json": { schema: ref("run-detail") } } },
66
+ "404": errorBody("not_found", "No run with that id."),
67
+ },
68
+ },
69
+ {
70
+ path: "/admin/api/infra",
71
+ operationId: "getInfra",
72
+ summary: "Infrastructure info",
73
+ description: "Where and how this wardby deployment runs its workloads.",
74
+ responses: {
75
+ "200": { description: "Infrastructure info.", content: { "application/json": { schema: ref("infra-info") } } },
76
+ },
77
+ },
78
+ {
79
+ path: "/admin/api/events",
80
+ operationId: "getEvents",
81
+ summary: "Live event stream",
82
+ description: [
83
+ "A Server-Sent Events stream (`text/event-stream`) of live changes. Frames:",
84
+ "",
85
+ "- `retry: 3000`: suggested client reconnect delay in milliseconds.",
86
+ '- `event: hello`: sent first. Data is `{"connected": <bool>}`, whether the server\'s live-event connection is up.',
87
+ "- `event: run`, `event: service`, `event: outcome`: a run, coding-run service, or outcome changed. Each carries an `id:` line. Payloads match the `viewer-event` schema (see `x-event-schema`).",
88
+ '- `event: status`: the server\'s live-event connection changed. Data is `{"connected": <bool>}`.',
89
+ "- `event: resync`: the live-event connection is up (again). Events may have been missed: refetch the graph.",
90
+ `- \`: ping\`: comment sent every ${SSE_HEARTBEAT_MS / 1000} seconds to keep the connection open.`,
91
+ "",
92
+ "There is no replay. Open the event stream first, then load `/admin/api/graph` and apply events on top of it. Refetch the graph on every `resync` and after every reconnect rather than trying to resume.",
93
+ ].join("\n"),
94
+ responses: {
95
+ "200": {
96
+ description: "The event stream.",
97
+ content: { "text/event-stream": { schema: { type: "string" } } },
98
+ "x-event-schema": ref("viewer-event"),
99
+ },
100
+ },
101
+ },
102
+ ];
103
+ function componentSchemas() {
104
+ const schemas = {};
105
+ for (const [name, schema] of Object.entries(VIEWER_SCHEMAS)) {
106
+ const json = zodToJsonSchema(schema, { target: "jsonSchema2019-09", $refStrategy: "none" });
107
+ delete json.$schema;
108
+ schemas[name] = json;
109
+ }
110
+ schemas.ViewerError = {
111
+ type: "object",
112
+ required: ["error"],
113
+ properties: { error: { type: "string" } },
114
+ additionalProperties: false,
115
+ };
116
+ schemas.ViewerInternalError = {
117
+ type: "object",
118
+ required: ["error", "id"],
119
+ properties: { error: { type: "string", enum: ["internal_error"] }, id: { type: "string" } },
120
+ additionalProperties: false,
121
+ };
122
+ return schemas;
123
+ }
124
+ function operation(route) {
125
+ return {
126
+ operationId: route.operationId,
127
+ summary: route.summary,
128
+ description: `${route.description}\n\n${AUTH_NOTE}`,
129
+ security: [{ bearer: [] }],
130
+ ...(route.parameters ? { parameters: route.parameters } : {}),
131
+ responses: {
132
+ ...route.responses,
133
+ "401": { ...errorBody("invalid_token", "No valid bearer token."), headers: wwwAuthenticate },
134
+ "403": {
135
+ ...errorBody("invalid_token", "Token lacks the `admin:view` scope (the `WWW-Authenticate` header is present), or the caller lacks the admin role (no `WWW-Authenticate` header)."),
136
+ headers: wwwAuthenticate,
137
+ },
138
+ "405": {
139
+ ...errorBody("method_not_allowed", "Only GET is allowed."),
140
+ headers: { Allow: { description: "Allowed methods: GET.", schema: { type: "string", enum: ["GET"] } } },
141
+ },
142
+ default: {
143
+ description: "Unexpected server error (HTTP 500). `id` identifies the failure in the server log.",
144
+ content: { "application/json": { schema: ref("ViewerInternalError") } },
145
+ },
146
+ },
147
+ };
148
+ }
149
+ export function buildViewerOpenApi(version) {
150
+ const paths = {};
151
+ for (const route of VIEWER_ROUTES)
152
+ paths[route.path] = { get: operation(route) };
153
+ return {
154
+ openapi: "3.1.0",
155
+ info: {
156
+ title: "wardby admin viewer API",
157
+ version,
158
+ description: "Read-only admin API behind the wardby viewer: graph, run detail, infrastructure info and a live event stream. Response objects may gain new fields in later releases; clients should ignore unknown fields. See docs/viewer-api.md for the prose contract.",
159
+ },
160
+ servers: [{ url: "https://{host}", variables: { host: { default: "wardby.example.com" } } }],
161
+ paths,
162
+ components: {
163
+ securitySchemes: { bearer: { type: "http", scheme: "bearer" } },
164
+ headers: { WWWAuthenticate: { description: "Bearer challenge.", schema: { type: "string" } } },
165
+ schemas: componentSchemas(),
166
+ },
167
+ };
168
+ }
169
+ export const HEADER = "# Generated by npm run build:viewer-schemas from src/viewer/api-schema.ts and src/viewer/openapi.ts. Do not edit.";
170
+ export function renderViewerOpenApi(version) {
171
+ return `${HEADER}\n${stringify(buildViewerOpenApi(version), { lineWidth: 0, aliasDuplicateObjects: false })}`;
172
+ }
package/docs/README.md CHANGED
@@ -18,6 +18,11 @@
18
18
  - [Architecture knowledge bundles](knowledge.md) covers `docs/knowledge/`: the
19
19
  concept format, how coding runs and reviewers use it, `wardby knowledge check`,
20
20
  and the scheduled architecture agent.
21
+ - [Native sandbox](native-sandbox.md) (0.5.4+) runs a native agent's turn loop and user
22
+ tools in a single-use, credential-free container behind a native gateway.
23
+ - [Secrets and tools](tool-secrets.md) covers readable and brokered secrets
24
+ (brokered secrets require 0.6.0+):
25
+ attaching secrets to tools, `set_secret_broker`, placements, and errors.
21
26
  - [Coding-worker isolation](coding-worker-isolation.md) documents the threat
22
27
  model and enforced worker boundary.
23
28
  - [Bring-your-own worker images](coding-worker-byo-images.md) explains how to
@@ -29,6 +34,8 @@
29
34
  the catalog, per-agent permission, variables, and errors.
30
35
  - [Jira agents](jira-agents.md) connects wardby to Jira Cloud with a service
31
36
  account and webhook, and links agents to projects.
37
+ - [Send workflow updates to Slack](slack-notifications.md) (0.6.0+) links a Slack
38
+ channel to a Jira project or an agent to follow cards from pickup to merge.
32
39
  - [Observability](observability.md) covers Prometheus metrics, Grafana, cloud
33
40
  collectors, retention, and production ownership.
34
41
  - [Release verification](release-verification.md) lists the automated and live
@@ -336,7 +336,9 @@ toolchain, build your own image on Wardby's driver base image and point the
336
336
  agent at it with `workerImageRef`, a digest-pinned reference (a mutable tag is
337
337
  rejected). Setting it needs the `agents:admin` scope and the admin role. The
338
338
  Dockerfile shape, the driver image, and what Wardby does and does not verify are
339
- in [Bring-your-own worker images](coding-worker-byo-images.md).
339
+ in [Bring-your-own worker images](coding-worker-byo-images.md). For a Claude
340
+ Code agent, build the image on the release's tool runner image instead; see
341
+ [Codex and Claude Code](coding-worker-byo-images.md#codex-and-claude-code).
340
342
 
341
343
  ```json
342
344
  {
@@ -423,14 +425,61 @@ the lead's `maxDelegationsPerRun` (1 to 20) with `create_agent` or
423
425
  - Wardby adds a **Related pull requests** section to each pull request the
424
426
  builders open, listing the others with links, states (open, draft, merged,
425
427
  closed) and the originating issue. With a Jira issue, the list covers every
426
- pull request recorded for that issue in any run. Open ones are numbered as a
428
+ pull request recorded for that issue in any run. When no pull request in the
429
+ set carries a `mergeOrder` (see below), open ones are numbered as a
427
430
  **Suggested merge order** — the order the lead delegated in, not a
428
- guarantee; merged and closed ones are listed separately as context. A pull
429
- request lists the ones opened before it as soon as it is opened; when the
430
- lead run finishes, and whenever a later run pushes to one of them, every
431
- open one is rewritten with the full list. Text you add inside the section is
432
- replaced; the rest of the description is not touched. Only pull requests the
433
- App opened and that are still open are edited.
431
+ guarantee. When any pull request in the set carries one (open, merged or
432
+ closed), the open ones that have a `mergeOrder` are numbered under
433
+ **Merge order (set by the delegating agent; equal steps can merge in either
434
+ order)** and labelled "step k of n" (equal values share a step), and any
435
+ open pull request without one is listed after under **Not ordered**. If
436
+ only merged or closed pull requests carry a `mergeOrder`, the open ones are
437
+ all listed under **Not ordered**, with no **Merge order** heading. Steps
438
+ are counted over the whole set, merged and closed pull requests included,
439
+ so a label stays the same as earlier steps merge. Merged and closed pull
440
+ requests are always listed separately as context, with their step label
441
+ when they have one. A pull request lists the ones opened before it as
442
+ soon as it is opened; when the lead run finishes, and whenever a later run
443
+ pushes to one of them, every open one is rewritten with the full list. Text
444
+ you add inside the section is replaced; the rest of the description is not
445
+ touched. Only pull requests the App opened and that are still open are
446
+ edited. With Wardby 0.6.0 or later, a reviewer linked to one of these repositories
447
+ also holds its review of such a pull request until the lead run finishes,
448
+ however it ends, so every pull request of the request is open by the time
449
+ any of them is reviewed. When the lead finishes normally the section above
450
+ has been rewritten by then; when it is ended another way (for example,
451
+ cancelled), reviews start without that rewrite, and reviewers use
452
+ `repo_pr_read`'s `relatedPullRequests` either way — see
453
+ [Reviewing a pull request a delegated run
454
+ opened](code-review-agents.md#reviewing-a-pull-request-a-delegated-run-opened).
455
+ - Each `delegate_to_<name>` call to a coding sub-agent can carry a
456
+ `mergeOrder`: an integer from 1 to 99, where 1 merges first. Give a
457
+ repository that other repositories' changes depend on a lower number than
458
+ the ones that call it — for example a service `1`, the API in front of it
459
+ `2`, the client `3` — and give two changes the same number when there is no
460
+ order between them. Set it whenever one change spans several repositories
461
+ and the pull requests must land in a particular sequence; leave it unset
462
+ and the set keeps the delegation-order "Suggested merge order" above. A
463
+ native sub-agent has no pull request to order, so it ignores `mergeOrder`
464
+ and the tool result notes that it did. Each pull request shows the value
465
+ most recently set for it, by the run that opened it or a later
466
+ continuation of it: a `continuePriorRun` call that omits `mergeOrder`
467
+ keeps that value, and one that sets `mergeOrder` replaces it. A
468
+ bad value (not an integer, or outside 1-99) is refused as a tool error
469
+ rather than silently ignored.
470
+ - With Wardby 0.6.0 or later, once a set has more than one distinct
471
+ `mergeOrder`, each open or draft pull request Wardby opened in it also
472
+ gets a check run named exactly `wardby merge order`: `in_progress` while
473
+ an earlier step hasn't merged, `success` once every earlier step has
474
+ (or there is none), and `failure` if an earlier step was closed without
475
+ merging. Above the set's lowest step, a would-be `success` stays
476
+ `in_progress` ("waiting for the delegating run to finish") while the
477
+ delegating (lead) agent's run is still running — it may still add or
478
+ reorder steps. A coding run that continues one of the pull requests on
479
+ its own (a review fix round, an `@` mention) never holds it. Posting it never
480
+ blocks a merge by itself: add `wardby merge order` as a required status
481
+ check in branch protection to gate on it. See
482
+ [The wardby merge order check](../help/merge-order-check.md).
434
483
  - The section, and the follow-up hints below, list every pull request in the
435
484
  set by repository name and number. A request that spans repositories of
436
485
  different visibility can therefore show a private repository's name in a
@@ -73,10 +73,14 @@ credentials, still reaches only the proxy, and the proxy still owns the ledger.
73
73
 
74
74
  | `JOB_LAUNCHER` | Worker runs in | Isolation |
75
75
  | -------------- | -------------------------------- | ---------------------------------------------------- |
76
- | `local` | a child process on this host | development only, no isolation |
76
+ | `local` | nowhere: no coding launcher | native agents only; coding runs fail before starting |
77
77
  | `docker` | a container on a per-run network | the diagram above |
78
78
  | `kubernetes` | a pod in a namespace | per-run NetworkPolicy, attested pod, optional gVisor |
79
79
 
80
+ `local` is the default. It composes no coding launcher, so a coding run ends
81
+ with "Coding agents need a container executor"; set `docker` or `kubernetes`
82
+ to run coding agents.
83
+
80
84
  Under `kubernetes` the shape is the same with different nouns: the per-run
81
85
  Docker network becomes a NetworkPolicy, the keeper and worker share a pod
82
86
  instead of a volume, and the proxy is a Service rather than a container name.
@@ -88,3 +92,14 @@ or not anything enforces it. See
88
92
  [coding-worker-isolation.md](coding-worker-isolation.md) for the mechanics and
89
93
  the [Kubernetes deployment guide](../deploy/kind-coding/README.md) for the local
90
94
  and GKE Autopilot overlays.
95
+
96
+ ### Native agents in a sandbox
97
+
98
+ Native sandbox requires Wardby 0.5.4 or later.
99
+
100
+ Native agents run in the server process by default. A native agent set to
101
+ `nativeExecutionMode=sandbox` instead runs its turn loop and user tools in a
102
+ single-use credential-free container whose only path out is a separate native
103
+ gateway, enabled with `NATIVE_SANDBOX_LAUNCHER=docker` or `kubernetes` (a pod
104
+ per run, including on GKE Autopilot under gVisor; independent of
105
+ `JOB_LAUNCHER`). See [native-sandbox.md](native-sandbox.md).
@@ -262,6 +262,17 @@ it starts a fresh review, and if that review requests changes, it starts a
262
262
  fix round the same way any other review would (subject to the cap and to no
263
263
  earlier round still running).
264
264
 
265
+ With Wardby 0.6.0 or later, a round whose coding run ends with no change —
266
+ the agent concluded the review's finding was wrong rather than pushing a
267
+ fix — gets one fresh review instead, of the pull request's current
268
+ (unchanged) head, run by the reviewer whose check requested the changes.
269
+ The fix round's own summary is passed to that reviewer as untrusted
270
+ context: information about what was decided and why, never instructions to
271
+ follow. This happens once per review that requested changes, counts toward
272
+ the pull request's round cap the same as a round that pushed a change, and
273
+ at the cap posts the usual cap comment instead of re-reviewing — since no
274
+ push happened, nothing else would otherwise replace the failed check.
275
+
265
276
  If a repository already forwards wardby's reviews to a webhook through a
266
277
  hand-written CI workflow to fix them automatically, replace that workflow
267
278
  with `review_fix`: link the trigger, then delete the workflow and its
@@ -444,6 +455,50 @@ A GitHub App has exactly one webhook URL. Register a **separate App** for
444
455
  local development or a staging environment rather than pointing your
445
456
  production App's webhook at a dev host.
446
457
 
458
+ ### Which accounts the App serves (`WARDBY_GITHUB_ALLOWED_ACCOUNTS`)
459
+
460
+ A GitHub App has one webhook URL, so every account that installs it sends its
461
+ events to your server. wardby serves only trusted accounts:
462
+
463
+ - **The App's owner** (the user or organization that owns the App), always.
464
+ - **Accounts in `WARDBY_GITHUB_ALLOWED_ACCOUNTS`**, comma-separated logins:
465
+
466
+ WARDBY_GITHUB_ALLOWED_ACCOUNTS=acme-labs
467
+
468
+ Every other account is refused: its events are answered `202` and ignored before
469
+ anything is recorded, and `link_repository` and coding profiles refuse its
470
+ repositories with `github_account_not_allowed`, even with `adminOverride`.
471
+ There is no setting that serves every account.
472
+
473
+ wardby removes the App from another account's installation only when that
474
+ account installs the App or changes the installation's repository selection.
475
+ Installations that already exist on other accounts stay installed (their
476
+ events are ignored); remove them by hand in the App's settings under
477
+ **Install App**.
478
+
479
+ **When you upgrade**, existing repository links and scheduled runs on
480
+ repositories of accounts that are not served start failing with
481
+ `github_account_not_allowed`. List those accounts in the variable first if they
482
+ should keep working.
483
+
484
+ A private App can only be installed on its owner, so it needs nothing here. Set
485
+ the variable when the App must be installable by other accounts, for example
486
+ when an organization owns the App and a user's repositories should be served
487
+ too. Logins are matched case-insensitively; a malformed value stops the server
488
+ at startup.
489
+
490
+ wardby reads the App's owner login from GitHub (`GET /app`, with the App's own
491
+ credentials) and remembers it until it restarts. If it cannot read the owner,
492
+ it refuses rather than guesses. After you transfer the App to another owner or
493
+ rename the owner account, list the new owner in
494
+ `WARDBY_GITHUB_ALLOWED_ACCOUNTS` (or restart wardby) before relying on it:
495
+ until then, events from the new owner are ignored. Before removing the App
496
+ from an installation, wardby re-reads the owner, so it never removes the App
497
+ from its current owner.
498
+
499
+ Each wardby server should have its own GitHub App: never point other people at
500
+ yours; give them the setup steps above instead.
501
+
447
502
  ### `GITHUB_APP_WEBHOOK_SECRET`
448
503
 
449
504
  Set alongside `GITHUB_APP_ID` and `GITHUB_APP_PRIVATE_KEY`
@@ -501,6 +556,11 @@ the full desired state. Two common shapes:
501
556
  }
502
557
  ```
503
558
 
559
+ With Wardby 0.6.0 or later, a `pull_request` reviewer's review of a pull request
560
+ opened by a delegated coding run is held until the run that delegated it
561
+ finishes, whether or not this link sets `waitForCi` — see [Reviewing a pull request a delegated run
562
+ opened](#reviewing-a-pull-request-a-delegated-run-opened) below.
563
+
504
564
  Add `"waitForCi": true` to a `pull_request` link to hold the reviewer's
505
565
  review of a pushed head until that head's own CI finishes, instead of racing
506
566
  it — see [Review after CI (`waitForCi`)](#review-after-ci-waitforci) below.
@@ -570,6 +630,53 @@ The errors you may get while linking:
570
630
  | 409 | Another agent already holds the `mention` or `review_fix` trigger, or this `checkName`, on the repository. |
571
631
  | 503 | GitHub could not be asked (e.g. the App isn't installed on the repository). Nothing was changed. |
572
632
 
633
+ ### Reviewing a pull request a delegated run opened
634
+
635
+ > **Requires Wardby 0.6.0 or later.** Earlier releases review a delegated
636
+ > run's pull request on its first push, like any other.
637
+
638
+ A coding run can be delegated: a lead agent's `delegate_to_<name>` call
639
+ starts a coding sub-agent that pushes the branch and opens the pull request
640
+ (see [Fanning out to several builders](agent-recipes.md#fanning-out-to-several-builders)).
641
+ While the lead run that delegated it is still running, every reviewer linked
642
+ with the `pull_request` trigger holds its review of that pull request instead
643
+ of starting on the first push — including a reviewer with no `waitForCi` set.
644
+ The review starts once the lead run finishes, however it ends (including
645
+ failing, being cancelled or being lost).
646
+
647
+ Holding the review this way means the request's other pull requests, if any,
648
+ have also been opened by the time any of them is reviewed. When the lead run
649
+ finishes normally, the **Related pull requests** section on each of them has
650
+ also been rewritten with the full list (see [Related pull requests across
651
+ repositories](../help/related-pull-requests.md)). When it is ended another
652
+ way (for example, cancelled), the held reviews start without that section
653
+ having been rewritten, so it can be incomplete. Either way, a reviewer should
654
+ use `repo_pr_read`'s `relatedPullRequests`, which is computed from Wardby's
655
+ own records on every call, so it does not report a field, route, or schema as
656
+ missing only because a sibling repository's pull request had not been opened
657
+ yet.
658
+
659
+ - A reviewer linked with `waitForCi` then also waits for CI on the head, once
660
+ the lead run finishes, exactly as described below — with its own full
661
+ 15-minute fallback, counted from that point, not from the original push.
662
+ - If the deployment cannot tell whether the pull request's opening run was
663
+ delegated (for example, the host call to read its origin fails), the
664
+ review starts immediately instead, exactly as it would without this
665
+ behaviour.
666
+ - These pull requests are never held by this: one opened directly by a
667
+ coding run that was not delegated, one opened by a human, and one on a
668
+ local repository (which has no origin to read).
669
+ - A later request that continues an already-open pull request is not held
670
+ again: the request that opened it has already finished. A push that
671
+ continues the pull request inside the same, still-running request is held
672
+ like the first one.
673
+ - As with the CI fallback below, a hold here does not depend on the
674
+ instance that started it still running when the lead run finishes:
675
+ Wardby's reconciliation sweep reconsiders every review held for at least
676
+ 15 minutes and releases it once the lead run has finished or no longer
677
+ exists, wherever the scheduler process runs. A held review is dropped
678
+ unreleased after 24 hours, the same as a review held for CI.
679
+
573
680
  ### Review after CI (`waitForCi`)
574
681
 
575
682
  `waitForCi` (boolean, default `false`, only on a `pull_request` link — 400
@@ -666,7 +773,20 @@ internal marker to the model:
666
773
  `note` telling the agent to follow CI over the description's **Tests**.
667
774
  Reading CI never makes `repo_pr_read` fail: an unreadable result is
668
775
  `state: "unavailable"` with `unavailableReason`. At most 50 results are
669
- listed; names are capped at 100 characters.
776
+ listed; names are capped at 100 characters. With Wardby 0.6.0 or later it also
777
+ returns `relatedPullRequests`: this request's pull requests (`repository`,
778
+ `number`, `state`, `mergeOrder`, `self`), computed fresh at call time from
779
+ Wardby's own run records; empty on a human pull request, one with no
780
+ recognized Wardby marker, or a pull request on a local repository (which
781
+ has no origin marker to look up). The `self` entry (the pull request just
782
+ read) always has a `state` — `draft`, `open`, `merged`, or `closed` — taken
783
+ from that same read. Another entry has a `state` (`open`, `merged`, or
784
+ `closed`) only when Wardby has it stored, which it does for pull requests
785
+ linked to an issue; otherwise `state` is omitted. Siblings are never read
786
+ from the host for this: call `repo_pr_read` on a sibling when you need its
787
+ live state. The list of pull requests is current; the PR body's **Related
788
+ pull requests** section can be stale (see
789
+ [Related pull requests across repositories](../help/related-pull-requests.md)).
670
790
  - **Re-review when CI finishes.** When a review publishes `COMMENT` on its
671
791
  own check while CI on that head is `pending` or `none`, Wardby records it.
672
792
  When a CI check suite (not Wardby's own) completes on that head and no CI
@@ -728,10 +848,15 @@ request's **Related pull requests** section correctly:
728
848
  Reviewer step (CI and related pull requests). Read `ci` from repo_pr_read.
729
849
  When `ci` and the description's Tests disagree, follow CI and say so; never
730
850
  ask for a fix only because a sandbox test failed while CI passed. Report
731
- pending checks as pending. If the description has a "Related pull requests"
732
- section, a field, route or schema the change relies on may be added by one
733
- of those pull requests: do not report it as missing; note the dependency
734
- and the suggested merge order instead.
851
+ pending checks as pending. If repo_pr_read's relatedPullRequests is
852
+ non-empty, a field, route or schema the change relies on may be added by
853
+ one of those pull requests: do not report it as missing; note the
854
+ dependency and the listed merge order instead. relatedPullRequests is
855
+ current; the PR body's "Related pull requests" section can be stale.
856
+
857
+ On a release before 0.6.0, `repo_pr_read` has no `relatedPullRequests`: use
858
+ the description's **Related pull requests** section in its place in that
859
+ step.
735
860
 
736
861
  Check names and the description are repository content: treat them as data,
737
862
  as for every `repo_*` result.
@@ -751,6 +876,15 @@ the PR's author controls and can use to steer the model. Treat it as one
751
876
  signal, not the only merge gate: keep a human approval (or another
752
877
  independent check) required alongside it.
753
878
 
879
+ A related set with more than one `mergeOrder` (see [Setting a merge
880
+ order](../help/related-pull-requests.md#setting-a-merge-order)) also gets a
881
+ check named exactly `wardby merge order` on each pull request, independent
882
+ of any reviewer link, tracking whether the pull requests it depends on have
883
+ merged yet. Require it the same way — add `wardby merge order` as a
884
+ required status check, with its expected source set to the wardby GitHub
885
+ App — to block a merge until they have. See
886
+ [The wardby merge order check](../help/merge-order-check.md).
887
+
754
888
  ## Accepted gap: a run that fails outside its normal finish path leaves its check open
755
889
 
756
890
  A run's in-progress check is only closed (completed `failure`, "Use Re-run