@wardby/cli 0.5.3 → 0.7.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 (763) hide show
  1. package/.env.example +33 -0
  2. package/README.md +25 -14
  3. package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
  4. package/dist/claude-coding-worker/context.d.ts +22 -0
  5. package/dist/claude-coding-worker/context.js +92 -0
  6. package/dist/claude-coding-worker/driver.d.ts +27 -3
  7. package/dist/claude-coding-worker/driver.js +161 -20
  8. package/dist/claude-coding-worker/main.js +34 -6
  9. package/dist/claude-coding-worker/sdk.js +25 -5
  10. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  11. package/dist/claude-coding-worker/tool-socket.js +111 -0
  12. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  13. package/dist/claude-coding-worker/transcript.js +77 -0
  14. package/dist/cli-help.d.ts +1 -1
  15. package/dist/cli-help.js +6 -2
  16. package/dist/cli-native-mode.d.ts +9 -0
  17. package/dist/cli-native-mode.js +20 -0
  18. package/dist/cli.d.ts +3 -1
  19. package/dist/cli.js +161 -11
  20. package/dist/coding/claude-context.d.ts +45 -0
  21. package/dist/coding/claude-context.js +434 -0
  22. package/dist/coding/continuation-wording.d.ts +35 -0
  23. package/dist/coding/continuation-wording.js +73 -0
  24. package/dist/coding/linked-issue-note.d.ts +23 -0
  25. package/dist/coding/linked-issue-note.js +47 -0
  26. package/dist/coding/merge-wording.d.ts +28 -0
  27. package/dist/coding/merge-wording.js +78 -0
  28. package/dist/coding/pr-description-note.d.ts +9 -0
  29. package/dist/coding/pr-description-note.js +32 -0
  30. package/dist/coding/profile.d.ts +50 -118
  31. package/dist/coding/profile.js +51 -4
  32. package/dist/coding/protected-path-wording.d.ts +8 -0
  33. package/dist/coding/protected-path-wording.js +1 -1
  34. package/dist/coding/protocol.d.ts +292 -270
  35. package/dist/coding/protocol.js +322 -15
  36. package/dist/coding/redact.d.ts +3 -0
  37. package/dist/coding/redact.js +12 -0
  38. package/dist/coding/registry/allowlist.d.ts +12 -0
  39. package/dist/coding/registry/allowlist.js +14 -1
  40. package/dist/coding/registry/audit-mode.d.ts +153 -0
  41. package/dist/coding/registry/audit-mode.js +304 -0
  42. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  43. package/dist/coding/registry/lockfile-shared.js +128 -0
  44. package/dist/coding/registry/lockfiles.js +1 -1
  45. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  46. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  47. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  48. package/dist/coding/registry/npm-lockfile.js +4 -6
  49. package/dist/coding/registry/npm.js +78 -8
  50. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  51. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  52. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  53. package/dist/coding/registry/pypi-plan.js +406 -0
  54. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  55. package/dist/coding/registry/pypi-requirements.js +155 -0
  56. package/dist/coding/registry/pypi.d.ts +3 -27
  57. package/dist/coding/registry/pypi.js +40 -154
  58. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  59. package/dist/coding/registry/refusal-hints.js +61 -0
  60. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  61. package/dist/coding/registry/refusal-wording.js +56 -0
  62. package/dist/coding/registry/report.d.ts +70 -8
  63. package/dist/coding/registry/report.js +112 -5
  64. package/dist/coding/registry/types.d.ts +58 -8
  65. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  66. package/dist/coding/registry/yarn-lockfile.js +367 -0
  67. package/dist/coding/services/catalog.d.ts +37 -351
  68. package/dist/coding/transcript/claude-code.d.ts +13 -0
  69. package/dist/coding/transcript/claude-code.js +273 -0
  70. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  71. package/dist/coding/transcript/download-protocol.js +18 -0
  72. package/dist/coding/transcript/format.d.ts +20 -0
  73. package/dist/coding/transcript/format.js +32 -0
  74. package/dist/coding/transcript/recorder.d.ts +51 -0
  75. package/dist/coding/transcript/recorder.js +225 -0
  76. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  77. package/dist/coding/transcript/resume/checkout.js +203 -0
  78. package/dist/coding/transcript/resume/command.d.ts +17 -0
  79. package/dist/coding/transcript/resume/command.js +176 -0
  80. package/dist/coding/transcript/resume/download.d.ts +20 -0
  81. package/dist/coding/transcript/resume/download.js +153 -0
  82. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  83. package/dist/coding/transcript/resume/launch.js +128 -0
  84. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  85. package/dist/coding/transcript/resume/session-file.js +79 -0
  86. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  87. package/dist/coding/transcript/resume/stand-in.js +49 -0
  88. package/dist/coding-worker/artifact.d.ts +16 -3
  89. package/dist/coding-worker/artifact.js +5 -3
  90. package/dist/coding-worker/debug-trace.d.ts +6 -5
  91. package/dist/coding-worker/debug-trace.js +13 -18
  92. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  93. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  94. package/dist/coding-worker/driver.d.ts +4 -3
  95. package/dist/coding-worker/driver.js +118 -38
  96. package/dist/coding-worker/errors.d.ts +1 -0
  97. package/dist/coding-worker/errors.js +32 -0
  98. package/dist/coding-worker/sdk.d.ts +6 -0
  99. package/dist/coding-worker/sdk.js +1 -0
  100. package/dist/coding-worker/skills.d.ts +23 -0
  101. package/dist/coding-worker/skills.js +117 -0
  102. package/dist/coding-worker/task-note.d.ts +11 -0
  103. package/dist/coding-worker/task-note.js +13 -0
  104. package/dist/coding-worker/types.d.ts +13 -0
  105. package/dist/config/dependency-cache.d.ts +23 -0
  106. package/dist/config/dependency-cache.js +32 -0
  107. package/dist/config/github-allowed-accounts.d.ts +15 -0
  108. package/dist/config/github-allowed-accounts.js +36 -0
  109. package/dist/config/low-power.d.ts +12 -0
  110. package/dist/config/low-power.js +18 -0
  111. package/dist/config/mobile.d.ts +12 -0
  112. package/dist/config/mobile.js +18 -0
  113. package/dist/config/providers.d.ts +65 -3
  114. package/dist/config/providers.js +147 -11
  115. package/dist/config/test-simulators.d.ts +82 -0
  116. package/dist/config/test-simulators.js +305 -0
  117. package/dist/core/async-context.d.ts +2 -0
  118. package/dist/core/async-context.js +12 -0
  119. package/dist/core/budget-events.d.ts +108 -0
  120. package/dist/core/budget-events.js +346 -0
  121. package/dist/core/budget-groups.d.ts +50 -1
  122. package/dist/core/budget-groups.js +236 -27
  123. package/dist/core/budget-stopped-head.d.ts +46 -0
  124. package/dist/core/budget-stopped-head.js +81 -0
  125. package/dist/core/budget-topup.d.ts +51 -0
  126. package/dist/core/budget-topup.js +156 -0
  127. package/dist/core/budget-wording.d.ts +16 -2
  128. package/dist/core/budget-wording.js +40 -2
  129. package/dist/core/coding-queue.d.ts +2 -1
  130. package/dist/core/coding-queue.js +7 -0
  131. package/dist/core/cron.d.ts +19 -1
  132. package/dist/core/cron.js +17 -0
  133. package/dist/core/datastores.js +1 -1
  134. package/dist/core/db.d.ts +16 -6
  135. package/dist/core/db.js +12 -10
  136. package/dist/core/deferred-coding.d.ts +14 -0
  137. package/dist/core/deferred-coding.js +62 -0
  138. package/dist/core/delegation-child.d.ts +25 -0
  139. package/dist/core/delegation-child.js +37 -0
  140. package/dist/core/dispatch.d.ts +53 -0
  141. package/dist/core/dispatch.js +167 -57
  142. package/dist/core/engine-native.js +10 -6
  143. package/dist/core/error-code.d.ts +38 -0
  144. package/dist/core/error-code.js +168 -0
  145. package/dist/core/grants.d.ts +19 -6
  146. package/dist/core/grants.js +55 -6
  147. package/dist/core/host-events.d.ts +67 -5
  148. package/dist/core/host-events.js +571 -37
  149. package/dist/core/host-status.d.ts +85 -3
  150. package/dist/core/host-status.js +298 -20
  151. package/dist/core/issue-bridge.d.ts +50 -6
  152. package/dist/core/issue-bridge.js +151 -20
  153. package/dist/core/issue-events.d.ts +1 -1
  154. package/dist/core/issue-events.js +16 -11
  155. package/dist/core/issue-status.d.ts +1 -1
  156. package/dist/core/issue-status.js +68 -29
  157. package/dist/core/logger.d.ts +5 -0
  158. package/dist/core/logger.js +14 -1
  159. package/dist/core/lost-run-children.d.ts +6 -0
  160. package/dist/core/lost-run-children.js +32 -0
  161. package/dist/core/mark-ready.d.ts +34 -0
  162. package/dist/core/mark-ready.js +152 -0
  163. package/dist/core/markdown-code.d.ts +8 -0
  164. package/dist/core/markdown-code.js +107 -0
  165. package/dist/core/memory-tools.js +7 -0
  166. package/dist/core/merge-order-check.d.ts +130 -0
  167. package/dist/core/merge-order-check.js +343 -0
  168. package/dist/core/notification-dispatcher.d.ts +70 -0
  169. package/dist/core/notification-dispatcher.js +368 -0
  170. package/dist/core/notification-templates.d.ts +19 -0
  171. package/dist/core/notification-templates.js +139 -0
  172. package/dist/core/notifications.d.ts +10 -0
  173. package/dist/core/notifications.js +38 -0
  174. package/dist/core/pg-auth.d.ts +22 -0
  175. package/dist/core/pg-auth.js +152 -0
  176. package/dist/core/power-composition.d.ts +16 -0
  177. package/dist/core/power-composition.js +37 -0
  178. package/dist/core/power-idle.d.ts +14 -0
  179. package/dist/core/power-idle.js +30 -0
  180. package/dist/core/power.d.ts +71 -0
  181. package/dist/core/power.js +202 -0
  182. package/dist/core/pull-request-state-sync.js +2 -2
  183. package/dist/core/reconciler.d.ts +8 -5
  184. package/dist/core/reconciler.js +37 -6
  185. package/dist/core/related-pull-requests.d.ts +59 -7
  186. package/dist/core/related-pull-requests.js +140 -25
  187. package/dist/core/reply-parts.d.ts +21 -0
  188. package/dist/core/reply-parts.js +73 -0
  189. package/dist/core/repo-access.d.ts +15 -0
  190. package/dist/core/repo-access.js +66 -0
  191. package/dist/core/review-fix.d.ts +38 -1
  192. package/dist/core/review-fix.js +209 -7
  193. package/dist/core/review-host-checks.d.ts +1 -1
  194. package/dist/core/review-host-tools.d.ts +23 -0
  195. package/dist/core/review-host-tools.js +156 -14
  196. package/dist/core/review-reads.d.ts +55 -0
  197. package/dist/core/review-reads.js +233 -0
  198. package/dist/core/run-status.d.ts +12 -0
  199. package/dist/core/run-status.js +12 -0
  200. package/dist/core/runner.d.ts +384 -5
  201. package/dist/core/runner.js +1244 -372
  202. package/dist/core/schedule-start.d.ts +12 -0
  203. package/dist/core/schedule-start.js +14 -0
  204. package/dist/core/secret-broker-config.d.ts +39 -0
  205. package/dist/core/secret-broker-config.js +112 -0
  206. package/dist/core/secret-guard.d.ts +46 -0
  207. package/dist/core/secret-guard.js +104 -0
  208. package/dist/core/secret-guarded-stores.d.ts +12 -0
  209. package/dist/core/secret-guarded-stores.js +41 -0
  210. package/dist/core/secret-spans.d.ts +50 -0
  211. package/dist/core/secret-spans.js +94 -0
  212. package/dist/core/secrets.d.ts +39 -4
  213. package/dist/core/secrets.js +148 -40
  214. package/dist/core/stop-run.d.ts +46 -0
  215. package/dist/core/stop-run.js +61 -0
  216. package/dist/core/workflow-event-recorder.d.ts +14 -0
  217. package/dist/core/workflow-event-recorder.js +120 -0
  218. package/dist/core/workflow-events.d.ts +94 -0
  219. package/dist/core/workflow-events.js +48 -0
  220. package/dist/core/workflow-run-events.d.ts +18 -0
  221. package/dist/core/workflow-run-events.js +75 -0
  222. package/dist/core/zod-json-schema.d.ts +4 -0
  223. package/dist/core/zod-json-schema.js +39 -0
  224. package/dist/core/zod3-window.d.ts +35 -0
  225. package/dist/core/zod3-window.js +124 -0
  226. package/dist/generated/prisma/browser.d.ts +92 -3
  227. package/dist/generated/prisma/client.d.ts +92 -3
  228. package/dist/generated/prisma/commonInputTypes.d.ts +364 -54
  229. package/dist/generated/prisma/enums.d.ts +37 -0
  230. package/dist/generated/prisma/enums.js +31 -0
  231. package/dist/generated/prisma/internal/class.d.ts +132 -0
  232. package/dist/generated/prisma/internal/class.js +4 -4
  233. package/dist/generated/prisma/internal/prismaNamespace.d.ts +1332 -142
  234. package/dist/generated/prisma/internal/prismaNamespace.js +227 -5
  235. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +234 -0
  236. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +227 -5
  237. package/dist/generated/prisma/models/Agent.d.ts +464 -7
  238. package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
  239. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +301 -1
  240. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  241. package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
  242. package/dist/generated/prisma/models/CodingRun.d.ts +1841 -1
  243. package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
  244. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  245. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  246. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  247. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  248. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1713 -0
  249. package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
  250. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1551 -0
  251. package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
  252. package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
  253. package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
  254. package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
  255. package/dist/generated/prisma/models/NotificationChannel.js +1 -0
  256. package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
  257. package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
  258. package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
  259. package/dist/generated/prisma/models/NotificationThread.js +1 -0
  260. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  261. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  262. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  263. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  264. package/dist/generated/prisma/models/Run.d.ts +1619 -58
  265. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  266. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  267. package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
  268. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  269. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  270. package/dist/generated/prisma/models/Secret.d.ts +37 -1
  271. package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
  272. package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
  273. package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
  274. package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
  275. package/dist/generated/prisma/models.d.ts +12 -0
  276. package/dist/help/build.js +4 -2
  277. package/dist/help/catalog.d.ts +1 -1
  278. package/dist/help/catalog.js +31 -6
  279. package/dist/help-index.json +2584 -146
  280. package/dist/import/create.js +49 -3
  281. package/dist/import/neutral-schema.d.ts +50 -277
  282. package/dist/import/neutral-schema.js +7 -4
  283. package/dist/knowledge/check.d.ts +1 -1
  284. package/dist/knowledge/cli.d.ts +11 -1
  285. package/dist/knowledge/cli.js +37 -4
  286. package/dist/knowledge/concept.d.ts +3 -19
  287. package/dist/knowledge/location.d.ts +31 -0
  288. package/dist/knowledge/location.js +78 -0
  289. package/dist/mcp/auth/access.d.ts +11 -2
  290. package/dist/mcp/auth/access.js +15 -1
  291. package/dist/mcp/auth/ownership.d.ts +7 -7
  292. package/dist/mcp/auth/repo-authorization.js +14 -0
  293. package/dist/mcp/auth/resource-server.d.ts +2 -1
  294. package/dist/mcp/auth/resource-server.js +7 -2
  295. package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
  296. package/dist/mcp/auth/self-hosted/browser.js +19 -6
  297. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  298. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  299. package/dist/mcp/context.d.ts +6 -0
  300. package/dist/mcp/host-events/github-ingress.d.ts +25 -1
  301. package/dist/mcp/host-events/github-ingress.js +70 -1
  302. package/dist/mcp/index.d.ts +19 -0
  303. package/dist/mcp/index.js +117 -20
  304. package/dist/mcp/server.d.ts +13 -0
  305. package/dist/mcp/server.js +33 -14
  306. package/dist/mcp/tools/agents.d.ts +4 -0
  307. package/dist/mcp/tools/agents.js +277 -24
  308. package/dist/mcp/tools/datastore.js +17 -8
  309. package/dist/mcp/tools/grants.js +9 -3
  310. package/dist/mcp/tools/memory.js +11 -1
  311. package/dist/mcp/tools/notification-channels.d.ts +2 -0
  312. package/dist/mcp/tools/notification-channels.js +293 -0
  313. package/dist/mcp/tools/packages.d.ts +2 -0
  314. package/dist/mcp/tools/packages.js +195 -0
  315. package/dist/mcp/tools/power.d.ts +2 -0
  316. package/dist/mcp/tools/power.js +77 -0
  317. package/dist/mcp/tools/repositories.js +18 -5
  318. package/dist/mcp/tools/run-access.d.ts +16 -0
  319. package/dist/mcp/tools/run-access.js +25 -0
  320. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  321. package/dist/mcp/tools/run-transcript-download.js +129 -0
  322. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  323. package/dist/mcp/tools/run-transcript.js +70 -0
  324. package/dist/mcp/tools/runs.d.ts +0 -6
  325. package/dist/mcp/tools/runs.js +41 -14
  326. package/dist/mcp/tools/scheduling.js +3 -1
  327. package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
  328. package/dist/mcp/tools/secret-broker-compat.js +23 -0
  329. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
  330. package/dist/mcp/tools/secret-elicitation-form.js +205 -10
  331. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  332. package/dist/mcp/tools/secret-elicitation-server.js +10 -54
  333. package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
  334. package/dist/mcp/tools/secret-elicitation.js +110 -12
  335. package/dist/mcp/tools/secrets.js +186 -9
  336. package/dist/mcp/tools/stop-run.d.ts +2 -0
  337. package/dist/mcp/tools/stop-run.js +82 -0
  338. package/dist/mcp/tools/subagents.js +2 -2
  339. package/dist/mcp/tools/tools.d.ts +2 -2
  340. package/dist/mcp/tools/tools.js +47 -11
  341. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  342. package/dist/mcp/transport/stdio-link-host.js +67 -0
  343. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  344. package/dist/mcp/transport/streamable-http.js +41 -1
  345. package/dist/native-worker/composition.d.ts +23 -0
  346. package/dist/native-worker/composition.js +77 -0
  347. package/dist/native-worker/docker-isolation.d.ts +65 -0
  348. package/dist/native-worker/docker-isolation.js +183 -0
  349. package/dist/native-worker/docker-launcher.d.ts +110 -0
  350. package/dist/native-worker/docker-launcher.js +297 -0
  351. package/dist/native-worker/gateway-server.d.ts +77 -0
  352. package/dist/native-worker/gateway-server.js +412 -0
  353. package/dist/native-worker/gateway.d.ts +70 -0
  354. package/dist/native-worker/gateway.js +263 -0
  355. package/dist/native-worker/http-server.d.ts +24 -0
  356. package/dist/native-worker/http-server.js +113 -0
  357. package/dist/native-worker/http-transport.d.ts +17 -0
  358. package/dist/native-worker/http-transport.js +88 -0
  359. package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
  360. package/dist/native-worker/kubernetes-isolation.js +218 -0
  361. package/dist/native-worker/kubernetes-launcher.d.ts +106 -0
  362. package/dist/native-worker/kubernetes-launcher.js +375 -0
  363. package/dist/native-worker/launch.d.ts +62 -0
  364. package/dist/native-worker/launch.js +49 -0
  365. package/dist/native-worker/ledger.d.ts +125 -0
  366. package/dist/native-worker/ledger.js +245 -0
  367. package/dist/native-worker/loopback.d.ts +12 -0
  368. package/dist/native-worker/loopback.js +44 -0
  369. package/dist/native-worker/main.d.ts +8 -0
  370. package/dist/native-worker/main.js +85 -0
  371. package/dist/native-worker/protocol.d.ts +296 -0
  372. package/dist/native-worker/protocol.js +246 -0
  373. package/dist/native-worker/sandbox-executor.d.ts +83 -0
  374. package/dist/native-worker/sandbox-executor.js +284 -0
  375. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  376. package/dist/native-worker/stderr-redaction.js +237 -0
  377. package/dist/native-worker/stdio.d.ts +29 -0
  378. package/dist/native-worker/stdio.js +189 -0
  379. package/dist/native-worker/warm-delivery.d.ts +16 -0
  380. package/dist/native-worker/warm-delivery.js +33 -0
  381. package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
  382. package/dist/native-worker/warm-pool-ledger.js +73 -0
  383. package/dist/native-worker/warm-pool.d.ts +107 -0
  384. package/dist/native-worker/warm-pool.js +283 -0
  385. package/dist/native-worker/worker.d.ts +17 -0
  386. package/dist/native-worker/worker.js +141 -0
  387. package/dist/observability/metrics.js +6 -1
  388. package/dist/providers/auth/authorization-server.d.ts +3 -0
  389. package/dist/providers/auth/index.js +2 -0
  390. package/dist/providers/auth/self-hosted.d.ts +14 -2
  391. package/dist/providers/auth/self-hosted.js +54 -4
  392. package/dist/providers/chat/fake.d.ts +46 -0
  393. package/dist/providers/chat/fake.js +39 -0
  394. package/dist/providers/chat/index.d.ts +4 -0
  395. package/dist/providers/chat/index.js +8 -0
  396. package/dist/providers/chat/slack.d.ts +37 -0
  397. package/dist/providers/chat/slack.js +105 -0
  398. package/dist/providers/chat/types.d.ts +42 -0
  399. package/dist/providers/chat/types.js +19 -0
  400. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  401. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  402. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  403. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  404. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  405. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  406. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  407. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  408. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  409. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  410. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  411. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  412. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  413. package/dist/providers/coding-proxy/hold.js +86 -0
  414. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  415. package/dist/providers/coding-proxy/interrupted.js +104 -0
  416. package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
  417. package/dist/providers/coding-proxy/memory-ledger.js +84 -8
  418. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  419. package/dist/providers/coding-proxy/metering.js +27 -4
  420. package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
  421. package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
  422. package/dist/providers/coding-proxy/proxy.d.ts +14 -1
  423. package/dist/providers/coding-proxy/proxy.js +166 -14
  424. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  425. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  426. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  427. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  428. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  429. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  430. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  431. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  432. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  433. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  434. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  435. package/dist/providers/coding-proxy/registry/service.js +579 -112
  436. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  437. package/dist/providers/coding-proxy/registry/store.js +54 -1
  438. package/dist/providers/coding-proxy/runtime.d.ts +4 -0
  439. package/dist/providers/coding-proxy/runtime.js +78 -16
  440. package/dist/providers/coding-proxy/server.d.ts +6 -1
  441. package/dist/providers/coding-proxy/server.js +45 -1
  442. package/dist/providers/coding-proxy/types.d.ts +65 -1
  443. package/dist/providers/datastore/types.d.ts +5 -0
  444. package/dist/providers/engine/types.d.ts +36 -2
  445. package/dist/providers/engine/types.js +39 -0
  446. package/dist/providers/executor/composition.d.ts +31 -1
  447. package/dist/providers/executor/composition.js +81 -8
  448. package/dist/providers/executor/container.d.ts +385 -9
  449. package/dist/providers/executor/container.js +1234 -99
  450. package/dist/providers/executor/dbos-status.d.ts +31 -0
  451. package/dist/providers/executor/dbos-status.js +64 -0
  452. package/dist/providers/executor/dbos.d.ts +91 -0
  453. package/dist/providers/executor/dbos.js +319 -26
  454. package/dist/providers/executor/deferred.d.ts +44 -0
  455. package/dist/providers/executor/deferred.js +100 -0
  456. package/dist/providers/executor/in-process.d.ts +9 -1
  457. package/dist/providers/executor/in-process.js +14 -4
  458. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  459. package/dist/providers/executor/linked-issue-reader.js +30 -0
  460. package/dist/providers/executor/routing.d.ts +39 -10
  461. package/dist/providers/executor/routing.js +77 -32
  462. package/dist/providers/executor/types.d.ts +25 -0
  463. package/dist/providers/index.d.ts +2 -1
  464. package/dist/providers/issue-tracker/types.d.ts +17 -0
  465. package/dist/providers/issue-tracker/types.js +39 -1
  466. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  467. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  468. package/dist/providers/jobs/docker-isolation.d.ts +8 -0
  469. package/dist/providers/jobs/docker-isolation.js +17 -0
  470. package/dist/providers/jobs/docker.d.ts +1 -0
  471. package/dist/providers/jobs/docker.js +29 -4
  472. package/dist/providers/jobs/fake-kubernetes-api.d.ts +23 -2
  473. package/dist/providers/jobs/fake-kubernetes-api.js +45 -1
  474. package/dist/providers/jobs/kubernetes-api.d.ts +25 -1
  475. package/dist/providers/jobs/kubernetes-api.js +17 -0
  476. package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
  477. package/dist/providers/jobs/kubernetes-client.js +61 -3
  478. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
  479. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
  480. package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
  481. package/dist/providers/jobs/kubernetes-isolation.js +23 -1
  482. package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
  483. package/dist/providers/jobs/kubernetes-platform.js +38 -1
  484. package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
  485. package/dist/providers/jobs/kubernetes-preflight.js +4 -2
  486. package/dist/providers/jobs/kubernetes.d.ts +42 -2
  487. package/dist/providers/jobs/kubernetes.js +178 -19
  488. package/dist/providers/jobs/metadata-probes.d.ts +11 -0
  489. package/dist/providers/jobs/metadata-probes.js +13 -0
  490. package/dist/providers/jobs/types.d.ts +42 -0
  491. package/dist/providers/jobs/types.js +13 -1
  492. package/dist/providers/llm/anthropic.js +5 -1
  493. package/dist/providers/llm/bedrock.d.ts +0 -12
  494. package/dist/providers/llm/bedrock.js +4 -0
  495. package/dist/providers/llm/claude-messages.d.ts +3 -1
  496. package/dist/providers/llm/claude-messages.js +4 -1
  497. package/dist/providers/llm/claude-provider.d.ts +2 -2
  498. package/dist/providers/llm/claude-provider.js +2 -2
  499. package/dist/providers/llm/openai.d.ts +2 -2
  500. package/dist/providers/llm/openai.js +6 -2
  501. package/dist/providers/llm/routing.d.ts +2 -2
  502. package/dist/providers/llm/routing.js +2 -2
  503. package/dist/providers/llm/types.d.ts +12 -2
  504. package/dist/providers/review-host/github-events.d.ts +9 -1
  505. package/dist/providers/review-host/github-events.js +34 -12
  506. package/dist/providers/review-host/github.d.ts +39 -2
  507. package/dist/providers/review-host/github.js +274 -29
  508. package/dist/providers/review-host/local.d.ts +8 -4
  509. package/dist/providers/review-host/local.js +49 -31
  510. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  511. package/dist/providers/review-host/patch-pages.js +176 -0
  512. package/dist/providers/review-host/review-format.d.ts +19 -1
  513. package/dist/providers/review-host/review-format.js +38 -7
  514. package/dist/providers/review-host/types.d.ts +157 -2
  515. package/dist/providers/review-host/types.js +8 -0
  516. package/dist/providers/storage/gcs.d.ts +63 -0
  517. package/dist/providers/storage/gcs.js +69 -0
  518. package/dist/providers/storage/index.d.ts +15 -0
  519. package/dist/providers/storage/index.js +14 -0
  520. package/dist/providers/storage/local.d.ts +24 -0
  521. package/dist/providers/storage/local.js +92 -0
  522. package/dist/providers/storage/meter.d.ts +14 -0
  523. package/dist/providers/storage/meter.js +34 -0
  524. package/dist/providers/storage/s3.d.ts +41 -0
  525. package/dist/providers/storage/s3.js +107 -0
  526. package/dist/providers/storage/types.d.ts +37 -3
  527. package/dist/providers/storage/types.js +21 -4
  528. package/dist/providers/vcs/git.d.ts +33 -2
  529. package/dist/providers/vcs/git.js +324 -22
  530. package/dist/providers/vcs/github-remote.d.ts +26 -3
  531. package/dist/providers/vcs/github-remote.js +124 -14
  532. package/dist/providers/vcs/github.d.ts +246 -12
  533. package/dist/providers/vcs/github.js +521 -61
  534. package/dist/providers/vcs/index.js +8 -1
  535. package/dist/providers/vcs/pr-description.d.ts +127 -0
  536. package/dist/providers/vcs/pr-description.js +270 -0
  537. package/dist/providers/vcs/remote.d.ts +33 -1
  538. package/dist/providers/vcs/routing.d.ts +4 -2
  539. package/dist/providers/vcs/routing.js +6 -0
  540. package/dist/providers/vcs/types.d.ts +80 -3
  541. package/dist/quickstart/coding-seed.d.ts +21 -3
  542. package/dist/quickstart/coding-seed.js +283 -3
  543. package/dist/quickstart/images.d.ts +2 -0
  544. package/dist/quickstart/images.js +7 -1
  545. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  546. package/dist/quickstart/reviewer-prompt.js +6 -6
  547. package/dist/quickstart-images.json +1 -1
  548. package/dist/sandbox/brokered-fetch.d.ts +23 -0
  549. package/dist/sandbox/brokered-fetch.js +37 -0
  550. package/dist/sandbox/generated/zod.bundle.js +62 -1
  551. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  552. package/dist/sandbox/host-functions.d.ts +35 -0
  553. package/dist/sandbox/host-functions.js +150 -91
  554. package/dist/sandbox/prelude.js +7 -1
  555. package/dist/sandbox/run-in-sandbox.d.ts +19 -0
  556. package/dist/sandbox/run-in-sandbox.js +28 -10
  557. package/dist/sandbox/safe-fetch.d.ts +2 -0
  558. package/dist/sandbox/safe-fetch.js +3 -1
  559. package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
  560. package/dist/sandbox/secret-broker-sigv4.js +49 -0
  561. package/dist/sandbox/secret-broker.d.ts +34 -0
  562. package/dist/sandbox/secret-broker.js +161 -0
  563. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  564. package/dist/sandbox/user-tool.d.ts +14 -0
  565. package/dist/sandbox/user-tool.js +32 -0
  566. package/dist/sandbox/zod-params.d.ts +37 -5
  567. package/dist/sandbox/zod-params.js +181 -26
  568. package/dist/serve.js +25 -0
  569. package/dist/viewer/api-schema.d.ts +372 -2454
  570. package/dist/viewer/api-schema.js +29 -0
  571. package/dist/viewer/build-schemas.js +10 -3
  572. package/dist/viewer/event-bus.d.ts +6 -0
  573. package/dist/viewer/event-bus.js +16 -7
  574. package/dist/viewer/graph.d.ts +5 -2
  575. package/dist/viewer/graph.js +7 -2
  576. package/dist/viewer/http.d.ts +0 -1
  577. package/dist/viewer/http.js +2 -2
  578. package/dist/viewer/infra.js +25 -2
  579. package/dist/viewer/limits.d.ts +4 -0
  580. package/dist/viewer/limits.js +4 -0
  581. package/dist/viewer/openapi.d.ts +15 -0
  582. package/dist/viewer/openapi.js +170 -0
  583. package/dist/wardby-bin.js +10 -0
  584. package/docs/README.md +7 -0
  585. package/docs/agent-recipes.md +114 -27
  586. package/docs/architecture-runtime.md +16 -1
  587. package/docs/code-review-agents.md +689 -45
  588. package/docs/coding-agent-setup.md +602 -12
  589. package/docs/coding-packages.md +1037 -92
  590. package/docs/coding-services.md +30 -13
  591. package/docs/coding-worker-byo-images.md +218 -6
  592. package/docs/coding-worker-isolation.md +173 -44
  593. package/docs/getting-started-gke.md +332 -129
  594. package/docs/getting-started-identity-provider.md +31 -11
  595. package/docs/getting-started.md +14 -4
  596. package/docs/jira-agents.md +22 -9
  597. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  598. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  599. package/docs/knowledge/delegation-admission-slots.md +52 -0
  600. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  601. package/docs/knowledge/import-rename-target.md +52 -0
  602. package/docs/knowledge/index.md +57 -0
  603. package/docs/knowledge/log.md +9 -0
  604. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  605. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  606. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  607. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  608. package/docs/knowledge/overview-cli.md +74 -0
  609. package/docs/knowledge/overview-coding-proxy.md +72 -0
  610. package/docs/knowledge/overview-coding.md +72 -0
  611. package/docs/knowledge/overview-config.md +60 -0
  612. package/docs/knowledge/overview-core.md +72 -0
  613. package/docs/knowledge/overview-deploy.md +83 -0
  614. package/docs/knowledge/overview-mcp.md +61 -0
  615. package/docs/knowledge/overview-prisma.md +72 -0
  616. package/docs/knowledge/overview-providers.md +89 -0
  617. package/docs/knowledge/overview-sandbox.md +83 -0
  618. package/docs/knowledge/overview-surfaces.md +83 -0
  619. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  620. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  621. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  622. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  623. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  624. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  625. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  626. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  627. package/docs/knowledge/warm-input-publication.md +30 -0
  628. package/docs/knowledge/workspace-staging-failure.md +54 -0
  629. package/docs/knowledge.md +54 -14
  630. package/docs/native-sandbox.md +731 -0
  631. package/docs/observability.md +4 -0
  632. package/docs/release-verification.md +9 -0
  633. package/docs/security-deployment.md +146 -14
  634. package/docs/slack-notifications.md +268 -0
  635. package/docs/tool-secrets.md +284 -0
  636. package/docs/viewer-api.md +46 -5
  637. package/docs/viewer-api.openapi.yml +1404 -0
  638. package/help/admin-viewer.md +29 -3
  639. package/help/agent-recipes.md +27 -0
  640. package/help/architecture-agent.md +11 -6
  641. package/help/brokered-secrets.md +79 -0
  642. package/help/build-claude-code-image.md +131 -0
  643. package/help/build-worker-image.md +6 -7
  644. package/help/builder-agent.md +19 -6
  645. package/help/code-review-agents.md +243 -10
  646. package/help/coding-packages.md +156 -6
  647. package/help/cost-attribution.md +9 -5
  648. package/help/creating-agents.md +14 -1
  649. package/help/dependency-cache.md +143 -0
  650. package/help/deploy-gke.md +23 -9
  651. package/help/deployment-targets.md +25 -14
  652. package/help/errors/budget-exhausted.md +187 -0
  653. package/help/errors/budget-group-exhausted.md +5 -1
  654. package/help/errors/coding-provider-not-configured.md +2 -2
  655. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  656. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  657. package/help/errors/continuation-closed.md +9 -12
  658. package/help/errors/database-auth-invalid.md +28 -0
  659. package/help/errors/delegation-conflict.md +24 -0
  660. package/help/errors/file-list-truncated.md +45 -0
  661. package/help/errors/full-read-required.md +49 -0
  662. package/help/errors/github-account-not-allowed.md +29 -0
  663. package/help/errors/graph-incomplete.md +43 -0
  664. package/help/errors/graph-limit.md +43 -0
  665. package/help/errors/low-power-disabled.md +29 -0
  666. package/help/errors/low-power-scale-forbidden.md +35 -0
  667. package/help/errors/low-power-wake-timeout.md +30 -0
  668. package/help/errors/merge-conflict.md +49 -0
  669. package/help/errors/mobile-disabled.md +31 -0
  670. package/help/errors/native-sandbox-capacity.md +22 -0
  671. package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
  672. package/help/errors/native-sandbox-docker-failed.md +20 -0
  673. package/help/errors/native-sandbox-gateway-error.md +20 -0
  674. package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
  675. package/help/errors/native-sandbox-image-not-pinned.md +19 -0
  676. package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
  677. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  678. package/help/errors/native-sandbox-network-unenforced.md +22 -0
  679. package/help/errors/native-sandbox-requires-catalog.md +31 -0
  680. package/help/errors/native-sandbox-unavailable.md +19 -0
  681. package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
  682. package/help/errors/native-sandbox-worker-exited.md +21 -0
  683. package/help/errors/native-sandbox-worker-lost.md +20 -0
  684. package/help/errors/native-sandbox-worker-unready.md +22 -0
  685. package/help/errors/package-not-allowed-pending.md +52 -0
  686. package/help/errors/package-not-allowed.md +51 -0
  687. package/help/errors/package-refusals.md +43 -0
  688. package/help/errors/patch-cursor-malformed.md +31 -0
  689. package/help/errors/run-lost.md +39 -0
  690. package/help/errors/run-transcript-download.md +44 -0
  691. package/help/errors/secret-broker-body-invalid.md +26 -0
  692. package/help/errors/secret-broker-changed.md +20 -0
  693. package/help/errors/secret-broker-config-invalid.md +30 -0
  694. package/help/errors/secret-broker-conflict.md +27 -0
  695. package/help/errors/secret-broker-destination-denied.md +28 -0
  696. package/help/errors/secret-broker-value-invalid.md +28 -0
  697. package/help/errors/secret-brokered.md +24 -0
  698. package/help/errors/secret-in-value.md +69 -0
  699. package/help/errors/secret-not-brokered.md +25 -0
  700. package/help/errors/slack-auth-failed.md +48 -0
  701. package/help/errors/slack-channel-unreachable.md +39 -0
  702. package/help/errors/slack-not-configured.md +33 -0
  703. package/help/errors/target-merge.md +40 -0
  704. package/help/fix-merge-conflicts.md +73 -0
  705. package/help/getting-started.md +4 -5
  706. package/help/github-app-setup.md +132 -0
  707. package/help/github.md +40 -1
  708. package/help/identity-and-access.md +7 -1
  709. package/help/jira.md +23 -6
  710. package/help/knowledge.md +16 -7
  711. package/help/local-repositories.md +3 -4
  712. package/help/low-power-mode.md +131 -0
  713. package/help/merge-order-check.md +122 -0
  714. package/help/mobile-app.md +54 -0
  715. package/help/native-capabilities.md +29 -1
  716. package/help/native-sandbox.md +150 -0
  717. package/help/observability.md +8 -0
  718. package/help/operating-agents.md +5 -0
  719. package/help/package-audit-mode.md +91 -0
  720. package/help/related-pull-requests.md +80 -16
  721. package/help/repo-instructions-and-skills.md +91 -0
  722. package/help/resume-runs-locally.md +131 -0
  723. package/help/review-fix-rounds.md +43 -1
  724. package/help/sharing-agents.md +59 -0
  725. package/help/slack-notifications.md +76 -0
  726. package/help/status-comments.md +31 -0
  727. package/help/stop-run.md +58 -0
  728. package/help/troubleshooting/budgets.md +28 -0
  729. package/help/troubleshooting/coding-workers.md +99 -7
  730. package/package.json +27 -13
  731. package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
  732. package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
  733. package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
  734. package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
  735. package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
  736. package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
  737. package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
  738. package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
  739. package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
  740. package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
  741. package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
  742. package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
  743. package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
  744. package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
  745. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  746. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  747. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  748. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  749. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  750. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  751. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  752. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  753. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  754. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  755. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  756. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  757. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  758. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  759. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  760. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  761. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  762. package/prisma/schema.prisma +631 -146
  763. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -11,16 +11,71 @@
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). After a
19
+ * takeover the fork has its own workflow id, so the two never share a step:
20
+ * the original stops the same way when it meets the takeover's cancel
21
+ * (dbosStepFor), and its start() handle writes nothing.
14
22
  */
