@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
@@ -29,20 +29,27 @@ import { finished } from "node:stream/promises";
29
29
  import { createHash } from "node:crypto";
30
30
  import { isIP } from "node:net";
31
31
  import { logger } from "../../core/logger.js";
32
- import { MAX_CODING_ARTIFACT_BYTES, parseCodingAgentOutputJson } from "../../coding/protocol.js";
32
+ import { MAX_CODING_ARTIFACT_BYTES, MAX_DEBUG_TRACE_LINE_BYTES, parseCodingAgentOutputJson, } from "../../coding/protocol.js";
33
33
  import { CODING_PROXY_DENY_PORT, CODING_PROXY_PORT } from "./docker-isolation.js";
34
34
  import { parseWorkerDiagnosticLine } from "./docker.js";
35
35
  import { KubernetesAlreadyExistsError, KubernetesConflictError } from "./kubernetes-api.js";
36
- import { ENFORCEMENT_PROBE_DENY_REACHABLE, ENFORCEMENT_PROBE_PROVEN, ENFORCEMENT_PROBE_DENY_REFUSED, ENFORCEMENT_PROBE_PROXY_UNREACHABLE, KEEPER_CONTAINER, KEEPER_SEEDED_MARKER, KUBERNETES_ISOLATION_ERROR, STORAGE_ROOT, WORKER_CONTAINER, assertRunNetworkPolicyMatches, assertRunPodMatches, buildCapabilitySecret, buildRunNetworkPolicy, buildRunPod, enforcementProbeScript, kubernetesRunNames, kubernetesRunNamesForToken, runLabels, validateKubernetesSpec, } from "./kubernetes-isolation.js";
36
+ import { ENFORCEMENT_PROBE_DENY_REACHABLE, ENFORCEMENT_PROBE_PROVEN, ENFORCEMENT_PROBE_DENY_REFUSED, ENFORCEMENT_PROBE_PROXY_UNREACHABLE, KEEPER_CONTAINER, KEEPER_SEEDED_MARKER, KUBERNETES_ISOLATION_ERROR, STORAGE_ROOT, TOOL_RUNNER_CONTAINER, WORKER_CONTAINER, assertRunNetworkPolicyMatches, assertRunPodMatches, buildCapabilitySecret, buildRunNetworkPolicy, buildRunPod, enforcementProbeScript, kubernetesRunNames, kubernetesRunNamesForToken, runLabels, serviceContainerName, validateKubernetesSpec, } from "./kubernetes-isolation.js";
37
+ import { claudeToolSetup } from "./claude-tool-setup.js";
37
38
  import { readProxyWitness } from "./kubernetes-witness.js";
38
39
  import { safeExtract } from "./safe-extract.js";
40
+ import { reportServiceState, } from "./service-state.js";
41
+ import { serviceUnreadyError } from "../../coding/services/wording.js";
39
42
  import { replaceDirectoryFromStaging } from "./workspace-swap.js";
43
+ import { collectExclusions, normalizeCollectExclusions, tarExcludeArgs, } from "../../coding/collect-exclude.js";
40
44
  const BACKEND = "kubernetes";
41
45
  const RECORD_SCHEMA_VERSION = 1;
42
46
  const RECORD_KEY = "record.json";
43
47
  const STOP_GRACE_SECONDS = 10;
44
48
  const DIAGNOSTIC_TAIL_LINES = 8;
45
- const DIAGNOSTIC_LIMIT_BYTES = 4096;
49
+ // The API cuts the tail from its FRONT at limitBytes, so this must hold every
50
+ // tail line at full size: a debug-traced run writes lines of up to
51
+ // MAX_DEBUG_TRACE_LINE_BYTES just before its diagnostic line.
52
+ const DIAGNOSTIC_LIMIT_BYTES = DIAGNOSTIC_TAIL_LINES * MAX_DEBUG_TRACE_LINE_BYTES;
46
53
  const MAX_WORKSPACE_ENTRIES = 100_000;
47
54
  const MAX_RECORD_ATTEMPTS = 5;
48
55
  const READY_POLL_MS = 250;
@@ -51,8 +58,17 @@ const DEFAULT_ENFORCEMENT_TIMEOUT_MS = 30_000;
51
58
  const ENFORCEMENT_POLL_MS = 500;
52
59
  /** Consecutive proven probes required (8787 reachable, 8788 blocked): one dropped SYN must not open the gate. */
53
60
  const ENFORCEMENT_BLOCKED_STREAK = 3;
