@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
@@ -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
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { mkdir, realpath, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { join, resolve, sep } from "node:path";
4
4
  import { withBaseCommit } from "../../coding/base-commit.js";
5
+ import { buildClaudeContext, MAX_RECORDED_SKIPS } from "../../coding/claude-context.js";
5
6
  import { normalizeCollectExclusions } from "../../coding/collect-exclude.js";
6
7
  import { codingProviderForModelProvider } from "../../coding/provider.js";
7
8
  import { CodingProfileSchema } from "../../coding/profile.js";
@@ -19,7 +20,7 @@ import { logger } from "../../core/logger.js";
19
20
  import { requiredLevel } from "../../core/repo-access.js";
20
21
  import { ensurePrivateDirectory } from "../../core/private-directory.js";
21
22
  import { codingRunObserver } from "../../coding/observability.js";
22
- import { CODING_PROTOCOL_VERSION, CodingRunResultSchema, CodingTaskInputSchema, parseCodingAgentOutputJson, redactAndTruncate, } from "../../coding/protocol.js";
23
+ import { CODING_PROTOCOL_VERSION, CodingRunResultSchema, CodingTaskInputSchema, MAX_CODING_INPUT_BYTES, parseCodingAgentOutputJson, redactAndTruncate, } from "../../coding/protocol.js";
23
24
  import { parseStoredEntry } from "../llm/catalog-types.js";
24
25
  import { resolveCodingEntry } from "../../core/run-pricing.js";
25
26
  import { CODING_PROXY_ALIAS, CODING_PROXY_PORT, isImmutableDockerImage } from "../jobs/docker-isolation.js";
@@ -28,6 +29,8 @@ import { ISSUE_KEY, ISSUE_TRACKER_NAMES } from "../issue-tracker/types.js";
28
29
  import { HEARTBEAT_TIMEOUT_MS } from "../../core/timing.js";
29
30
  import { collectRelatedPullRequests } from "../../core/related-pull-requests.js";
30
31
  const containerLog = logger.child({ module: "container-executor" });
32
+ /** A logged context skip path is cut to this many characters: a refused import is reported as written. */
33
+ const MAX_LOGGED_SKIP_PATH_CHARS = 256;
31
34
  /** The input path in a spec built only to ask the launcher about capacity; never written or read. */
32
35
  const CAPACITY_PROBE_INPUT = "/dev/null";
33
36
  const TERMINAL_STATUSES = new Set(["succeeded", "failed", "refused", "lost", "budget_exhausted", "cancelled"]);
@@ -109,6 +112,7 @@ export class PrismaContainerExecutionStore {
109
112
  rootCodingRunId: row.codingRun.rootCodingRunId,
110
113
  issueProvider: row.codingRun.issueProvider,
111
114
  issueKey: row.codingRun.issueKey,
115
+ mergeOrder: row.codingRun.mergeOrder,
112
116
  budgetUsd: Number(row.codingRun.budgetReservedUsd),
113
117
  agentBudgetUsd: Number(row.agent.budgetUsd),
114
118
  budgetGroupName: row.agent.budgetGroup?.name ?? null,
@@ -126,6 +130,8 @@ export class PrismaContainerExecutionStore {
126
130
  workspaceDiskMb: row.codingRun.workspaceDiskMb,
127
131
  debugTrace: row.codingRun.debugTrace,
128
132
  maxTurns: row.codingRun.maxTurns,
133
+ repoSkills: row.codingRun.repoSkills,
134
+ claudeBareMode: row.codingRun.claudeBareMode,
129
135
  services: row.codingRun.services,
130
136
  failureCategory: row.codingRun.failureCategory,
131
137
  profileRepository: row.agent.codingProfile?.repository ?? null,
@@ -141,6 +147,7 @@ export class PrismaContainerExecutionStore {
141
147
  repository: pr.repository,
142
148
  number: pr.number,
143
149
  ...(pr.state ? { state: pr.state } : {}),
150
+ ...(pr.mergeOrder !== undefined ? { mergeOrder: pr.mergeOrder } : {}),
144
151
  }));
145
152
  }