15
23
  import { DBOS, Error as DbosErrors } from "@dbos-inc/dbos-sdk";
16
- import { executeRun, RunCancelledError } from "../../core/runner.js";
24
+ import pg from "pg";
25
+ import { RunOwnershipLostError, StepReplayMismatchError } from "../engine/types.js";
26
+ import { executeRun, failNativeRun, loseNativeRun, nativeRunIntegrations, RunCancelledError, stopAwareStep, } from "../../core/runner.js";
17
27
  import { markRunFailedFromExecutorError } from "../../core/dispatch.js";
18
28
  import { prisma as defaultDb } from "../../core/db.js";
19
29
  import { HEARTBEAT_INTERVAL_MS } from "../../core/timing.js";
30
+ import { DRIVABLE } from "../../core/run-status.js";
20
31
  import { logger } from "../../core/logger.js";
21
- import { ADOPTION_EXHAUSTED_REASON, decideRecovery, shouldGiveUpAdoption, versionMismatchReason, } from "./dbos-status.js";
32
+ import { databaseAuthFromEnv, pgConnectionConfig } from "../../core/pg-auth.js";
33
+ import { ADOPTION_EXHAUSTED_REASON, STEPS_CHANGED_REASON, decideRecovery, decideTakeover, shouldGiveUpAdoption, versionMismatchReason, } from "./dbos-status.js";
22
34
  export const DBOS_BACKEND = "dbos";
