@wardby/cli 0.5.2 → 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 (411) 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/local-git.js +9 -1
  17. package/dist/coding/profile.d.ts +12 -0
  18. package/dist/coding/profile.js +6 -0
  19. package/dist/coding/protocol.d.ts +104 -0
  20. package/dist/coding/protocol.js +87 -3
  21. package/dist/coding/registry/pypi.d.ts +25 -1
  22. package/dist/coding/registry/pypi.js +140 -16
  23. package/dist/coding/registry/types.d.ts +17 -3
  24. package/dist/coding-worker/artifact.d.ts +8 -0
  25. package/dist/coding-worker/artifact.js +2 -2
  26. package/dist/coding-worker/driver.js +2 -0
  27. package/dist/coding-worker/sdk.d.ts +6 -0
  28. package/dist/coding-worker/sdk.js +1 -0
  29. package/dist/coding-worker/skills.d.ts +23 -0
  30. package/dist/coding-worker/skills.js +117 -0
  31. package/dist/coding-worker/types.d.ts +2 -0
  32. package/dist/config/github-allowed-accounts.d.ts +15 -0
  33. package/dist/config/github-allowed-accounts.js +36 -0
  34. package/dist/config/low-power.d.ts +12 -0
  35. package/dist/config/low-power.js +18 -0
  36. package/dist/config/mobile.d.ts +12 -0
  37. package/dist/config/mobile.js +18 -0
  38. package/dist/config/providers.d.ts +56 -2
  39. package/dist/config/providers.js +92 -6
  40. package/dist/core/db.d.ts +16 -6
  41. package/dist/core/db.js +12 -10
  42. package/dist/core/dispatch.d.ts +11 -0
  43. package/dist/core/dispatch.js +36 -1
  44. package/dist/core/engine-native.js +9 -5
  45. package/dist/core/host-events.d.ts +49 -3
  46. package/dist/core/host-events.js +289 -15
  47. package/dist/core/http-runtime.js +13 -6
  48. package/dist/core/issue-bridge.js +42 -2
  49. package/dist/core/issue-events.js +12 -1
  50. package/dist/core/issue-status.js +14 -3
  51. package/dist/core/merge-order-check.d.ts +129 -0
  52. package/dist/core/merge-order-check.js +336 -0
  53. package/dist/core/notification-dispatcher.d.ts +70 -0
  54. package/dist/core/notification-dispatcher.js +368 -0
  55. package/dist/core/notification-templates.d.ts +25 -0
  56. package/dist/core/notification-templates.js +105 -0
  57. package/dist/core/notifications.d.ts +10 -0
  58. package/dist/core/notifications.js +38 -0
  59. package/dist/core/pg-auth.d.ts +22 -0
  60. package/dist/core/pg-auth.js +152 -0
  61. package/dist/core/power-composition.d.ts +16 -0
  62. package/dist/core/power-composition.js +37 -0
  63. package/dist/core/power-idle.d.ts +14 -0
  64. package/dist/core/power-idle.js +30 -0
  65. package/dist/core/power.d.ts +71 -0
  66. package/dist/core/power.js +202 -0
  67. package/dist/core/reconciler.d.ts +4 -2
  68. package/dist/core/reconciler.js +29 -5
  69. package/dist/core/related-pull-requests.d.ts +48 -4
  70. package/dist/core/related-pull-requests.js +113 -11
  71. package/dist/core/repo-access.d.ts +15 -0
  72. package/dist/core/repo-access.js +66 -0
  73. package/dist/core/review-fix.d.ts +37 -0
  74. package/dist/core/review-fix.js +207 -6
  75. package/dist/core/review-host-tools.d.ts +20 -0
  76. package/dist/core/review-host-tools.js +58 -2
  77. package/dist/core/runner.d.ts +336 -3
  78. package/dist/core/runner.js +894 -317
  79. package/dist/core/secret-broker-config.d.ts +103 -0
  80. package/dist/core/secret-broker-config.js +112 -0
  81. package/dist/core/secrets.d.ts +39 -4
  82. package/dist/core/secrets.js +148 -40
  83. package/dist/core/workflow-event-recorder.d.ts +14 -0
  84. package/dist/core/workflow-event-recorder.js +120 -0
  85. package/dist/core/workflow-events.d.ts +82 -0
  86. package/dist/core/workflow-events.js +44 -0
  87. package/dist/core/workflow-run-events.d.ts +16 -0
  88. package/dist/core/workflow-run-events.js +40 -0
  89. package/dist/generated/prisma/browser.d.ts +58 -0
  90. package/dist/generated/prisma/client.d.ts +58 -0
  91. package/dist/generated/prisma/commonInputTypes.d.ts +150 -0
  92. package/dist/generated/prisma/enums.d.ts +27 -0
  93. package/dist/generated/prisma/enums.js +23 -0
  94. package/dist/generated/prisma/internal/class.d.ts +88 -0
  95. package/dist/generated/prisma/internal/class.js +4 -4
  96. package/dist/generated/prisma/internal/prismaNamespace.d.ts +772 -1
  97. package/dist/generated/prisma/internal/prismaNamespace.js +135 -4
  98. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +139 -0
  99. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +135 -4
  100. package/dist/generated/prisma/models/Agent.d.ts +360 -1
  101. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +73 -1
  102. package/dist/generated/prisma/models/CodingRun.d.ts +205 -1
  103. package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
  104. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1675 -0
  105. package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
  106. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1517 -0
  107. package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
  108. package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
  109. package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
  110. package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
  111. package/dist/generated/prisma/models/NotificationChannel.js +1 -0
  112. package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
  113. package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
  114. package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
  115. package/dist/generated/prisma/models/NotificationThread.js +1 -0
  116. package/dist/generated/prisma/models/Run.d.ts +826 -1
  117. package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
  118. package/dist/generated/prisma/models/Secret.d.ts +37 -1
  119. package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
  120. package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
  121. package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
  122. package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
  123. package/dist/generated/prisma/models.d.ts +8 -0
  124. package/dist/help/build.js +4 -2
  125. package/dist/help/catalog.d.ts +1 -1
  126. package/dist/help/catalog.js +31 -6
  127. package/dist/help-index.json +1492 -113
  128. package/dist/import/create.js +17 -0
  129. package/dist/import/neutral-schema.d.ts +6 -2
  130. package/dist/import/neutral-schema.js +2 -0
  131. package/dist/mcp/auth/access.d.ts +1 -0
  132. package/dist/mcp/auth/ownership.d.ts +1 -1
  133. package/dist/mcp/auth/repo-authorization.js +14 -0
  134. package/dist/mcp/auth/resource-server.d.ts +2 -1
  135. package/dist/mcp/auth/resource-server.js +7 -2
  136. package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
  137. package/dist/mcp/auth/self-hosted/browser.js +19 -6
  138. package/dist/mcp/context.d.ts +6 -0
  139. package/dist/mcp/host-events/github-ingress.d.ts +23 -1
  140. package/dist/mcp/host-events/github-ingress.js +68 -0
  141. package/dist/mcp/index.d.ts +13 -0
  142. package/dist/mcp/index.js +59 -10
  143. package/dist/mcp/tools/agents.js +83 -12
  144. package/dist/mcp/tools/notification-channels.d.ts +2 -0
  145. package/dist/mcp/tools/notification-channels.js +293 -0
  146. package/dist/mcp/tools/power.d.ts +2 -0
  147. package/dist/mcp/tools/power.js +77 -0
  148. package/dist/mcp/tools/runs.d.ts +0 -6
  149. package/dist/mcp/tools/runs.js +7 -2
  150. package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
  151. package/dist/mcp/tools/secret-broker-compat.js +23 -0
  152. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
  153. package/dist/mcp/tools/secret-elicitation-form.js +200 -10
  154. package/dist/mcp/tools/secret-elicitation-server.js +8 -1
  155. package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
  156. package/dist/mcp/tools/secret-elicitation.js +110 -12
  157. package/dist/mcp/tools/secrets.js +184 -7
  158. package/dist/mcp/tools/tools.d.ts +1 -1
  159. package/dist/mcp/tools/tools.js +22 -2
  160. package/dist/native-worker/composition.d.ts +23 -0
  161. package/dist/native-worker/composition.js +77 -0
  162. package/dist/native-worker/docker-isolation.d.ts +65 -0
  163. package/dist/native-worker/docker-isolation.js +183 -0
  164. package/dist/native-worker/docker-launcher.d.ts +74 -0
  165. package/dist/native-worker/docker-launcher.js +237 -0
  166. package/dist/native-worker/gateway-server.d.ts +39 -0
  167. package/dist/native-worker/gateway-server.js +315 -0
  168. package/dist/native-worker/gateway.d.ts +44 -0
  169. package/dist/native-worker/gateway.js +197 -0
  170. package/dist/native-worker/http-server.d.ts +22 -0
  171. package/dist/native-worker/http-server.js +109 -0
  172. package/dist/native-worker/http-transport.d.ts +17 -0
  173. package/dist/native-worker/http-transport.js +88 -0
  174. package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
  175. package/dist/native-worker/kubernetes-isolation.js +218 -0
  176. package/dist/native-worker/kubernetes-launcher.d.ts +102 -0
  177. package/dist/native-worker/kubernetes-launcher.js +335 -0
  178. package/dist/native-worker/launch.d.ts +45 -0
  179. package/dist/native-worker/launch.js +44 -0
  180. package/dist/native-worker/ledger.d.ts +109 -0
  181. package/dist/native-worker/ledger.js +192 -0
  182. package/dist/native-worker/loopback.d.ts +12 -0
  183. package/dist/native-worker/loopback.js +49 -0
  184. package/dist/native-worker/main.d.ts +7 -0
  185. package/dist/native-worker/main.js +74 -0
  186. package/dist/native-worker/protocol.d.ts +744 -0
  187. package/dist/native-worker/protocol.js +200 -0
  188. package/dist/native-worker/sandbox-executor.d.ts +68 -0
  189. package/dist/native-worker/sandbox-executor.js +210 -0
  190. package/dist/native-worker/stdio.d.ts +29 -0
  191. package/dist/native-worker/stdio.js +188 -0
  192. package/dist/native-worker/warm-delivery.d.ts +16 -0
  193. package/dist/native-worker/warm-delivery.js +33 -0
  194. package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
  195. package/dist/native-worker/warm-pool-ledger.js +73 -0
  196. package/dist/native-worker/warm-pool.d.ts +107 -0
  197. package/dist/native-worker/warm-pool.js +283 -0
  198. package/dist/native-worker/worker.d.ts +17 -0
  199. package/dist/native-worker/worker.js +115 -0
  200. package/dist/providers/auth/authorization-server.d.ts +3 -0
  201. package/dist/providers/auth/index.js +2 -0
  202. package/dist/providers/auth/self-hosted.d.ts +13 -1
  203. package/dist/providers/auth/self-hosted.js +54 -4
  204. package/dist/providers/chat/fake.d.ts +46 -0
  205. package/dist/providers/chat/fake.js +39 -0
  206. package/dist/providers/chat/index.d.ts +4 -0
  207. package/dist/providers/chat/index.js +8 -0
  208. package/dist/providers/chat/slack.d.ts +37 -0
  209. package/dist/providers/chat/slack.js +105 -0
  210. package/dist/providers/chat/types.d.ts +42 -0
  211. package/dist/providers/chat/types.js +19 -0
  212. package/dist/providers/coding-proxy/mock-upstream.d.ts +33 -0
  213. package/dist/providers/coding-proxy/mock-upstream.js +116 -0
  214. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +3 -0
  215. package/dist/providers/coding-proxy/registry/prisma-store.js +17 -0
  216. package/dist/providers/coding-proxy/registry/service.d.ts +4 -0
  217. package/dist/providers/coding-proxy/registry/service.js +20 -3
  218. package/dist/providers/coding-proxy/registry/store.d.ts +18 -1
  219. package/dist/providers/coding-proxy/registry/store.js +33 -0
  220. package/dist/providers/coding-proxy/runtime.js +12 -1
  221. package/dist/providers/coding-proxy/types.d.ts +2 -0
  222. package/dist/providers/engine/types.d.ts +19 -0
  223. package/dist/providers/engine/types.js +22 -0
  224. package/dist/providers/executor/composition.d.ts +24 -1
  225. package/dist/providers/executor/composition.js +39 -6
  226. package/dist/providers/executor/container.d.ts +24 -1
  227. package/dist/providers/executor/container.js +101 -11
  228. package/dist/providers/executor/dbos.d.ts +42 -0
  229. package/dist/providers/executor/dbos.js +118 -12
  230. package/dist/providers/executor/deferred.d.ts +56 -0
  231. package/dist/providers/executor/deferred.js +119 -0
  232. package/dist/providers/executor/routing.d.ts +37 -10
  233. package/dist/providers/executor/routing.js +73 -32
  234. package/dist/providers/executor/types.d.ts +12 -0
  235. package/dist/providers/jobs/docker.js +3 -3
  236. package/dist/providers/jobs/fake-kubernetes-api.d.ts +21 -2
  237. package/dist/providers/jobs/fake-kubernetes-api.js +42 -1
  238. package/dist/providers/jobs/kubernetes-api.d.ts +17 -1
  239. package/dist/providers/jobs/kubernetes-api.js +7 -0
  240. package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
  241. package/dist/providers/jobs/kubernetes-client.js +52 -3
  242. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
  243. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
  244. package/dist/providers/jobs/kubernetes-isolation.d.ts +16 -1
  245. package/dist/providers/jobs/kubernetes-isolation.js +58 -5
  246. package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
  247. package/dist/providers/jobs/kubernetes-platform.js +38 -1
  248. package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
  249. package/dist/providers/jobs/kubernetes-preflight.js +4 -2
  250. package/dist/providers/jobs/kubernetes.d.ts +56 -7
  251. package/dist/providers/jobs/kubernetes.js +117 -36
  252. package/dist/providers/jobs/metadata-probes.d.ts +11 -0
  253. package/dist/providers/jobs/metadata-probes.js +13 -0
  254. package/dist/providers/jobs/types.d.ts +9 -0
  255. package/dist/providers/llm/openai.js +0 -1
  256. package/dist/providers/review-host/github.d.ts +11 -1
  257. package/dist/providers/review-host/github.js +50 -0
  258. package/dist/providers/review-host/types.d.ts +23 -0
  259. package/dist/providers/vcs/github.d.ts +32 -6
  260. package/dist/providers/vcs/github.js +74 -16
  261. package/dist/quickstart/coding-db.js +14 -2
  262. package/dist/quickstart/coding-doctor.d.ts +3 -0
  263. package/dist/quickstart/coding-doctor.js +3 -0
  264. package/dist/quickstart/coding-images.d.ts +9 -0
  265. package/dist/quickstart/coding-images.js +39 -0
  266. package/dist/quickstart/coding-seed.d.ts +20 -1
  267. package/dist/quickstart/coding-seed.js +96 -7
  268. package/dist/quickstart/coding.d.ts +2 -0
  269. package/dist/quickstart/coding.js +75 -3
  270. package/dist/quickstart/config.d.ts +2 -0
  271. package/dist/quickstart/config.js +4 -0
  272. package/dist/quickstart/images.d.ts +13 -0
  273. package/dist/quickstart/images.js +80 -12
  274. package/dist/quickstart/index.d.ts +0 -2
  275. package/dist/quickstart/index.js +10 -14
  276. package/dist/quickstart/manifests.d.ts +56 -0
  277. package/dist/quickstart/manifests.js +523 -0
  278. package/dist/quickstart/python-detect.d.ts +10 -0
  279. package/dist/quickstart/python-detect.js +32 -0
  280. package/dist/quickstart/repo-packages.d.ts +10 -0
  281. package/dist/quickstart/repo-packages.js +132 -0
  282. package/dist/quickstart/reviewer-prompt.d.ts +12 -0
  283. package/dist/quickstart/reviewer-prompt.js +84 -0
  284. package/dist/quickstart/scenarios.d.ts +19 -0
  285. package/dist/quickstart/scenarios.js +28 -0
  286. package/dist/quickstart/sync-reviewer-prompt.d.ts +1 -0
  287. package/dist/quickstart/sync-reviewer-prompt.js +10 -0
  288. package/dist/quickstart-images.json +1 -1
  289. package/dist/sandbox/brokered-fetch.d.ts +23 -0
  290. package/dist/sandbox/brokered-fetch.js +37 -0
  291. package/dist/sandbox/host-functions.d.ts +34 -0
  292. package/dist/sandbox/host-functions.js +144 -80
  293. package/dist/sandbox/prelude.js +7 -1
  294. package/dist/sandbox/run-in-sandbox.d.ts +19 -0
  295. package/dist/sandbox/run-in-sandbox.js +28 -10
  296. package/dist/sandbox/safe-fetch.d.ts +2 -0
  297. package/dist/sandbox/safe-fetch.js +3 -1
  298. package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
  299. package/dist/sandbox/secret-broker-sigv4.js +49 -0
  300. package/dist/sandbox/secret-broker.d.ts +34 -0
  301. package/dist/sandbox/secret-broker.js +162 -0
  302. package/dist/sandbox/user-tool.d.ts +14 -0
  303. package/dist/sandbox/user-tool.js +32 -0
  304. package/dist/serve.js +18 -0
  305. package/dist/viewer/api-schema.d.ts +214 -18
  306. package/dist/viewer/api-schema.js +22 -0
  307. package/dist/viewer/build-schemas.js +4 -1
  308. package/dist/viewer/event-bus.d.ts +6 -0
  309. package/dist/viewer/event-bus.js +16 -7
  310. package/dist/viewer/graph.d.ts +5 -2
  311. package/dist/viewer/graph.js +7 -2
  312. package/dist/viewer/http.d.ts +0 -1
  313. package/dist/viewer/http.js +2 -2
  314. package/dist/viewer/infra.js +25 -2
  315. package/dist/viewer/limits.d.ts +4 -0
  316. package/dist/viewer/limits.js +4 -0
  317. package/dist/viewer/openapi.d.ts +15 -0
  318. package/dist/viewer/openapi.js +172 -0
  319. package/docs/README.md +7 -0
  320. package/docs/agent-recipes.md +57 -8
  321. package/docs/architecture-runtime.md +16 -1
  322. package/docs/code-review-agents.md +139 -5
  323. package/docs/coding-agent-setup.md +127 -2
  324. package/docs/coding-packages.md +105 -5
  325. package/docs/coding-services.md +3 -1
  326. package/docs/coding-worker-byo-images.md +239 -2
  327. package/docs/coding-worker-isolation.md +88 -23
  328. package/docs/getting-started-gke.md +225 -9
  329. package/docs/getting-started-identity-provider.md +21 -10
  330. package/docs/getting-started.md +140 -11
  331. package/docs/jira-agents.md +5 -1
  332. package/docs/knowledge.md +11 -0
  333. package/docs/native-sandbox.md +635 -0
  334. package/docs/release-verification.md +9 -0
  335. package/docs/security-deployment.md +113 -12
  336. package/docs/slack-notifications.md +252 -0
  337. package/docs/tool-secrets.md +252 -0
  338. package/docs/viewer-api.md +46 -5
  339. package/docs/viewer-api.openapi.yml +1404 -0
  340. package/help/admin-viewer.md +6 -2
  341. package/help/agent-recipes.md +27 -0
  342. package/help/architecture-agent.md +136 -0
  343. package/help/brokered-secrets.md +79 -0
  344. package/help/build-claude-code-image.md +131 -0
  345. package/help/build-worker-image.md +195 -0
  346. package/help/code-review-agents.md +68 -6
  347. package/help/coding-packages.md +31 -2
  348. package/help/creating-agents.md +14 -0
  349. package/help/deploy-gke.md +37 -6
  350. package/help/deployment-targets.md +24 -13
  351. package/help/errors/coding-provider-not-configured.md +2 -2
  352. package/help/errors/database-auth-invalid.md +28 -0
  353. package/help/errors/github-account-not-allowed.md +25 -0
  354. package/help/errors/low-power-disabled.md +29 -0
  355. package/help/errors/low-power-scale-forbidden.md +35 -0
  356. package/help/errors/low-power-wake-timeout.md +30 -0
  357. package/help/errors/mobile-disabled.md +31 -0
  358. package/help/errors/native-sandbox-capacity.md +22 -0
  359. package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
  360. package/help/errors/native-sandbox-docker-failed.md +20 -0
  361. package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
  362. package/help/errors/native-sandbox-image-not-pinned.md +19 -0
  363. package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
  364. package/help/errors/native-sandbox-network-unenforced.md +22 -0
  365. package/help/errors/native-sandbox-requires-catalog.md +31 -0
  366. package/help/errors/native-sandbox-unavailable.md +19 -0
  367. package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
  368. package/help/errors/native-sandbox-worker-exited.md +20 -0
  369. package/help/errors/native-sandbox-worker-lost.md +20 -0
  370. package/help/errors/native-sandbox-worker-unready.md +22 -0
  371. package/help/errors/secret-broker-body-invalid.md +26 -0
  372. package/help/errors/secret-broker-changed.md +20 -0
  373. package/help/errors/secret-broker-config-invalid.md +30 -0
  374. package/help/errors/secret-broker-conflict.md +27 -0
  375. package/help/errors/secret-broker-destination-denied.md +28 -0
  376. package/help/errors/secret-broker-value-invalid.md +28 -0
  377. package/help/errors/secret-brokered.md +24 -0
  378. package/help/errors/secret-not-brokered.md +25 -0
  379. package/help/errors/slack-auth-failed.md +48 -0
  380. package/help/errors/slack-channel-unreachable.md +39 -0
  381. package/help/errors/slack-not-configured.md +33 -0
  382. package/help/getting-started.md +18 -0
  383. package/help/github.md +18 -1
  384. package/help/identity-and-access.md +5 -1
  385. package/help/local-repositories.md +35 -5
  386. package/help/low-power-mode.md +125 -0
  387. package/help/merge-order-check.md +117 -0
  388. package/help/mobile-app.md +54 -0
  389. package/help/native-sandbox.md +136 -0
  390. package/help/observability.md +8 -0
  391. package/help/related-pull-requests.md +70 -9
  392. package/help/repo-instructions-and-skills.md +91 -0
  393. package/help/review-fix-rounds.md +10 -0
  394. package/help/slack-notifications.md +62 -0
  395. package/help/troubleshooting/coding-workers.md +21 -0
  396. package/package.json +13 -5
  397. package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
  398. package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
  399. package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
  400. package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
  401. package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
  402. package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
  403. package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
  404. package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
  405. package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
  406. package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
  407. package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
  408. package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
  409. package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
  410. package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
  411. package/prisma/schema.prisma +362 -91