146
153
  async claimProvisioning(runId, claimId) {
@@ -545,7 +552,7 @@ export class ContainerExecutor {
545
552
  spendEnabled = true;
546
553
  sessionId = session.id;
547
554
  this.options.capabilities.set(runId, session.capability);
548
- const inputArtifact = await this.writeInput(run, deadlineAt, workspace.baseCommit);
555
+ const inputArtifact = await this.writeInput(run, deadlineAt, workspace);
549
556
  const beforeLaunch = await this.requireCurrent(runId);
550
557
  if (TERMINAL_STATUSES.has(beforeLaunch.status))
551
558
  throw new Error("coding_run_no_longer_active");
@@ -715,7 +722,14 @@ export class ContainerExecutor {
715
722
  const { issue } = this.issueFor(run);
716
723
  return {
717
724
  related: {
718
- entries: [...earlier, { repository: run.repository, self: true }],
725
+ entries: [
726
+ ...earlier,
727
+ {
728
+ repository: run.repository,
729
+ self: true,
730
+ ...(run.mergeOrder != null ? { mergeOrder: run.mergeOrder } : {}),
731
+ },
732
+ ],
719
733
  ...(issue ? { issue } : {}),
720
734
  },
721
735
  };
@@ -920,6 +934,19 @@ export class ContainerExecutor {
920
934
  }
921
935
  await rm(this.artifactPath(run.runId), { recursive: true, force: true }).catch(() => undefined);
922
936
  this.emit({ stage: "cleanup", runId: run.runId, jobId: handle.id, cleanupSucceeded: true });
937
+ await this.notifyTerminal(run.runId);
938
+ }
939
+ }
940
+ /** Runs the onCodingRunTerminal hook; nothing it does, throws, or rejects reaches the caller. */
941
+ async notifyTerminal(runId) {
942
+ const hook = this.options.onCodingRunTerminal;
943
+ if (!hook)
944
+ return;
945
+ try {
946
+ await hook(runId);
947
+ }
948
+ catch (err) {
949
+ containerLog.warn({ err, runId }, "coding run terminal hook failed");
923
950
  }
924
951
  }
925
952
  /** The package report is informational: any failure loading it (a
@@ -965,8 +992,10 @@ export class ContainerExecutor {
965
992
  }
966
993
  resolveCodingWorkerImage(selector) {
967
994
  if (selector.provider === "claude-code") {
995
+ // workerImageRef never replaces the Claude Code agent image (the container that holds the
996
+ // run's key); on a Claude Code agent it selects the tool runner (claudeToolImage).
968
997
  this.claudeToolImage(selector);
969
- const image = selector.workerImageRef ?? this.options.claudeWorkerImage;
998
+ const image = this.options.claudeWorkerImage;
970
999
  if (!image)
971
1000
  throw new Error("coding_provider_not_configured:claude-code");
972
1001
  if (!isImmutableDockerImage(image))
@@ -976,7 +1005,7 @@ export class ContainerExecutor {
976
1005
  if (selector.provider !== "codex") {
977
1006
  throw new Error(`coding_provider_unsupported:${String(selector.provider)}`);
978
1007
  }
979
- if (selector.workerImageRef) {
1008
+ if (selector.workerImageRef !== null) {
980
1009
  if (!isImmutableDockerImage(selector.workerImageRef))
981
1010
  throw new Error("coding_worker_image_invalid");
982
1011
  return selector.workerImageRef;
@@ -997,10 +1026,20 @@ export class ContainerExecutor {
997
1026
  resolveCodingToolImage(selector) {
998
1027
  return selector.provider === "claude-code" ? this.claudeToolImage(selector) : null;
999
1028
  }
1000
- /** The tool runner is what runs a Claude agent's commands, so it is what the toolchain selects. */
1029
+ /**
1030
+ * The tool runner is what runs a Claude agent's commands, so it is what the toolchain selects —
1031
+ * unless the agent has a BYO workerImageRef, which replaces the tool runner directly (never the
1032
+ * agent image; see resolveCodingWorkerImage).
1033
+ */
1001
1034
  claudeToolImage(selector) {
1002
1035
  if (!this.options.claudeToolRunnerImage)
1003
1036
  throw new Error("coding_provider_not_configured:claude-code");
1037
+ // An admin-set custom image (workerImageRef) is where this agent's commands run.
1038
+ if (selector.workerImageRef !== null) {
1039
+ if (!isImmutableDockerImage(selector.workerImageRef))
1040
+ throw new Error("coding_worker_image_invalid");
1041
+ return selector.workerImageRef;
1042
+ }
1004
1043
  const image = selector.toolchain === "node" && selector.toolchainVersion === null
1005
1044
  ? this.options.claudeToolRunnerImage
1006
1045
  : selector.toolchainVersion !== null
@@ -1038,6 +1077,10 @@ export class ContainerExecutor {
1038
1077
  supportsCodingServices(provider) {
1039
1078
  return this.options.jobs.supportsServicesFor?.(provider) === true;
1040
1079
  }
1080
+ /** Delegates to the job launcher's own warm-up (Executor.warmUp); a no-op for a launcher without one. */
1081
+ async warmUp() {
1082
+ await this.options.jobs.warmUp?.();
1083
+ }
1041
1084
  async requireCurrent(runId) {
1042
1085
  const current = await this.options.store.load(runId);
1043
1086
  if (!current)
@@ -1099,7 +1142,7 @@ export class ContainerExecutor {
1099
1142
  return this.options.anthropicCredentialRef;
1100
1143
  throw new Error("coding_provider_not_configured:claude-code");
1101
1144
  }
1102
- async writeInput(run, deadlineAt, baseCommit) {
1145
+ async writeInput(run, deadlineAt, workspace) {
1103
1146
  await ensurePrivateDirectory(this.artifactRoot);
1104
1147
  const rootReal = await realpath(this.artifactRoot);
1105
1148
  const directory = resolve(rootReal, run.runId);
@@ -1111,11 +1154,24 @@ export class ContainerExecutor {
1111
1154
  const destination = join(directory, "input.json");
1112
1155
  const temporary = join(directory, `.input-${randomUUID()}.tmp`);
1113
1156
  const services = parseStoredServices(run.services);
1114
- const task = withBaseCommit(run.task, baseCommit);
1115
- if (task === run.task && /^[0-9a-f]{40}$/.test(baseCommit)) {
1157
+ const task = withBaseCommit(run.task, workspace.baseCommit);
1158
+ if (task === run.task && /^[0-9a-f]{40}$/.test(workspace.baseCommit)) {
1116
1159
  containerLog.warn({ event: "coding.base_commit_omitted", runId: run.runId }, "the coding task left no room for the base commit line");
1117
1160
  }
1118
- const input = CodingTaskInputSchema.parse({
1161
+ // A repository context read must never fail a run ("the run never fails because of context"):
1162
+ // any fs error (an inaccessible workspace, EACCES, ...) is logged once and swallowed, leaving
1163
+ // claudeContext null, exactly as if the run had nothing to load.
1164
+ let claudeContext = null;
1165
+ if (run.provider === "claude-code") {
1166
+ try {
1167
+ claudeContext = await buildClaudeContext(workspace.workspacePath, { skills: run.repoSkills !== false });
1168
+ }
1169
+ catch (error) {
1170
+ const code = error?.code;
1171
+ containerLog.warn({ event: "coding.claude_context_unavailable", runId: run.runId, ...(code ? { code } : {}) }, "repository context could not be read; continuing without it");
1172
+ }
1173
+ }
1174
+ const build = (contextFiles) => CodingTaskInputSchema.parse({
1119
1175
  schemaVersion: CODING_PROTOCOL_VERSION,
1120
1176
  runId: run.runId,
1121
1177
  repository: run.repository,
@@ -1130,11 +1186,45 @@ export class ContainerExecutor {
1130
1186
  ...(run.debugTrace ? { debugTrace: true } : {}),
1131
1187
  // Only when the agent sets one: every other run's input stays exactly what older workers expect.
1132
1188
  ...(run.maxTurns ? { maxTurns: run.maxTurns } : {}),
1189
+ // Only when off: every other run's input stays exactly what older workers expect.
1190
+ ...(run.repoSkills === false ? { repoSkills: false } : {}),
1191
+ // Only when off: every other run's input stays exactly what older workers expect.
1192
+ ...(run.claudeBareMode === false ? { claudeBareMode: false } : {}),
1133
1193
  // Only when there are some: every other run's input stays exactly what older workers expect.
1134
1194
  ...(services.length > 0 ? { services: workerServices(services) } : {}),
1195
+ // Only when there is something to load: every other run's input stays exactly what older workers expect.
1196
+ ...(contextFiles.length > 0 ? { claudeContext: { files: contextFiles } } : {}),
1135
1197
  });
1198
+ // The content limits bound bytes, but JSON escaping can grow them up to sixfold (a control
1199
+ // character becomes \u00XX), so a hostile repository could still push input.json past
1200
+ // MAX_CODING_INPUT_BYTES and fail the launch. Drop context files from the tail (skills, then the
1201
+ // deepest imports; the root instructions go last) until the serialized input fits.
1202
+ const contextFiles = [...(claudeContext?.files ?? [])];
1203
+ const skipped = [...(claudeContext?.skipped ?? [])];
1204
+ let skippedOverflow = claudeContext?.skippedOverflow ?? 0;
1205
+ let serialized = JSON.stringify(build(contextFiles));
1206
+ while (contextFiles.length > 0 && Buffer.byteLength(serialized) > MAX_CODING_INPUT_BYTES) {
1207
+ const dropped = contextFiles.pop();
1208
+ if (skipped.length < MAX_RECORDED_SKIPS)
1209
+ skipped.push({ path: dropped.path, reason: "limit" });
1210
+ else
1211
+ skippedOverflow++;
1212
+ serialized = JSON.stringify(build(contextFiles));
1213
+ }
1214
+ for (const skip of skipped) {
1215
+ containerLog.warn({
1216
+ event: "coding.claude_context_skipped",
1217
+ runId: run.runId,
1218
+ // A refused import is logged as written, which a repository can make arbitrarily long.
1219
+ path: skip.path.slice(0, MAX_LOGGED_SKIP_PATH_CHARS),
1220
+ reason: skip.reason,
1221
+ }, "a repository context file was not loaded");
1222
+ }
1223
+ if (skippedOverflow > 0) {
1224
+ containerLog.warn({ event: "coding.claude_context_skipped", runId: run.runId, overflow: skippedOverflow }, "further repository context files were not loaded");
1225
+ }
1136
1226
  // The run directory is 0700; world-readable mode only crosses Docker's UID boundary.
1137
- await writeFile(temporary, JSON.stringify(input), { flag: "wx", mode: 0o444 });
1227
+ await writeFile(temporary, serialized, { flag: "wx", mode: 0o444 });
1138
1228
  await rename(temporary, destination);
1139
1229
  return destination;
1140
1230
  }
@@ -11,14 +11,56 @@
11
11
  * The heartbeat is kept while the workflow runs here so the reconciler's
12
12
  * stale-heartbeat detection is unchanged; the reconciler consults
13
13
  * `recover()` (Task 6) before declaring a DBOS run lost.
14
+ *
15
+ * A stalled-but-alive owner can overlap an adopted attempt of the same run:
16
+ * whichever records a step second loses ownership, stops at that step
17
+ * without writing the run, and hands the SDK's conflict back so DBOS parks
18
+ * it as a duplicate execution (see dbosStep and runInsideWorkflow).
14
19
  */
20
+ import pg from "pg";
15
21
  import type { PrismaClient } from "#prisma";
16
22
  import type { DbosConfig } from "../../config/providers.js";
23
+ import { type StepRunner } from "../engine/types.js";
17
24
  import { type NativeRunProviders, type RunnerDb } from "../../core/runner.js";
25
+ import { type DatabaseAuth, type PgAuthOptions } from "../../core/pg-auth.js";
18
26
  import type { Executor, ExecutionRecoveryResult, PersistedExecutionHandle } from "./types.js";
19
27
  export declare const DBOS_BACKEND = "dbos";
20
28
  type Providers = NativeRunProviders;
21
29
  type Db = RunnerDb & Pick<PrismaClient, "run">;
30
+ /**
31
+ * DBOS.setConfig input. Under password auth this is exactly what launch() always passed, and DBOS
32
+ * opens its own pool from the URL. Under rds-iam DBOS gets a pool whose password is the IAM token;
33
+ * DBOS then runs its migrations, queries and LISTEN through that pool and never opens a URL
34
+ * connection (system_database.js: a custom pool skips database creation and is what every
35
+ * connection borrows from). The pool copies what DBOS would have set on its own: size, connect
36
+ * timeout and application_name. DBOS never ends a pool it was given — see endSystemPool().
37
+ */
38
+ export declare function dbosLaunchConfig(config: DbosConfig, executorId: string, auth: DatabaseAuth, pgAuth?: PgAuthOptions): {
39
+ name: string;
40
+ systemDatabaseUrl: string;
41
+ systemDatabaseSchemaName: string;
42
+ executorID: string;
43
+ runAdminServer: false;
44
+ logLevel: "warn";
45
+ systemDatabasePool?: pg.Pool;
46
+ };
47
+ /**
48
+ * Bind the engine's step boundary to a DBOS checkpointed step. Never
49
+ * retried: a retry would re-spend.
50
+ *
51
+ * DBOS signals a cancelled workflow by throwing `DBOSWorkflowCancelledError`
52
+ * out of the next step boundary. Translated here into a `RunCancelledError`
53
+ * so executeRun's backstop records `cancelled` plus the operator's reason,
54
+ * rather than `failed` plus an SDK-internal message.
55
+ *
56
+ * DBOS signals that another execution of this workflow recorded the step
57
+ * first by throwing `DBOSWorkflowConflictError` after this attempt's step
58
+ * body already ran. Translated into a `RunOwnershipLostError` (carrying the
59
+ * discarded step's usage, if any, for the log) so executeRun's backstop stops
60
+ * this attempt without writing the run; runInsideWorkflow turns it back into
61
+ * the SDK error.
62
+ */
63
+ export declare const dbosStep: StepRunner;
22
64
  export declare class DbosExecutor implements Executor {
23
65
  private readonly providers;
24
66
  private readonly config;