@wardby/cli 0.2.1 → 0.4.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 (555) hide show
  1. package/.env.example +53 -4
  2. package/README.md +52 -13
  3. package/dist/claude-coding-worker/driver.d.ts +6 -1
  4. package/dist/claude-coding-worker/driver.js +27 -1
  5. package/dist/claude-coding-worker/main.js +2 -0
  6. package/dist/claude-coding-worker/tool-socket.d.ts +9 -0
  7. package/dist/claude-coding-worker/tool-socket.js +26 -0
  8. package/dist/cli-help.d.ts +1 -1
  9. package/dist/cli-help.js +14 -4
  10. package/dist/cli.d.ts +1 -1
  11. package/dist/cli.js +284 -36
  12. package/dist/coding/base-commit.d.ts +6 -0
  13. package/dist/coding/base-commit.js +12 -0
  14. package/dist/coding/collect-exclude.d.ts +25 -0
  15. package/dist/coding/collect-exclude.js +76 -0
  16. package/dist/coding/profile.d.ts +67 -22
  17. package/dist/coding/profile.js +58 -25
  18. package/dist/coding/protected-path-wording.d.ts +24 -0
  19. package/dist/coding/protected-path-wording.js +55 -0
  20. package/dist/coding/protected-paths.d.ts +31 -0
  21. package/dist/coding/protected-paths.js +48 -0
  22. package/dist/coding/protocol.d.ts +91 -4
  23. package/dist/coding/protocol.js +123 -12
  24. package/dist/coding/provider.d.ts +6 -1
  25. package/dist/coding/provider.js +16 -9
  26. package/dist/coding/registry/adapters.d.ts +2 -0
  27. package/dist/coding/registry/adapters.js +9 -0
  28. package/dist/coding/registry/allowlist.d.ts +9 -0
  29. package/dist/coding/registry/allowlist.js +28 -0
  30. package/dist/coding/registry/json-scan.d.ts +55 -0
  31. package/dist/coding/registry/json-scan.js +191 -0
  32. package/dist/coding/registry/lockfiles.d.ts +6 -0
  33. package/dist/coding/registry/lockfiles.js +89 -0
  34. package/dist/coding/registry/npm-lockfile.d.ts +9 -0
  35. package/dist/coding/registry/npm-lockfile.js +73 -0
  36. package/dist/coding/registry/npm-plan.d.ts +29 -0
  37. package/dist/coding/registry/npm-plan.js +289 -0
  38. package/dist/coding/registry/npm.d.ts +7 -0
  39. package/dist/coding/registry/npm.js +252 -0
  40. package/dist/coding/registry/pypi.d.ts +4 -0
  41. package/dist/coding/registry/pypi.js +210 -0
  42. package/dist/coding/registry/report.d.ts +37 -0
  43. package/dist/coding/registry/report.js +31 -0
  44. package/dist/coding/registry/token.d.ts +4 -0
  45. package/dist/coding/registry/token.js +7 -0
  46. package/dist/coding/registry/types.d.ts +286 -0
  47. package/dist/coding/registry/types.js +19 -0
  48. package/dist/coding/registry/worker-config.d.ts +14 -0
  49. package/dist/coding/registry/worker-config.js +31 -0
  50. package/dist/coding/services/builtins.d.ts +22 -0
  51. package/dist/coding/services/builtins.js +85 -0
  52. package/dist/coding/services/catalog.d.ts +443 -0
  53. package/dist/coding/services/catalog.js +159 -0
  54. package/dist/coding/services/declaration.d.ts +11 -0
  55. package/dist/coding/services/declaration.js +114 -0
  56. package/dist/coding/services/note.d.ts +8 -0
  57. package/dist/coding/services/note.js +15 -0
  58. package/dist/coding/services/resolve.d.ts +25 -0
  59. package/dist/coding/services/resolve.js +50 -0
  60. package/dist/coding/services/wording.d.ts +25 -0
  61. package/dist/coding/services/wording.js +70 -0
  62. package/dist/coding-proxy/main.js +24 -4
  63. package/dist/coding-worker/artifact.d.ts +6 -0
  64. package/dist/coding-worker/debug-trace.d.ts +37 -0
  65. package/dist/coding-worker/debug-trace.js +117 -0
  66. package/dist/coding-worker/driver.d.ts +13 -1
  67. package/dist/coding-worker/driver.js +102 -13
  68. package/dist/coding-worker/errors.js +8 -0
  69. package/dist/coding-worker/main.js +10 -2
  70. package/dist/coding-worker/sdk.d.ts +2 -2
  71. package/dist/coding-worker/sdk.js +7 -2
  72. package/dist/coding-worker/types.d.ts +3 -0
  73. package/dist/config/providers.d.ts +66 -0
  74. package/dist/config/providers.js +137 -0
  75. package/dist/core/attribution.d.ts +101 -0
  76. package/dist/core/attribution.js +208 -0
  77. package/dist/core/budget-groups.d.ts +120 -10
  78. package/dist/core/budget-groups.js +133 -24
  79. package/dist/core/budget-wording.d.ts +22 -0
  80. package/dist/core/budget-wording.js +55 -0
  81. package/dist/core/coding-queue.d.ts +3 -0
  82. package/dist/core/coding-queue.js +6 -2
  83. package/dist/core/coding-service-status.d.ts +11 -0
  84. package/dist/core/coding-service-status.js +17 -0
  85. package/dist/core/cost-report.d.ts +88 -0
  86. package/dist/core/cost-report.js +248 -0
  87. package/dist/core/datastores.js +18 -2
  88. package/dist/core/db.d.ts +5 -1
  89. package/dist/core/db.js +8 -2
  90. package/dist/core/dispatch.d.ts +74 -7
  91. package/dist/core/dispatch.js +382 -47
  92. package/dist/core/engine-native.js +44 -14
  93. package/dist/core/glob.d.ts +10 -0
  94. package/dist/core/glob.js +33 -0
  95. package/dist/core/grants.d.ts +86 -0
  96. package/dist/core/grants.js +126 -0
  97. package/dist/core/host-events.d.ts +72 -0
  98. package/dist/core/host-events.js +597 -0
  99. package/dist/core/host-identity-links.d.ts +54 -0
  100. package/dist/core/host-identity-links.js +189 -0
  101. package/dist/core/host-status.d.ts +78 -0
  102. package/dist/core/host-status.js +228 -0
  103. package/dist/core/in-flight-runs.d.ts +8 -0
  104. package/dist/core/in-flight-runs.js +56 -0
  105. package/dist/core/issue-bridge.d.ts +60 -0
  106. package/dist/core/issue-bridge.js +189 -0
  107. package/dist/core/issue-dedupe.d.ts +70 -0
  108. package/dist/core/issue-dedupe.js +255 -0
  109. package/dist/core/issue-events.d.ts +42 -0
  110. package/dist/core/issue-events.js +155 -0
  111. package/dist/core/issue-status.d.ts +29 -0
  112. package/dist/core/issue-status.js +241 -0
  113. package/dist/core/issue-tracker-tools.d.ts +64 -0
  114. package/dist/core/issue-tracker-tools.js +850 -0
  115. package/dist/core/model-usage.d.ts +10 -0
  116. package/dist/core/model-usage.js +24 -0
  117. package/dist/core/provider-wording.d.ts +12 -0
  118. package/dist/core/provider-wording.js +44 -0
  119. package/dist/core/reconciler.d.ts +42 -2
  120. package/dist/core/reconciler.js +97 -2
  121. package/dist/core/repo-access.d.ts +99 -0
  122. package/dist/core/repo-access.js +136 -0
  123. package/dist/core/review-host-checks.d.ts +11 -0
  124. package/dist/core/review-host-checks.js +41 -0
  125. package/dist/core/review-host-tools.d.ts +47 -0
  126. package/dist/core/review-host-tools.js +354 -0
  127. package/dist/core/run-heartbeat.d.ts +27 -0
  128. package/dist/core/run-heartbeat.js +54 -0
  129. package/dist/core/run-pricing.d.ts +61 -0
  130. package/dist/core/run-pricing.js +56 -0
  131. package/dist/core/runner.d.ts +33 -8
  132. package/dist/core/runner.js +410 -62
  133. package/dist/core/scheduler.d.ts +4 -1
  134. package/dist/core/scheduler.js +3 -2
  135. package/dist/core/secrets.d.ts +11 -2
  136. package/dist/core/secrets.js +25 -6
  137. package/dist/core/self-defects.d.ts +80 -0
  138. package/dist/core/self-defects.js +180 -0
  139. package/dist/core/subagent-memory-tools.d.ts +1 -1
  140. package/dist/core/subagent-memory-tools.js +16 -3
  141. package/dist/core/tool-admin.d.ts +81 -0
  142. package/dist/core/tool-admin.js +129 -0
  143. package/dist/core/tool-names.d.ts +42 -0
  144. package/dist/core/tool-names.js +67 -0
  145. package/dist/core/untrusted-content.d.ts +32 -0
  146. package/dist/core/untrusted-content.js +72 -0
  147. package/dist/core/webhooks.d.ts +17 -2
  148. package/dist/core/webhooks.js +42 -3
  149. package/dist/generated/prisma/browser.d.ts +166 -0
  150. package/dist/generated/prisma/client.d.ts +166 -0
  151. package/dist/generated/prisma/commonInputTypes.d.ts +152 -52
  152. package/dist/generated/prisma/enums.d.ts +13 -0
  153. package/dist/generated/prisma/enums.js +12 -1
  154. package/dist/generated/prisma/internal/class.d.ts +242 -0
  155. package/dist/generated/prisma/internal/class.js +4 -4
  156. package/dist/generated/prisma/internal/prismaNamespace.d.ts +2571 -577
  157. package/dist/generated/prisma/internal/prismaNamespace.js +312 -6
  158. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +328 -0
  159. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +312 -6
  160. package/dist/generated/prisma/models/Agent.d.ts +682 -1
  161. package/dist/generated/prisma/models/AgentIssueProject.d.ts +1838 -0
  162. package/dist/generated/prisma/models/AgentIssueProject.js +1 -0
  163. package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
  164. package/dist/generated/prisma/models/AgentRepository.js +1 -0
  165. package/dist/generated/prisma/models/AgentTool.d.ts +95 -1
  166. package/dist/generated/prisma/models/AuthUser.d.ts +56 -1
  167. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +258 -7
  168. package/dist/generated/prisma/models/CodingProxySession.d.ts +195 -2
  169. package/dist/generated/prisma/models/CodingRun.d.ts +1405 -95
  170. package/dist/generated/prisma/models/CodingRunServiceStatus.d.ts +1404 -0
  171. package/dist/generated/prisma/models/CodingRunServiceStatus.js +1 -0
  172. package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
  173. package/dist/generated/prisma/models/CodingService.js +1 -0
  174. package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
  175. package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
  176. package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
  177. package/dist/generated/prisma/models/HostIdentity.js +1 -0
  178. package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
  179. package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
  180. package/dist/generated/prisma/models/IssueFingerprint.d.ts +1183 -0
  181. package/dist/generated/prisma/models/IssueFingerprint.js +1 -0
  182. package/dist/generated/prisma/models/IssuePullRequest.d.ts +1255 -0
  183. package/dist/generated/prisma/models/IssuePullRequest.js +1 -0
  184. package/dist/generated/prisma/models/ModelCatalogEntry.d.ts +1322 -0
  185. package/dist/generated/prisma/models/ModelCatalogEntry.js +1 -0
  186. package/dist/generated/prisma/models/Principal.d.ts +455 -0
  187. package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
  188. package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
  189. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
  190. package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
  191. package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
  192. package/dist/generated/prisma/models/RegistryFetch.js +1 -0
  193. package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
  194. package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
  195. package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
  196. package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
  197. package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
  198. package/dist/generated/prisma/models/ResourceGrant.js +1 -0
  199. package/dist/generated/prisma/models/Run.d.ts +1402 -82
  200. package/dist/generated/prisma/models/RunAttribution.d.ts +1259 -0
  201. package/dist/generated/prisma/models/RunAttribution.js +1 -0
  202. package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
  203. package/dist/generated/prisma/models/RunHostCheck.js +1 -0
  204. package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
  205. package/dist/generated/prisma/models/RunHostStatus.js +1 -0
  206. package/dist/generated/prisma/models/RunIssueStatus.d.ts +1199 -0
  207. package/dist/generated/prisma/models/RunIssueStatus.js +1 -0
  208. package/dist/generated/prisma/models/RunModelUsage.d.ts +1316 -0
  209. package/dist/generated/prisma/models/RunModelUsage.js +1 -0
  210. package/dist/generated/prisma/models/Tool.d.ts +15 -3
  211. package/dist/generated/prisma/models/WorkItem.d.ts +1408 -0
  212. package/dist/generated/prisma/models/WorkItem.js +1 -0
  213. package/dist/generated/prisma/models.d.ts +22 -0
  214. package/dist/help/build.d.ts +1 -0
  215. package/dist/help/build.js +9 -0
  216. package/dist/help/catalog.d.ts +24 -0
  217. package/dist/help/catalog.js +160 -0
  218. package/dist/help/cli.d.ts +2 -0
  219. package/dist/help/cli.js +65 -0
  220. package/dist/help/runtime.d.ts +3 -0
  221. package/dist/help/runtime.js +44 -0
  222. package/dist/help/search.d.ts +9 -0
  223. package/dist/help/search.js +104 -0
  224. package/dist/help-index.json +999 -0
  225. package/dist/import/cli-args.js +3 -2
  226. package/dist/import/create.d.ts +5 -0
  227. package/dist/import/create.js +67 -13
  228. package/dist/import/index.js +19 -9
  229. package/dist/import/neutral-schema.d.ts +18 -18
  230. package/dist/knowledge/check.d.ts +13 -0
  231. package/dist/knowledge/check.js +69 -0
  232. package/dist/knowledge/cli.d.ts +14 -0
  233. package/dist/knowledge/cli.js +67 -0
  234. package/dist/knowledge/concept.d.ts +54 -0
  235. package/dist/knowledge/concept.js +78 -0
  236. package/dist/knowledge/note.d.ts +11 -0
  237. package/dist/knowledge/note.js +39 -0
  238. package/dist/knowledge/relevance.d.ts +11 -0
  239. package/dist/knowledge/relevance.js +14 -0
  240. package/dist/knowledge/span-hash.d.ts +3 -0
  241. package/dist/knowledge/span-hash.js +16 -0
  242. package/dist/mcp/auth/access.d.ts +72 -0
  243. package/dist/mcp/auth/access.js +58 -0
  244. package/dist/mcp/auth/grants-cli.d.ts +149 -0
  245. package/dist/mcp/auth/grants-cli.js +518 -0
  246. package/dist/mcp/auth/host-account-cli.d.ts +2 -0
  247. package/dist/mcp/auth/host-account-cli.js +47 -0
  248. package/dist/mcp/auth/ownership.d.ts +25 -51
  249. package/dist/mcp/auth/ownership.js +19 -14
  250. package/dist/mcp/auth/repo-authorization.d.ts +22 -0
  251. package/dist/mcp/auth/repo-authorization.js +51 -0
  252. package/dist/mcp/auth/resource-server.d.ts +33 -2
  253. package/dist/mcp/auth/resource-server.js +99 -3
  254. package/dist/mcp/auth/self-hosted/browser.js +2 -2
  255. package/dist/mcp/auth/self-hosted/cli.js +47 -13
  256. package/dist/mcp/auth/self-hosted/credentials.d.ts +23 -5
  257. package/dist/mcp/auth/self-hosted/credentials.js +62 -4
  258. package/dist/mcp/auth/self-hosted/session.d.ts +7 -6
  259. package/dist/mcp/context.d.ts +30 -1
  260. package/dist/mcp/errors.d.ts +25 -6
  261. package/dist/mcp/errors.js +98 -0
  262. package/dist/mcp/host-events/deliveries.d.ts +9 -0
  263. package/dist/mcp/host-events/deliveries.js +17 -0
  264. package/dist/mcp/host-events/github-ingress.d.ts +38 -0
  265. package/dist/mcp/host-events/github-ingress.js +83 -0
  266. package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
  267. package/dist/mcp/host-events/github-user-callback.js +50 -0
  268. package/dist/mcp/host-events/jira-ingress.d.ts +29 -0
  269. package/dist/mcp/host-events/jira-ingress.js +92 -0
  270. package/dist/mcp/index.d.ts +10 -1
  271. package/dist/mcp/index.js +187 -19
  272. package/dist/mcp/server.js +32 -11
  273. package/dist/mcp/tools/agents.js +519 -50
  274. package/dist/mcp/tools/budget-groups.js +3 -3
  275. package/dist/mcp/tools/cost-report.d.ts +8 -0
  276. package/dist/mcp/tools/cost-report.js +60 -0
  277. package/dist/mcp/tools/datastore.js +22 -15
  278. package/dist/mcp/tools/grants.d.ts +2 -0
  279. package/dist/mcp/tools/grants.js +239 -0
  280. package/dist/mcp/tools/help.d.ts +5 -0
  281. package/dist/mcp/tools/help.js +67 -0
  282. package/dist/mcp/tools/host-accounts.d.ts +2 -0
  283. package/dist/mcp/tools/host-accounts.js +114 -0
  284. package/dist/mcp/tools/issue-projects.d.ts +2 -0
  285. package/dist/mcp/tools/issue-projects.js +238 -0
  286. package/dist/mcp/tools/memory.d.ts +7 -1
  287. package/dist/mcp/tools/memory.js +5 -5
  288. package/dist/mcp/tools/model-catalog.d.ts +22 -0
  289. package/dist/mcp/tools/model-catalog.js +423 -0
  290. package/dist/mcp/tools/repositories.d.ts +2 -0
  291. package/dist/mcp/tools/repositories.js +182 -0
  292. package/dist/mcp/tools/runs.d.ts +6 -0
  293. package/dist/mcp/tools/runs.js +60 -6
  294. package/dist/mcp/tools/scheduling.js +3 -6
  295. package/dist/mcp/tools/secrets.js +18 -6
  296. package/dist/mcp/tools/services.d.ts +2 -0
  297. package/dist/mcp/tools/services.js +222 -0
  298. package/dist/mcp/tools/subagents.js +52 -16
  299. package/dist/mcp/tools/tools.d.ts +41 -0
  300. package/dist/mcp/tools/tools.js +201 -40
  301. package/dist/mcp/tools/trigger.js +65 -7
  302. package/dist/mcp/tools/webhooks.js +15 -4
  303. package/dist/mcp/transport/streamable-http.d.ts +15 -0
  304. package/dist/mcp/transport/streamable-http.js +55 -3
  305. package/dist/mcp/webhooks/ingress.d.ts +2 -1
  306. package/dist/mcp/webhooks/ingress.js +9 -2
  307. package/dist/providers/auth/delegating.d.ts +19 -0
  308. package/dist/providers/auth/delegating.js +71 -0
  309. package/dist/providers/auth/index.d.ts +2 -0
  310. package/dist/providers/auth/index.js +11 -0
  311. package/dist/providers/auth/self-hosted.d.ts +10 -2
  312. package/dist/providers/auth/self-hosted.js +55 -6
  313. package/dist/providers/auth/types.d.ts +6 -0
  314. package/dist/providers/coding-proxy/memory-ledger.d.ts +4 -1
  315. package/dist/providers/coding-proxy/memory-ledger.js +31 -3
  316. package/dist/providers/coding-proxy/metering.d.ts +6 -1
  317. package/dist/providers/coding-proxy/metering.js +41 -4
  318. package/dist/providers/coding-proxy/prisma-ledger.d.ts +17 -0
  319. package/dist/providers/coding-proxy/prisma-ledger.js +106 -8
  320. package/dist/providers/coding-proxy/proxy.d.ts +25 -2
  321. package/dist/providers/coding-proxy/proxy.js +561 -38
  322. package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
  323. package/dist/providers/coding-proxy/registry/audit.js +380 -0
  324. package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
  325. package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
  326. package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
  327. package/dist/providers/coding-proxy/registry/plan.js +304 -0
  328. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
  329. package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
  330. package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
  331. package/dist/providers/coding-proxy/registry/service.js +1137 -0
  332. package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
  333. package/dist/providers/coding-proxy/registry/store.js +70 -0
  334. package/dist/providers/coding-proxy/runtime.d.ts +17 -0
  335. package/dist/providers/coding-proxy/runtime.js +63 -0
  336. package/dist/providers/coding-proxy/secure-fetch.js +0 -1
  337. package/dist/providers/coding-proxy/server.d.ts +11 -0
  338. package/dist/providers/coding-proxy/server.js +163 -0
  339. package/dist/providers/coding-proxy/types.d.ts +33 -1
  340. package/dist/providers/coding-proxy/types.js +12 -1
  341. package/dist/providers/engine/types.d.ts +29 -0
  342. package/dist/providers/executor/build.d.ts +2 -2
  343. package/dist/providers/executor/composition.d.ts +3 -0
  344. package/dist/providers/executor/composition.js +28 -1
  345. package/dist/providers/executor/container.d.ts +134 -4
  346. package/dist/providers/executor/container.js +394 -37
  347. package/dist/providers/executor/dbos.d.ts +4 -3
  348. package/dist/providers/executor/dbos.js +7 -5
  349. package/dist/providers/executor/in-process.d.ts +2 -3
  350. package/dist/providers/executor/routing.d.ts +13 -0
  351. package/dist/providers/executor/routing.js +18 -0
  352. package/dist/providers/executor/types.d.ts +34 -0
  353. package/dist/providers/issue-tracker/adf.d.ts +31 -0
  354. package/dist/providers/issue-tracker/adf.js +181 -0
  355. package/dist/providers/issue-tracker/index.d.ts +5 -0
  356. package/dist/providers/issue-tracker/index.js +12 -0
  357. package/dist/providers/issue-tracker/jira-client.d.ts +41 -0
  358. package/dist/providers/issue-tracker/jira-client.js +151 -0
  359. package/dist/providers/issue-tracker/jira-events.d.ts +3 -0
  360. package/dist/providers/issue-tracker/jira-events.js +98 -0
  361. package/dist/providers/issue-tracker/jira.d.ts +116 -0
  362. package/dist/providers/issue-tracker/jira.js +502 -0
  363. package/dist/providers/issue-tracker/types.d.ts +269 -0
  364. package/dist/providers/issue-tracker/types.js +16 -0
  365. package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
  366. package/dist/providers/jobs/claude-tool-setup.js +50 -0
  367. package/dist/providers/jobs/collect-prune.d.ts +7 -0
  368. package/dist/providers/jobs/collect-prune.js +27 -0
  369. package/dist/providers/jobs/docker-isolation.d.ts +48 -3
  370. package/dist/providers/jobs/docker-isolation.js +213 -22
  371. package/dist/providers/jobs/docker-services.d.ts +35 -0
  372. package/dist/providers/jobs/docker-services.js +191 -0
  373. package/dist/providers/jobs/docker.d.ts +53 -2
  374. package/dist/providers/jobs/docker.js +307 -32
  375. package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
  376. package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
  377. package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
  378. package/dist/providers/jobs/kubernetes-isolation.js +238 -57
  379. package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
  380. package/dist/providers/jobs/kubernetes-platform.js +11 -5
  381. package/dist/providers/jobs/kubernetes-preflight.js +3 -0
  382. package/dist/providers/jobs/kubernetes.d.ts +24 -2
  383. package/dist/providers/jobs/kubernetes.js +153 -22
  384. package/dist/providers/jobs/service-state.d.ts +22 -0
  385. package/dist/providers/jobs/service-state.js +17 -0
  386. package/dist/providers/jobs/types.d.ts +18 -0
  387. package/dist/providers/llm/anthropic.d.ts +3 -3
  388. package/dist/providers/llm/anthropic.js +3 -5
  389. package/dist/providers/llm/bedrock.d.ts +3 -3
  390. package/dist/providers/llm/bedrock.js +3 -8
  391. package/dist/providers/llm/catalog-lookup.d.ts +10 -0
  392. package/dist/providers/llm/catalog-lookup.js +15 -0
  393. package/dist/providers/llm/catalog-shipped.d.ts +18 -0
  394. package/dist/providers/llm/catalog-shipped.js +197 -0
  395. package/dist/providers/llm/catalog-store.d.ts +58 -0
  396. package/dist/providers/llm/catalog-store.js +138 -0
  397. package/dist/providers/llm/catalog-types.d.ts +66 -0
  398. package/dist/providers/llm/catalog-types.js +64 -0
  399. package/dist/providers/llm/catalog.d.ts +61 -0
  400. package/dist/providers/llm/catalog.js +147 -0
  401. package/dist/providers/llm/claude-messages.d.ts +5 -1
  402. package/dist/providers/llm/claude-messages.js +1 -0
  403. package/dist/providers/llm/claude-provider.d.ts +10 -12
  404. package/dist/providers/llm/claude-provider.js +15 -6
  405. package/dist/providers/llm/index.d.ts +9 -6
  406. package/dist/providers/llm/index.js +8 -5
  407. package/dist/providers/llm/openai.d.ts +14 -5
  408. package/dist/providers/llm/openai.js +24 -14
  409. package/dist/providers/llm/pricing-core.d.ts +5 -3
  410. package/dist/providers/llm/registration.js +8 -12
  411. package/dist/providers/llm/routing.d.ts +21 -11
  412. package/dist/providers/llm/routing.js +47 -13
  413. package/dist/providers/llm/types.d.ts +12 -0
  414. package/dist/providers/llm/types.js +8 -1
  415. package/dist/providers/review-host/diff-lines.d.ts +16 -0
  416. package/dist/providers/review-host/diff-lines.js +59 -0
  417. package/dist/providers/review-host/github-events.d.ts +6 -0
  418. package/dist/providers/review-host/github-events.js +226 -0
  419. package/dist/providers/review-host/github-user-auth.d.ts +38 -0
  420. package/dist/providers/review-host/github-user-auth.js +128 -0
  421. package/dist/providers/review-host/github.d.ts +57 -0
  422. package/dist/providers/review-host/github.js +568 -0
  423. package/dist/providers/review-host/index.d.ts +12 -0
  424. package/dist/providers/review-host/index.js +30 -0
  425. package/dist/providers/review-host/review-format.d.ts +19 -0
  426. package/dist/providers/review-host/review-format.js +59 -0
  427. package/dist/providers/review-host/types.d.ts +309 -0
  428. package/dist/providers/review-host/types.js +24 -0
  429. package/dist/providers/vcs/git.d.ts +16 -6
  430. package/dist/providers/vcs/git.js +78 -34
  431. package/dist/providers/vcs/github.d.ts +94 -3
  432. package/dist/providers/vcs/github.js +223 -17
  433. package/dist/providers/vcs/types.d.ts +48 -4
  434. package/dist/quickstart/index.d.ts +2 -0
  435. package/dist/quickstart/index.js +36 -8
  436. package/dist/sandbox/fetch-policy.d.ts +20 -2
  437. package/dist/sandbox/fetch-policy.js +64 -3
  438. package/dist/sandbox/host-functions.d.ts +9 -1
  439. package/dist/sandbox/host-functions.js +12 -5
  440. package/dist/serve.js +8 -2
  441. package/dist/viewer/api-schema.d.ts +2757 -0
  442. package/dist/viewer/api-schema.js +165 -0
  443. package/dist/viewer/build-schemas.d.ts +2 -0
  444. package/dist/viewer/build-schemas.js +18 -0
  445. package/dist/viewer/event-bus.d.ts +38 -0
  446. package/dist/viewer/event-bus.js +232 -0
  447. package/dist/viewer/graph.d.ts +40 -0
  448. package/dist/viewer/graph.js +243 -0
  449. package/dist/viewer/http.d.ts +30 -0
  450. package/dist/viewer/http.js +133 -0
  451. package/dist/viewer/run-detail.d.ts +4 -0
  452. package/dist/viewer/run-detail.js +61 -0
  453. package/dist/wardby-bin.js +11 -0
  454. package/docs/README.md +40 -0
  455. package/docs/agent-recipes.md +383 -0
  456. package/docs/architecture-runtime.md +90 -0
  457. package/docs/assets/brand/wardby-icon-512.png +0 -0
  458. package/docs/assets/brand/wardby-icon.svg +16 -0
  459. package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
  460. package/docs/assets/brand/wardby-mascot.png +0 -0
  461. package/docs/assets/brand/wardby-mascot.svg +5 -0
  462. package/docs/assets/wardby-workflow.svg +106 -0
  463. package/docs/code-review-agents.md +508 -0
  464. package/docs/coding-agent-setup.md +175 -0
  465. package/docs/coding-packages.md +455 -0
  466. package/docs/coding-services.md +300 -0
  467. package/docs/coding-worker-byo-images.md +98 -0
  468. package/docs/coding-worker-isolation.md +1068 -0
  469. package/docs/getting-started-gke.md +632 -0
  470. package/docs/getting-started-identity-provider.md +319 -0
  471. package/docs/getting-started.md +147 -0
  472. package/docs/jira-agents.md +649 -0
  473. package/docs/knowledge.md +387 -0
  474. package/docs/models.md +221 -0
  475. package/docs/observability.md +53 -0
  476. package/docs/release-verification.md +66 -0
  477. package/docs/security-deployment.md +667 -0
  478. package/docs/viewer-api.md +142 -0
  479. package/help/admin-viewer.md +39 -0
  480. package/help/agent-recipes.md +173 -0
  481. package/help/architecture-agent.md +189 -0
  482. package/help/builder-agent.md +80 -0
  483. package/help/code-review-agents.md +37 -0
  484. package/help/coding-packages.md +31 -0
  485. package/help/coding-services.md +71 -0
  486. package/help/cost-attribution.md +67 -0
  487. package/help/creating-agents.md +90 -0
  488. package/help/deploy-gke.md +45 -0
  489. package/help/deployment-targets.md +39 -0
  490. package/help/errors/budget-group-exhausted.md +25 -0
  491. package/help/errors/docker-isolation-unsupported.md +26 -0
  492. package/help/errors/model-unavailable.md +63 -0
  493. package/help/errors/protected-path.md +45 -0
  494. package/help/errors/repo-access.md +27 -0
  495. package/help/errors/service-declaration-invalid.md +27 -0
  496. package/help/errors/service-declaration-unavailable.md +25 -0
  497. package/help/errors/service-launcher-unsupported.md +30 -0
  498. package/help/errors/service-not-allowed.md +27 -0
  499. package/help/errors/service-unknown.md +23 -0
  500. package/help/errors/service-unready.md +49 -0
  501. package/help/getting-started.md +32 -0
  502. package/help/github.md +48 -0
  503. package/help/identity-and-access.md +44 -0
  504. package/help/jira.md +135 -0
  505. package/help/knowledge.md +47 -0
  506. package/help/mcp.md +30 -0
  507. package/help/models.md +90 -0
  508. package/help/native-capabilities.md +30 -0
  509. package/help/observability.md +41 -0
  510. package/help/operating-agents.md +36 -0
  511. package/help/security.md +27 -0
  512. package/help/troubleshooting/budgets.md +32 -0
  513. package/help/troubleshooting/coding-workers.md +47 -0
  514. package/help/troubleshooting/repository-access.md +27 -0
  515. package/package.json +14 -3
  516. package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
  517. package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
  518. package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
  519. package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
  520. package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
  521. package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
  522. package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
  523. package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
  524. package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
  525. package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
  526. package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
  527. package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
  528. package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
  529. package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
  530. package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
  531. package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
  532. package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
  533. package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
  534. package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
  535. package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
  536. package/prisma/migrations/20260930000000_jira_issue_projects/migration.sql +34 -0
  537. package/prisma/migrations/20261001000000_jira_phase2_allowlists/migration.sql +3 -0
  538. package/prisma/migrations/20261001010000_jira_link_types_allowlist/migration.sql +2 -0
  539. package/prisma/migrations/20261002000000_jira_coding_bridge/migration.sql +28 -0
  540. package/prisma/migrations/20261002010000_jira_issue_creation/migration.sql +25 -0
  541. package/prisma/migrations/20261003000000_issue_cost_attribution/migration.sql +56 -0
  542. package/prisma/migrations/20261003010000_coding_run_service_status/migration.sql +23 -0
  543. package/prisma/migrations/20261003020000_viewer_notify/migration.sql +54 -0
  544. package/prisma/migrations/20261003030000_viewer_notify_fixes/migration.sql +47 -0
  545. package/prisma/migrations/20261003040000_viewer_indexes/migration.sql +12 -0
  546. package/prisma/migrations/20261004000000_model_catalog/migration.sql +26 -0
  547. package/prisma/schema.prisma +663 -21
  548. package/dist/mcp/tools/models.d.ts +0 -8
  549. package/dist/mcp/tools/models.js +0 -15
  550. package/dist/providers/llm/pricing-anthropic.d.ts +0 -4
  551. package/dist/providers/llm/pricing-anthropic.js +0 -30
  552. package/dist/providers/llm/pricing-bedrock-claude.d.ts +0 -12
  553. package/dist/providers/llm/pricing-bedrock-claude.js +0 -37
  554. package/dist/providers/llm/pricing.d.ts +0 -30
  555. package/dist/providers/llm/pricing.js +0 -74