@@ -3,9 +3,18 @@
3
3
  * request opened by a coding run in the same top-level run tree (a lead that
4
4
  * fanned out to several repositories), plus any recorded for the same tracker
5
5
  * issue (IssuePullRequest). Control-plane rows only.
6
- * Ordered by when each pull request's coding run was dispatched: the lead's
7
- * delegation order (for a lead with parallelDelegations, the order its
8
- * concurrent delegations were admitted, ties broken by repository#number).
6
+ * Ordered by the delegating agent's declared merge order when any entry has
7
+ * one (CodingRun.mergeOrder; nulls last), then by when each pull request's
8
+ * coding run was dispatched: the lead's delegation order (for a lead with
9
+ * parallelDelegations, the order its concurrent delegations were admitted,
10
+ * ties broken by repository#number). A pull request's mergeOrder is the
11
+ * newest non-null value set by its opener run or any later continuation
12
+ * that acted on it, so a lead that re-delegates with a different order
13
+ * after the fact is reflected here. When mergeOrder is set on any entry,
14
+ * every truncation cap below this collector (MAX_RELATED_GROUP here,
15
+ * MAX_SIBLING_HINTS on openSiblingsOf, MAX_RELATED_PULL_REQUESTS on
16
+ * renderRelatedSection) drops entries with no order first, since they sort
17
+ * last.
9
18
  * A PR opened while siblings were still running lists only the PRs opened
10
19
  * before it; updateRelatedPullRequests rewrites every open PR of the set
11
20
  * with the full list when the lead run ends. Continuations join
@@ -13,7 +22,7 @@
13
22
  * pull requests brings the original request's tree, and the original request
14
23
  * brings every later follow-up tree that continued one of its pull requests.
15
24
  */
16
- import { type PrismaClient, type Run } from "#prisma";
25
+ import { type PrismaClient, type Run, type RunStatus } from "#prisma";
17
26
  import { type IssueTrackerRegistry } from "../providers/issue-tracker/types.js";
18
27
  import type { ReviewHostRegistry } from "../providers/review-host/types.js";
19
28
  /** Most pull requests a group holds; the description shows fewer (MAX_RELATED_PULL_REQUESTS). */
@@ -28,6 +37,13 @@ export interface RelatedPullRequest {
28
37
  openedByRunId: string;
29
38
  /** Only when stored (IssuePullRequest.state, kept current by pr_closed); otherwise unknown. */
30
39
  state?: StoredPullRequestState;
40
+ /**
41
+ * Step in the delegating agent's merge order (CodingRun.mergeOrder, 1-99):
42
+ * the newest non-null value among the coding run that opened it and its
43
+ * continuations. Absent when none of them set one, or when the entry only
44
+ * came from IssuePullRequest (no CodingRun to read it from).
45
+ */
46
+ mergeOrder?: number;
31
47
  }
32
48
  export interface RelatedPullRequestGroup {
33
49
  pullRequests: RelatedPullRequest[];
@@ -36,7 +52,35 @@ export interface RelatedPullRequestGroup {
36
52
  provider: string;
37
53
  key: string;
38
54
  };
55
+ /**
56
+ * The top-level run of every run tree the walk visited (the original
57
+ * request and each follow-up tree that continued one of its pull
58
+ * requests), with its status; absent when none was read. `codingRun` is
59
+ * true when the root is itself a coding run (a top-level follow-up such
60
+ * as a review fix round or an @mention picked up by a coding link), not a
61
+ * native lead agent's run.
62
+ */
63
+ roots?: Array<{
64
+ id: string;
65
+ status: RunStatus;
66
+ codingRun: boolean;
67
+ }>;
39
68
  }
69
+ /**
70
+ * The top-level run of the tree a pull request's marker run belongs to,
71
+ * whatever its status: the marker's coding run (a continuation resolves to
72
+ * its root coding run first), then up its parents. Null when the marker
73
+ * names no coding run, or one recorded for a different repository than
74
+ * `repository` (compared case-insensitively; omit it to skip the check).
75
+ * `isOpener` is true when that root is the opening coding run itself (the
76
+ * pull request was not delegated). The single place this walk and its
77
+ * repository guard live (requestLeadRunId, the merge order check).
78
+ */
79
+ export declare function runTreeRoot(db: Pick<PrismaClient, "$queryRaw">, markerRunId: string, repository?: string): Promise<{
80
+ id: string;
81
+ status: RunStatus;
82
+ isOpener: boolean;
83
+ } | null>;
40
84
  export declare function collectRelatedPullRequests(db: RelatedPullRequestsDb, runId: string,
41
85
  /**
42
86
  * Scopes the issue join (and any tree row explicitly tagged for a
@@ -3,9 +3,18 @@
3
3
  * request opened by a coding run in the same top-level run tree (a lead that
4
4
  * fanned out to several repositories), plus any recorded for the same tracker
5
5
  * issue (IssuePullRequest). Control-plane rows only.
6
- * Ordered by when each pull request's coding run was dispatched: the lead's
7
- * delegation order (for a lead with parallelDelegations, the order its
8
- * concurrent delegations were admitted, ties broken by repository#number).
6
+ * Ordered by the delegating agent's declared merge order when any entry has
7
+ * one (CodingRun.mergeOrder; nulls last), then by when each pull request's
8
+ * coding run was dispatched: the lead's delegation order (for a lead with
9
+ * parallelDelegations, the order its concurrent delegations were admitted,
10
+ * ties broken by repository#number). A pull request's mergeOrder is the
11
+ * newest non-null value set by its opener run or any later continuation
12
+ * that acted on it, so a lead that re-delegates with a different order
13
+ * after the fact is reflected here. When mergeOrder is set on any entry,
14
+ * every truncation cap below this collector (MAX_RELATED_GROUP here,
15
+ * MAX_SIBLING_HINTS on openSiblingsOf, MAX_RELATED_PULL_REQUESTS on
16
+ * renderRelatedSection) drops entries with no order first, since they sort
17
+ * last.
9
18
  * A PR opened while siblings were still running lists only the PRs opened
10
19
  * before it; updateRelatedPullRequests rewrites every open PR of the set
11
20
  * with the full list when the lead run ends. Continuations join
@@ -36,17 +45,50 @@ async function treeCodingRuns(db, seeds) {
36
45
  UNION
37
46
  SELECT p."id", p."parentRunId" FROM "Run" p JOIN up u ON p."id" = u."parentRunId"
38
47
  ), down AS (
39
- SELECT u."id" FROM up u WHERE u."parentRunId" IS NULL
48
+ SELECT u."id", u."id" AS "rootId" FROM up u WHERE u."parentRunId" IS NULL
40
49
  UNION
41
- SELECT c."id" FROM "Run" c JOIN down d ON c."parentRunId" = d."id"
50
+ SELECT c."id", d."rootId" FROM "Run" c JOIN down d ON c."parentRunId" = d."id"
42
51
  )
43
- SELECT cr."runId", cr."result", cr."rootCodingRunId", cr."issueProvider", cr."issueKey", r."startedAt"
52
+ SELECT cr."runId", cr."result", cr."rootCodingRunId", cr."issueProvider", cr."issueKey", cr."mergeOrder", r."startedAt",
53
+ d."rootId" AS "treeRootId", root."status"::text AS "treeRootStatus",
54
+ EXISTS (SELECT 1 FROM "CodingRun" rc WHERE rc."runId" = d."rootId") AS "treeRootIsCodingRun"
44
55
  FROM "CodingRun" cr
45
56
  JOIN down d ON cr."runId" = d."id"
46
57
  JOIN "Run" r ON r."id" = cr."runId"
58
+ JOIN "Run" root ON root."id" = d."rootId"
47
59
  ORDER BY r."startedAt" ASC, cr."runId" ASC
48
60
  LIMIT ${MAX_TREE_CODING_RUNS}`;
49
61
  }
62
+ /**
63
+ * The top-level run of the tree a pull request's marker run belongs to,
64
+ * whatever its status: the marker's coding run (a continuation resolves to
65
+ * its root coding run first), then up its parents. Null when the marker
66
+ * names no coding run, or one recorded for a different repository than
67
+ * `repository` (compared case-insensitively; omit it to skip the check).
68
+ * `isOpener` is true when that root is the opening coding run itself (the
69
+ * pull request was not delegated). The single place this walk and its
70
+ * repository guard live (requestLeadRunId, the merge order check).
71
+ */
72
+ export async function runTreeRoot(db, markerRunId, repository) {
73
+ const repo = repository ?? null;
74
+ // UNION, not UNION ALL: a parentRunId cycle (never written, but not a constraint) can't recurse forever.
75
+ const rows = await db.$queryRaw `
76
+ WITH RECURSIVE opener AS (
77
+ SELECT COALESCE(cr."rootCodingRunId", cr."runId") AS "id"
78
+ FROM "CodingRun" cr
79
+ WHERE cr."runId" = ${markerRunId}
80
+ AND (${repo}::text IS NULL OR lower(cr."repository") = lower(${repo}::text))
81
+ ), up AS (
82
+ SELECT r."id", r."parentRunId", r."status"::text AS "status" FROM "Run" r JOIN opener o ON r."id" = o."id"
83
+ UNION
84
+ SELECT p."id", p."parentRunId", p."status"::text FROM "Run" p JOIN up u ON p."id" = u."parentRunId"
85
+ )
86
+ SELECT u."id", u."status", u."id" IN (SELECT "id" FROM opener) AS "isOpener"
87
+ FROM up u
88
+ WHERE u."parentRunId" IS NULL
89
+ LIMIT 1`;
90
+ return rows[0] ?? null;
91
+ }
50
92
  function safeRepository(value) {
51
93
  try {
52
94
  return normalizeGitHubRepository(value);
@@ -139,9 +181,40 @@ onlyIssueKey) {
139
181
  number: pr.pullRequestNumber,
140
182
  openedAt: new Date(r.startedAt),
141
183
  openedByRunId: r.runId,
184
+ ...(r.mergeOrder != null ? { mergeOrder: r.mergeOrder } : {}),
142
185
  });
143
186
  }
144
187
  }