54
- /** Bound for one enforcement probe exec (the probe makes two sequential connects, so it gives up after at most 6 s). */
55
- const ENFORCEMENT_EXEC_TIMEOUT_MS = 10_000;
61
+ /**
62
+ * Default bound for one enforcement probe exec (the probe makes two sequential connects, so it
63
+ * gives up after at most 6 s of its own connect timeouts). Overridable per KubernetesJobConfig's
64
+ * `enforcementExecTimeoutMs` (KUBERNETES_ENFORCEMENT_EXEC_TIMEOUT_MS) — a resource-constrained
65
+ * keeper (e.g. a laptop `kind` cluster's default 250m CPU / 128Mi limit) can take noticeably
66
+ * longer than this to run even a healthy probe to completion. DEFAULT_ENFORCEMENT_TIMEOUT_MS
67
+ * above is exactly this default times ENFORCEMENT_BLOCKED_STREAK, which is not a coincidence: see
68
+ * the constructor, which derives the effective overall bound the same way from whichever exec
69
+ * timeout is actually configured, so the two never drift apart.
70
+ */
71
+ const DEFAULT_ENFORCEMENT_EXEC_TIMEOUT_MS = 10_000;
56
72
  /**
57
73
  * What the gate reports at its bound, by the last probe's exit code. Each names a different place
58
74
  * to look, and each carries the reason in its own message rather than in the documentation: an
@@ -141,6 +157,29 @@ const FATAL_WAITING_REASONS = new Set([
141
157
  "CreateContainerError",
142
158
  "CrashLoopBackOff",
143
159
  ]);
160
+ const IMAGE_WAITING_REASONS = new Set(["ErrImagePull", "ImagePullBackOff", "InvalidImageName"]);
161
+ /**
162
+ * A service sidecar's start-up state as the pod status shows it. The kubelet runs the startup
163
+ * probe, so attempt counts are unknown here; checks mirror waitForKeeper's own failure rules.
164
+ */
165
+ function observedServiceState(status) {
166
+ if (status === undefined)
167
+ return { state: "pending" };
168
+ if ((status.restartCount ?? 0) > 0)
169
+ return { state: "failed", reason: "probe_failed" };
170
+ const waiting = status.state?.waiting?.reason ?? "";
171
+ if (IMAGE_WAITING_REASONS.has(waiting))
172
+ return { state: "failed", reason: "image_unavailable" };
173
+ if (FATAL_WAITING_REASONS.has(waiting))
174
+ return { state: "failed", reason: "start_failed" };
175
+ if (status.state?.terminated !== undefined)
176
+ return { state: "failed", reason: "exited" };
177
+ if (status.started === true)
178
+ return { state: "ready" };
179
+ if (status.state?.running !== undefined)
180
+ return { state: "probing" };
181
+ return { state: "pending" };
182
+ }
144
183
  const CAPABILITY = /^rrp_[A-Za-z0-9_-]{16,512}$/;
145
184
  const TOKEN = /^[a-f0-9]{20}$/;
146
185
  const WORKSPACE_STORAGE = `${STORAGE_ROOT}/workspace`;
@@ -224,6 +263,11 @@ function exitedCleanlyInTime(pod, finishedAt, deadlineAt) {
224
263
  const finished = new Date(finishedAt).getTime();
225
264
  return Number.isFinite(finished) && finished <= deadlineAt + FINISHED_AT_SKEW_MS;
226
265
  }
266
+ /** A Claude run's tool runner that restarted or exited: its socket (and any in-flight command) is gone. */
267
+ function toolRunnerFailed(statuses) {
268
+ const tool = statuses?.find((status) => status.name === TOOL_RUNNER_CONTAINER);
269
+ return tool !== undefined && ((tool.restartCount ?? 0) > 0 || tool.state?.terminated !== undefined);
270
+ }
227
271
  /** Maps a pod read-back onto the next record state; `undefined` means "no change". Never called for terminal records. */