@@ -1,6 +1,18 @@
1
- import { CODING_PROTOCOL_VERSION, CodingTaskInputSchema, normalizeGitHubRepository, publicCodingRunResult, composeCodingTask, } from "../coding/protocol.js";
2
- import { assertCodingProviderModel } from "../coding/provider.js";
1
+ import { CODING_PROTOCOL_VERSION, CodingTaskInputSchema, normalizeGitHubRepository, normalizeGitRef, publicCodingRunResult, composeCodingTask, } from "../coding/protocol.js";
2
+ import { assertCodingProvider, assertCodingProviderModel } from "../coding/provider.js";
3
+ import { ModelUnavailableError, entryOf } from "../providers/llm/catalog-types.js";
4
+ import { parseAllowedServiceNames, workerServices } from "../coding/services/catalog.js";
5
+ import { MAX_SERVICE_DECLARATION_BYTES, ServiceDeclarationError, parseServiceDeclaration, } from "../coding/services/declaration.js";
6
+ import { servicesInstructionNote } from "../coding/services/note.js";
7
+ import { resolveRunServices } from "../coding/services/resolve.js";
8
+ import { DECLARATION_UNAVAILABLE_SENTENCE, LAUNCHER_UNSUPPORTED_SENTENCE, invalidDeclarationSentence, serviceRefusal, } from "../coding/services/wording.js";
9
+ import { attributeRun } from "./attribution.js";
10
+ import { effectiveBudgetForRun, MIN_RESERVATION_USD } from "./budget-groups.js";
11
+ import { DEFAULT_KNOWLEDGE_BUNDLE_PATH } from "../knowledge/concept.js";
12
+ import { KNOWLEDGE_INDEX_READ_MAX_BYTES, knowledgeSection } from "../knowledge/note.js";
3
13
  import { logger } from "./logger.js";