188
+ // A continuation dispatched with its own mergeOrder overrides the opener's
189
+ // (one that omits it stores the value it inherited), and it starts after
190
+ // the opener; the entry's mergeOrder is the newest non-null
191
+ // value among the opener row and every continuation row (same PR key,
192
+ // "pull_request_opened" or "pull_request_updated") found in the tree walk.
193
+ const newestMergeOrder = new Map();
194
+ for (const r of rows) {
195
+ if (r.mergeOrder == null)
196
+ continue;
197
+ const pr = pullRequestOutcome(r.result);
198
+ if (pr?.outcome !== "pull_request_opened" && pr?.outcome !== "pull_request_updated")
199
+ continue;
200
+ if (onlyIssueKey && r.issueKey && (r.issueProvider !== onlyIssueKey.provider || r.issueKey !== onlyIssueKey.key)) {
201
+ continue;
202
+ }
203
+ const repository = safeRepository(pr.repository);
204
+ if (!repository)
205
+ continue;
206
+ const key = keyOf(repository, pr.pullRequestNumber);
207
+ const startedAt = new Date(r.startedAt);
208
+ const current = newestMergeOrder.get(key);
209
+ if (!current || startedAt.getTime() >= current.startedAt.getTime()) {
210
+ newestMergeOrder.set(key, { startedAt, mergeOrder: r.mergeOrder });
211
+ }
212
+ }
213
+ for (const [key, entry] of byKey) {
214
+ const newest = newestMergeOrder.get(key);
215
+ if (newest)
216
+ entry.mergeOrder = newest.mergeOrder;
217
+ }
145
218
  const issueFilter = onlyIssueKey