23
35
  const dbosLog = logger.child({ module: "dbos-executor" });
36
+ /** DBOS's own system pool size (DEFAULT_POOL_SIZE in the SDK's system_database.js); kept for ours. */
37
+ const DBOS_SYSTEM_POOL_SIZE = 10;
38
+ /** DBOS's own connect timeout when the URL sets no connect_timeout (getClientConfig in the SDK's utils.js). */
39
+ const DBOS_CONNECT_TIMEOUT_MS = 10_000;
40
+ /**
41
+ * DBOS.setConfig input. Under password auth this is exactly what launch() always passed, and DBOS
42
+ * opens its own pool from the URL. Under rds-iam DBOS gets a pool whose password is the IAM token;
43
+ * DBOS then runs its migrations, queries and LISTEN through that pool and never opens a URL
44
+ * connection (system_database.js: a custom pool skips database creation and is what every
45
+ * connection borrows from). The pool copies what DBOS would have set on its own: size, connect
46
+ * timeout and application_name. DBOS never ends a pool it was given — see endSystemPool().
47
+ */
48
+ export function dbosLaunchConfig(config, executorId, auth, pgAuth) {
49
+ const url = config.systemDatabaseUrl;
50
+ const launch = {
51
+ name: "wardby",
52
+ systemDatabaseUrl: url,
53
+ systemDatabaseSchemaName: config.schemaName,
54
+ executorID: executorId,
55
+ runAdminServer: false,
56
+ logLevel: "warn",
57
+ };
58
+ if (auth !== "rds-iam")
59
+ return launch;
60
+ const connection = pgConnectionConfig(url, auth, pgAuth); // validates the URL first
61
+ const connectTimeout = Number.parseInt(new URL(url).searchParams.get("connect_timeout") ?? "", 10);
62
+ const pool = new pg.Pool({
63
+ application_name: `dbos_transact_${executorId}`,
64
+ ...connection,
65
+ max: DBOS_SYSTEM_POOL_SIZE,
66
+ connectionTimeoutMillis: connectTimeout ? connectTimeout * 1000 : DBOS_CONNECT_TIMEOUT_MS,
67
+ });
68
+ // DBOS attaches no listener to a caller's pool; an idle connection's error would otherwise crash the process.
69
+ pool.on("error", (err) => dbosLog.warn({ err }, "DBOS system database pool error"));
70
+ return { ...launch, systemDatabasePool: pool };
71
+ }
72
+ /** The pool launch() handed DBOS, if any. Module-level like DBOS itself: whoever shuts DBOS down ends it. */
73
+ let systemPool;
74
+ async function endSystemPool() {
75
+ const pool = systemPool;
76
+ systemPool = undefined;
77
+ await pool?.end().catch((err) => dbosLog.warn({ err }, "failed to close the DBOS system database pool"));
78
+ }
24
79
  /** The executor whose deps the registered workflow uses. Set by launch(). */