14
+ import { CodingModelProviderMismatchError, resolveCodingEntry } from "./run-pricing.js";
15
+ import { fileSelfDefectForRun } from "./self-defects.js";
4
16
  const dispatchLog = logger.child({ module: "dispatch" });
5
17
  /** SQLSTATEs worth retrying the persist transaction for: serialization failure, deadlock. */
6
18
  const RETRYABLE_SQLSTATES = new Set(["40001", "40P01"]);
@@ -15,6 +27,10 @@ const RETRYABLE_SQLSTATES = new Set(["40001", "40P01"]);
15
27
  * (Prisma 7) -- Prisma 6's engine put 40001 at meta.code, still accepted;
16
28
  * - at COMMIT (e.g. SSI write skew): an unwrapped DriverAdapterError, no
17
29
  * code or meta, with the SQLSTATE at cause.originalCode.
30
+ * Also a unique violation (P2002) on WorkItem: concurrent first dispatches
31
+ * attributed to one new issue each insert its WorkItem, and Postgres reports
32
+ * the loser as 23505 rather than 40001. The retry finds the committed row.
33
+ * Unique violations on other models are real errors and are not retried.
18
34
  *
19
35
  * @internal Exported only for the real-PostgreSQL tests.
20
36
  */
@@ -24,6 +40,8 @@ export function isSerializationConflict(err) {
24
40
  const candidate = err;
25
41
  if (candidate.code === "P2034")
26
42
  return true;
43
+ if (candidate.code === "P2002")
44
+ return candidate.meta?.modelName === "WorkItem";
27
45
  if (candidate.code === "P2010") {
28
46
  const sqlState = candidate.meta?.driverAdapterError?.cause?.originalCode;
29
47
  return (typeof sqlState === "string" && RETRYABLE_SQLSTATES.has(sqlState)) || candidate.meta?.code === "40001";
@@ -42,8 +60,8 @@ export function isSerializationConflict(err) {
42
60
  * the conditional `updateMany` makes the second call match zero rows rather
43
61
  * than overwrite whatever landed in between.
44
62
  */
45
- export async function markRunFailedFromExecutorError(db, runId, err) {
46
- await db.run.updateMany({
63
+ export async function markRunFailedFromExecutorError(db, runId, err, selfDefects) {
64
+ const updated = await db.run.updateMany({
47
65
  where: { id: runId, status: { in: ["pending", "running"] } },
48
66
  data: {
49
67
  status: "failed",
@@ -51,6 +69,232 @@ export async function markRunFailedFromExecutorError(db, runId, err) {
51
69
  finishedAt: new Date(),
52
70
  },
53
71
  });
72
+ // Only the call that made the row failed files (the duplicate call matches zero rows); bounded, never throws.
73
+ if (updated.count > 0)
74
+ await fileSelfDefectForRun(selfDefects, runId);
75
+ }
76
+ /**
77
+ * The `Run.error` of a coding run refused at dispatch because a budget
78
+ * constraint has nothing left: `budget_group_exhausted:<period>` or
79
+ * `run_tree_exhausted`, then a sentence for people.
80
+ */
81
+ export function budgetExhaustedError(constraint) {
82
+ if (constraint === "run-tree") {
83
+ return "run_tree_exhausted: the run tree's shared budget is spent; the run was not started.";
84
+ }
85
+ return (`budget_group_exhausted:${constraint}: the agent's budget group has no ${constraint} budget left ` +
86
+ "(recorded spend plus live in-flight runs' holds have reached its cap); the run was not started.");
87
+ }
88
+ /**
89
+ * Serializes grouped coding dispatches (security review I1). Under
90
+ * Serializable, a row lock taken after the transaction's first read cannot
91
+ * queue anything: the snapshot is already fixed, so each waiter wakes up
92
+ * with a stale view and aborts. LOCK TABLE is the one statement that takes
93
+ * no snapshot, so as the transaction's first statement it makes a waiter's
94
+ * snapshot start only after the previous holder committed. SHARE ROW
95
+ * EXCLUSIVE conflicts with itself and with writes to BudgetGroup rows, but not
96
+ * with the ROW SHARE that foreign-key checks from Agent take, so attaching
97
+ * agents to groups is not blocked. It serializes grouped coding dispatches
98
+ * across all groups; each holds it only for one short transaction.
99
+ */
100
+ const GROUP_DISPATCH_LOCK_SQL = 'LOCK TABLE "BudgetGroup" IN SHARE ROW EXCLUSIVE MODE';
101
+ /**
102
+ * A coding run's budget reservation: the requested ceiling (override or the
103
+ * agent's budgetUsd) tightened by its budget group and run tree, where every
104
+ * live in-flight run's unspent hold already counts as spent. Rounded down to
105
+ * CodingRun.budgetReservedUsd's 6 decimal places; less than that is refused.
106
+ */
107
+ async function reserveCodingBudget(tx, agent, now, options) {
108
+ const effective = await effectiveBudgetForRun(tx, agent, now, options.parentRunId);
109
+ const requested = options.budgetUsdOverride ?? Number(agent.budgetUsd);
110
+ const budgetUsd = Math.floor(Math.min(requested, effective.effectiveBudgetUsd) / MIN_RESERVATION_USD) * MIN_RESERVATION_USD;
111
+ if (budgetUsd < MIN_RESERVATION_USD && effective.exhaustedBy) {
112
+ return { budgetUsd: 0, refusal: budgetExhaustedError(effective.exhaustedBy) };
113
+ }
114
+ return { budgetUsd };
115
+ }
116
+ /**
117
+ * Attempts for the persist transaction, and the jittered backoff between
118
+ * them, for serialization failures and deadlocks.
119
+ *
120
+ * @internal Exported only for the real-PostgreSQL tests.
121
+ */
122
+ export const PERSIST_ATTEMPTS = 8;
123
+ const RETRY_BASE_MS = 20;
124
+ const RETRY_MAX_MS = 250;
125
+ function retryDelayMs(attempt) {
126
+ const ceiling = Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** attempt);
127
+ return Math.floor(ceiling / 2 + Math.random() * (ceiling / 2));
128
+ }
129
+ const CONTINUATION_REFUSALS = {
130
+ unknown_run: "Cannot continue an unknown coding run.",
131
+ other_repository: "Cannot continue a coding run from a different repository.",
132
+ no_pull_request: "Cannot continue a coding run that never opened a pull request.",
133
+ };
134
+ /** A continuation refused because of the run it names. Its message is fixed text, safe to show the model. */
135
+ export class ContinuationRefusedError extends Error {
136
+ reason;
137
+ constructor(reason) {
138
+ super(CONTINUATION_REFUSALS[reason]);
139
+ this.reason = reason;
140
+ this.name = "ContinuationRefusedError";
141
+ }
142
+ }
143
+ /**
144
+ * Whether this deployment can continue coding run `runId` in `repository`: the
145
+ * run (or its root) is in this database, in that repository, and opened a pull
146
+ * request. A run id read from a pull request can name a run that another
147
+ * deployment sharing the same App made, so check before relying on one.
148
+ */
149
+ export async function checkContinuation(reader, runId, repository) {
150
+ const candidate = await reader.codingRun.findUnique({ where: { runId } });
151
+ if (!candidate)
152
+ return { ok: false, reason: "unknown_run" };
153
+ const root = candidate.rootCodingRunId
154
+ ? await reader.codingRun.findUnique({ where: { runId: candidate.rootCodingRunId } })
155
+ : candidate;
156
+ if (!root)
157
+ return { ok: false, reason: "unknown_run" };
158
+ if (normalizeGitHubRepository(root.repository) !== normalizeGitHubRepository(repository)) {
159
+ return { ok: false, reason: "other_repository" };
160
+ }
161
+ const rootResult = publicCodingRunResult(root.result);
162
+ if ((rootResult?.outcome !== "pull_request_opened" && rootResult?.outcome !== "pull_request_updated") ||
163
+ rootResult.pullRequestNumber === undefined) {
164
+ return { ok: false, reason: "no_pull_request" };
165
+ }
166
+ return {
167
+ ok: true,
168
+ root: {
169
+ runId: root.runId,
170
+ baseRef: root.baseRef,
171
+ headRef: root.headRef,
172
+ pullRequestNumber: rootResult.pullRequestNumber,
173
+ },
174
+ };
175
+ }
176
+ /**
177
+ * Resolves a coding run's branch: an override, else a continuation root's
178
+ * (see checkContinuation), else the profile's base.
179
+ */
180
+ async function resolveCodingBranch(reader, options, profile) {
181
+ if (options.continuesCodingRunId === undefined)
182
+ return { baseRef: options.codingBaseRef ?? profile.baseRef };
183
+ if (options.codingBaseRef !== undefined) {
184
+ throw new Error("continuesCodingRunId cannot be combined with codingBaseRef.");
185
+ }
186
+ const check = await checkContinuation(reader, options.continuesCodingRunId, profile.repository);
187
+ if (!check.ok)
188
+ throw new ContinuationRefusedError(check.reason);
189
+ const { root } = check;
190
+ return {
191
+ baseRef: root.baseRef,
192
+ headRef: root.headRef,
193
+ continuationOf: { runId: root.runId },
194
+ rootCodingRunId: root.runId,
195
+ };
196
+ }
197
+ /** Read failures that are the file's fault rather than the host's: reported as an invalid declaration. */
198
+ const UNREADABLE_DECLARATION = {
199
+ github_file_too_large: `it is larger than ${MAX_SERVICE_DECLARATION_BYTES} bytes`,
200
+ github_file_not_a_file: "it is not a file",
201
+ github_file_not_utf8: "it is not UTF-8 text",
202
+ };
203
+ /**
204
+ * The knowledge note's input (docs/knowledge.md): the repository's bundle
205
+ * index at the run's base, read before the transaction like the services
206
+ * declaration. Any failure means no note, never a failed dispatch.
207
+ */
208
+ async function readKnowledgeIndex(options, profile, resolvedBranch) {
209
+ const executor = options.executor;
210
+ if (!executor.readCodingRepositoryFile)
211
+ return undefined;
212
+ try {
213
+ // Resolved here, inside the try: a branch problem is the transaction's to report, not the note's.
214
+ const branch = resolvedBranch ?? (await resolveCodingBranch(options.db, options, profile));
215
+ const indexText = await executor.readCodingRepositoryFile({
216
+ repository: profile.repository,
217
+ baseRef: normalizeGitRef(branch.baseRef),
218
+ path: `${DEFAULT_KNOWLEDGE_BUNDLE_PATH}/index.md`,
219
+ maxBytes: KNOWLEDGE_INDEX_READ_MAX_BYTES,
220
+ });
221
+ return indexText ? { bundlePath: DEFAULT_KNOWLEDGE_BUNDLE_PATH, indexText } : undefined;
222
+ }
223
+ catch (err) {
224
+ if (err instanceof Error && err.message in UNREADABLE_DECLARATION) {
225
+ dispatchLog.info({ repository: profile.repository, reason: err.message }, "knowledge index unreadable; dispatching without it");
226
+ return undefined;
227
+ }
228
+ dispatchLog.warn({ err, repository: profile.repository }, "knowledge index read failed; dispatching without it");
229
+ return undefined;
230
+ }
231
+ }
232
+ /**
233
+ * Coding-run services (docs/coding-services.md): resolves the run's branch and
234
+ * reads the repository's declaration from its base, then parses it. A network
235
+ * call, so it runs before the Serializable transaction, which reuses the
236
+ * branch and resolves the services against the catalog and the agent.
237
+ */
238
+ async function readServiceDeclaration(options, profile) {
239
+ const branch = await resolveCodingBranch(options.db, options, profile);
240
+ const read = { repository: profile.repository, profileBaseRef: profile.baseRef, branch };
241
+ const executor = options.executor;
242
+ if (!executor.readCodingServiceDeclaration)
243
+ return { ...read, outcome: { kind: "none" } };
244
+ let text;
245
+ try {
246
+ text = await executor.readCodingServiceDeclaration({
247
+ repository: profile.repository,
248
+ baseRef: normalizeGitRef(branch.baseRef),
249
+ });
250
+ }
251
+ catch (err) {
252
+ const reason = UNREADABLE_DECLARATION[err instanceof Error ? err.message : ""];
253
+ if (reason) {
254
+ return {
255
+ ...read,
256
+ outcome: {
257
+ kind: "refused",
258
+ refusal: serviceRefusal("service_declaration_invalid", invalidDeclarationSentence(reason)),
259
+ },
260
+ };
261
+ }
262
+ dispatchLog.warn({ err, agentId: options.agentId }, "could not read the repository's service declaration");
263
+ return {
264
+ ...read,
265
+ outcome: {
266
+ kind: "refused",
267
+ refusal: serviceRefusal("service_declaration_unavailable", DECLARATION_UNAVAILABLE_SENTENCE),
268
+ },
269
+ };
270
+ }
271
+ if (text === null)
272
+ return { ...read, outcome: { kind: "none" } };
273
+ try {
274
+ return { ...read, outcome: { kind: "declared", services: parseServiceDeclaration(text) } };
275
+ }
276
+ catch (err) {
277
+ if (!(err instanceof ServiceDeclarationError))
278
+ throw err;
279
+ return {
280
+ ...read,
281
+ outcome: {
282
+ kind: "refused",
283
+ refusal: serviceRefusal("service_declaration_invalid", invalidDeclarationSentence(err.reason)),
284
+ },
285
+ };
286
+ }
287
+ }
288
+ /** Inside the transaction: the run's services, or the refusal that stops it. */
289
+ async function resolveDispatchServices(tx, outcome, allowed, executor, provider, request, instructions) {
290
+ if (outcome.kind === "refused")
291
+ return { refusal: outcome.refusal };
292
+ if (outcome.kind === "none" || outcome.services.length === 0)
293
+ return { services: [] };
294
+ if (executor.supportsCodingServices?.(provider) !== true) {
295
+ return { refusal: serviceRefusal("service_launcher_unsupported", LAUNCHER_UNSUPPORTED_SENTENCE) };
296
+ }
297
+ return resolveRunServices({ findMany: (args) => tx.codingService.findMany(args) }, outcome.services, parseAllowedServiceNames(allowed), request, instructions);
54
298
  }
55
299
  /**
56
300
  * Persists every detached run input in one transaction, then invokes the
@@ -59,7 +303,34 @@ export async function markRunFailedFromExecutorError(db, runId, err) {
59
303
  */
60
304
  export async function dispatchRun(options) {
61
305
  const now = options.now ?? new Date();
306
+ // Read outside the transaction only to decide whether to take the group
307
+ // dispatch lock before the transaction's first read, and whether to read the
308
+ // repository's service declaration (a network call); everything the run is
309
+ // built from is re-read inside. If the agent changes in between, the
310
+ // Serializable transaction still refuses a conflicting commit.
311
+ const preview = await options.db.agent.findUnique({
312
+ where: { id: options.agentId },
313
+ select: {
314
+ kind: true,
315
+ budgetGroupId: true,
316
+ codingProfile: { select: { repository: true, baseRef: true, services: true } },
317
+ },
318
+ });
319
+ const lockGroups = preview?.kind === "coding" && preview.budgetGroupId != null;
320
+ // Only an agent allowed some service reads the repository's declaration; any
321
+ // other coding agent never calls the host for it and gets no services.
322
+ const declarationRead = preview?.kind === "coding" &&
323
+ preview.codingProfile &&
324
+ parseAllowedServiceNames(preview.codingProfile.services).length > 0
325
+ ? await readServiceDeclaration(options, preview.codingProfile)
326
+ : undefined;
327
+ // The knowledge note's input: the repository's bundle index at the run's base (a network call).
328
+ const knowledgeIndex = preview?.kind === "coding" && preview.codingProfile && options.executor.readCodingRepositoryFile
329
+ ? await readKnowledgeIndex(options, preview.codingProfile, declarationRead?.branch)
330
+ : undefined;
62
331
  const persistOnce = () => options.db.$transaction(async (tx) => {
332
+ if (lockGroups)
333
+ await tx.$executeRawUnsafe(GROUP_DISPATCH_LOCK_SQL);
63
334
  if (options.lockAgent) {
64
335
  const locked = await tx.$queryRaw `
65
336
  SELECT "id" FROM "Agent" WHERE "id" = ${options.agentId} FOR UPDATE SKIP LOCKED
@@ -78,6 +349,52 @@ export async function dispatchRun(options) {
78
349
  if (options.taskOverride !== undefined && agent.kind !== "native") {
79
350
  throw new Error("taskOverride can only be supplied for a native agent.");
80
351
  }
352
+ // A coding run's services are resolved, and its budget reserved, here,
353
+ // at dispatch (E-01): the container only ever checks the run's own
354
+ // reservation. A native run computes its effective budget in
355
+ // executeRun's load step instead.
356
+ let codingBudget;
357
+ let codingEntry;
358
+ let modelFailure;
359
+ let services = [];
360
+ let servicesRefusal;
361
+ if (agent.kind === "coding") {
362
+ if (!agent.codingProfile)
363
+ throw new Error(`Coding agent "${agent.id}" has no coding profile.`);
364
+ // An unknown coding provider is a broken profile, not a catalog state: still thrown.
365
+ assertCodingProvider(agent.codingProfile.provider);
366
+ // Recorded on the run row below: the run is billed at this entry for its whole life.
367
+ // A model the catalog cannot run (missing, disabled, or another provider's) fails
368
+ // the run here instead of throwing: the run row commits with the reason, so the
369
+ // caller's own writes stand (a scheduler's lastScheduledAt, a mention's status
370
+ // row) and the owner sees why in list_runs, rather than a rolled-back
371
+ // transaction that a scheduler would retry on every tick.
372
+ try {
373
+ codingEntry = resolveCodingEntry(agent.codingProfile.provider, agent.model);
374
+ }
375
+ catch (err) {
376
+ if (!(err instanceof ModelUnavailableError || err instanceof CodingModelProviderMismatchError))
377
+ throw err;
378
+ modelFailure = err.message;
379
+ }
380
+ if (!modelFailure && declarationRead) {
381
+ if (declarationRead.repository !== agent.codingProfile.repository ||
382
+ declarationRead.profileBaseRef !== agent.codingProfile.baseRef) {
383
+ // The declaration was read for a profile that changed before this transaction.
384
+ throw new Error("The coding agent's repository or base branch changed during dispatch; try again.");
385
+ }
386
+ // A missing request fails below, with its own error.
387
+ const request = options.codingTask ?? agent.codingProfile.defaultTask ?? "";
388
+ const resolved = await resolveDispatchServices(tx, declarationRead.outcome, agent.codingProfile.services, options.executor, agent.codingProfile.provider, request, agent.systemPrompt);
389
+ if ("refusal" in resolved)
390
+ servicesRefusal = resolved.refusal;
391
+ else
392
+ services = resolved.services;
393
+ }
394
+ if (!modelFailure && !servicesRefusal)
395
+ codingBudget = await reserveCodingBudget(tx, agent, now, options);
396
+ }
397
+ const refusal = servicesRefusal ?? codingBudget?.refusal;
81
398
  const run = await tx.run.create({
82
399
  data: {
83
400
  agentId: agent.id,
@@ -86,46 +403,44 @@ export async function dispatchRun(options) {
86
403
  parentRunId: options.parentRunId,
87
404
  grantedParentMemoryKeys: options.grantedParentMemoryKeys ?? [],
88
405
  taskOverride: options.taskOverride,
406
+ triggeredById: options.triggeredById ?? null,
407
+ // Failed before it starts, like a native run whose model the
408
+ // runner's load step finds unavailable: zero spend, never started.
409
+ ...(modelFailure ? { status: "failed", error: modelFailure, finishedAt: now } : {}),
410
+ // Refused before it starts, the same terminal status (and zero
411
+ // spend) as a native run whose budget is gone at turn 1.
412
+ ...(refusal ? { status: "refused", error: refusal, finishedAt: now } : {}),
413
+ ...(codingEntry
414
+ ? {
415
+ pricingVersion: codingEntry.priceVersion,
416
+ // entryOf returns plain JSON data (fresh array, no Dates); the interface's readonly
417
+ // efforts array is all that keeps it from matching Prisma's Json input type.
418
+ pricingSnapshot: entryOf(codingEntry),
419
+ }
420
+ : {}),
89
421
  },
90
422
  });
91
- if (agent.kind === "coding") {
92
- if (!agent.codingProfile)
93
- throw new Error(`Coding agent "${agent.id}" has no coding profile.`);
423
+ if (options.afterPersist)
424
+ await options.afterPersist(tx, run);
425
+ const attributed = await attributeRun(tx, run.id, {
426
+ parentRunId: options.parentRunId,
427
+ continuesCodingRunId: options.continuesCodingRunId,
428
+ intent: options.attribution,
429
+ }, now);
430
+ if (agent.kind === "coding" && agent.codingProfile && codingBudget && !refusal) {
431
+ // Checked above too; repeated so the provider type narrows here.
94
432
  assertCodingProviderModel(agent.codingProfile.provider, agent.model);
95
433
  const request = options.codingTask ?? agent.codingProfile.defaultTask;
96
434
  if (!request)
97
435
  throw new Error(`Coding agent "${agent.id}" requires a task.`);
98
- // The worker sees only the task text, so the agent's own instructions ride in it.
99
- const task = composeCodingTask(agent.systemPrompt, request);
100
- const budgetUsd = options.budgetUsdOverride ?? Number(agent.budgetUsd);
101
- let baseRef = options.codingBaseRef ?? agent.codingProfile.baseRef;
102
- let headRef = `wardby/run-${run.id}`;
103
- let continuationOf;
104
- let rootCodingRunId;
105
- if (options.continuesCodingRunId !== undefined) {
106
- if (options.codingBaseRef !== undefined) {
107
- throw new Error("continuesCodingRunId cannot be combined with codingBaseRef.");
108
- }
109
- const candidate = await tx.codingRun.findUnique({ where: { runId: options.continuesCodingRunId } });
110
- if (!candidate)
111
- throw new Error("Cannot continue an unknown coding run.");
112
- const root = candidate.rootCodingRunId
113
- ? await tx.codingRun.findUnique({ where: { runId: candidate.rootCodingRunId } })
114
- : candidate;
115
- if (!root)
116
- throw new Error("Cannot continue an unknown coding run.");
117
- if (normalizeGitHubRepository(root.repository) !== normalizeGitHubRepository(agent.codingProfile.repository)) {
118
- throw new Error("Cannot continue a coding run from a different repository.");
119
- }
120
- const rootResult = publicCodingRunResult(root.result);
121
- if (rootResult?.outcome !== "pull_request_opened" && rootResult?.outcome !== "pull_request_updated") {
122
- throw new Error("Cannot continue a coding run that never opened a pull request.");
123
- }
124
- baseRef = root.baseRef;
125
- headRef = root.headRef;
126
- continuationOf = { runId: root.runId };
127
- rootCodingRunId = root.runId;
128
- }
436
+ // The worker sees only the task text, so the agent's own instructions, and the
437
+ // services note, ride in it.
438
+ const task = composeCodingTask(agent.systemPrompt, request, servicesInstructionNote(services), knowledgeIndex ? knowledgeSection(knowledgeIndex) : undefined);
439
+ const budgetUsd = codingBudget.budgetUsd;
440
+ // Resolved once: before the transaction when the declaration was read from it.
441
+ const branch = declarationRead?.branch ?? (await resolveCodingBranch(tx, options, agent.codingProfile));
442
+ const { baseRef, continuationOf, rootCodingRunId } = branch;
443
+ const headRef = branch.headRef ?? `wardby/run-${run.id}`;
129
444
  const input = CodingTaskInputSchema.parse({
130
445
  schemaVersion: CODING_PROTOCOL_VERSION,
131
446
  runId: run.id,
@@ -137,16 +452,23 @@ export async function dispatchRun(options) {
137
452
  budgetUsd,
138
453
  deadlineAt: new Date(now.getTime() + agent.codingProfile.timeoutSec * 1000).toISOString(),
139
454
  continuationOf,
455
+ ...(services.length > 0 ? { services: workerServices(services) } : {}),
140
456
  });
141
- const workerImage = options.executor.resolveCodingWorkerImage?.({
457
+ const imageSelector = {
142
458
  provider: agent.codingProfile.provider,
143
459
  toolchain: agent.codingProfile.toolchain,
144
460
  toolchainVersion: agent.codingProfile.toolchainVersion,
145
461
  workerImageRef: agent.codingProfile.workerImageRef,
146
- });
462
+ };
463
+ const workerImage = options.executor.resolveCodingWorkerImage?.(imageSelector);
464
+ // Claude Code's commands run in its tool runner, so the toolchain picks that image too; fixed
465
+ // here with the worker image so the run keeps both however the deployment changes later.
466
+ const toolImage = options.executor.resolveCodingToolImage?.(imageSelector) ?? null;
147
467
  await tx.codingRun.create({
148
468
  data: {
149
469
  runId: run.id,
470
+ issueProvider: attributed?.provider ?? null,
471
+ issueKey: attributed?.key ?? null,
150
472
  task: input.task,
151
473
  repository: input.repository,
152
474
  baseRef: input.baseRef,
@@ -154,18 +476,26 @@ export async function dispatchRun(options) {
154
476
  provider: agent.codingProfile.provider,
155
477
  model: input.model,
156
478
  timeoutSec: agent.codingProfile.timeoutSec,
157
- allowedEgress: agent.codingProfile.allowedEgress,
158
479
  protectedPaths: agent.codingProfile.protectedPaths,
480
+ collectExclude: agent.codingProfile.collectExclude,
481
+ packageAllowlist: agent.codingProfile.packageAllowlist,
482
+ packagePolicy: agent.codingProfile.packagePolicy,
159
483
  workerImage,
484
+ toolImage,
160
485
  budgetReservedUsd: budgetUsd,
161
486
  rootCodingRunId,
162
487
  workspaceDiskMb: agent.codingProfile.workspaceDiskMb,
488
+ // Fixed here so a run's tracing never changes mid-run.
489
+ debugTrace: agent.codingProfile.debugTraceUntil != null &&
490
+ now.getTime() < agent.codingProfile.debugTraceUntil.getTime(),
491
+ services,
163
492
  },
164
493
  });
165
494
  }
166
- else if (options.codingTask !== undefined ||
167
- options.codingBaseRef !== undefined ||
168
- options.continuesCodingRunId !== undefined) {
495
+ else if (agent.kind !== "coding" &&
496
+ (options.codingTask !== undefined ||
497
+ options.codingBaseRef !== undefined ||
498
+ options.continuesCodingRunId !== undefined)) {
169
499
  throw new Error("Coding overrides cannot be supplied for a native agent.");
170
500
  }
171
501
  const task = options.task
@@ -182,24 +512,29 @@ export async function dispatchRun(options) {
182
512
  return { run, task };
183
513
  }, { isolationLevel: "Serializable" });
184
514
  let persisted = null;
185
- for (let attempt = 0; attempt < 3; attempt += 1) {
515
+ for (let attempt = 0; attempt < PERSIST_ATTEMPTS; attempt += 1) {
186
516
  try {
187
517
  persisted = await persistOnce();
188
518
  break;
189
519
  }
190
520
  catch (err) {
191
- if (!isSerializationConflict(err) || attempt === 2)
521
+ if (!isSerializationConflict(err) || attempt === PERSIST_ATTEMPTS - 1)
192
522
  throw err;
523
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs(attempt)));
193
524
  }
194
525
  }
195
526
  if (!persisted)
196
527
  return null;
528
+ if (persisted.run.status === "refused" || persisted.run.status === "failed") {
529
+ dispatchLog.warn({ runId: persisted.run.id, agentId: options.agentId, reason: persisted.run.error }, `coding run ${persisted.run.status} at dispatch`);
530
+ return persisted;
531
+ }
197
532
  const runStart = async () => {
198
533
  try {
199
534
  await options.executor.start(persisted.run.id);
200
535
  }
201
536
  catch (err) {
202
- await markRunFailedFromExecutorError(options.db, persisted.run.id, err).catch((err2) => dispatchLog.error({ err: err2, runId: persisted.run.id }, "failed to persist executor start failure"));
537
+ await markRunFailedFromExecutorError(options.db, persisted.run.id, err, options.selfDefects).catch((err2) => dispatchLog.error({ err: err2, runId: persisted.run.id }, "failed to persist executor start failure"));
203
538
  }
204
539
  };
205
540
  if (options.awaitExecution) {