146
219
  ? new Map([[`${onlyIssueKey.provider}\0${onlyIssueKey.key}`, onlyIssueKey]])
147
220
  : issues;
@@ -177,11 +250,23 @@ onlyIssueKey) {
177
250
  });
178
251
  }
179
252
  }
253
+ const order = (e) => e.mergeOrder ?? Number.POSITIVE_INFINITY;
180
254
  const pullRequests = [...byKey.values()]
181
- .sort((a, b) => a.openedAt.getTime() - b.openedAt.getTime() ||
255
+ .sort((a, b) => order(a) - order(b) ||
256
+ a.openedAt.getTime() - b.openedAt.getTime() ||
182
257
  `${a.repository}#${a.number}`.localeCompare(`${b.repository}#${b.number}`))
183
258
  .slice(0, MAX_RELATED_GROUP);
184
- return { pullRequests, ...(issue ? { issue } : {}) };
259
+ const roots = new Map();
260
+ for (const r of rows) {
261
+ if (r.treeRootId && r.treeRootStatus) {
262
+ roots.set(r.treeRootId, { status: r.treeRootStatus, codingRun: r.treeRootIsCodingRun === true });
263
+ }
264
+ }
265
+ return {
266
+ pullRequests,
267
+ ...(issue ? { issue } : {}),
268
+ ...(roots.size > 0 ? { roots: [...roots].map(([id, root]) => ({ id, ...root })) } : {}),
269
+ };
185
270
  }
