@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
@@ -0,0 +1,39 @@
1
+ export class FakeChatProvider {
2
+ name = "slack";
3
+ posts = [];
4
+ updates = [];
5
+ channels = new Map();
6
+ queuedErrors = {
7
+ postMessage: [],
8
+ updateMessage: [],
9
+ channelInfo: [],
10
+ authTest: [],
11
+ };
12
+ nextTs = 1;
13
+ failNext(method, err) {
14
+ this.queuedErrors[method].push(err);
15
+ }
16
+ consumeFailure(method) {
17
+ const err = this.queuedErrors[method].shift();
18
+ if (err)
19
+ throw err;
20
+ }
21
+ async postMessage(channelId, msg, opts = {}) {
22
+ this.consumeFailure("postMessage");
23
+ const ts = `${this.nextTs++}.000`;
24
+ this.posts.push({ channelId, ts, msg, threadTs: opts.threadTs, broadcast: opts.broadcast });
25
+ return { ts };
26
+ }
27
+ async updateMessage(channelId, ts, msg) {
28
+ this.consumeFailure("updateMessage");
29
+ this.updates.push({ channelId, ts, msg });
30
+ }
31
+ async channelInfo(channel) {
32
+ this.consumeFailure("channelInfo");
33
+ return this.channels.get(channel) ?? null;
34
+ }
35
+ async authTest() {
36
+ this.consumeFailure("authTest");
37
+ return { team: "fake", botUserId: "UFAKE" };
38
+ }
39
+ }
@@ -0,0 +1,4 @@
1
+ import type { ChatProviderRegistry } from "./types.js";
2
+ export * from "./types.js";
3
+ /** One provider per configured chat service; empty when Slack is not configured. */
4
+ export declare function buildChatProviders(env?: NodeJS.ProcessEnv, fetchImpl?: typeof fetch): ChatProviderRegistry;
@@ -0,0 +1,8 @@
1
+ import { loadSlackConfig } from "../../config/providers.js";
2
+ import { SlackChatProvider } from "./slack.js";
3
+ export * from "./types.js";
4
+ /** One provider per configured chat service; empty when Slack is not configured. */
5
+ export function buildChatProviders(env = process.env, fetchImpl) {
6
+ const slack = loadSlackConfig(env);
7
+ return slack ? { slack: new SlackChatProvider(slack, fetchImpl) } : {};
8
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Slack Web API client for workflow notifications: chat.postMessage,
3
+ * chat.update, conversations.info, auth.test. Plain fetch (JSON bodies for
4
+ * writes, form-encoded for reads), bot token. Every failure becomes a ChatError with a normalized code the
5
+ * dispatcher acts on; Slack's own error string is kept for the operator.
6
+ */
7
+ import type { SlackConfig } from "../../config/providers.js";
8
+ import { type ChatMessage, type ChatProvider } from "./types.js";
9
+ export declare class SlackChatProvider implements ChatProvider {
10
+ private readonly config;
11
+ private readonly fetchImpl;
12
+ readonly name: "slack";
13
+ constructor(config: SlackConfig, fetchImpl?: typeof fetch);
14
+ /**
15
+ * `form` for read methods (conversations.info, auth.test): Slack accepts JSON
16
+ * bodies only on write methods and answers a read method's JSON body with
17
+ * invalid_arguments.
18
+ */
19
+ private call;
20
+ private messageBody;
21
+ postMessage(channelId: string, msg: ChatMessage, opts?: {
22
+ threadTs?: string;
23
+ broadcast?: boolean;
24
+ }): Promise<{
25
+ ts: string;
26
+ }>;
27
+ updateMessage(channelId: string, ts: string, msg: ChatMessage): Promise<void>;
28
+ channelInfo(channel: string): Promise<{
29
+ id: string;
30
+ name: string;
31
+ isPrivate: boolean;
32
+ } | null>;
33
+ authTest(): Promise<{
34
+ team: string;
35
+ botUserId: string;
36
+ }>;
37
+ }
@@ -0,0 +1,105 @@
1
+ import { ChatError } from "./types.js";
2
+ const CHANNEL_UNREACHABLE = new Set(["channel_not_found", "not_in_channel", "is_archived"]);
3
+ const AUTH_FAILED = new Set([
4
+ "invalid_auth",
5
+ "not_authed",
6
+ "token_revoked",
7
+ "token_expired",
8
+ "account_inactive",
9
+ "missing_scope",
10
+ ]);
11
+ const TIMEOUT_MS = 10_000;
12
+ function classify(slackError) {
13
+ if (CHANNEL_UNREACHABLE.has(slackError))
14
+ return "channel_unreachable";
15
+ if (AUTH_FAILED.has(slackError))
16
+ return "auth_failed";
17
+ if (slackError === "message_not_found")
18
+ return "message_not_found";
19
+ if (slackError === "ratelimited")
20
+ return "rate_limited";
21
+ return "transient";
22
+ }
23
+ export class SlackChatProvider {
24
+ config;
25
+ fetchImpl;
26
+ name = "slack";
27
+ constructor(config, fetchImpl = fetch) {
28
+ this.config = config;
29
+ this.fetchImpl = fetchImpl;
30
+ }
31
+ /**
32
+ * `form` for read methods (conversations.info, auth.test): Slack accepts JSON
33
+ * bodies only on write methods and answers a read method's JSON body with
34
+ * invalid_arguments.
35
+ */
36
+ async call(method, body, encoding = "json") {
37
+ let res;
38
+ try {
39
+ res = await this.fetchImpl(`${this.config.apiBaseUrl}/${method}`, {
40
+ method: "POST",
41
+ headers: {
42
+ authorization: `Bearer ${this.config.botToken}`,
43
+ "content-type": encoding === "json" ? "application/json; charset=utf-8" : "application/x-www-form-urlencoded",
44
+ },
45
+ body: encoding === "json"
46
+ ? JSON.stringify(body)
47
+ : new URLSearchParams(Object.fromEntries(Object.entries(body).map(([k, v]) => [k, String(v)]))).toString(),
48
+ signal: AbortSignal.timeout(TIMEOUT_MS),
49
+ });
50
+ }
51
+ catch (err) {
52
+ throw new ChatError("transient", err instanceof Error ? err.message : String(err));
53
+ }
54
+ if (res.status === 429) {
55
+ const seconds = Number(res.headers.get("retry-after") ?? "1");
56
+ throw new ChatError("rate_limited", "ratelimited", (Number.isFinite(seconds) && seconds > 0 ? seconds : 1) * 1000);
57
+ }
58
+ if (!res.ok)
59
+ throw new ChatError("transient", `http_${res.status}`);
60
+ const json = (await res.json().catch(() => ({ ok: false, error: "invalid_json" })));
61
+ if (json.ok !== true) {
62
+ const slackError = typeof json.error === "string" ? json.error : "unknown_error";
63
+ throw new ChatError(classify(slackError), slackError);
64
+ }
65
+ return json;
66
+ }
67
+ messageBody(msg) {
68
+ return {
69
+ text: msg.text,
70
+ ...(msg.blocks ? { blocks: msg.blocks } : {}),
71
+ ...(this.config.customize && msg.username ? { username: msg.username } : {}),
72
+ ...(this.config.customize && msg.iconEmoji ? { icon_emoji: msg.iconEmoji } : {}),
73
+ };
74
+ }
75
+ async postMessage(channelId, msg, opts = {}) {
76
+ const json = await this.call("chat.postMessage", {
77
+ channel: channelId,
78
+ ...this.messageBody(msg),
79
+ ...(opts.threadTs ? { thread_ts: opts.threadTs } : {}),
80
+ ...(opts.threadTs && opts.broadcast ? { reply_broadcast: true } : {}),
81
+ unfurl_links: false,
82
+ unfurl_media: false,
83
+ });
84
+ return { ts: String(json.ts) };
85
+ }
86
+ async updateMessage(channelId, ts, msg) {
87
+ await this.call("chat.update", { channel: channelId, ts, ...this.messageBody(msg) });
88
+ }
89
+ async channelInfo(channel) {
90
+ try {
91
+ const json = await this.call("conversations.info", { channel }, "form");
92
+ const c = json.channel;
93
+ return { id: c.id, name: c.name, isPrivate: c.is_private === true };
94
+ }
95
+ catch (err) {
96
+ if (err instanceof ChatError && err.code === "channel_unreachable")
97
+ return null;
98
+ throw err;
99
+ }
100
+ }
101
+ async authTest() {
102
+ const json = await this.call("auth.test", {}, "form");
103
+ return { team: String(json.team), botUserId: String(json.user_id) };
104
+ }
105
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Host-neutral chat surface for outbound workflow notifications. Slack is
3
+ * the first (and only) implementation (./slack.ts). wardby only ever posts
4
+ * or updates messages here — it never reads channel history or listens for
5
+ * events.
6
+ */
7
+ export declare const CHAT_PROVIDERS: readonly ["slack"];
8
+ export type ChatProviderName = (typeof CHAT_PROVIDERS)[number];
9
+ export type ChatErrorCode = "rate_limited" | "channel_unreachable" | "auth_failed" | "message_not_found" | "transient";
10
+ export declare class ChatError extends Error {
11
+ readonly code: ChatErrorCode;
12
+ readonly slackError: string;
13
+ readonly retryAfterMs?: number | undefined;
14
+ constructor(code: ChatErrorCode, slackError: string, retryAfterMs?: number | undefined);
15
+ }
16
+ export interface ChatMessage {
17
+ text: string;
18
+ blocks?: unknown[];
19
+ username?: string;
20
+ iconEmoji?: string;
21
+ }
22
+ export interface ChatProvider {
23
+ readonly name: ChatProviderName;
24
+ postMessage(channelId: string, msg: ChatMessage, opts?: {
25
+ threadTs?: string;
26
+ broadcast?: boolean;
27
+ }): Promise<{
28
+ ts: string;
29
+ }>;
30
+ updateMessage(channelId: string, ts: string, msg: ChatMessage): Promise<void>;
31
+ /** null when the bot cannot see the channel; throws ChatError("auth_failed") on missing scope. */
32
+ channelInfo(channel: string): Promise<{
33
+ id: string;
34
+ name: string;
35
+ isPrivate: boolean;
36
+ } | null>;
37
+ authTest(): Promise<{
38
+ team: string;
39
+ botUserId: string;
40
+ }>;
41
+ }
42
+ export type ChatProviderRegistry = Partial<Record<ChatProviderName, ChatProvider>>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Host-neutral chat surface for outbound workflow notifications. Slack is
3
+ * the first (and only) implementation (./slack.ts). wardby only ever posts
4
+ * or updates messages here — it never reads channel history or listens for
5
+ * events.
6
+ */
7
+ export const CHAT_PROVIDERS = ["slack"];
8
+ export class ChatError extends Error {
9
+ code;
10
+ slackError;
11
+ retryAfterMs;
12
+ constructor(code, slackError, retryAfterMs) {
13
+ super(`chat_error:${code}:${slackError}`);
14
+ this.code = code;
15
+ this.slackError = slackError;
16
+ this.retryAfterMs = retryAfterMs;
17
+ this.name = "ChatError";
18
+ }
19
+ }
@@ -48,6 +48,25 @@ export interface LoadedTool {
48
48
  * only on earlier step results and on `agent` fields fixed at run start.
49
49
  */
50
50
  export type StepRunner = <T>(name: string, fn: () => Promise<T>) => Promise<T>;
51
+ /**
52
+ * Part of the StepRunner contract: a step runner may throw this when another
53
+ * execution of the same run recorded the step first, so this attempt no
54
+ * longer owns the run. The attempt must stop without writing the run (the
55
+ * winner does that); engines and the runner rethrow it untouched.
56
+ */
57
+ export declare class RunOwnershipLostError extends Error {
58
+ readonly step: string;
59
+ /**
60
+ * Usage the losing step's body reported before its result was discarded
61
+ * (an LLM turn's token counts and cost), when the step runner saw it. Not
62
+ * recorded on any run: the winner's result replaces it. Logged only.
63
+ */
64
+ readonly discardedUsage?: Readonly<Record<string, number>>;
65
+ constructor(step: string, options?: {
66
+ cause?: unknown;
67
+ discardedUsage?: Readonly<Record<string, number>>;
68
+ });
69
+ }
51
70
  /** The no-checkpoint default: run the step body directly. */
52
71
  export declare const runStepInline: StepRunner;
53
72
  /**
@@ -12,5 +12,27 @@
12
12
  * which engine is driving: an engine that calls a provider SDK directly
13
13
  * blinds the pre-flight refuse and mid-stream cutoff, and is not allowed.
14
14
  */
15
+ /**
16
+ * Part of the StepRunner contract: a step runner may throw this when another
17
+ * execution of the same run recorded the step first, so this attempt no
18
+ * longer owns the run. The attempt must stop without writing the run (the
19
+ * winner does that); engines and the runner rethrow it untouched.
20
+ */
21
+ export class RunOwnershipLostError extends Error {
22
+ step;
23
+ /**
24
+ * Usage the losing step's body reported before its result was discarded
25
+ * (an LLM turn's token counts and cost), when the step runner saw it. Not
26
+ * recorded on any run: the winner's result replaces it. Logged only.
27
+ */
28
+ discardedUsage;
29
+ constructor(step, options) {
30
+ super(`run_ownership_lost: another execution recorded step "${step}" first; this attempt stops.`, options?.cause === undefined ? undefined : { cause: options.cause });
31
+ this.name = "RunOwnershipLostError";
32
+ this.step = step;
33
+ if (options?.discardedUsage)
34
+ this.discardedUsage = options.discardedUsage;
35
+ }
36
+ }
15
37
  /** The no-checkpoint default: run the step body directly. */
16
38
  export const runStepInline = (_name, fn) => fn();
@@ -1,10 +1,25 @@
1
1
  import type { PrismaClient } from "#prisma";
2
2
  import { type ProviderConfig } from "../../config/providers.js";
3
+ import { type Power } from "../../core/power.js";
4
+ import { type ReReviewDeps } from "../../core/review-fix.js";
3
5
  import type { KubernetesApi } from "../jobs/kubernetes-api.js";
4
6
  import type { Executor } from "./types.js";
5
7
  import { type RepoAccessGate } from "../../core/repo-access.js";
8
+ /**
9
+ * The coding-run terminal hook: a review-fix round's coding run that made no change re-reviews
10
+ * the PR once (core/review-fix.ts). Started in the background so the executor's terminal path
11
+ * (and the slot release after it) never waits on the host; idempotent, and never throws.
12
+ * `deps` is read only when a run finishes, after composition returned.
13
+ */
14
+ export declare function reReviewOnCodingRunTerminal(deps: () => ReReviewDeps): (runId: string) => void;
6
15
  export interface ConfiguredExecutorOptions {
7
16
  native: Executor;
17
+ /**
18
+ * Runs native agents whose run snapshot says `sandbox`. Composed whether or
19
+ * not a coding job launcher is configured. Absent: sandbox runs go to
20
+ * `native`, whose runner refuses them (RoutingExecutor).
21
+ */
22
+ nativeSandbox?: Executor;
8
23
  db: PrismaClient;
9
24
  env?: NodeJS.ProcessEnv;
10
25
  providerConfig?: ProviderConfig;
@@ -12,6 +27,14 @@ export interface ConfiguredExecutorOptions {
12
27
  kubernetesApi?: KubernetesApi;
13
28
  /** Repository authorization for coding runs; built from the configured review hosts when absent. */
14
29
  repoAccess?: RepoAccessGate;
30
+ /**
31
+ * Low-power mode, built once by the composition root and shared. Used only by the Kubernetes
32
+ * launcher (wakes the coding proxy before a run); absent: `DISABLED_POWER`.
33
+ */
34
+ power?: Power;
15
35
  }
16
- /** Builds container execution only when Docker or Kubernetes is explicitly selected. */
36
+ /**
37
+ * Builds container execution only when Docker or Kubernetes is explicitly
38
+ * selected, and native sandbox routing whenever a sandbox executor is given.
39
+ */
17
40
  export declare function buildConfiguredExecutor(options: ConfiguredExecutorOptions): Executor;
@@ -5,6 +5,8 @@ import { summarizeRegistryFetches } from "../../coding/registry/report.js";
5
5
  import { drainCodingQueue } from "../../core/coding-queue.js";
6
6
  import { prismaServiceStateReporter } from "../../core/coding-service-status.js";
7
7
  import { logger } from "../../core/logger.js";
8
+ import { DISABLED_POWER } from "../../core/power.js";
9
+ import { reReviewAfterNoChangeFix } from "../../core/review-fix.js";
8
10
  import { EnvironmentCredentialResolver } from "../coding-proxy/environment-credentials.js";
9
11
  import { CodingProxy } from "../coding-proxy/proxy.js";
10
12
  import { PrismaProxyLedger } from "../coding-proxy/prisma-ledger.js";
@@ -22,12 +24,33 @@ import { createRepoAccessGate } from "../../core/repo-access.js";
22
24
  import { buildIssueTrackers } from "../issue-tracker/index.js";
23
25
  import { buildReviewHosts } from "../review-host/index.js";
24
26
  const compositionLog = logger.child({ module: "executor-composition" });
25
- /** Builds container execution only when Docker or Kubernetes is explicitly selected. */
27
+ /**
28
+ * The coding-run terminal hook: a review-fix round's coding run that made no change re-reviews
29
+ * the PR once (core/review-fix.ts). Started in the background so the executor's terminal path
30
+ * (and the slot release after it) never waits on the host; idempotent, and never throws.
31
+ * `deps` is read only when a run finishes, after composition returned.
32
+ */
33
+ export function reReviewOnCodingRunTerminal(deps) {
34
+ return (runId) => {
35
+ void Promise.resolve()
36
+ .then(() => reReviewAfterNoChangeFix(runId, deps()))
37
+ .catch((err) => compositionLog.warn({ err, runId }, "no-change re-review hook failed"));
38
+ };
39
+ }
40
+ /**
41
+ * Builds container execution only when Docker or Kubernetes is explicitly
42
+ * selected, and native sandbox routing whenever a sandbox executor is given.
43
+ */
26
44
  export function buildConfiguredExecutor(options) {
27
45
  const env = options.env ?? process.env;
28
46
  const providerConfig = options.providerConfig ?? loadProviderConfig(env);
29
- if (providerConfig.jobs !== "docker" && providerConfig.jobs !== "kubernetes")
30
- return options.native;
47
+ if (providerConfig.jobs !== "docker" && providerConfig.jobs !== "kubernetes") {
48
+ if (!options.nativeSandbox)
49
+ return options.native;
50
+ // No coding launcher: coding runs reach the native executor, whose runner fails them with
51
+ // the "needs a container executor" explanation, exactly as without this wrapper.
52
+ return new RoutingExecutor(new PrismaExecutionKindResolver(options.db), options.native, options.native, options.nativeSandbox);
53
+ }
31
54
  const github = loadGitHubVcsConfig(env);
32
55
  const config = loadContainerExecutorConfig(env);
33
56
  // Each provider's images are optional, but a coding launcher with neither can run nothing.
@@ -80,6 +103,7 @@ export function buildConfiguredExecutor(options) {
80
103
  resolveCapability: (runId) => capabilities.get(runId),
81
104
  readyTimeoutMs: kubernetes.readyTimeoutMs,
82
105
  enforcementExecTimeoutMs: kubernetes.enforcementExecTimeoutMs,
106
+ power: options.power ?? DISABLED_POWER,
83
107
  preflight: async () => {
84
108
  const { proxyIp } = await runKubernetesPreflight({
85
109
  api,
@@ -112,7 +136,9 @@ export function buildConfiguredExecutor(options) {
112
136
  }
113
137
  const issueTrackers = buildIssueTrackers(env);
114
138
  const concurrency = loadCodingConcurrencyConfig(env);
115
- // The release hook needs the composed RoutingExecutor, which only exists
139
+ const reviewHosts = buildReviewHosts(env, options.db);
140
+ const repoAccess = options.repoAccess ?? createRepoAccessGate({ db: options.db, hosts: reviewHosts });
141
+ // The release and terminal hooks need the composed RoutingExecutor, which only exists
116
142
  // after the ContainerExecutor it wraps is built. The closure reads
117
143
  // `composed` only when a run finishes, which is after this function returns.
118
144
  const coding = new ContainerExecutor({
@@ -131,12 +157,19 @@ export function buildConfiguredExecutor(options) {
131
157
  anthropicCredentialRef: config.anthropicCredentialRef,
132
158
  limits: { cpus: config.cpus, memoryMb: config.memoryMb, pids: config.pids, diskMb: config.diskMb },
133
159
  maxDiskMb: config.maxDiskMb,
134
- repoAccess: options.repoAccess ?? createRepoAccessGate({ db: options.db, hosts: buildReviewHosts(env, options.db) }),
160
+ repoAccess,
135
161
  issueUrl: (provider, key) => (provider === "jira" ? issueTrackers.jira?.issueUrl(key) : undefined),
136
162
  registryReport: async (runId) => {
137
163
  const rows = await options.db.registryFetch.findMany({ where: { runId }, orderBy: { createdAt: "asc" } });
138
164
  return summarizeRegistryFetches(rows);
139
165
  },
166
+ onCodingRunTerminal: reReviewOnCodingRunTerminal(() => ({
167
+ db: options.db,
168
+ executor: composed,
169
+ hosts: reviewHosts,
170
+ repoAccess,
171
+ issueTrackers,
172
+ })),
140
173
  onSlotReleased: () => {
141
174
  void drainCodingQueue({
142
175
  db: options.db,
@@ -150,6 +183,6 @@ export function buildConfiguredExecutor(options) {
150
183
  });
151
184
  },
152
185
  });
153
- const composed = new RoutingExecutor(new PrismaExecutionKindResolver(options.db), options.native, coding);
186
+ const composed = new RoutingExecutor(new PrismaExecutionKindResolver(options.db), options.native, coding, options.nativeSandbox);
154
187
  return composed;
155
188
  }
@@ -44,6 +44,8 @@ export interface ContainerRunSnapshot {
44
44
  /** The issue that triggered this run (CodingRun.issueProvider/issueKey); null when none. */
45
45
  issueProvider?: string | null;
46
46
  issueKey?: string | null;
47
+ /** Step in the delegating agent's declared merge order (CodingRun.mergeOrder); null = no order. */
48
+ mergeOrder?: number | null;
47
49
  budgetUsd: number;
48
50
  /** The agent's own per-run budget; `budgetUsd` is less when its budget group had less left. */
49
51
  agentBudgetUsd?: number;
@@ -63,6 +65,10 @@ export interface ContainerRunSnapshot {
63
65
  debugTrace?: boolean;
64
66
  /** Claude Code turn limit, fixed at dispatch (CodingRun.maxTurns); null = the worker default. */
65
67
  maxTurns?: number | null;
68
+ /** Load the repo's agent skills, fixed at dispatch (CodingRun.repoSkills); absent on older snapshots = true. */
69
+ repoSkills?: boolean;
70
+ /** Claude Code loading mode, fixed at dispatch (CodingRun.claudeBareMode); absent on older snapshots = true. */
71
+ claudeBareMode?: boolean;
66
72
  /** Coding-run services resolved at dispatch (CodingRun.services); parsed with parseStoredServices. */
67
73
  services?: unknown;
68
74
  /** The terminal failure category, once the run has one (CodingRun.failureCategory). */
@@ -195,6 +201,15 @@ export interface ContainerExecutorOptions {
195
201
  * than on the next scheduler tick. Never called for a run that was queued.
196
202
  */
197
203
  onSlotReleased?: () => void;
204
+ /**
205
+ * Called with the run id at the end of each terminal finish of a collected
206
+ * job (succeeded, no change, budget, or failed), after the terminal write
207
+ * and cleanup. It may run more than once for one run (a replayed or
208
+ * duplicate finish), so it must be idempotent; a rejection or throw is
209
+ * logged and never reaches the terminal path. composition.ts wires the
210
+ * review-fix re-review here, so this executor imports no review logic.
211
+ */
212
+ onCodingRunTerminal?: (runId: string) => Promise<void> | void;
198
213
  /**
199
214
  * Loads this run's RegistryFetch ledger (composition.ts wires the Prisma
200
215
  * query) so finalizeChanges can surface installed/refused packages in the
@@ -278,6 +293,8 @@ export declare class ContainerExecutor implements Executor {
278
293
  private modelTerms;
279
294
  private preflight;
280
295
  private finishTerminal;
296
+ /** Runs the onCodingRunTerminal hook; nothing it does, throws, or rejects reaches the caller. */
297
+ private notifyTerminal;
281
298
  /** The package report is informational: any failure loading it (a
282
299
  * rejection, a synchronous throw, or a malformed result) yields no
283
300
  * package section rather than failing finalization. */
@@ -286,7 +303,11 @@ export declare class ContainerExecutor implements Executor {
286
303
  resolveCodingWorkerImage(selector: CodingImageSelector): string;
287
304
  /** Claude's tool-runner image for the agent's toolchain, at dispatch (Executor.resolveCodingToolImage); null for Codex. */
288
305
  resolveCodingToolImage(selector: CodingImageSelector): string | null;
289
- /** The tool runner is what runs a Claude agent's commands, so it is what the toolchain selects. */
306
+ /**
307
+ * The tool runner is what runs a Claude agent's commands, so it is what the toolchain selects —
308
+ * unless the agent has a BYO workerImageRef, which replaces the tool runner directly (never the
309
+ * agent image; see resolveCodingWorkerImage).
310
+ */
290
311
  private claudeToolImage;
291
312
  /** Coding-run services: the repository's declaration at its base ref (Executor.readCodingServiceDeclaration). */
292
313
  readCodingServiceDeclaration(input: {
@@ -302,6 +323,8 @@ export declare class ContainerExecutor implements Executor {
302
323
  }): Promise<string | null>;
303
324
  /** The job launcher decides (Kubernetes and Docker start services for both providers). */
304
325
  supportsCodingServices(provider: CodingProvider): boolean;
326
+ /** Delegates to the job launcher's own warm-up (Executor.warmUp); a no-op for a launcher without one. */
327
+ warmUp(): Promise<void>;
305
328
  private requireCurrent;
306
329
  /**
307
330
  * False when the launcher reports this run's job would not fit the cluster right now; the run