25
80
  let activeExecutor;
26
81
  /** Setter (rather than `activeExecutor = this` inline) to avoid aliasing `this` to a variable. */
@@ -36,6 +91,27 @@ function setActiveExecutor(executor) {
36
91
  * `runInsideWorkflow`'s finally.
37
92
  */
38
93
  const cancellationReasons = new Map();
94
+ /**
95
+ * The id a takeover gives the fork of workflow `from` under application `version`. Deterministic, so
96
+ * a takeover that forked but never recorded the fork finishes it rather than forking again; and
97
+ * descendants share their ancestor's id as a prefix, which isForkOf relies on.
98
+ */
99
+ export function forkWorkflowId(from, version) {
100
+ return `${from}@${version}`;
101
+ }
102
+ /** Whether workflow `id` was forked from `from`, directly or through further forks (forkWorkflowId). */
103
+ export function isForkOf(id, from) {
104
+ return id.startsWith(`${from}@`);
105
+ }
106
+ /**
107
+ * The DBOS workflow id that drives a run: `Run.executionWorkflowId` once the
108
+ * run's workflow was forked under a new application version, otherwise the
109
+ * run id (a run's first workflow is started with its run id).
110
+ */
111
+ export async function workflowIdOf(db, runId) {
112
+ const row = await db.run.findUnique({ where: { id: runId }, select: { executionWorkflowId: true } });
113
+ return row?.executionWorkflowId ?? runId;
114
+ }
39
115
  /**
40
116
  * Bind the engine's step boundary to a DBOS checkpointed step. Never
41
117
  * retried: a retry would re-spend.
@@ -44,23 +120,108 @@ const cancellationReasons = new Map();
44
120
  * out of the next step boundary. Translated here into a `RunCancelledError`
45
121
  * so executeRun's backstop records `cancelled` plus the operator's reason,
46
122
  * rather than `failed` plus an SDK-internal message.
123
+ *
124
+ * DBOS signals that another execution of this workflow recorded the step
125
+ * first by throwing `DBOSWorkflowConflictError` after this attempt's step
126
+ * body already ran. Translated into a `RunOwnershipLostError` (carrying the
127
+ * discarded step's usage, if any, for the log) so executeRun's backstop stops
128
+ * this attempt without writing the run; runInsideWorkflow turns it back into
129
+ * the SDK error.
130
+ *
131
+ * DBOS signals that a replay reached a step whose recorded name differs (the
132
+ * run was recorded by a release whose steps differ, e.g. after a takeover
133
+ * fork) by throwing `DBOSUnexpectedStepError`. Translated into a
134
+ * `StepReplayMismatchError`, which executeRun's backstop settles as `lost`
135
+ * (runInsideWorkflow does it for a mismatch at the load step, which is outside
136
+ * that backstop).
137
+ */
138
+ export const dbosStep = (name, fn) => runDbosStep(name, fn);
139
+ /**
140
+ * dbosStep for one run's workflow body. A cancellation of a workflow the run has moved off (its
141
+ * `executionWorkflowId` names a fork of it) is not a stop: recover() took the run over (forked it) and cancelled this,
142
+ * the forked-from workflow, while its owner was still alive. That attempt stops like one that lost
143
+ * a step's checkpoint (RunOwnershipLostError: no terminal write), so the fork, not a reasonless
144
+ * "cancelled" from the original, settles the run. takeOver records the fork's id before it
145
+ * cancels, so the original always reads the new id by the time it sees the cancel.
146
+ */
147
+ export function dbosStepFor(db, runId) {
148
+ const supersedes = async (cancelledWorkflowId) => {
149
+ // A failed read falls back to an ordinary cancellation, as before this check existed.
150
+ const current = await workflowIdOf(db, runId).catch(() => cancelledWorkflowId);
151
+ return isForkOf(current, cancelledWorkflowId);
152
+ };
153
+ return (name, fn) => runDbosStep(name, fn, supersedes);
154
+ }
155
+ /**
156
+ * dbosStepFor behind the same per-step row read as inline runs (stopAwareStep), failing open. DBOS
157
+ * stops a workflow it was told to cancel, but stop() can cancel only the workflow the run names, and
158
+ * a takeover's fork is named only once recorded: a fork already running before that (or whose
159
+ * record failed) would otherwise keep paying for turns under a run stop() already made terminal.
160
+ * The same read fences out a taken-over original as soon as the run names its fork, before the
161
+ * takeover's cancel lands, and even when that cancel failed: it stops as an ownership loss, without
162
+ * a terminal write or the settle side effects (host checks, status comments) the fork owns.
47
163
  */
48
- const dbosStep = async (name, fn) => {
164
+ export function stopAwareDbosStep(db, runId) {
165
+ return stopAwareStep(db, runId, dbosStepFor(db, runId), {
166
+ failOpen: true,
167
+ ownership: { workflowId: () => DBOS.workflowID, forkedFrom: isForkOf },
168
+ });
169
+ }
170
+ async function runDbosStep(name, fn, supersededBy) {
171
+ let ran;
49
172
  try {
50
- return await DBOS.runStep(fn, { name, retriesAllowed: false });
173
+ return await DBOS.runStep(async () => {
174
+ const value = await fn();
175
+ ran = { value };
176
+ return value;
177
+ }, { name, retriesAllowed: false });
51
178
  }
52
179
  catch (err) {
53
180
  if (err instanceof DbosErrors.DBOSWorkflowCancelledError) {
181
+ if (await supersededBy?.(err.workflowID))
182
+ throw new RunOwnershipLostError(name, { cause: err });
54
183
  const reason = cancellationReasons.get(err.workflowID);
55
184
  throw new RunCancelledError(`Run cancelled: ${reason ?? "no reason given"}`);
56
185
  }
186
+ if (err instanceof DbosErrors.DBOSWorkflowConflictError) {
187
+ const discardedUsage = usageOf(ran?.value);
188
+ throw new RunOwnershipLostError(name, { cause: err, ...(discardedUsage ? { discardedUsage } : {}) });
189
+ }
190
+ if (err instanceof DbosErrors.DBOSUnexpectedStepError)
191
+ throw new StepReplayMismatchError(name, { cause: err });
57
192
  throw err;
58
193
  }
59
- };
194
+ }
195
+ /**
196
+ * The numeric `usage` fields of a step result, if it has any (an LLM turn's
197
+ * token counts and cost). Tool steps return a string and yield nothing.
198
+ */
199
+ function usageOf(value) {
200
+ if (typeof value !== "object" || value === null || !("usage" in value))
201
+ return undefined;
202
+ const usage = value.usage;
203
+ if (typeof usage !== "object" || usage === null)
204
+ return undefined;
205
+ const numeric = Object.entries(usage).filter((entry) => typeof entry[1] === "number");
206
+ return numeric.length > 0 ? Object.fromEntries(numeric) : undefined;
207
+ }
60
208
  /**
61
209
  * Registered once at module load — DBOS requires registration before
62
210
  * launch(). The body must be deterministic between steps; everything
63
211
  * non-deterministic in executeRun/engine is inside a runStep.
212
+ *
213
+ * Replay constraints. A run's workflow is replayed both by a same-version
214
+ * resume and, when recover() takes a waiting lead over after a deploy, by a
215
+ * fork that runs this body under the *new* release against steps the *old*
216
+ * release recorded (see decideTakeover). So:
217
+ * - Code between steps must stay deterministic and safe to repeat: it runs
218
+ * again on every replay, now possibly under newer code.
219
+ * - Step names and their order must only change in ways a replay can still
220
+ * follow; a replay that meets a different recorded name ends the run lost
221
+ * with STEPS_CHANGED_REASON (executeRun's backstop, or runInsideWorkflow).
222
+ * - New code must accept step outputs recorded by the previous release (the
223
+ * `turn:N:llm` TurnResult, tool results). A release that changes a recorded
224
+ * shape keeps reading the old one, or a takeover fails at that step (lost).
64
225
  */
65
226
  const runWorkflow = DBOS.registerWorkflow(async (runId) => {
66
227
  const self = activeExecutor;
@@ -112,15 +273,24 @@ export class DbosExecutor {
112
273
  }
113
274
  setActiveExecutor(this);
114
275
  if (!DBOS.isInitialized()) {
115
- DBOS.setConfig({
116
- name: "wardby",
117
- systemDatabaseUrl: this.config.systemDatabaseUrl,
118
- systemDatabaseSchemaName: this.config.schemaName,
119
- executorID: this.id,
120
- runAdminServer: false,
121
- logLevel: "warn",
122
- });
123
- await DBOS.launch();
276
+ const launchConfig = dbosLaunchConfig(this.config, this.id, databaseAuthFromEnv());
277
+ systemPool = launchConfig.systemDatabasePool;
278
+ try {
279
+ DBOS.setConfig(launchConfig);
280
+ await DBOS.launch();
281
+ }
282
+ catch (err) {
283
+ // DBOS.launch can throw after it initialized (registering the application version, starting
284
+ // event receivers). Shut that half-launched DBOS down so the next launch() starts clean, then
285
+ // end the pool either way: the next launch() makes a new one.
286
+ if (activeExecutor === this)
287
+ setActiveExecutor(undefined);
288
+ if (DBOS.isInitialized()) {
289
+ await DBOS.shutdown().catch((shutdownErr) => dbosLog.warn({ err: shutdownErr }, "failed to shut down DBOS after a failed launch"));
290
+ }
291
+ await endSystemPool();
292
+ throw err;
293
+ }
124
294
  }
125
295
  this.launched = true;
126
296
  dbosLog.info({ executorId: DBOS.executorID }, "DBOS executor launched");
@@ -129,9 +299,18 @@ export class DbosExecutor {
129
299
  if (!this.launched)
130
300
  return;
131
301
  this.launched = false;
132
- if (activeExecutor === this)
133
- setActiveExecutor(undefined);
134
- await DBOS.shutdown({ workflowCompletionTimeoutMS: 5_000 });
302
+ try {
303
+ await DBOS.shutdown({ workflowCompletionTimeoutMS: 5_000 });
304
+ }
305
+ finally {
306
+ // Only now: shutdown first lets the queue runner finish the dispatch it is in, so a workflow
307
+ // the queue claimed just before (a takeover's fork, an adoption) still starts. Without its
308
+ // executor its body would throw, and DBOS could record that as the workflow's outcome: the
309
+ // next process would then mark a run failed that was only waiting to be taken over.
310
+ if (activeExecutor === this)
311
+ setActiveExecutor(undefined);
312
+ await endSystemPool();
313
+ }
135
314
  }
136
315
  /** Where a run this executor marks failed files its self-defect (no-op without a configured issue tracker). */
137
316
  get selfDefects() {
@@ -169,6 +348,15 @@ export class DbosExecutor {
169
348
  // the same failure — dispatchRun's own `.catch` around `start()` calls
170
349
  // it too — which is harmless precisely because it is conditional and
171
350
  // idempotent: the second call matches zero rows.
351
+ //
352
+ // A workflow that recover() took over (forked, then cancelled) no longer drives the run: the
353
+ // fork does, and settles it. Its rejection is the takeover's cancel, not the run's failure.
354
+ if ((await workflowIdOf(this.db, runId).catch(() => runId)) !== runId) {
355
+ // The error's name only: this path adds no message text to any output.
356
+ const error = err instanceof Error ? err.name : typeof err;
357
+ dbosLog.info({ runId, error }, "the run's original workflow ended after a takeover; its fork drives the run");
358
+ return;
359
+ }
172
360
  await markRunFailedFromExecutorError(this.db, runId, err, this.selfDefects);
173
361
  throw err;
174
362
  }
@@ -180,11 +368,43 @@ export class DbosExecutor {
180
368
  if (!this.launched)
181
369
  await this.launch();
182
370
  dbosLog.info({ runId, reason }, "cancelling durable run");
371
+ // The terminal write comes first and is conditional (the first writer wins), so the run is
372
+ // cancelled with the caller's reason even when its workflow runs in another process (where the
373
+ // reason map below is empty) or has no workflow at all yet (cancelWorkflow then matches
374
+ // nothing). The workflow's next step then throws, and its own terminal write matches no row.
375
+ // The cancel is still attempted when that settle throws (a host or issue update failing after
376
+ // the write) or the database is unreachable: a cancelled row whose workflow kept going would
377
+ // keep spending. The settle's error, if any, is the one rethrown.
378
+ let settleFailed;
379
+ try {
380
+ const row = await this.db.run.findUnique({ where: { id: runId }, select: { status: true } });
381
+ if (row && (row.status === "pending" || row.status === "running")) {
382
+ await failNativeRun({ runId, db: this.db, providers: this.providers, ...nativeRunIntegrations(this.providers, this.db) }, new RunCancelledError(reason ?? "The run was cancelled."));
383
+ }
384
+ }
385
+ catch (err) {
386
+ settleFailed = { err };
387
+ }
183
388
  // Recorded before the cancel so the workflow's next step boundary can
184
389
  // find it: DBOS only reports "cancelled", never why.
185
- if (reason)
390
+ // Keyed by both ids: dbosStep looks it up by the cancelled workflow's id, which is the forked
391
+ // id for a forked run. A failed read targets the run id, the workflow of any run never forked.
392
+ const workflowId = await workflowIdOf(this.db, runId).catch(() => runId);
393
+ if (reason) {
186
394
  cancellationReasons.set(runId, reason);
187
- await DBOS.cancelWorkflow(runId);
395
+ cancellationReasons.set(workflowId, reason);
396
+ }
397
+ try {
398
+ await DBOS.cancelWorkflow(workflowId);
399
+ }
400
+ catch (err) {
401
+ if (!settleFailed)
402
+ throw err;
403
+ // The error's name only: this path adds no message text to any output.
404
+ dbosLog.warn({ runId, error: err instanceof Error ? err.name : typeof err }, "could not cancel the workflow");
405
+ }
406
+ if (settleFailed)
407
+ throw settleFailed.err;
188
408
  }
189
409
  /**
190
410
  * Answer the reconciler for a stale run. Never relaunches: `resume`
@@ -213,13 +433,12 @@ export class DbosExecutor {
213
433
  // DBOS gates recovery and dequeue on application_version. A workflow
214
434
  // recorded under a different version is never dequeued here, so
215
435
  // resuming it would be an unbounded loop that holds the run
216
- // `running` forever: give up at once and let the reconciler reap it.
436
+ // `running` forever. Instead it is forked under this version when it
437
+ // is only waiting on durable children, and otherwise given up at once
438
+ // so the reconciler reaps it (takeOver).
217
439
  const mismatch = versionMismatchReason(status?.applicationVersion, DBOS.applicationVersion);
218
- if (mismatch) {
219
- this.resumeAttempts.delete(handle.runId);
220
- dbosLog.warn({ runId: handle.runId, workflowVersion: status?.applicationVersion }, mismatch);
221
- return { state: "lost", reason: mismatch };
222
- }
440
+ if (mismatch)
441
+ return this.takeOver(handle, mismatch, status?.applicationVersion);
223
442
  // Belt and braces for every other reason a resume can fail to take
224
443
  // (an id we can't dequeue for, a queue that never drains): bound the
225
444
  // number of adoptions of one run so the reconciler stops re-driving
@@ -253,6 +472,56 @@ export class DbosExecutor {
253
472
  return { state: "lost", reason: decision.reason };
254
473
  }
255
474
  }
475
+ /**
476
+ * A workflow recorded under another application version: fork it under this one when it is only
477
+ * waiting on durable children (decideTakeover), otherwise answer lost with the mismatch. The
478
+ * fork counts as an adoption attempt, so repeated failed takeovers of one run end lost too.
479
+ */
480
+ async takeOver(handle, mismatch, workflowVersion) {
481
+ const steps = (await DBOS.listWorkflowSteps(handle.id)) ?? [];
482
+ const children = await this.db.run.findMany({
483
+ where: { parentRunId: handle.runId, status: { in: [...DRIVABLE] } },
484
+ select: { status: true, nativeExecutionMode: true, agent: { select: { kind: true } } },
485
+ });
486
+ const decision = decideTakeover(steps.map((s) => ({ functionID: s.functionID, name: s.name, output: s.output })), children.map((c) => ({ status: c.status, kind: c.agent.kind, nativeExecutionMode: c.nativeExecutionMode })), mismatch);
487
+ if (decision.action === "lost") {
488
+ this.resumeAttempts.delete(handle.runId);
489
+ dbosLog.warn({ runId: handle.runId, workflowVersion }, mismatch);
490
+ return { state: "lost", reason: decision.reason };
491
+ }
492
+ const attempts = this.resumeAttempts.get(handle.runId) ?? 0;
493
+ if (shouldGiveUpAdoption(attempts)) {
494
+ this.resumeAttempts.delete(handle.runId);
495
+ dbosLog.warn({ runId: handle.runId, attempts }, "giving up on taking over durable run");
496
+ return { state: "lost", reason: ADOPTION_EXHAUSTED_REASON };
497
+ }
498
+ this.resumeAttempts.set(handle.runId, attempts + 1);
499
+ // Deterministic, so a takeover that forked but never recorded the fork (the run write below
500
+ // failed, or the process died) is finished by the next pass rather than forked a second time:
501
+ // two workflows driving one run would each spend on every turn. DBOS inserts a fork's row with
502
+ // a plain INSERT (bulkForkWorkflows in the SDK's system_database.js), so a repeated id would
503
+ // fail on the key: look first, and treat a lost race the same way.
504
+ const forkedId = forkWorkflowId(handle.id, DBOS.applicationVersion);
505
+ if (!(await DBOS.getWorkflowStatus(forkedId))) {
506
+ try {
507
+ await DBOS.forkWorkflow(handle.id, decision.startStep, {
508
+ newWorkflowID: forkedId,
509
+ applicationVersion: DBOS.applicationVersion,
510
+ });
511
+ }
512
+ catch (err) {
513
+ if (!(await DBOS.getWorkflowStatus(forkedId)))
514
+ throw err;
515
+ }
516
+ }
517
+ const forked = DBOS.retrieveWorkflow(forkedId);
518
+ await this.db.run.update({ where: { id: handle.runId }, data: { executionWorkflowId: forkedId } });
519
+ // So nothing can dequeue the original again (it stays recorded as forked from).
520
+ await DBOS.cancelWorkflow(handle.id).catch((err) => dbosLog.warn({ err, runId: handle.runId }, "could not cancel the forked-from workflow"));
521
+ dbosLog.info({ runId: handle.runId, from: handle.id, to: forkedId, startStep: decision.startStep, workflowVersion }, "run taken over under this application version");
522
+ void forked.getResult().catch((err) => dbosLog.error({ err, runId: handle.runId }, "taken-over run failed"));
523
+ return { state: "active" };
524
+ }
256
525
  /** Workflow body. Public only so the module-level registration can reach it. */
257
526
  async runInsideWorkflow(runId) {
258
527
  const beat = () => this.db.run.update({ where: { id: runId }, data: { heartbeatAt: new Date() } }).catch(() => {
@@ -261,11 +530,35 @@ export class DbosExecutor {
261
530
  await beat();
262
531
  const timer = setInterval(() => void beat(), this.heartbeatIntervalMs);
263
532
  try {
264
- await executeRun(runId, this.providers, this.db, undefined, dbosStep);
533
+ await executeRun(runId, this.providers, this.db, undefined, stopAwareDbosStep(this.db, runId));
534
+ }
535
+ catch (err) {
536
+ // An ownership loss leaves the workflow body as the SDK's own conflict error, so DBOS takes
537
+ // its duplicate-execution path: it records nothing and parks this attempt until the winner
538
+ // records the outcome. Any other error escaping here would be recorded as the workflow's
539
+ // outcome while the winner still runs. The runner already logged the loss. A forked-from
540
+ // workflow's own cancellation (dbosStepFor) goes back as itself: DBOS parks that too.
541
+ if (err instanceof RunOwnershipLostError) {
542
+ throw err.cause instanceof DbosErrors.DBOSWorkflowConflictError ||
543
+ err.cause instanceof DbosErrors.DBOSWorkflowCancelledError
544
+ ? err.cause
545
+ : new DbosErrors.DBOSWorkflowConflictError(DBOS.workflowID ?? runId);
546
+ }
547
+ // A replay met a step the recorded run does not have at the load step, ahead of executeRun's
548
+ // backstop (which settles a mismatch in any later step itself).
549
+ if (err instanceof StepReplayMismatchError) {
550
+ dbosLog.warn({ err, runId }, "replay no longer matches the recorded run");
551
+ // The same settle as executeRun's backstop: lost (first writer wins), its children stopped.
552
+ await loseNativeRun({ runId, db: this.db, providers: this.providers, ...nativeRunIntegrations(this.providers, this.db) }, STEPS_CHANGED_REASON);
553
+ return;
554
+ }
555
+ throw err;
265
556
  }
266
557
  finally {
267
558
  clearInterval(timer);
268
559
  cancellationReasons.delete(runId);
560
+ if (DBOS.workflowID)
561
+ cancellationReasons.delete(DBOS.workflowID);
269
562
  }
270
563
  }
271
564
  }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * An Executor for a process that must never start or stop runs itself: the
3
+ * native sandbox gateway (docs/native-sandbox.md). Sandbox workers can reach
4
+ * the gateway, so it holds no Docker socket, cluster credential, or in-process
5
+ * engine; a child it dispatches is only recorded (Run.startDeferredAt) and a
6
+ * stop it needs only requested (Run.stopRequestedAt). The scheduler leader
7
+ * carries both out through the server's own executor (`drainDeferredRuns`).
8
+ *
9
+ * Coding dispatch is recorded unresolved (`defersCodingResolution`): the worker image,
10
+ * service declaration and knowledge files are resolved by the process that starts the run
11
+ * (the drain's `beforeStart` hook), not here.
12
+ */
13
+ import type { PrismaClient } from "#prisma";
14
+ import type { Executor } from "./types.js";
15
+ export type DeferredExecutorDb = Pick<PrismaClient, "run">;
16
+ export declare class DeferredExecutor implements Executor {
17
+ private readonly db;
18
+ readonly defersCodingResolution = true;
19
+ constructor(db: DeferredExecutorDb);
20
+ start(runId: string): Promise<void>;
21
+ stop(runId: string, reason?: string): Promise<void>;
22
+ }
23
+ export interface DrainDeferredRunsOptions {
24
+ db: Pick<PrismaClient, "run">;
25
+ executor: Executor;
26
+ /** Where a start failure is recorded; defaults to marking the run failed with the error. */
27
+ onStartFailed?: (runId: string, err: unknown) => Promise<void>;
28
+ /**
29
+ * Runs after a row is claimed and before `executor.start`. Resolves inputs the deferring process
30
+ * could not; false means the hook ended the run itself so it must not start. A throw is handled
31
+ * like a start failure.
32
+ */
33
+ beforeStart?: (runId: string) => Promise<boolean>;
34
+ limit?: number;
35
+ }
36
+ /**
37
+ * Starts runs a deferred executor dispatched, and stops runs it asked to stop, through the
38
+ * server's executor. Called on the scheduler leader's tick. Each row is claimed by clearing its
39
+ * marker in a conditional update first, so two drains never start or stop the same run twice.
40
+ */
41
+ export declare function drainDeferredRuns(options: DrainDeferredRunsOptions): Promise<{
42
+ started: number;
43
+ stopped: number;
44
+ }>;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * An Executor for a process that must never start or stop runs itself: the
3
+ * native sandbox gateway (docs/native-sandbox.md). Sandbox workers can reach
4
+ * the gateway, so it holds no Docker socket, cluster credential, or in-process
5
+ * engine; a child it dispatches is only recorded (Run.startDeferredAt) and a
6
+ * stop it needs only requested (Run.stopRequestedAt). The scheduler leader
7
+ * carries both out through the server's own executor (`drainDeferredRuns`).
8
+ *
9
+ * Coding dispatch is recorded unresolved (`defersCodingResolution`): the worker image,
10
+ * service declaration and knowledge files are resolved by the process that starts the run
11
+ * (the drain's `beforeStart` hook), not here.
12
+ */
13
+ import { logger } from "../../core/logger.js";
14
+ const deferredLog = logger.child({ module: "deferred-executor" });
15
+ export class DeferredExecutor {
16
+ db;
17
+ defersCodingResolution = true;
18
+ constructor(db) {
19
+ this.db = db;
20
+ }
21
+ async start(runId) {
22
+ await this.db.run.updateMany({ where: { id: runId, status: "pending" }, data: { startDeferredAt: new Date() } });
23
+ }
24
+ async stop(runId, reason) {
25
+ // Never started: nothing runs it, so it can simply end here.
26
+ const cancelled = await this.db.run.updateMany({
27
+ where: { id: runId, status: "pending", startDeferredAt: { not: null } },
28
+ data: {
29
+ status: "cancelled",
30
+ error: reason ?? "Cancelled before it started.",
31
+ finishedAt: new Date(),
32
+ startDeferredAt: null,
33
+ },
34
+ });
35
+ if (cancelled.count > 0)
36
+ return;
37
+ await this.db.run.updateMany({
38
+ where: { id: runId, status: { in: ["pending", "running"] } },
39
+ data: { stopRequestedAt: new Date(), stopRequestReason: reason ?? null },
40
+ });
41
+ }
42
+ }
43
+ /**
44
+ * Starts runs a deferred executor dispatched, and stops runs it asked to stop, through the
45
+ * server's executor. Called on the scheduler leader's tick. Each row is claimed by clearing its
46
+ * marker in a conditional update first, so two drains never start or stop the same run twice.
47
+ */
48
+ export async function drainDeferredRuns(options) {
49
+ const { db, executor } = options;
50
+ const limit = options.limit ?? 50;
51
+ let started = 0;
52
+ let stopped = 0;
53
+ const toStart = await db.run.findMany({
54
+ where: { startDeferredAt: { not: null }, status: "pending" },
55
+ orderBy: { startDeferredAt: "asc" },
56
+ take: limit,
57
+ select: { id: true },
58
+ });
59
+ for (const { id } of toStart) {
60
+ const claimed = await db.run.updateMany({
61
+ where: { id, startDeferredAt: { not: null }, status: "pending" },
62
+ data: { startDeferredAt: null },
63
+ });
64
+ if (claimed.count === 0)
65
+ continue;
66
+ started += 1;
67
+ // Not awaited: an in-process executor's start runs the whole run.
68
+ void (async () => {
69
+ if (options.beforeStart && !(await options.beforeStart(id)))
70
+ return;
71
+ await executor.start(id);
72
+ })().catch(async (err) => {
73
+ deferredLog.error({ err, runId: id }, "deferred run failed to start");
74
+ await (options.onStartFailed?.(id, err) ??
75
+ db.run.updateMany({
76
+ where: { id, status: { in: ["pending", "running"] } },
77
+ data: { status: "failed", error: err instanceof Error ? err.message : String(err), finishedAt: new Date() },
78
+ }));
79
+ });
80
+ }
81
+ const toStop = await db.run.findMany({
82
+ where: { stopRequestedAt: { not: null } },
83
+ orderBy: { stopRequestedAt: "asc" },
84
+ take: limit,
85
+ select: { id: true, stopRequestReason: true, status: true },
86
+ });
87
+ for (const row of toStop) {
88
+ const claimed = await db.run.updateMany({
89
+ where: { id: row.id, stopRequestedAt: { not: null } },
90
+ data: { stopRequestedAt: null, stopRequestReason: null },
91
+ });
92
+ if (claimed.count === 0 || !["pending", "running"].includes(row.status))
93
+ continue;
94
+ stopped += 1;
95
+ await executor.stop(row.id, row.stopRequestReason ?? undefined).catch((err) => {
96
+ deferredLog.warn({ err, runId: row.id }, "deferred stop request failed");
97
+ });
98
+ }
99
+ return { started, stopped };
100
+ }
@@ -13,5 +13,13 @@ export declare class InProcessExecutor implements Executor {
13
13
  private readonly heartbeatIntervalMs;
14
14
  constructor(providers: NativeRunProviders, db?: RunnerDb, heartbeatIntervalMs?: number);
15
15
  start(runId: string): Promise<void>;
16
- stop(_runId: string, _reason?: string): Promise<void>;
16
+ /**
17
+ * Records the run cancelled (only while it is still pending or running: the first terminal write
18
+ * wins) and settles it like any finished run (its review check, status comments, notifications).
19
+ * The engine itself is stopped cooperatively: executeRun's inline step runner reads the run's row
20
+ * before every step (stopAwareStep), so the process executing it, this one or another, stops it
21
+ * at the next step boundary, and a run that has not started yet never does. A step already in
22
+ * flight (one model turn or tool call) finishes first; its spend is still recorded.
23
+ */
24
+ stop(runId: string, reason?: string): Promise<void>;
17
25
  }
@@ -5,7 +5,7 @@
5
5
  * heartbeat and recovers the run to `lost` rather than leaving it stuck
6
6
  * `running` forever.
7
7
  */
8
- import { executeRun } from "../../core/runner.js";
8
+ import { executeRun, failNativeRun, nativeRunIntegrations, RunCancelledError, } from "../../core/runner.js";
9
9
  import { prisma as defaultDb } from "../../core/db.js";
10
10
  import { HEARTBEAT_INTERVAL_MS } from "../../core/timing.js";
11
11
  export class InProcessExecutor {
@@ -31,8 +31,18 @@ export class InProcessExecutor {
31
31
  clearInterval(timer);
32
32
  }
33
33
  }
34
- async stop(_runId, _reason) {
35
- // Native engine cancellation remains cooperative until Engine accepts an
36
- // AbortSignal. The task state still records the caller's request.
34
+ /**
35
+ * Records the run cancelled (only while it is still pending or running: the first terminal write
36
+ * wins) and settles it like any finished run (its review check, status comments, notifications).
37
+ * The engine itself is stopped cooperatively: executeRun's inline step runner reads the run's row
38
+ * before every step (stopAwareStep), so the process executing it, this one or another, stops it
39
+ * at the next step boundary, and a run that has not started yet never does. A step already in
40
+ * flight (one model turn or tool call) finishes first; its spend is still recorded.
41
+ */
42
+ async stop(runId, reason) {
43
+ const run = await this.db.run.findUnique({ where: { id: runId }, select: { status: true } });
44
+ if (!run || (run.status !== "pending" && run.status !== "running"))
45
+ return;
46
+ await failNativeRun({ runId, db: this.db, providers: this.providers, ...nativeRunIntegrations(this.providers, this.db) }, new RunCancelledError(reason ?? "The run was cancelled."));
37
47
  }
38
48
  }
@@ -0,0 +1,16 @@
1
+ import type { IssueTrackerRegistry } from "../issue-tracker/types.js";
2
+ import type { ReviewHostRegistry } from "../review-host/types.js";
3
+ import type { LinkedIssueRef } from "./container.js";
4
+ /**
5
+ * The executor's readLinkedIssue: a GitHub issue through the review host's
6
+ * issue read (the App's installation token for the run's repository), a Jira
7
+ * issue through the configured tracker. Null when the number is a pull
8
+ * request, the issue is missing, or no host or tracker is configured.
9
+ */
10
+ export declare function linkedIssueReader(deps: {
11
+ hosts: ReviewHostRegistry;
12
+ issueTrackers: IssueTrackerRegistry;
13
+ }): (ref: LinkedIssueRef) => Promise<{
14
+ title: string;
15
+ body: string;
16
+ } | null>;