186
271
  function issueFor(group, trackers) {
187
272
  if (!group.issue)
@@ -219,7 +304,12 @@ export async function updateRelatedPullRequests(db, run, hosts, trackers) {
219
304
  for (const pr of group.pullRequests) {
220
305
  // A stored merged/closed state is final and such a PR is never edited: no host read.
221
306
  if (pr.state === "merged" || pr.state === "closed") {
222
- live.push({ repository: pr.repository, number: pr.number, state: pr.state });
307
+ live.push({
308
+ repository: pr.repository,
309
+ number: pr.number,
310
+ state: pr.state,
311
+ ...(pr.mergeOrder !== undefined ? { mergeOrder: pr.mergeOrder } : {}),
312
+ });
223
313
  continue;
224
314
  }
225
315
  try {
@@ -240,12 +330,23 @@ export async function updateRelatedPullRequests(db, run, hosts, trackers) {
240
330
  if (opener && opener.repository.toLowerCase() === pr.repository)
241
331
  markerRunId = origin.markerRunId;
242
332
  }
243
- live.push({ repository: pr.repository, number: pr.number, state, ...(markerRunId ? { markerRunId } : {}) });
333
+ live.push({
334
+ repository: pr.repository,
335
+ number: pr.number,
336
+ state,
337
+ ...(markerRunId ? { markerRunId } : {}),
338
+ ...(pr.mergeOrder !== undefined ? { mergeOrder: pr.mergeOrder } : {}),
339
+ });
244
340
  }
245
341
  catch (err) {
246
342
  log.warn({ err, runId: run.id, repository: pr.repository, number: pr.number }, "could not read a related pull request");
247
343
  // The stored state (issue-recorded PRs) is better than none; never edited without a live read.
248
- live.push({ repository: pr.repository, number: pr.number, ...(pr.state ? { state: pr.state } : {}) });
344
+ live.push({
345
+ repository: pr.repository,
346
+ number: pr.number,
347
+ ...(pr.state ? { state: pr.state } : {}),
348
+ ...(pr.mergeOrder !== undefined ? { mergeOrder: pr.mergeOrder } : {}),
349
+ });
249
350
  }
250
351
  }
251
352
  const issue = issueFor(group, trackers);
@@ -258,6 +359,7 @@ export async function updateRelatedPullRequests(db, run, hosts, trackers) {
258
359
  number: pr.number,
259
360
  ...(pr.state ? { state: pr.state } : {}),
260
361
  ...(pr === target ? { self: true } : {}),
362
+ ...(pr.mergeOrder !== undefined ? { mergeOrder: pr.mergeOrder } : {}),
261
363
  })),