228
272
  function observePod(pod, record, now, readyTimeoutMs) {
229
273
  if (!pod) {
@@ -242,6 +286,16 @@ function observePod(pod, record, now, readyTimeoutMs) {
242
286
  if (now >= record.deadlineAt || pod.status?.reason === "DeadlineExceeded") {
243
287
  return { phase: "failed", result: { exitCode: 124, reason: "timed_out" }, deleteGraceSeconds: STOP_GRACE_SECONDS };
244
288
  }
289
+ // Docker's worker_tool_runner_failed, for the same reason: without its tool runner a Claude worker
290
+ // can only stall until the deadline. Checked only while the worker still runs, so a clean finish
291
+ // (checked above) or the pod's own teardown never reads as a tool-runner failure.
292
+ if (!terminated && toolRunnerFailed(pod.status?.initContainerStatuses)) {
293
+ return {
294
+ phase: "failed",
295
+ result: { exitCode: 1, reason: "failed", diagnostic: "worker_tool_runner_failed" },
296
+ deleteGraceSeconds: STOP_GRACE_SECONDS,
297
+ };
298
+ }
245
299
  if (terminated) {
246
300
  // An exit 0 that failed the guard above (pod being deleted, no usable finish time) is not a success.
247
301
  if (terminated.exitCode === 0)
@@ -328,6 +382,7 @@ export class KubernetesJobLauncher {
328
382
  createArchive;
329
383
  warn;
330
384
  enforcementTimeoutMs;
385
+ enforcementExecTimeoutMs;
331
386
  preflightResult;
332
387
  constructor(options) {
333
388
  this.options = options;
@@ -339,10 +394,24 @@ export class KubernetesJobLauncher {
339
394
  this.now = options.now ?? Date.now;
340
395
  this.sleep = options.sleep ?? ((ms) => new Promise((resolvePromise) => setTimeout(resolvePromise, ms)));
341
396
  this.readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
342
- this.enforcementTimeoutMs = options.enforcementTimeoutMs ?? DEFAULT_ENFORCEMENT_TIMEOUT_MS;
397
+ this.enforcementExecTimeoutMs = options.enforcementExecTimeoutMs ?? DEFAULT_ENFORCEMENT_EXEC_TIMEOUT_MS;
398
+ // Never less than a full blocked-streak's worth of worst-case probes: a longer configured exec
399
+ // timeout that left this unchanged could make the wall-clock bound expire before the loop ever
400
+ // has a chance to observe ENFORCEMENT_BLOCKED_STREAK consecutive probes, which would turn "the
401
+ // keeper is just slow" into an indistinguishable "the policy is not enforced" false negative.
402
+ // DEFAULT_ENFORCEMENT_TIMEOUT_MS (30_000) already equals the default exec timeout times the
403
+ // streak (10_000 * 3), so this is a no-op unless a longer exec timeout is actually configured.
404
+ this.enforcementTimeoutMs = Math.max(options.enforcementTimeoutMs ?? DEFAULT_ENFORCEMENT_TIMEOUT_MS, this.enforcementExecTimeoutMs * ENFORCEMENT_BLOCKED_STREAK);
343
405
  this.createArchive = options.createArchive ?? hostTarArchive;
344
406
  this.warn = options.onWarning ?? ((message) => kubernetesLog.warn(message));
345
407
  }
408
+ /**
409
+ * Services run as native sidecars in the run pod (kubernetes-isolation.ts), for either provider:
410
+ * Claude Code's tool runner is a sidecar in the same pod, so it reaches them on 127.0.0.1 too.
411
+ */
412
+ supportsServicesFor(provider) {
413
+ return provider === "codex" || provider === "claude-code";
414
+ }
346
415
  /**
347
416
  * Every per-run object name derives from the run id, so the handle is known before any cluster call.
348
417
  * The executor persists it first; a crash mid-launch then still has a handle to clean up with (the
@@ -359,7 +428,19 @@ export class KubernetesJobLauncher {
359
428
  }
360
429
  }
361
430
  async launch(spec) {
362
- validateKubernetesSpec(spec);
431
+ try {
432
+ validateKubernetesSpec(spec);
433
+ }
434
+ catch (error) {
435
+ // The thrown error already carries the real reason (e.g.
436
+ // "kubernetes_isolation_unsupported:image-not-registry-digest") and is rethrown unchanged;
437
+ // this only makes that reason visible to an operator watching logs before the caller (which
438
+ // may only surface the top-level error code) does anything with it. Nothing here is derived
439
+ // from spec content beyond that fixed reason tag — no image reference, no limit value.
440
+ if (error instanceof Error)
441
+ this.warn(`kubernetes_spec_rejected: ${error.message}`);
442
+ throw error;
443
+ }
363
444
  await this.runPreflight();
364
445
  const names = kubernetesRunNames(spec.runId);
365
446
  const handle = { backend: BACKEND, id: `${this.namespace}/${names.token}` };
@@ -376,6 +457,7 @@ export class KubernetesJobLauncher {
376
457
  createdAt,
377
458
  deadlineAt: createdAt + spec.timeoutSec * 1000,
378
459
  phase: "provisioning",
460
+ collectExclude: spec.collectExclude ?? collectExclusions([]),
379
461
  };
380
462
  try {
381
463
  // The record is the idempotency fence before any other cluster side effect.
@@ -454,7 +536,9 @@ export class KubernetesJobLauncher {
454
536
  throw new Error("kubernetes_workspace_destination_invalid");
455
537
  }
456
538
  const maxBytes = record.diskMb * 1024 * 1024;
457
- await replaceDirectoryFromStaging(expected, maxBytes, "kubernetes_workspace_destination_invalid", (staging) => this.extractWorkspace(names, staging, maxBytes, this.transferBudgetMs(record)));
539
+ await replaceDirectoryFromStaging(expected, maxBytes, "kubernetes_workspace_destination_invalid", (staging) => this.extractWorkspace(names, staging, maxBytes, this.transferBudgetMs(record),
540
+ // Names are always the current built-in list; only the paths come from the record.
541
+ normalizeCollectExclusions(record.collectExclude?.paths)));
458
542
  }
459
543
  async stop(handle, _reason) {
460
544
  const names = this.namesFor(handle);
@@ -532,7 +616,7 @@ export class KubernetesJobLauncher {
532
616
  // `exitCode` is this iteration's probe, and the bound below is only ever reached from here —
533
617
  // so the verdict is always the *last* probe's, never a remembered earlier one.
534
618
  const exitCode = await this.api.exec(this.namespace, names.pod, KEEPER_CONTAINER, command, {
535
- timeoutMs: ENFORCEMENT_EXEC_TIMEOUT_MS,
619
+ timeoutMs: this.enforcementExecTimeoutMs,
536
620
  });
537
621
  blocked = exitCode === 0 ? blocked + 1 : 0;
538
622
  if (blocked >= ENFORCEMENT_BLOCKED_STREAK)
@@ -552,7 +636,7 @@ export class KubernetesJobLauncher {
552
636
  return structuredClone(handle);
553
637
  }
554
638
  async provision(spec, names, record) {
555
- const { runtimeClassName, proxyService, platform } = this.options.config;
639
+ const { runtimeClassName, priorityClassName, proxyService, platform } = this.options.config;
556
640
  if (!runtimeClassName) {
557
641
  this.warn("kubernetes_runtime_class_unset: no runtime class configured; coding pods run without gVisor (development clusters only)");
558
642
  }
@@ -563,12 +647,19 @@ export class KubernetesJobLauncher {
563
647
  // which is only meaningful against a Service that actually exposes it with a ready backend.
564
648
  const witness = await readProxyWitness(this.api, this.namespace, proxyService);
565
649
  const proxyIp = witness.clusterIp;
566
- const pod = buildRunPod(spec, { namespace: this.namespace, proxyIp, runtimeClassName, platform });
650
+ const pod = buildRunPod(spec, {
651
+ namespace: this.namespace,
652
+ proxyIp,
653
+ runtimeClassName,
654
+ priorityClassName,
655
+ platform,
656
+ });
567
657
  const policy = buildRunNetworkPolicy(spec, this.namespace);
568
- await this.createIfMissing(() => this.api.createSecret(this.namespace, buildCapabilitySecret(spec, this.namespace, capability)));
658
+ const toolSetup = spec.provider === "claude-code" ? claudeToolSetup(spec, capability) : undefined;
659
+ await this.createIfMissing(() => this.api.createSecret(this.namespace, buildCapabilitySecret(spec, this.namespace, capability, toolSetup)));
569
660
  await this.createIfMissing(() => this.api.createNetworkPolicy(this.namespace, policy));
570
661
  await this.createIfMissing(() => this.api.createPod(this.namespace, pod));
571
- await this.waitForKeeper(names);
662
+ await this.waitForKeeper(names, spec.runId, (spec.services ?? []).map((service) => service.name), spec.provider === "claude-code");
572
663
  const [actualPod, actualPolicy] = await Promise.all([
573
664
  this.api.readPod(this.namespace, names.pod),
574
665
  this.api.readNetworkPolicy(this.namespace, names.policy),
@@ -612,14 +703,41 @@ export class KubernetesJobLauncher {
612
703
  throw error;
613
704
  }
614
705
  }
615
- async waitForKeeper(names) {
706
+ async waitForKeeper(names, runId, serviceNames, toolRunner = false) {
616
707
  const started = this.now();
708
+ const reported = new Map();
709
+ const report = async (name, observed) => {
710
+ const key = `${observed.state}:${observed.reason ?? ""}`;
711
+ if (reported.get(name) === key)
712
+ return;
713
+ reported.set(name, key);
714
+ await reportServiceState(this.options.onServiceState, { runId, name, ...observed });
715
+ };
617
716
  for (;;) {
618
717
  const pod = await this.api.readPod(this.namespace, names.pod);
619
718
  if (!pod || pod.status?.phase === "Failed")
620
719
  throw new Error("kubernetes_pod_start_failed");
621
720
  const statuses = pod.status?.containerStatuses ?? [];
622
721
  const initStatuses = pod.status?.initContainerStatuses ?? [];
722
+ const sidecar = (name) => initStatuses.find((status) => status.name === serviceContainerName(name));
723
+ for (const name of serviceNames)
724
+ await report(name, observedServiceState(sidecar(name)));
725
+ // A service sidecar that restarted (its startup probe gave up), can't be pulled or created, or
726
+ // exited will never let the keeper start. Name the service rather than a generic start failure.
727
+ const failedService = serviceNames.find((name) => {
728
+ const status = sidecar(name);
729
+ return (status !== undefined &&
730
+ ((status.restartCount ?? 0) > 0 ||
731
+ FATAL_WAITING_REASONS.has(status.state?.waiting?.reason ?? "") ||
732
+ status.state?.terminated !== undefined));
733
+ });
734
+ if (failedService !== undefined)
735
+ throw serviceUnreadyError(failedService);
736
+ const toolStatus = initStatuses.find((status) => status.name === TOOL_RUNNER_CONTAINER);
737
+ if (toolRunner &&
738
+ (toolRunnerFailed(initStatuses) || FATAL_WAITING_REASONS.has(toolStatus?.state?.waiting?.reason ?? ""))) {
739
+ throw new Error("kubernetes_tool_runner_failed");
740
+ }
623
741
  const keeper = statuses.find((status) => status.name === KEEPER_CONTAINER);
624
742
  if ([...initStatuses, ...statuses].some((status) => FATAL_WAITING_REASONS.has(status.state?.waiting?.reason ?? "")) ||
625
743
  // A failed init container (kubectl's Init:Error) or a keeper that already exited can never become ready.
@@ -627,10 +745,25 @@ export class KubernetesJobLauncher {
627
745
  keeper?.state?.terminated !== undefined) {
628
746
  throw new Error("kubernetes_pod_start_failed");
629
747
  }
630
- if (keeper?.ready === true)
748
+ if (keeper?.ready === true) {
749
+ // Native sidecars start in order before the keeper, so a ready keeper means every service started.
750
+ for (const name of serviceNames)
751
+ await report(name, { state: "ready" });
631
752
  return;
632
- if (this.now() - started >= this.readyTimeoutMs)
753
+ }
754
+ if (this.now() - started >= this.readyTimeoutMs) {
755
+ if (toolRunner && toolStatus?.started !== true) {
756
+ throw new Error("kubernetes_tool_runner_unready");
757
+ }
758
+ // At the bound, a service that never passed its startup probe (still pulling, still starting)
759
+ // is why the keeper never started.
760
+ const waiting = serviceNames.find((name) => sidecar(name)?.started !== true);
761
+ if (waiting !== undefined) {
762
+ await report(waiting, { state: "failed", reason: "timed_out" });
763
+ throw serviceUnreadyError(waiting);
764
+ }
633
765
  throw new Error("kubernetes_pod_start_timeout");
766
+ }
634
767
  await this.sleep(READY_POLL_MS);
635
768
  }
636
769
  }
@@ -754,9 +887,10 @@ export class KubernetesJobLauncher {
754
887
  * Streams the keeper's workspace through the strict extractor into `staging`.
755
888
  * The transfer is bounded by `timeoutMs` (see transferBudgetMs): on expiry the
756
889
  * extraction is aborted. On any failure the output stream this method created
757
- * is destroyed, since the exec's own timeout does not end it.
890
+ * is destroyed, since the exec's own timeout does not end it. Excluded dependency
891
+ * and cache paths never leave the pod (see src/coding/collect-exclude.ts).
758
892
  */
759
- async extractWorkspace(names, staging, maxBytes, timeoutMs) {
893
+ async extractWorkspace(names, staging, maxBytes, timeoutMs, exclusions) {
760
894
  const output = new PassThrough();
761
895
  // Errors are surfaced through the exec/extraction promises; never let a late destroy() crash the process.
762
896
  output.on("error", () => undefined);
@@ -767,10 +901,7 @@ export class KubernetesJobLauncher {
767
901
  signal: controller.signal,
768
902
  });
769
903
  const execution = this.api
770
- .exec(this.namespace, names.pod, KEEPER_CONTAINER, ["tar", "-C", WORKSPACE_STORAGE, "-cf", "-", "."], {
771
- stdout: output,
772
- timeoutMs,
773
- })
904
+ .exec(this.namespace, names.pod, KEEPER_CONTAINER, ["tar", "-C", WORKSPACE_STORAGE, ...tarExcludeArgs(exclusions), "-cf", "-", "."], { stdout: output, timeoutMs })
774
905
  .then((exitCode) => {
775
906
  if (exitCode !== 0)
776
907
  throw new Error("kubernetes_workspace_archive_failed");
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Display-only observation of coding-run service start-up (docs/coding-services.md): launchers
3
+ * report each service's state as they see it, for the viewer. Never part of the launch's own
4
+ * control flow: a reporter error is swallowed. The launcher does await each report inline,
5
+ * though, so a reporter must be fast.
6
+ */
7
+ export type ServiceState = "pending" | "probing" | "ready" | "failed";
8
+ /** Fixed identifiers only: never probe output, container logs, or anything from the repository. */
9
+ export type ServiceFailureReason = "image_unavailable" | "start_failed" | "exited" | "probe_failed" | "timed_out";
10
+ export interface ServiceStateUpdate {
11
+ runId: string;
12
+ /** The catalog service name (CodingService.name). */
13
+ name: string;
14
+ state: ServiceState;
15
+ /** Readiness probes completed so far; only launchers that run the probe themselves (Docker) know it. */
16
+ attempts?: number;
17
+ /** Set only with state "failed". */
18
+ reason?: ServiceFailureReason;
19
+ }
20
+ export type ServiceStateReporter = (update: ServiceStateUpdate) => Promise<void>;
21
+ /** Calls `reporter` if there is one; any error it throws is dropped (status is display-only). */
22
+ export declare function reportServiceState(reporter: ServiceStateReporter | undefined, update: ServiceStateUpdate): Promise<void>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Display-only observation of coding-run service start-up (docs/coding-services.md): launchers
3
+ * report each service's state as they see it, for the viewer. Never part of the launch's own
4
+ * control flow: a reporter error is swallowed. The launcher does await each report inline,
5
+ * though, so a reporter must be fast.
6
+ */
7
+ /** Calls `reporter` if there is one; any error it throws is dropped (status is display-only). */
8
+ export async function reportServiceState(reporter, update) {
9
+ if (!reporter)
10
+ return;
11
+ try {
12
+ await reporter(update);
13
+ }
14
+ catch {
15
+ // Display-only: a lost update must never fail or slow a launch.
16
+ }
17
+ }
@@ -3,12 +3,15 @@
3
3
  * values are carried in a versioned input artifact, never expanded into an
4
4
  * arbitrary environment map or shell command.
5
5
  */
6
+ import type { CodingProvider } from "../../coding/provider.js";
6
7
  export interface JobResourceLimits {
7
8
  cpus: number;
8
9
  memoryMb: number;
9
10
  pids: number;
10
11
  diskMb: number;
11
12
  }
13
+ import type { CollectExclusions } from "../../coding/collect-exclude.js";
14
+ import type { ResolvedCodingService } from "../../coding/services/catalog.js";
12
15
  export interface JobSpec {
13
16
  kind: "coding-agent";
14
17
  runId: string;
@@ -21,6 +24,16 @@ export interface JobSpec {
21
24
  timeoutSec: number;
22
25
  limits: JobResourceLimits;
23
26
  labels: Record<string, string>;
27
+ /** Workspace paths never collected; absent on legacy specs, which get the built-in names. */
28
+ collectExclude?: CollectExclusions;
29
+ /**
30
+ * Coding-run services (docs/coding-services.md): catalog snapshots resolved
31
+ * at dispatch, started next to the worker. Their images and environments come
32
+ * from the admin-managed catalog, never from repository content. Absent for
33
+ * a run without services (never an empty list), so such a spec, and its hash,
34
+ * is unchanged.
35
+ */
36
+ services?: ResolvedCodingService[];
24
37
  }
25
38
  /** Opaque provider reference. Callers persist both fields exactly as given. */
26
39
  export interface JobHandle {
@@ -77,4 +90,9 @@ export interface JobLauncher {
77
90
  /** A launcher that can safely copy a terminal worker workspace back to trusted storage. */
78
91
  export interface WorkspaceJobLauncher extends JobLauncher {
79
92
  materializeWorkspace: (handle: JobHandle, destination: string) => Promise<void>;
93
+ /**
94
+ * Whether this launcher starts JobSpec.services for a run of `provider`: Kubernetes and Docker, for
95
+ * Codex and Claude Code. Absent means no services at all.
96
+ */
97
+ supportsServicesFor?(provider: CodingProvider): boolean;
80
98
  }
@@ -2,12 +2,12 @@
2
2
  * Direct Anthropic (Claude) adapter for the LlmProvider seam. `@anthropic-ai/sdk`
3
3
  * is imported only here; all protocol/pricing-dispatch logic lives in the
4
4
  * shared ClaudeLlmProvider base class (claude-provider.ts) — this file's only
5
- * job is constructing the right client and pricing module.
5
+ * job is constructing the right client.
6
6
  */
7
7
  import Anthropic from "@anthropic-ai/sdk";
8
8
  import { ClaudeLlmProvider } from "./claude-provider.js";
9
- export { anthropicSupportedModels } from "./pricing-anthropic.js";
9
+ import type { CatalogLookup } from "./catalog-lookup.js";
10
10
  export declare function anthropicCredentialsPresent(env?: NodeJS.ProcessEnv): boolean;
11
11
  export declare class AnthropicLlmProvider extends ClaudeLlmProvider {
12
- constructor(apiKey?: string, client?: Anthropic);
12
+ constructor(apiKey?: string, client?: Anthropic, lookup?: CatalogLookup);
13
13
  }
@@ -2,20 +2,18 @@
2
2
  * Direct Anthropic (Claude) adapter for the LlmProvider seam. `@anthropic-ai/sdk`
3
3
  * is imported only here; all protocol/pricing-dispatch logic lives in the
4
4
  * shared ClaudeLlmProvider base class (claude-provider.ts) — this file's only
5
- * job is constructing the right client and pricing module.
5
+ * job is constructing the right client.
6
6
  */
7
7
  import Anthropic from "@anthropic-ai/sdk";
8
8
  import { ClaudeLlmProvider } from "./claude-provider.js";
9
- import { anthropicPriceUsd, getAnthropicPricing } from "./pricing-anthropic.js";
10
- export { anthropicSupportedModels } from "./pricing-anthropic.js";
11
9
  export function anthropicCredentialsPresent(env = process.env) {
12
10
  return Boolean(env.ANTHROPIC_API_KEY);
13
11
  }
14
12
  export class AnthropicLlmProvider extends ClaudeLlmProvider {
15
- constructor(apiKey = process.env.ANTHROPIC_API_KEY ?? "", client) {
13
+ constructor(apiKey = process.env.ANTHROPIC_API_KEY ?? "", client, lookup) {
16
14
  if (!client && !apiKey) {
17
15
  throw new Error("ANTHROPIC_API_KEY is not set — required by the Anthropic LlmProvider adapter.");
18
16
  }
19
- super(client ?? new Anthropic({ apiKey }), { getPricing: getAnthropicPricing, priceUsd: anthropicPriceUsd });
17
+ super(client ?? new Anthropic({ apiKey }), lookup);
20
18
  }
21
19
  }
@@ -3,7 +3,7 @@
3
3
  * is imported only here; all protocol/pricing-dispatch logic lives in the
4
4
  * shared ClaudeLlmProvider base class (claude-provider.ts) — AnthropicBedrock
5
5
  * exposes the identical .messages.stream() surface as @anthropic-ai/sdk, so
6
- * this file's only job is constructing the right client and pricing module.
6
+ * this file's only job is constructing the right client.
7
7
  *
8
8
  * Named BedrockClaudeLlmProvider, not BedrockLlmProvider: Bedrock hosts
9
9
  * multiple model vendors, and this adapter only ever speaks the
@@ -12,8 +12,8 @@
12
12
  */
13
13
  import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
14
14
  import { ClaudeLlmProvider } from "./claude-provider.js";
15
- export { bedrockClaudeSupportedModels } from "./pricing-bedrock-claude.js";
15
+ import type { CatalogLookup } from "./catalog-lookup.js";
16
16
  export declare function bedrockCredentialsPresent(env?: NodeJS.ProcessEnv): boolean;
17
17
  export declare class BedrockClaudeLlmProvider extends ClaudeLlmProvider {
18
- constructor(region?: string, client?: AnthropicBedrock);
18
+ constructor(region?: string, client?: AnthropicBedrock, lookup?: CatalogLookup);
19
19
  }
@@ -3,7 +3,7 @@
3
3
  * is imported only here; all protocol/pricing-dispatch logic lives in the
4
4
  * shared ClaudeLlmProvider base class (claude-provider.ts) — AnthropicBedrock
5
5
  * exposes the identical .messages.stream() surface as @anthropic-ai/sdk, so
6
- * this file's only job is constructing the right client and pricing module.
6
+ * this file's only job is constructing the right client.
7
7
  *
8
8
  * Named BedrockClaudeLlmProvider, not BedrockLlmProvider: Bedrock hosts
9
9
  * multiple model vendors, and this adapter only ever speaks the
@@ -12,8 +12,6 @@
12
12
  */
13
13
  import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
14
14
  import { ClaudeLlmProvider } from "./claude-provider.js";
15
- import { bedrockClaudePriceUsd, getBedrockClaudePricing } from "./pricing-bedrock-claude.js";
16
- export { bedrockClaudeSupportedModels } from "./pricing-bedrock-claude.js";
17
15
  export function bedrockCredentialsPresent(env = process.env) {
18
16
  // A region is the one thing Bedrock always needs; AWS resolves actual
19
17
  // credentials from the standard default chain (env keys, shared config,
@@ -21,13 +19,10 @@ export function bedrockCredentialsPresent(env = process.env) {
21
19
  return Boolean(env.BEDROCK_REGION ?? env.AWS_REGION);
22
20
  }
23
21
  export class BedrockClaudeLlmProvider extends ClaudeLlmProvider {
24
- constructor(region = process.env.BEDROCK_REGION ?? process.env.AWS_REGION ?? "", client) {
22
+ constructor(region = process.env.BEDROCK_REGION ?? process.env.AWS_REGION ?? "", client, lookup) {
25
23
  if (!client && !region) {
26
24
  throw new Error("BEDROCK_REGION (or AWS_REGION) is required by the Bedrock Claude LlmProvider adapter.");
27
25
  }
28
- super(client ?? new AnthropicBedrock({ awsRegion: region }), {
29
- getPricing: getBedrockClaudePricing,
30
- priceUsd: bedrockClaudePriceUsd,
31
- });
26
+ super(client ?? new AnthropicBedrock({ awsRegion: region }), lookup);
32
27
  }
33
28
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * How an adapter finds the catalog entry for a model. The default reads the
3
+ * process's current catalog; pinnedLookup binds an adapter to one run's
4
+ * stored entry. Kept apart from the store so adapters depend only on this.
5
+ */
6
+ import { type CatalogEntry } from "./catalog-types.js";
7
+ /** Throws ModelUnavailableError for a model it does not serve. */
8
+ export type CatalogLookup = (model: string) => CatalogEntry;
9
+ export declare const currentLookup: CatalogLookup;
10
+ export declare function pinnedLookup(entry: CatalogEntry): CatalogLookup;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * How an adapter finds the catalog entry for a model. The default reads the
3
+ * process's current catalog; pinnedLookup binds an adapter to one run's
4
+ * stored entry. Kept apart from the store so adapters depend only on this.
5
+ */
6
+ import { ModelUnavailableError } from "./catalog-types.js";
7
+ import { currentModelCatalog } from "./catalog-store.js";
8
+ export const currentLookup = (model) => currentModelCatalog().require(model);
9
+ export function pinnedLookup(entry) {
10
+ return (model) => {
11
+ if (model !== entry.modelId)
12
+ throw new ModelUnavailableError(model, "not_in_catalog");
13
+ return entry;
14
+ };
15
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The model catalog wardby ships. Every entry is fully literal: rates are the
3
+ * provider's own published numbers for that exact model, never derived from
4
+ * another field (CLAUDE.md "LLM pricing tables — STRICT"). A deployment's
5
+ * admins override or extend this with ModelCatalogEntry rows (set_model);
6
+ * this file changes only with a wardby release, and SHIPPED_CATALOG_VERSION
7
+ * must be bumped whenever any value here changes.
8
+ *
9
+ * Anthropic and Bedrock rates are the 5-minute cache-TTL numbers
10
+ * (platform.claude.com/docs/en/about-claude/pricing): wardby only emits the
11
+ * default 5-minute cache_control breakpoint. OpenAI's pre-GPT-5.6 models have
12
+ * no distinct cache-write tier (a first-time prefix bills at the standard
13
+ * input rate), so their cacheWritePerMTok is their own input rate, stated
14
+ * literally.
15
+ */
16
+ import type { CatalogEntry } from "./catalog-types.js";
17
+ export declare const SHIPPED_CATALOG_VERSION = "2026-10-03";
18
+ export declare const SHIPPED_CATALOG: readonly CatalogEntry[];