@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
@@ -0,0 +1,152 @@
1
+ /**
2
+ * How wardby authenticates to Postgres (DATABASE_AUTH).
3
+ *
4
+ * `password` (default): the URL carries everything, exactly as before — pgConnectionConfig returns
5
+ * `{ connectionString }` and nothing else, so unset DATABASE_AUTH changes no connection.
6
+ *
7
+ * `rds-iam`: Amazon RDS IAM database authentication. The password is a short-lived token signed
8
+ * with the workload's AWS credentials (EKS Pod Identity via the default provider chain), minted per
9
+ * new connection and reused for RDS_IAM_TOKEN_REUSE_MS — tokens are valid 15 minutes, and only for
10
+ * establishing a connection, so an open connection outlives its token. TLS with certificate
11
+ * verification is mandatory: the URL must say sslmode=verify-full and name the RDS CA bundle in
12
+ * sslrootcert.
13
+ *
14
+ * Under rds-iam the URL is parsed here into explicit fields rather than passed as connectionString:
15
+ * pg merges a parsed connection string over explicit config, and a password-less URL would replace
16
+ * the token function with an empty password. Nothing in the URL is dropped silently: each query
17
+ * parameter is consumed here (sslmode, sslrootcert), carried over as the same field pg would have
18
+ * read from the connection string (SESSION_PARAMS), read from the URL by other code
19
+ * (OTHER_READERS_PARAMS), or refused by name.
20
+ *
21
+ * Refusals never include the URL, its credentials, or a token.
22
+ */
23
+ import { readFileSync } from "node:fs";
24
+ import { Signer } from "@aws-sdk/rds-signer";
25
+ export const DATABASE_AUTH_ERROR = "database_auth_invalid";
26
+ export const RDS_IAM_TOKEN_REUSE_MS = 600_000;
27
+ export function databaseAuthFromEnv(env = process.env) {
28
+ const value = env.DATABASE_AUTH?.trim() || "password";
29
+ if (value === "password" || value === "rds-iam")
30
+ return value;
31
+ throw new Error(`${DATABASE_AUTH_ERROR}: DATABASE_AUTH must be "password" or "rds-iam" (found "${value}")`);
32
+ }
33
+ /** pg reads these from a connection string as same-named config fields (strings); carried over as-is. */
34
+ const SESSION_PARAMS = [
35
+ "application_name",
36
+ "fallback_application_name",
37
+ "options",
38
+ "client_encoding",
39
+ "statement_timeout",
40
+ "lock_timeout",
41
+ "idle_in_transaction_session_timeout",
42
+ "query_timeout",
43
+ ];
44
+ /**
45
+ * Read from the URL elsewhere, so allowed through: connection_limit and pool_timeout (poolSettings
46
+ * in db.ts), connect_timeout (the DBOS system pool, as DBOS reads it for its own; pg's JavaScript
47
+ * client never reads it), schema (Prisma's CLI; the pg adapter ignores it, so it has no effect at
48
+ * run time under either auth mode).
49
+ */
50
+ const OTHER_READERS_PARAMS = ["connection_limit", "pool_timeout", "connect_timeout", "schema"];
51
+ const ACCEPTED_PARAMS = new Set([
52
+ "sslmode",
53
+ "sslrootcert",
54
+ ...SESSION_PARAMS,
55
+ ...OTHER_READERS_PARAMS,
56
+ ]);
57
+ function refuse(detail) {
58
+ throw new Error(`${DATABASE_AUTH_ERROR}: DATABASE_AUTH=rds-iam ${detail}`);
59
+ }
60
+ /** One token at a time: concurrent connects share a signing call; a failure is never cached. */
61
+ export function cachedToken(signer, now = Date.now, reuseMs = RDS_IAM_TOKEN_REUSE_MS) {
62
+ let token;
63
+ let mintedAt = 0;
64
+ let inflight;
65
+ return async () => {
66
+ if (token !== undefined && now() - mintedAt < reuseMs)
67
+ return token;
68
+ if (!inflight) {
69
+ const startedAt = now();
70
+ inflight = signer
71
+ .getAuthToken()
72
+ .then((fresh) => {
73
+ token = fresh;
74
+ mintedAt = startedAt;
75
+ return fresh;
76
+ })
77
+ .finally(() => {
78
+ inflight = undefined;
79
+ });
80
+ }
81
+ return inflight;
82
+ };
83
+ }
84
+ function decode(component, what) {
85
+ try {
86
+ return decodeURIComponent(component);
87
+ }
88
+ catch {
89
+ return refuse(`needs a correctly percent-encoded ${what} in DATABASE_URL`);
90
+ }
91
+ }
92
+ export function pgConnectionConfig(url, auth, options = {}) {
93
+ if (auth === "password")
94
+ return { connectionString: url };
95
+ const env = options.env ?? process.env;
96
+ let parsed;
97
+ try {
98
+ parsed = new URL(url);
99
+ }
100
+ catch {
101
+ refuse("needs a valid postgresql:// DATABASE_URL");
102
+ }
103
+ if (parsed.protocol !== "postgresql:" && parsed.protocol !== "postgres:") {
104
+ refuse("needs a postgresql:// (or postgres://) DATABASE_URL");
105
+ }
106
+ for (const name of parsed.searchParams.keys()) {
107
+ // The name only: a refused parameter's value can be a key path or a secret.
108
+ if (!ACCEPTED_PARAMS.has(name))
109
+ refuse(`does not support the DATABASE_URL parameter "${name}"`);
110
+ }
111
+ if (parsed.password)
112
+ refuse("takes no password in DATABASE_URL (the IAM token is the password)");
113
+ const user = decode(parsed.username, "user name");
114
+ if (!user)
115
+ refuse("needs a user name in DATABASE_URL (the database user mapped to the IAM role)");
116
+ const region = env.DATABASE_AWS_REGION?.trim() || env.AWS_REGION?.trim();
117
+ if (!region)
118
+ refuse("needs AWS_REGION (or DATABASE_AWS_REGION)");
119
+ const rootCert = parsed.searchParams.get("sslrootcert");
120
+ if (parsed.searchParams.get("sslmode") !== "verify-full" || !rootCert) {
121
+ refuse("needs sslmode=verify-full and sslrootcert=<path to the RDS CA bundle> in DATABASE_URL");
122
+ }
123
+ const host = parsed.hostname;
124
+ const port = parsed.port ? Number(parsed.port) : 5432;
125
+ const database = decode(parsed.pathname.replace(/^\//, ""), "database name") || undefined;
126
+ const makeSigner = options.makeSigner ?? ((params) => new Signer(params));
127
+ const readFile = options.readFile ?? ((path) => readFileSync(path, "utf8"));
128
+ let ca;
129
+ try {
130
+ ca = readFile(rootCert);
131
+ }
132
+ catch (err) {
133
+ // The error code only (ENOENT, EACCES, ...): the message repeats the path.
134
+ const code = err.code;
135
+ refuse(`could not read the sslrootcert file named in DATABASE_URL${code ? ` (${code})` : ""}`);
136
+ }
137
+ const session = {};
138
+ for (const name of SESSION_PARAMS) {
139
+ const value = parsed.searchParams.get(name);
140
+ if (value !== null)
141
+ session[name] = value;
142
+ }
143
+ return {
144
+ ...session,
145
+ host,
146
+ port,
147
+ user,
148
+ database,
149
+ password: cachedToken(makeSigner({ hostname: host, port, username: user, region }), options.now),
150
+ ssl: { ca, rejectUnauthorized: true, servername: host },
151
+ };
152
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Builds the process's single low-power `Power` from the environment. Every
3
+ * composition root (serve, mcp, scheduler) calls this once and hands the same
4
+ * instance to both executors, so wake and sleep agree on state.
5
+ */
6
+ import type { PrismaClient } from "#prisma";
7
+ import { type Power } from "./power.js";
8
+ /**
9
+ * Whether buildPower would return an enabled Power for this environment (WARDBY_LOW_POWER=1 and
10
+ * JOB_LAUNCHER=kubernetes), without building one. Throws on an invalid WARDBY_LOW_POWER.
11
+ */
12
+ export declare function lowPowerActive(env?: NodeJS.ProcessEnv): boolean;
13
+ export declare function buildPower({ env, db }: {
14
+ env?: NodeJS.ProcessEnv;
15
+ db: PrismaClient;
16
+ }): Power;
@@ -0,0 +1,37 @@
1
+ import { DEFAULT_NATIVE_GATEWAY_SERVICE, loadKubernetesJobConfig } from "../config/providers.js";
2
+ import { loadLowPowerConfig } from "../config/low-power.js";
3
+ import { ClientNodeKubernetesApi } from "../providers/jobs/kubernetes-client.js";
4
+ import { logger } from "./logger.js";
5
+ import { createPower, DISABLED_POWER } from "./power.js";
6
+ import { powerBlockers, powerBusy } from "./power-idle.js";
7
+ const log = logger.child({ module: "power-composition" });
8
+ /** Low-power mode only scales Kubernetes Deployments; with any other job launcher it is ignored. */
9
+ const kubernetesJobs = (env) => env.JOB_LAUNCHER === "kubernetes";
10
+ /**
11
+ * Whether buildPower would return an enabled Power for this environment (WARDBY_LOW_POWER=1 and
12
+ * JOB_LAUNCHER=kubernetes), without building one. Throws on an invalid WARDBY_LOW_POWER.
13
+ */
14
+ export function lowPowerActive(env = process.env) {
15
+ return loadLowPowerConfig(env).enabled && kubernetesJobs(env);
16
+ }
17
+ export function buildPower({ env = process.env, db }) {
18
+ const config = loadLowPowerConfig(env);
19
+ if (!config.enabled)
20
+ return DISABLED_POWER;
21
+ if (!kubernetesJobs(env)) {
22
+ log.warn("low_power_ignored: WARDBY_LOW_POWER requires JOB_LAUNCHER=kubernetes");
23
+ return DISABLED_POWER;
24
+ }
25
+ const kubernetes = loadKubernetesJobConfig(env);
26
+ return createPower({
27
+ config,
28
+ api: new ClientNodeKubernetesApi({ context: kubernetes.context }),
29
+ namespace: kubernetes.namespace,
30
+ deployments: {
31
+ proxy: kubernetes.proxyService,
32
+ gateway: env.NATIVE_GATEWAY_SERVICE?.trim() || DEFAULT_NATIVE_GATEWAY_SERVICE,
33
+ },
34
+ busy: powerBusy(db),
35
+ blockers: (target) => powerBlockers(db, target),
36
+ });
37
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Low-power mode's idle rules: whether the coding proxy or native gateway has
3
+ * had work since `since`. A target is busy while any of its runs is pending
4
+ * (queued included) or running, or finished at or after `since`; the gateway
5
+ * is also busy while any gateway session is active. powerBlockers lists the
6
+ * run ids that keep a target busy right now (recent finishes do not count).
7
+ */
8
+ import type { PrismaClient } from "#prisma";
9
+ import type { PowerTarget } from "./power.js";
10
+ export declare function proxyBusy(db: PrismaClient, since: Date): Promise<boolean>;
11
+ export declare function gatewayBusy(db: PrismaClient, since: Date): Promise<boolean>;
12
+ export declare function powerBusy(db: PrismaClient): (target: PowerTarget, since: Date) => Promise<boolean>;
13
+ /** Run ids keeping `target` busy right now: active or queued runs (plus active gateway sessions for the gateway). */
14
+ export declare function powerBlockers(db: PrismaClient, target: PowerTarget): Promise<string[]>;
@@ -0,0 +1,30 @@
1
+ const ACTIVE = { in: ["pending", "running"] };
2
+ export async function proxyBusy(db, since) {
3
+ const n = await db.codingRun.count({
4
+ where: { run: { OR: [{ status: ACTIVE }, { finishedAt: { gte: since } }] } },
5
+ });
6
+ return n > 0;
7
+ }
8
+ export async function gatewayBusy(db, since) {
9
+ const runs = await db.run.count({
10
+ where: { nativeExecutionMode: "sandbox", OR: [{ status: ACTIVE }, { finishedAt: { gte: since } }] },
11
+ });
12
+ if (runs > 0)
13
+ return true;
14
+ return (await db.nativeGatewaySession.count({ where: { status: "active" } })) > 0;
15
+ }
16
+ export function powerBusy(db) {
17
+ return (target, since) => (target === "proxy" ? proxyBusy(db, since) : gatewayBusy(db, since));
18
+ }
19
+ /** Run ids keeping `target` busy right now: active or queued runs (plus active gateway sessions for the gateway). */
20
+ export async function powerBlockers(db, target) {
21
+ if (target === "proxy") {
22
+ const rows = await db.codingRun.findMany({ where: { run: { status: ACTIVE } }, select: { runId: true } });
23
+ return [...new Set(rows.map((r) => r.runId))].sort();
24
+ }
25
+ const [runs, sessions] = await Promise.all([
26
+ db.run.findMany({ where: { nativeExecutionMode: "sandbox", status: ACTIVE }, select: { id: true } }),
27
+ db.nativeGatewaySession.findMany({ where: { status: "active" }, select: { runId: true } }),
28
+ ]);
29
+ return [...new Set([...runs.map((r) => r.id), ...sessions.map((s) => s.runId)])].sort();
30
+ }
@@ -0,0 +1,71 @@
1
+ import type { LowPowerConfig } from "../config/low-power.js";
2
+ import { type KubernetesApi } from "../providers/jobs/kubernetes-api.js";
3
+ export type PowerTarget = "proxy" | "gateway";
4
+ export declare const LOW_POWER_WAKE_TIMEOUT = "low_power_wake_timeout";
5
+ export declare const LOW_POWER_SCALE_FORBIDDEN = "low_power_scale_forbidden";
6
+ export declare const LOW_POWER_DISABLED = "low_power_disabled";
7
+ /** ISO-8601 time the control plane last scaled the Deployment up from zero. */
8
+ export declare const POWER_WOKE_AT = "wardby.io/power-woke-at";
9
+ /**
10
+ * The least time a launcher waits for a woken target: a cold node can take a minute or two to
11
+ * come up. A launcher's own ready timeout above this raises the bound.
12
+ */
13
+ export declare const LOW_POWER_WAKE_FLOOR_MS = 300000;
14
+ /** How long a launcher with this ready timeout lets ensureAwake wait. */
15
+ export declare const wakeTimeoutMs: (readyTimeoutMs: number) => number;
16
+ export interface PowerOptions {
17
+ config: LowPowerConfig;
18
+ /** Required when config.enabled. */
19
+ api?: KubernetesApi;
20
+ namespace: string;
21
+ /** Deployment name per target; each has the same name as its Service. */
22
+ deployments: Record<PowerTarget, string>;
23
+ /** Whether the target has had work since `since` (used by sleepIfIdle). */
24
+ busy?: (target: PowerTarget, since: Date) => Promise<boolean>;
25
+ /** Run ids keeping the target busy right now (active or queued; ignores recent finishes). Needed by sleepNow. */
26
+ blockers?: (target: PowerTarget) => Promise<string[]>;
27
+ now?: () => Date;
28
+ sleep?: (ms: number) => Promise<void>;
29
+ /** How often ensureAwake polls for a ready endpoint. Default 2000. */
30
+ pollMs?: number;
31
+ }
32
+ export interface Power {
33
+ readonly enabled: boolean;
34
+ /** Scales the target up from zero if needed and waits for a ready endpoint. */
35
+ ensureAwake(target: PowerTarget, opts: {
36
+ timeoutMs: number;
37
+ runId: string;
38
+ }): Promise<void>;
39
+ isAsleep(target: PowerTarget): Promise<boolean>;
40
+ sleepIfIdle(): Promise<void>;
41
+ /** Missing permissions, e.g. "patch deployments/wardby-coding-proxy". */
42
+ checkAccess(): Promise<string[]>;
43
+ /** Each target's state. A target whose Deployment does not exist is left out. Disabled: `{ enabled: false }`, no API call. */
44
+ status(): Promise<PowerStatus>;
45
+ /**
46
+ * Scales each target to zero now, skipping the idle window and woke-at grace,
47
+ * unless it has blockers (then it is reported, untouched). Never stops a run.
48
+ * A target whose Deployment does not exist is neither slept nor blocked.
49
+ */
50
+ sleepNow(targets: PowerTarget[]): Promise<SleepNowResult>;
51
+ }
52
+ export interface PowerTargetStatus {
53
+ target: PowerTarget;
54
+ replicas: number;
55
+ ready: boolean;
56
+ wokeAt: string | null;
57
+ blockers: string[];
58
+ }
59
+ export interface PowerStatus {
60
+ enabled: boolean;
61
+ targets?: PowerTargetStatus[];
62
+ }
63
+ export interface SleepNowResult {
64
+ slept: PowerTarget[];
65
+ blocked: Array<{
66
+ target: PowerTarget;
67
+ runIds: string[];
68
+ }>;
69
+ }
70
+ export declare const DISABLED_POWER: Power;
71
+ export declare function createPower(options: PowerOptions): Power;
@@ -0,0 +1,202 @@
1
+ import { KubernetesForbiddenError } from "../providers/jobs/kubernetes-api.js";
2
+ import { logger } from "./logger.js";
3
+ const powerLog = logger.child({ module: "power" });
4
+ export const LOW_POWER_WAKE_TIMEOUT = "low_power_wake_timeout";
5
+ export const LOW_POWER_SCALE_FORBIDDEN = "low_power_scale_forbidden";
6
+ export const LOW_POWER_DISABLED = "low_power_disabled";
7
+ /** ISO-8601 time the control plane last scaled the Deployment up from zero. */
8
+ export const POWER_WOKE_AT = "wardby.io/power-woke-at";
9
+ /**
10
+ * The least time a launcher waits for a woken target: a cold node can take a minute or two to
11
+ * come up. A launcher's own ready timeout above this raises the bound.
12
+ */
13
+ export const LOW_POWER_WAKE_FLOOR_MS = 300_000;
14
+ /** How long a launcher with this ready timeout lets ensureAwake wait. */
15
+ export const wakeTimeoutMs = (readyTimeoutMs) => Math.max(readyTimeoutMs, LOW_POWER_WAKE_FLOOR_MS);
16
+ /** sleepIfIdle does real work at most this often. */
17
+ const SLEEP_SWEEP_INTERVAL_MS = 60_000;
18
+ export const DISABLED_POWER = {
19
+ enabled: false,
20
+ async ensureAwake() { },
21
+ async isAsleep() {
22
+ return false;
23
+ },
24
+ async sleepIfIdle() { },
25
+ async checkAccess() {
26
+ return [];
27
+ },
28
+ async status() {
29
+ return { enabled: false };
30
+ },
31
+ async sleepNow() {
32
+ throw new Error(`${LOW_POWER_DISABLED}: WARDBY_LOW_POWER is not 1 on this deployment.`);
33
+ },
34
+ };
35
+ const ready = (ep) => (ep?.subsets ?? []).some((s) => (s.addresses ?? []).length > 0);
36
+ /** Rethrows a Forbidden read or patch as low_power_scale_forbidden; anything else unchanged. */
37
+ function scaleError(error, name, access = "patch Deployment") {
38
+ if (!(error instanceof KubernetesForbiddenError))
39
+ return error;
40
+ return new Error(`${LOW_POWER_SCALE_FORBIDDEN}: the control plane may not ${access} "${name}"; apply the wardby-power Role (up.sh with WARDBY_LOW_POWER=1).`, { cause: error });
41
+ }
42
+ export function createPower(options) {
43
+ if (!options.config.enabled)
44
+ return DISABLED_POWER;
45
+ const { api, namespace, deployments } = options;
46
+ if (!api)
47
+ throw new Error("Low-power mode needs a Kubernetes API client.");
48
+ const now = options.now ?? (() => new Date());
49
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
50
+ const pollMs = options.pollMs ?? 2000;
51
+ const { busy, blockers } = options;
52
+ const idleMinutes = options.config.idleMinutes;
53
+ const idleMs = idleMinutes * 60_000;
54
+ // The idle window counts from the later of the Deployment's woke-at stamp and this process's
55
+ // start: a stamp left from before a restart (or none at all) never sleeps a target sooner.
56
+ const startedAt = now().getTime();
57
+ let lastSweep;
58
+ const readDeployment = async (name) => {
59
+ try {
60
+ return await api.readDeployment(namespace, name);
61
+ }
62
+ catch (error) {
63
+ throw scaleError(error, name, "get Deployment");
64
+ }
65
+ };
66
+ const readEndpoints = async (name) => {
67
+ try {
68
+ return await api.readEndpoints(namespace, name);
69
+ }
70
+ catch (error) {
71
+ throw scaleError(error, name, "get Endpoints");
72
+ }
73
+ };
74
+ async function sleepTarget(target, at) {
75
+ if (!api || !busy)
76
+ return;
77
+ const name = deployments[target];
78
+ const dep = await readDeployment(name);
79
+ if (!dep || (dep.spec?.replicas ?? 1) === 0)
80
+ return;
81
+ const stamped = Date.parse(dep.metadata?.annotations?.[POWER_WOKE_AT] ?? "");
82
+ const wokeAt = Number.isNaN(stamped) ? startedAt : Math.max(stamped, startedAt);
83
+ if (at - wokeAt < idleMs)
84
+ return;
85
+ const since = new Date(at - idleMs);
86
+ if (await busy(target, since))
87
+ return;
88
+ // A run may have started since the first check; look again right before scaling down.
89
+ if (await busy(target, since))
90
+ return;
91
+ await api.patchDeployment(namespace, name, { replicas: 0 });
92
+ powerLog.info({ target }, `power: ${target} slept (idle ${idleMinutes}m)`);
93
+ }
94
+ return {
95
+ enabled: true,
96
+ async ensureAwake(target, { timeoutMs, runId }) {
97
+ const name = deployments[target];
98
+ const dep = await readDeployment(name);
99
+ if (!dep)
100
+ throw new Error(`${LOW_POWER_WAKE_TIMEOUT}: Deployment "${name}" not found in "${namespace}".`);
101
+ if ((dep.spec?.replicas ?? 1) === 0) {
102
+ try {
103
+ await api.patchDeployment(namespace, name, {
104
+ replicas: 1,
105
+ annotations: { [POWER_WOKE_AT]: now().toISOString() },
106
+ });
107
+ }
108
+ catch (error) {
109
+ throw scaleError(error, name);
110
+ }
111
+ powerLog.info({ target, runId }, `power: ${target} woke`);
112
+ }
113
+ const deadline = now().getTime() + timeoutMs;
114
+ while (!ready(await readEndpoints(name))) {
115
+ if (now().getTime() >= deadline) {
116
+ throw new Error(`${LOW_POWER_WAKE_TIMEOUT}: ${target} "${name}" had no ready endpoint within ${timeoutMs} ms.`);
117
+ }
118
+ await sleep(pollMs);
119
+ }
120
+ },
121
+ async isAsleep(target) {
122
+ return ((await readDeployment(deployments[target]))?.spec?.replicas ?? 1) === 0;
123
+ },
124
+ async sleepIfIdle() {
125
+ const at = now().getTime();
126
+ if (lastSweep !== undefined && at - lastSweep < SLEEP_SWEEP_INTERVAL_MS)
127
+ return;
128
+ lastSweep = at;
129
+ for (const target of Object.keys(deployments)) {
130
+ try {
131
+ await sleepTarget(target, at);
132
+ }
133
+ catch (err) {
134
+ powerLog.warn({ err, target }, "power_sleep_failed");
135
+ }
136
+ }
137
+ },
138
+ async status() {
139
+ const targets = [];
140
+ for (const target of Object.keys(deployments)) {
141
+ const name = deployments[target];
142
+ const dep = await readDeployment(name);
143
+ if (!dep)
144
+ continue;
145
+ targets.push({
146
+ target,
147
+ replicas: dep.spec?.replicas ?? 1,
148
+ ready: ready(await readEndpoints(name)),
149
+ wokeAt: dep.metadata?.annotations?.[POWER_WOKE_AT] ?? null,
150
+ blockers: blockers ? await blockers(target) : [],
151
+ });
152
+ }
153
+ return { enabled: true, targets };
154
+ },
155
+ async sleepNow(targets) {
156
+ // Without a blockers check this could scale a target out from under a run.
157
+ if (!blockers)
158
+ throw new Error("power: sleepNow needs a blockers check.");
159
+ const result = { slept: [], blocked: [] };
160
+ for (const target of targets) {
161
+ const name = deployments[target];
162
+ const dep = await readDeployment(name);
163
+ if (!dep)
164
+ continue;
165
+ if ((dep.spec?.replicas ?? 1) === 0) {
166
+ result.slept.push(target);
167
+ continue;
168
+ }
169
+ let runIds = await blockers(target);
170
+ // A run may have started since the first check; look again right before scaling down.
171
+ if (runIds.length === 0)
172
+ runIds = await blockers(target);
173
+ if (runIds.length > 0) {
174
+ result.blocked.push({ target, runIds });
175
+ continue;
176
+ }
177
+ try {
178
+ await api.patchDeployment(namespace, name, { replicas: 0 });
179
+ }
180
+ catch (error) {
181
+ throw scaleError(error, name);
182
+ }
183
+ powerLog.info({ target }, `power: ${target} slept (forced)`);
184
+ result.slept.push(target);
185
+ }
186
+ return result;
187
+ },
188
+ async checkAccess() {
189
+ const missing = [];
190
+ for (const name of Object.values(deployments)) {
191
+ for (const verb of ["get", "patch"]) {
192
+ if (!(await api.canI(namespace, verb, "apps", "deployments", name)))
193
+ missing.push(`${verb} deployments/${name}`);
194
+ }
195
+ // ensureAwake and status poll the Service's Endpoints (same name as the Deployment).
196
+ if (!(await api.canI(namespace, "get", "", "endpoints", name)))
197
+ missing.push(`get endpoints/${name}`);
198
+ }
199
+ return missing;
200
+ },
201
+ };
202
+ }
@@ -6,8 +6,8 @@ export const PR_STATE_SYNC_BATCH = 10;
6
6
  /** A row is re-checked at most this often. */
7
7
  export const PR_STATE_SYNC_MIN_AGE_MS = 10 * 60_000;
8
8
  export async function syncOpenPullRequestStates(db, hosts, trackers, now = new Date()) {
9
- // handlePullRequestClosed needs trackers; without them no IssuePullRequest rows are written anyway.
10
- if (!hosts || !trackers)
9
+ // Without trackers the rows (a GitHub issue's, say) are still settled; only tracker actions are skipped.
10
+ if (!hosts)
11
11
  return 0;
12
12
  let settled = 0;
13
13
  try {
@@ -36,15 +36,18 @@
36
36
  * it also catches a run that ended before its comment was posted.
37
37
  *
38
38
  * Given host-event deps, each pass also starts reviews deferred until CI
39
- * finished (waitForCi links) whose CI has not finished in time, and drops
40
- * deferred reviews that are too old (host-events.ts startDeferredReviews).
39
+ * finished (waitForCi links) whose CI has not finished in time, releases
40
+ * reviews that waited for a delegating run that ended without its finalizer
41
+ * (lost, including leads this pass just marked lost), and drops deferred
42
+ * reviews that are too old (host-events.ts startDeferredReviews).
41
43
  */
42
44
  import type { PrismaClient } from "#prisma";
43
45
  import type { Executor } from "../providers/executor/types.js";
44
46
  import type { ReviewHostRegistry } from "../providers/review-host/types.js";
45
47
  import type { IssueTrackerRegistry } from "../providers/issue-tracker/types.js";
48
+ import { type HostStatusDb } from "./host-status.js";
46
49
  import { type ReviewStartDeps } from "./host-events.js";
47
- export type ReconcilerDb = Pick<PrismaClient, "run" | "runHostCheck" | "runHostStatus" | "runIssueStatus" | "agentIssueProject" | "issuePullRequest" | "codingRun" | "agent" | "$transaction" | "$queryRaw">;
50
+ export type ReconcilerDb = Pick<PrismaClient, "run" | "runHostCheck" | "runBudgetEvent" | "runHostStatus" | "runIssueStatus" | "agentIssueProject" | "issuePullRequest" | "codingRun" | "registryFetch" | "registryAuditRecord" | "agent" | "agentRepository" | "$transaction" | "$queryRaw">;
48
51
  /**
49
52
  * How long after a run finishes before its still-open check counts as
50
53
  * orphaned: long enough that the sweep never races `executeRun`'s own
@@ -64,14 +67,14 @@ export declare const ORPHANED_CHECK_MAX_AGE_MS: number;
64
67
  * than retried forever; its Re-run button still works. Never queries when
65
68
  * no host is configured. `closeOpenHostCheck` is best-effort and never throws.
66
69
  */
67
- export declare function closeOrphanedHostChecks(db: Pick<PrismaClient, "runHostCheck" | "run">, hosts: ReviewHostRegistry | undefined, now?: Date): Promise<void>;
70
+ export declare function closeOrphanedHostChecks(db: Pick<PrismaClient, "runHostCheck" | "run" | "runBudgetEvent">, hosts: ReviewHostRegistry | undefined, now?: Date): Promise<void>;
68
71
  /**
69
72
  * Completes open mention status comments on the same terms as
70
73
  * closeOrphanedHostChecks: the run ended between ORPHANED_CHECK_GRACE_MS and
71
74
  * ORPHANED_CHECK_MAX_AGE_MS ago, newest first, at most ORPHANED_CHECK_BATCH per
72
75
  * pass. `completeHostStatus` is best-effort and never throws.
73
76
  */
74
- export declare function closeOrphanedHostStatuses(db: Pick<PrismaClient, "runHostStatus" | "run">, hosts: ReviewHostRegistry | undefined, now?: Date): Promise<void>;
77
+ export declare function closeOrphanedHostStatuses(db: HostStatusDb, hosts: ReviewHostRegistry | undefined, now?: Date): Promise<void>;
75
78
  /** Runs one reconciliation pass. Returns the number of runs marked `lost`. */
76
79
  export declare function reconcileOnce(db: ReconcilerDb, now?: Date, heartbeatTimeoutMs?: number, executor?: Executor, reviewHosts?: ReviewHostRegistry, issueTrackers?: IssueTrackerRegistry,
77
80
  /** What starting a deferred review needs; absent = no deferred-review sweep. */
@@ -36,17 +36,22 @@
36
36
  * it also catches a run that ended before its comment was posted.
37
37
  *
38
38
  * Given host-event deps, each pass also starts reviews deferred until CI
39
- * finished (waitForCi links) whose CI has not finished in time, and drops
40
- * deferred reviews that are too old (host-events.ts startDeferredReviews).
39
+ * finished (waitForCi links) whose CI has not finished in time, releases
40
+ * reviews that waited for a delegating run that ended without its finalizer
41
+ * (lost, including leads this pass just marked lost), and drops deferred
42
+ * reviews that are too old (host-events.ts startDeferredReviews).
41
43
  */
42
44
  import { HEARTBEAT_TIMEOUT_MS, RECONCILE_INTERVAL_MS } from "./timing.js";
43
45
  import { prisma as defaultDb } from "./db.js";
44
46
  import { logger } from "./logger.js";
47
+ import { stopChildrenOfLostRun } from "./lost-run-children.js";
45
48
  import { closeOpenHostCheck } from "./review-host-checks.js";
46
49
  import { completeHostStatus } from "./host-status.js";
47
50
  import { closeOrphanedIssueStatuses } from "./issue-status.js";
48
51
  import { fileSelfDefect } from "./self-defects.js";
52
+ import { emitRunFinishedEvents } from "./workflow-run-events.js";
49
53
  import { syncOpenPullRequestStates } from "./pull-request-state-sync.js";
54
+ import { sweepMergeOrderChecks } from "./merge-order-check.js";
50
55
  import { startDeferredReviews } from "./host-events.js";
51
56
  const reconcilerLog = logger.child({ module: "reconciler" });
52
57
  /** A pass waits this long per self-defect, then moves on; the filing finishes (or logs) in the background. */
@@ -206,7 +211,11 @@ deferredReviews) {
206
211
  continue;
207
212
  let recovered;
208
213
  try {
209
- recovered = await executor.recover({ runId: run.id, backend: run.executionBackend, id: run.id });
214
+ recovered = await executor.recover({
215
+ runId: run.id,
216
+ backend: run.executionBackend,
217
+ id: run.executionWorkflowId ?? run.id,
218
+ });
210
219
  }
211
220
  catch (err) {
212
221
  reconcilerLog.error({ err, runId: run.id }, "durable run recovery failed");
@@ -220,8 +229,17 @@ deferredReviews) {
220
229
  data: { status: "lost", error: reason, finishedAt: now },
221
230
  });
222
231
  lost += result.count;
223
- if (result.count > 0)
232
+ if (result.count > 0) {
233
+ await stopChildrenOfLostRun(db, executor, run.id);
224
234
  await fileSelfDefect(db, issueTrackers, { ...run, status: "lost", error: reason, finishedAt: now }, SELF_DEFECT_WAIT);
235
+ await emitRunFinishedEvents(db, {
236
+ id: run.id,
237
+ agentId: run.agentId,
238
+ status: "lost",
239
+ error: reason,
240
+ parentRunId: run.parentRunId,
241
+ });
242
+ }
225
243
  continue;
226
244
  }
227
245
  const result = await db.run.updateMany({
@@ -230,17 +248,30 @@ deferredReviews) {
230
248
  });
231
249
  lost += result.count;
232
250
  // Only after this pass made the row lost (not when another instance won the race); bounded, never throws.
233
- if (result.count > 0)
251
+ if (result.count > 0) {
252
+ await stopChildrenOfLostRun(db, executor, run.id);
234
253
  await fileSelfDefect(db, issueTrackers, { ...run, status: "lost", error: reason, finishedAt: now }, SELF_DEFECT_WAIT);
254
+ await emitRunFinishedEvents(db, {
255
+ id: run.id,
256
+ agentId: run.agentId,
257
+ status: "lost",
258
+ error: reason,
259
+ parentRunId: run.parentRunId,
260
+ });
261
+ }
235
262
  }
236
263
  await closeOrphanedHostChecks(db, reviewHosts, now);
237
264
  await closeOrphanedHostStatuses(db, reviewHosts, now);
238
265
  await closeOrphanedIssueStatuses(db, issueTrackers, now);
239
266
  // Settle stored pull requests whose merge/close webhook was missed; bounded per pass, never throws.
240
267
  await syncOpenPullRequestStates(db, reviewHosts, issueTrackers, now);
241
- // Start reviews whose head's CI never finished (waitForCi links); bounded per pass, never throws.
268
+ // Start reviews whose head's CI never finished (waitForCi links), and reviews whose delegating run
269
+ // ended without releasing them (after the lost marking above); bounded per pass, never throws.
242
270
  if (deferredReviews)
243
271
  await startDeferredReviews(deferredReviews, now);
272
+ // Re-post `wardby merge order` checks whose pr_closed or new-head event was missed; after the
273
+ // deferred-review start, so no review waits on it. Throttled and bounded per pass, never throws.
274
+ await sweepMergeOrderChecks({ db, hosts: reviewHosts }, now);
244
275
  return lost;
245
276
  }
246
277
  export function startReconciler(options = {}) {