262
364
  ...(issue ? { issue } : {}),
263
365
  });
@@ -23,6 +23,8 @@ export declare const AUTHORIZED_VIA: readonly AuthorizedVia[];
23
23
  export type RepoAccessDenial = "owner_required" | "not_authorized" | "identity_not_linked" | "insufficient_permission" | "check_failed"
24
24
  /** A `local:` repository that is not inside the current trusted roots (LOCAL_REPO_ROOTS). */
25
25
  | "local_repo_not_allowed"
26
+ /** A GitHub repository whose owner is neither the App's owner nor in WARDBY_GITHUB_ALLOWED_ACCOUNTS. */
27
+ | "github_account_not_allowed"
26
28
  /** In-flight use only: the host was unreachable or rate-limited, even after one retry. */
27
29
  | "check_unavailable";
28
30
  export type RepoAccessDecision = {
@@ -78,6 +80,8 @@ export interface RepoAccessGate {
78
80
  required: HostPermission;
79
81
  fresh?: boolean;
80
82
  }): Promise<RepoAccessDecision>;
83
+ /** Is this repository's account served by the GitHub App? undefined = yes (or not a GitHub repository). */
84
+ checkAccount?(provider: string, repository: string): Promise<RepoAccessDecision | undefined>;
81
85
  }
82
86
  export interface RepoAccessGateOptions {
83
87
  db: Pick<PrismaClient, "hostIdentity">;
@@ -92,9 +96,20 @@ export interface RepoAccessGateOptions {
92
96
  /** Delay before the one retry of a transient error (default 1s). */
93
97
  retryDelayMs?: number;
94
98
  sleep?: (ms: number) => Promise<void>;
99
+ /**
100
+ * The served GitHub accounts (default: the App owner from hosts.github plus
101
+ * WARDBY_GITHUB_ALLOWED_ACCOUNTS). undefined = no GitHub App, nothing to guard.
102
+ * Throwing = fail closed.
103
+ */
104
+ trustedAccounts?: () => Promise<ReadonlySet<string> | undefined>;
95
105
  }
96
106
  /** 5xx, rate limits (403/429), and transport failures: worth one retry for a run already under way. */
97
107
  export declare function isTransientHostError(err: unknown): boolean;
108
+ /**
109
+ * Why the trusted GitHub accounts could not be read, as a fixed string: every
110
+ * branch returns a literal, so nothing from the error itself reaches a log.
111
+ */
112
+ export declare function trustedAccountsFailure(err: unknown): string;
98
113
  export declare const DEFAULT_REPO_ACCESS_TTL_MS: number;
99
114
  export declare function createRepoAccessGate(options: RepoAccessGateOptions): RepoAccessGate;
100
115
  /** Actionable, non-leaking text for a denial, for tool results and run errors. */
@@ -1,5 +1,6 @@
1
1
  import { HOST_PERMISSION_RANK, ReviewHostError, } from "../providers/review-host/types.js";
2
2
  import { LocalRepoError, isLocalRepository, loadLocalRepoRoots, resolveLocalRepository } from "../coding/local-repo.js";
3
+ import { githubAccountOf, isGitHubAccountAllowed, loadGitHubAllowedAccounts, trustedAccounts as trustedAccountSet, } from "../config/github-allowed-accounts.js";
3
4
  import { logger } from "./logger.js";
4
5
  const log = logger.child({ module: "repo-access" });
5
6
  export const AUTHORIZED_VIA = ["host_permission", "admin", "grandfathered", "local_root"];
@@ -20,6 +21,24 @@ export function isTransientHostError(err) {
20
21
  return false;
21
22
  return err.message === "github_api_unavailable" || /^github_api_error:(5\d\d|429|403)(:|$)/.test(err.message);
22
23
  }
24
+ /**
25
+ * Why the trusted GitHub accounts could not be read, as a fixed string: every
26
+ * branch returns a literal, so nothing from the error itself reaches a log.
27
+ */
28
+ export function trustedAccountsFailure(err) {
29
+ const message = err instanceof Error ? err.message : "";
30
+ if (message === "github_allowed_accounts_invalid")
31
+ return "github_allowed_accounts_invalid";
32
+ if (message === "github_api_unavailable")
33
+ return "github_api_unavailable";
34
+ if (message === "github_api_invalid_response")
35
+ return "github_api_invalid_response";
36
+ if (message === "github_app_private_key_invalid")
37
+ return "github_app_private_key_invalid";
38
+ if (message.startsWith("github_api_error:"))
39
+ return "github_api_error";
40
+ return "unexpected_error";
41
+ }
23
42
  const defaultLocalRoots = () => loadLocalRepoRoots(process.env).roots;
24
43
  export const DEFAULT_REPO_ACCESS_TTL_MS = 5 * 60_000;
25
44
  export function createRepoAccessGate(options) {
@@ -29,6 +48,41 @@ export function createRepoAccessGate(options) {
29
48
  const retryDelayMs = options.retryDelayMs ?? 1000;
30
49
  const sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
31
50
  const cache = new Map();
51
+ const readTrusted = options.trustedAccounts ??
52
+ (async () => {
53
+ const host = options.hosts.github;
54
+ if (!host?.appOwnerLogin)
55
+ return undefined;
56
+ let extra;
57
+ try {
58
+ extra = loadGitHubAllowedAccounts();
59
+ }
60
+ catch {
61
+ // A fixed code: the parse error quotes the raw value, which must not reach the log.
62
+ throw new Error("github_allowed_accounts_invalid");
63
+ }
64
+ return trustedAccountSet(await host.appOwnerLogin(), extra);
65
+ });
66
+ /** A server-wide boundary, checked before any stamp, owner, or host call. Local repositories are exempt. */
67
+ async function checkAccount(provider, repository) {
68
+ if (provider !== "github" || isLocalRepository(repository))
69
+ return undefined;
70
+ let trusted;
71
+ try {
72
+ trusted = await readTrusted();
73
+ }
74
+ catch (err) {
75
+ // Only a fixed code is logged, never the error: its message may carry
76
+ // WARDBY_GITHUB_ALLOWED_ACCOUNTS's value (CodeQL js/clear-text-logging).
77
+ log.warn({ code: trustedAccountsFailure(err) }, "could not read the GitHub App's trusted accounts; denying");
78
+ return { ok: false, reason: "check_failed" };
79
+ }
80
+ if (trusted === undefined)
81
+ return undefined;
82
+ return isGitHubAccountAllowed(trusted, githubAccountOf(repository))
83
+ ? undefined
84
+ : { ok: false, reason: "github_account_not_allowed" };
85
+ }
32
86
  /** The user's level, or why it could not be determined (host missing or failing). */
33
87
  async function levelOf(provider, repository, user, fresh, retryTransient) {
34
88
  const key = `${provider}\u0000${repository}\u0000${user.id}`;
@@ -69,6 +123,9 @@ export function createRepoAccessGate(options) {
69
123
  return atLeast(level, required) ? { ok: true, level } : { ok: false, reason: "insufficient_permission", level };
70
124
  }
71
125
  async function authorizePrincipal(input) {
126
+ const denied = await checkAccount(input.provider, input.repository);
127
+ if (denied)
128
+ return denied;
72
129
  let identity;
73
130
  try {
74
131
  identity = await options.db.hostIdentity.findUnique({
@@ -108,6 +165,9 @@ export function createRepoAccessGate(options) {
108
165
  return { ok: false, reason: "local_repo_not_allowed" };
109
166
  }
110
167
  }
168
+ const denied = await checkAccount(input.provider, input.repository);
169
+ if (denied)
170
+ return denied;
111
171
  if (!input.ownerId)
112
172
  return { ok: false, reason: "owner_required" };
113
173
  if (input.authorizedVia === "admin" || input.authorizedVia === "grandfathered")
@@ -124,11 +184,15 @@ export function createRepoAccessGate(options) {
124
184
  },
125
185
  authorizePrincipal,
126
186
  async authorizeHostUser(input) {
187
+ const denied = await checkAccount(input.provider, input.repository);
188
+ if (denied)
189
+ return denied;
127
190
  const answer = await levelOf(input.provider, input.repository, input.user, input.fresh === true, false);
128
191
  if (!answer.ok)
129
192
  return unavailable(answer);
130
193
  return decide(answer.level, input.required);
131
194
  },
195
+ checkAccount,
132
196
  };
133
197
  }
134
198
  /** Actionable, non-leaking text for a denial, for tool results and run errors. */
@@ -144,6 +208,8 @@ export function describeDenial(decision, repository) {
144
208
  return `The agent owner's GitHub account has ${decision.level ?? "no"} access to ${repository}, which is not enough.`;
145
209
  case "local_repo_not_allowed":
146
210
  return `local_repo_not_allowed: ${repository} is not a git repository inside the configured local roots (LOCAL_REPO_ROOTS).`;
211
+ case "github_account_not_allowed":
212
+ return `github_account_not_allowed: ${repository} belongs to a GitHub account this server does not serve (the App's owner and WARDBY_GITHUB_ALLOWED_ACCOUNTS).`;
147
213
  case "check_failed":
148
214
  return `Could not verify access to ${repository} right now; try again later.`;
149
215
  case "check_unavailable":
@@ -6,12 +6,18 @@
6
6
  * (startReviewFixAfterReview), once per run. What the agent does with the
7
7
  * review is up to its own instructions; this module only decides whether a
8
8
  * round may start. See docs/private/2026-10-03-review-fix-rounds-design.md.
9
+ *
10
+ * A round whose coding run ends with no change (the agent concluded the
11
+ * finding is wrong) gets one fresh review instead, which counts as a round
12
+ * (reReviewAfterNoChangeFix, from the coding run's terminal path): no push
13
+ * means no new review would otherwise replace the failed check.
9
14
  */
10
15
  import type { PrismaClient } from "#prisma";
11
16
  import type { Executor } from "../providers/executor/types.js";
12
17
  import type { IssueTrackerRegistry } from "../providers/issue-tracker/types.js";
13
18
  import type { ReviewHostProvider, ReviewHostRegistry } from "../providers/review-host/types.js";
14
19
  import { type DispatchDb } from "./dispatch.js";
20
+ import { type ReviewStartDeps } from "./host-events.js";
15
21
  import { type RepoAccessGate } from "./repo-access.js";
16
22
  export declare const DEFAULT_MAX_FIX_ROUNDS = 2;
17
23
  export type ReviewFixDb = DispatchDb & Pick<PrismaClient, "agentRepository" | "codingRun" | "runHostStatus" | "runHostCheck" | "agentIssueProject" | "issuePullRequest" | "workItem">;
@@ -40,6 +46,14 @@ export type ReviewFixResult = {
40
46
  reason: ReviewFixSkip;
41
47
  };
42
48
  export declare function capBody(maxRounds: number): string;
49
+ /**
50
+ * Whether a run's stored task is an automatic fix round's for this pull
51
+ * request: the continuation hint, then exactly the fix header, then the fix
52
+ * request. Every one of those sections is written by wardby, and a mention's
53
+ * header (the first section after the hint a person could influence) names
54
+ * its author instead, so a comment cannot pass for a fix round.
55
+ */
56
+ export declare function isReviewFixTask(taskOverride: string | null, repository: string, prNumber: number): boolean;
43
57
  /**
44
58
  * The fix round's task. The trusted part (what the runner puts in the system
45
59
  * prompt) is only what wardby itself wrote: the continuation hint, the header
@@ -58,3 +72,26 @@ export declare function reviewFixTaskText(input: {
58
72
  export declare function startReviewFixRound(req: ReviewFixRequest, deps: ReviewFixDeps): Promise<ReviewFixResult>;
59
73
  /** The finalizer's entry point: a fix round for the review this run published, if it requested changes. Never throws. */
60
74
  export declare function startReviewFixAfterReview(runId: string, deps: ReviewFixDeps): Promise<void>;
75
+ /** Most of a no-change fix run's summary (model output, already redacted by the protocol) put in the re-review's context. */
76
+ export declare const MAX_NO_CHANGE_SUMMARY_CHARS = 4000;
77
+ export type ReReviewDeps = ReviewStartDeps;
78
+ export type ReReviewSkip = "not_no_change" | "not_fix_round" | "no_host" | "no_request" | "not_current" | "opted_out" | "no_reviewer" | "not_authorized" | "claimed" | "capped" | "record_failed";
79
+ export type ReReviewResult = {
80
+ kind: "started";
81
+ runIds: string[];
82
+ round: number;
83
+ } | {
84
+ kind: "skipped";
85
+ reason: ReReviewSkip;
86
+ };
87
+ /** The re-review's extra context: a fixed, trusted pointer, and the fix run's summary as untrusted data. */
88
+ export declare function noChangeReviewContext(summary: string): {
89
+ task: string;
90
+ untrustedContext: string;
91
+ };
92
+ /**
93
+ * The coding-run terminal hook: a fix round's coding run that ended with no change starts one
94
+ * fresh review of the PR's unchanged head by the reviewer that requested changes, counted as a
95
+ * round. Does nothing for any other run. Never throws.
96
+ */
97
+ export declare function reReviewAfterNoChangeFix(runId: string, deps: ReReviewDeps): Promise<void>;