@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
@@ -0,0 +1,127 @@
1
+ import type { PackageAllowlist } from "../../../coding/registry/allowlist.js";
2
+ import type { DeclaredDependency } from "../../../coding/registry/types.js";
3
+ export interface RegistryRunContext {
4
+ runId: string;
5
+ deadlineAt: Date;
6
+ allowlist: PackageAllowlist;
7
+ policy: unknown;
8
+ }
9
+ export interface RegistryFetchRecord {
10
+ runId: string;
11
+ ecosystem: string;
12
+ name: string;
13
+ version?: string;
14
+ filename?: string;
15
+ integrity?: string;
16
+ sizeBytes?: number;
17
+ outcome: "served" | "refused";
18
+ reason?: string;
19
+ }
20
+ /** A registry-verified version fact as stored: always with its publish time. */
21
+ export interface StoredVersionFact {
22
+ name: string;
23
+ version: string;
24
+ publishedAt: Date;
25
+ integrity: string;
26
+ downloadUrl: string;
27
+ dependencies: readonly DeclaredDependency[];
28
+ }
29
+ /** One exact version a lockfile plan approved for a run. */
30
+ export interface ApprovedVersion {
31
+ name: string;
32
+ version: string;
33
+ integrity: string;
34
+ }
35
+ /** One exact version a lockfile plan definitively refused for a run. */
36
+ export interface PlanRefusedVersion {
37
+ name: string;
38
+ version: string;
39
+ code: string;
40
+ reason: string;
41
+ /** Set for a too-new refusal: it lapses once the version is old enough. */
42
+ publishedAt?: Date | null;
43
+ }
44
+ /** Run-scoped store over the registry-only token session lookup and the
45
+ * RegistryAllowance/RegistryFetch tables (Task 5). Backs the registry proxy:
46
+ * it never sees the model capability, only the derived registry token. */
47
+ export interface RegistryStore {
48
+ findRunByRegistryTokenHash(hash: string, now: Date): Promise<RegistryRunContext | null>;
49
+ isAllowedDependency(runId: string, ecosystem: string, name: string): Promise<boolean>;
50
+ addAllowances(runId: string, ecosystem: string, names: readonly string[]): Promise<void>;
51
+ recordFetch(record: RegistryFetchRecord): Promise<void>;
52
+ usage(runId: string): Promise<{
53
+ files: number;
54
+ bytes: number;
55
+ }>;
56
+ /** Number of refused RegistryFetch rows recorded for the run. */
57
+ refusalCount(runId: string): Promise<number>;
58
+ listFetches(runId: string): Promise<(RegistryFetchRecord & {
59
+ createdAt: Date;
60
+ })[]>;
61
+ /** Stored facts for these versions (any not stored are absent). */
62
+ getVersionFacts(ecosystem: string, versions: readonly {
63
+ name: string;
64
+ version: string;
65
+ }[]): Promise<StoredVersionFact[]>;
66
+ /** Stores facts; one already stored is kept as it is (facts are immutable). */
67
+ putVersionFacts(ecosystem: string, facts: readonly StoredVersionFact[]): Promise<void>;
68
+ /** Approves exact versions for the run (an existing approval is kept). */
69
+ approveVersions(runId: string, ecosystem: string, versions: readonly ApprovedVersion[]): Promise<void>;
70
+ /** The run's approval of this exact version, with its download URL (from
71
+ * the version's fact), or null. */
72
+ findApprovedVersion(runId: string, ecosystem: string, name: string, version: string): Promise<{
73
+ integrity: string;
74
+ downloadUrl: string;
75
+ } | null>;
76
+ /** Stores the run's plan refusals (an existing one is kept). */
77
+ refusePlanVersions(runId: string, ecosystem: string, versions: readonly PlanRefusedVersion[]): Promise<void>;
78
+ /** The run's plan refusal of this exact version, or null. */
79
+ findPlanRefusal(runId: string, ecosystem: string, name: string, version: string): Promise<{
80
+ code: string;
81
+ reason: string;
82
+ publishedAt: Date | null;
83
+ } | null>;
84
+ }
85
+ /** In-memory adapter for tests. `contexts` is settable directly so tests can
86
+ * seed a run without going through a full proxy session. */
87
+ export declare class MemoryRegistryStore implements RegistryStore {
88
+ readonly contexts: Map<string, RegistryRunContext>;
89
+ readonly allowances: Set<string>;
90
+ readonly fetches: (RegistryFetchRecord & {
91
+ createdAt: Date;
92
+ })[];
93
+ /** `ecosystem\0name\0version` -> fact. */
94
+ readonly facts: Map<string, StoredVersionFact>;
95
+ /** `runId\0ecosystem\0name\0version` -> approval. */
96
+ readonly approvals: Map<string, ApprovedVersion>;
97
+ /** `runId\0ecosystem\0name\0version` -> plan refusal. */
98
+ readonly planRefusals: Map<string, PlanRefusedVersion>;
99
+ findRunByRegistryTokenHash(hash: string, now: Date): Promise<RegistryRunContext | null>;
100
+ isAllowedDependency(runId: string, ecosystem: string, name: string): Promise<boolean>;
101
+ addAllowances(runId: string, ecosystem: string, names: readonly string[]): Promise<void>;
102
+ recordFetch(record: RegistryFetchRecord): Promise<void>;
103
+ usage(runId: string): Promise<{
104
+ files: number;
105
+ bytes: number;
106
+ }>;
107
+ refusalCount(runId: string): Promise<number>;
108
+ listFetches(runId: string): Promise<(RegistryFetchRecord & {
109
+ createdAt: Date;
110
+ })[]>;
111
+ getVersionFacts(ecosystem: string, versions: readonly {
112
+ name: string;
113
+ version: string;
114
+ }[]): Promise<StoredVersionFact[]>;
115
+ putVersionFacts(ecosystem: string, facts: readonly StoredVersionFact[]): Promise<void>;
116
+ approveVersions(runId: string, ecosystem: string, versions: readonly ApprovedVersion[]): Promise<void>;
117
+ findApprovedVersion(runId: string, ecosystem: string, name: string, version: string): Promise<{
118
+ integrity: string;
119
+ downloadUrl: string;
120
+ } | null>;
121
+ refusePlanVersions(runId: string, ecosystem: string, versions: readonly PlanRefusedVersion[]): Promise<void>;
122
+ findPlanRefusal(runId: string, ecosystem: string, name: string, version: string): Promise<{
123
+ code: string;
124
+ reason: string;
125
+ publishedAt: Date | null;
126
+ } | null>;
127
+ }
@@ -0,0 +1,70 @@
1
+ /** In-memory adapter for tests. `contexts` is settable directly so tests can
2
+ * seed a run without going through a full proxy session. */
3
+ export class MemoryRegistryStore {
4
+ contexts = new Map();
5
+ allowances = new Set();
6
+ fetches = [];
7
+ /** `ecosystem\0name\0version` -> fact. */
8
+ facts = new Map();
9
+ /** `runId\0ecosystem\0name\0version` -> approval. */
10
+ approvals = new Map();
11
+ /** `runId\0ecosystem\0name\0version` -> plan refusal. */
12
+ planRefusals = new Map();
13
+ async findRunByRegistryTokenHash(hash, now) {
14
+ const context = this.contexts.get(hash);
15
+ return context && context.deadlineAt > now ? context : null;
16
+ }
17
+ async isAllowedDependency(runId, ecosystem, name) {
18
+ return this.allowances.has(`${runId}\0${ecosystem}\0${name}`);
19
+ }
20
+ async addAllowances(runId, ecosystem, names) {
21
+ for (const name of names)
22
+ this.allowances.add(`${runId}\0${ecosystem}\0${name}`);
23
+ }
24
+ async recordFetch(record) {
25
+ this.fetches.push({ ...record, createdAt: new Date() });
26
+ }
27
+ async usage(runId) {
28
+ const served = this.fetches.filter((fetch) => fetch.runId === runId && fetch.outcome === "served");
29
+ return { files: served.length, bytes: served.reduce((sum, fetch) => sum + (fetch.sizeBytes ?? 0), 0) };
30
+ }
31
+ async refusalCount(runId) {
32
+ return this.fetches.filter((fetch) => fetch.runId === runId && fetch.outcome === "refused").length;
33
+ }
34
+ async listFetches(runId) {
35
+ return this.fetches.filter((fetch) => fetch.runId === runId);
36
+ }
37
+ async getVersionFacts(ecosystem, versions) {
38
+ return versions.flatMap(({ name, version }) => this.facts.get(`${ecosystem}\0${name}\0${version}`) ?? []);
39
+ }
40
+ async putVersionFacts(ecosystem, facts) {
41
+ for (const fact of facts) {
42
+ const key = `${ecosystem}\0${fact.name}\0${fact.version}`;
43
+ if (!this.facts.has(key))
44
+ this.facts.set(key, fact);
45
+ }
46
+ }
47
+ async approveVersions(runId, ecosystem, versions) {
48
+ for (const approval of versions) {
49
+ const key = `${runId}\0${ecosystem}\0${approval.name}\0${approval.version}`;
50
+ if (!this.approvals.has(key))
51
+ this.approvals.set(key, approval);
52
+ }
53
+ }
54
+ async findApprovedVersion(runId, ecosystem, name, version) {
55
+ const approval = this.approvals.get(`${runId}\0${ecosystem}\0${name}\0${version}`);
56
+ const fact = this.facts.get(`${ecosystem}\0${name}\0${version}`);
57
+ return approval && fact ? { integrity: approval.integrity, downloadUrl: fact.downloadUrl } : null;
58
+ }
59
+ async refusePlanVersions(runId, ecosystem, versions) {
60
+ for (const refusal of versions) {
61
+ const key = `${runId}\0${ecosystem}\0${refusal.name}\0${refusal.version}`;
62
+ if (!this.planRefusals.has(key))
63
+ this.planRefusals.set(key, refusal);
64
+ }
65
+ }
66
+ async findPlanRefusal(runId, ecosystem, name, version) {
67
+ const refusal = this.planRefusals.get(`${runId}\0${ecosystem}\0${name}\0${version}`);
68
+ return refusal ? { code: refusal.code, reason: refusal.reason, publishedAt: refusal.publishedAt ?? null } : null;
69
+ }
70
+ }
@@ -1,12 +1,29 @@
1
1
  import type { PrismaClient } from "#prisma";
2
+ import type { UpstreamFetch } from "../../coding/registry/types.js";
2
3
  import { startDenyPortListener } from "./deny-port.js";
4
+ import { type PinnedProxyFetchOptions } from "./secure-fetch.js";
3
5
  import { startCodingProxyServer, type CodingProxyServerHandle } from "./server.js";
4
6
  import type { ProxyAuditSink } from "./types.js";
7
+ /** Adapts the pinned upstream `fetch` (which only forwards `init.headers`)
8
+ * to `UpstreamFetch`'s narrower init shape: `accept` becomes an `accept`
9
+ * header, `acceptEncoding` an `accept-encoding` header (the pinned fetch
10
+ * never decompresses; the caller that asks for gzip does), and a `content-type: application/json` header is set whenever a
11
+ * body is present (every registry/OSV upstream call sends or expects
12
+ * JSON). Exported so its header-mapping can be unit-tested directly,
13
+ * without needing a live upstream. */
14
+ export declare function createRegistryUpstream(pinned: typeof globalThis.fetch): UpstreamFetch;
5
15
  export interface CodingProxyRuntimeOptions {
6
16
  db: PrismaClient;
17
+ /** The package registry's own client, so its traffic (many concurrent
18
+ * downloads during an install) cannot starve the budget ledger that every
19
+ * model request needs. Defaults to `db`. */
20
+ registryDb?: PrismaClient;
7
21
  env?: NodeJS.ProcessEnv;
8
22
  startServer?: typeof startCodingProxyServer;
9
23
  startDenyPort?: typeof startDenyPortListener;
24
+ /** Overridable for tests: proves the OSV host and every adapter's
25
+ * upstream hosts are actually passed to the pinned-fetch allowlist. */
26
+ createPinnedFetch?: (options: PinnedProxyFetchOptions) => typeof globalThis.fetch;
10
27
  audit?: ProxyAuditSink;
11
28
  onRequest?: (event: {
12
29
  protocol: "openai-responses" | "anthropic-messages" | "other";
@@ -1,9 +1,40 @@
1
+ import { REGISTRY_ADAPTERS } from "../../coding/registry/adapters.js";
1
2
  import { CODING_PROXY_ALIAS, CODING_PROXY_DENY_PORT, CODING_PROXY_PORT } from "../jobs/docker-isolation.js";
2
3
  import { startDenyPortListener } from "./deny-port.js";
3
4
  import { EnvironmentCredentialResolver } from "./environment-credentials.js";
4
5
  import { CodingProxy } from "./proxy.js";
5
6
  import { PrismaProxyLedger } from "./prisma-ledger.js";
7
+ import { OsvAudit } from "./registry/audit.js";
8
+ import { PrismaRegistryStore } from "./registry/prisma-store.js";
9
+ import { DEFAULT_PLAN_MAX_ENTRIES, DEFAULT_PLAN_TIMEOUT_MS } from "./registry/plan.js";
10
+ import { DEFAULT_GRAPH_TIMEOUT_MS, DEFAULT_MAX_GRAPH_PACKAGES, DEFAULT_PLAN_MAX_PER_RUN, RegistryService, } from "./registry/service.js";
11
+ import { createPinnedProxyFetch } from "./secure-fetch.js";
6
12
  import { startCodingProxyServer } from "./server.js";
13
+ const MIB = 1024 * 1024;
14
+ function positiveInt(value, fallback) {
15
+ const parsed = Number(value);
16
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
17
+ }
18
+ /** Adapts the pinned upstream `fetch` (which only forwards `init.headers`)
19
+ * to `UpstreamFetch`'s narrower init shape: `accept` becomes an `accept`
20
+ * header, `acceptEncoding` an `accept-encoding` header (the pinned fetch
21
+ * never decompresses; the caller that asks for gzip does), and a `content-type: application/json` header is set whenever a
22
+ * body is present (every registry/OSV upstream call sends or expects
23
+ * JSON). Exported so its header-mapping can be unit-tested directly,
24
+ * without needing a live upstream. */
25
+ export function createRegistryUpstream(pinned) {
26
+ return (url, init = {}) => pinned(url, {
27
+ method: init.method ?? "GET",
28
+ body: init.body,
29
+ signal: init.signal,
30
+ redirect: "error",
31
+ headers: {
32
+ ...(init.accept ? { accept: init.accept } : {}),
33
+ ...(init.acceptEncoding ? { "accept-encoding": init.acceptEncoding } : {}),
34
+ ...(init.body ? { "content-type": "application/json" } : {}),
35
+ },
36
+ });
37
+ }
7
38
  /** Starts the trusted proxy with the fixed worker-only Docker endpoint, plus the deny port the enforcement witness probes. */
8
39
  export async function startConfiguredCodingProxy(options) {
9
40
  const env = options.env ?? process.env;
@@ -12,11 +43,43 @@ export async function startConfiguredCodingProxy(options) {
12
43
  credentials: new EnvironmentCredentialResolver(env),
13
44
  audit: options.audit,
14
45
  });
46
+ const buildPinnedFetch = options.createPinnedFetch ?? createPinnedProxyFetch;
47
+ const upstreamHosts = [...new Set([...REGISTRY_ADAPTERS.values()].flatMap((adapter) => adapter.upstreamHosts))];
48
+ const pinned = buildPinnedFetch({ allowedHosts: [...upstreamHosts, "api.osv.dev"] });
49
+ const upstream = createRegistryUpstream(pinned);
50
+ const metadataTimeoutMs = positiveInt(env.REGISTRY_METADATA_TIMEOUT_MS, 30_000);
51
+ const maxMetadataBytes = positiveInt(env.REGISTRY_MAX_METADATA_MB, 64) * MIB;
52
+ const registry = new RegistryService({
53
+ adapters: REGISTRY_ADAPTERS,
54
+ store: new PrismaRegistryStore(options.registryDb ?? options.db),
55
+ audit: new OsvAudit({
56
+ fetch: upstream,
57
+ failOpen: env.REGISTRY_AUDIT_FAIL_OPEN === "true",
58
+ timeoutMs: metadataTimeoutMs,
59
+ maxBytes: maxMetadataBytes,
60
+ }),
61
+ upstream,
62
+ metadataTimeoutMs,
63
+ maxMetadataBytes,
64
+ maxGraphPackages: positiveInt(env.REGISTRY_MAX_GRAPH_PACKAGES, DEFAULT_MAX_GRAPH_PACKAGES),
65
+ graphTimeoutMs: positiveInt(env.REGISTRY_GRAPH_TIMEOUT_MS, DEFAULT_GRAPH_TIMEOUT_MS),
66
+ planMaxEntries: positiveInt(env.REGISTRY_PLAN_MAX_ENTRIES, DEFAULT_PLAN_MAX_ENTRIES),
67
+ planTimeoutMs: positiveInt(env.REGISTRY_PLAN_TIMEOUT_MS, DEFAULT_PLAN_TIMEOUT_MS),
68
+ planMaxPerRun: positiveInt(env.REGISTRY_PLAN_MAX_PER_RUN, DEFAULT_PLAN_MAX_PER_RUN),
69
+ proxyBase: `http://${CODING_PROXY_ALIAS}:${CODING_PROXY_PORT}/registry/`,
70
+ limits: {
71
+ maxFileBytes: positiveInt(env.REGISTRY_MAX_FILE_MB, 200) * MIB,
72
+ maxTotalBytes: positiveInt(env.REGISTRY_MAX_TOTAL_MB, 2048) * MIB,
73
+ maxFiles: positiveInt(env.REGISTRY_MAX_FILES, 5000),
74
+ idleTimeoutMs: positiveInt(env.REGISTRY_IDLE_TIMEOUT_MS, 120_000),
75
+ },
76
+ });
15
77
  const startServer = options.startServer ?? startCodingProxyServer;
16
78
  const server = await startServer(proxy, {
17
79
  host: "0.0.0.0",
18
80
  port: CODING_PROXY_PORT,
19
81
  expectedHost: `${CODING_PROXY_ALIAS}:${CODING_PROXY_PORT}`,
82
+ registry,
20
83
  onRequest: options.onRequest,
21
84
  });
22
85
  let deny;
@@ -37,7 +37,6 @@ export function createPinnedProxyFetch(options) {
37
37
  throw blocked();
38
38
  const destination = await resolveDestination(url, {
39
39
  allowedHosts,
40
- allowPrivateHosts: false,
41
40
  restrictToAllowedHosts: true,
42
41
  resolve: options.resolve,
43
42
  });
@@ -1,9 +1,19 @@
1
+ import type { ProxyAuditEvent } from "./types.js";
1
2
  import { type CodingProxy } from "./proxy.js";
3
+ import { type RegistryService } from "./registry/service.js";
2
4
  import type { ProxyProtocol } from "./types.js";
5
+ declare const proxyLog: import("pino").Logger<never, boolean>;
6
+ /**
7
+ * Writes a proxy audit event to the operator log. The events carry ids,
8
+ * models, amounts, statuses and fixed reason codes only, never request or
9
+ * response content. `sink` defaults to the proxy's own logger.
10
+ */
11
+ export declare function logProxyAudit(event: ProxyAuditEvent, sink?: Pick<typeof proxyLog, "info">): void;
3
12
  export interface CodingProxyServerConfig {
4
13
  host: string;
5
14
  port: number;
6
15
  expectedHost?: string;
16
+ registry?: Pick<RegistryService, "handle"> & Partial<Pick<RegistryService, "plan">>;
7
17
  onRequest?: (event: {
8
18
  protocol: ProxyProtocol | "other";
9
19
  status: number;
@@ -15,3 +25,4 @@ export interface CodingProxyServerHandle {
15
25
  close(): Promise<void>;
16
26
  }
17
27
  export declare function startCodingProxyServer(proxy: CodingProxy, config: CodingProxyServerConfig): Promise<CodingProxyServerHandle>;
28
+ export {};
@@ -1,8 +1,21 @@
1
1
  import { createServer } from "node:http";
2
+ import { StringDecoder } from "node:string_decoder";
3
+ import { pipeline, Readable } from "node:stream";
2
4
  import { HTTP_LIMITS, HttpBoundaryError, readBody } from "../../mcp/transport/http-limits.js";
3
5
  import { logger } from "../../core/logger.js";
4
6
  import { CodingProxyError, PROXY_MAX_BODY_BYTES } from "./proxy.js";
7
+ import { RegistryError } from "../../coding/registry/types.js";
8
+ import { MAX_PLAN_BODY_BYTES } from "./registry/service.js";
5
9
  const proxyLog = logger.child({ module: "coding-proxy" });
10
+ /**
11
+ * Writes a proxy audit event to the operator log. The events carry ids,
12
+ * models, amounts, statuses and fixed reason codes only, never request or
13
+ * response content. `sink` defaults to the proxy's own logger.
14
+ */
15
+ export function logProxyAudit(event, sink = proxyLog) {
16
+ const { type, ...fields } = event;
17
+ sink.info({ ...fields, event: `audit.${type}` }, "coding proxy audit");
18
+ }
6
19
  function sendError(response, status, code) {
7
20
  response
8
21
  .writeHead(status, { "content-type": "application/json", "cache-control": "no-store" })
@@ -13,6 +26,79 @@ function bearer(value) {
13
26
  return "";
14
27
  return value.slice(7);
15
28
  }
29
+ /** The registry's own auth: a registry-only token (`rrg_…`) carried as either
30
+ * a bearer token or the password half of HTTP basic auth (some clients,
31
+ * e.g. pip, only support basic auth for a package index). */
32
+ function registryToken(authorization) {
33
+ if (!authorization)
34
+ return "";
35
+ const bearerToken = bearer(authorization);
36
+ if (bearerToken)
37
+ return bearerToken;
38
+ const basic = authorization.match(/^Basic ([A-Za-z0-9+/=]+)$/);
39
+ if (!basic)
40
+ return "";
41
+ const decoded = Buffer.from(basic[1], "base64").toString("utf8");
42
+ const colon = decoded.indexOf(":");
43
+ return colon >= 0 ? decoded.slice(colon + 1) : "";
44
+ }
45
+ /** Time a client has to upload a lockfile to the plan route. */
46
+ const PLAN_UPLOAD_MS = 60_000;
47
+ function sendRegistry(response, result) {
48
+ response
49
+ .writeHead(result.status, { "content-type": result.contentType, "cache-control": "no-store" })
50
+ .end(result.body);
51
+ }
52
+ /** Reads a lockfile body within MAX_PLAN_BODY_BYTES, decoding each chunk
53
+ * as it arrives (no buffered copy of the raw bytes), and joins the text
54
+ * once. A RegistryError says why it could not be read. */
55
+ function readPlanBody(request, signal) {
56
+ const tooLarge = () => new RegistryError(413, "wardby_lockfile_too_large", "the lockfile is larger than 20 MiB");
57
+ const length = request.headers["content-length"];
58
+ if (length !== undefined && (!/^\d+$/.test(length) || Number(length) > MAX_PLAN_BODY_BYTES))
59
+ return Promise.reject(tooLarge());
60
+ const encoding = request.headers["content-encoding"];
61
+ if (encoding && encoding !== "identity")
62
+ return Promise.reject(new RegistryError(400, "wardby_bad_request", "the lockfile must not be content-encoded"));
63
+ return new Promise((resolve, reject) => {
64
+ const decoder = new StringDecoder("utf8");
65
+ const parts = [];
66
+ let size = 0;
67
+ const cleanup = () => {
68
+ request.off("data", data);
69
+ request.off("end", end);
70
+ request.off("error", failed);
71
+ request.off("aborted", failed);
72
+ signal.removeEventListener("abort", failed);
73
+ };
74
+ const fail = (error) => {
75
+ cleanup();
76
+ parts.length = 0;
77
+ request.pause();
78
+ reject(error);
79
+ };
80
+ const failed = () => fail(new RegistryError(400, "wardby_bad_request", "the lockfile could not be read"));
81
+ const data = (chunk) => {
82
+ size += chunk.length;
83
+ if (size > MAX_PLAN_BODY_BYTES)
84
+ fail(tooLarge());
85
+ else
86
+ parts.push(decoder.write(chunk));
87
+ };
88
+ const end = () => {
89
+ cleanup();
90
+ parts.push(decoder.end());
91
+ resolve(parts.join(""));
92
+ };
93
+ request.on("data", data);
94
+ request.once("end", end);
95
+ request.once("error", failed);
96
+ request.once("aborted", failed);
97
+ signal.addEventListener("abort", failed, { once: true });
98
+ if (signal.aborted)
99
+ failed();
100
+ });
101
+ }
16
102
  function routeProtocol(method, url) {
17
103
  if (method !== "POST")
18
104
  return undefined;
@@ -60,6 +146,83 @@ export async function startCodingProxyServer(proxy, config) {
60
146
  sendError(response, 403, "invalid_host");
61
147
  return;
62
148
  }
149
+ if (request.url?.startsWith("/registry/")) {
150
+ if (!config.registry) {
151
+ sendError(response, 404, "not_found");
152
+ return;
153
+ }
154
+ const plan = request.url.match(/^\/registry\/([a-z0-9-]+)\/-\/plan(?:\?.*)?$/);
155
+ if (plan && request.method === "POST" && config.registry.plan) {
156
+ // Lockfile verification. The registry authenticates the token and
157
+ // takes a plan slot before it asks for the body, which is then read
158
+ // within its own size and time bounds.
159
+ const controller = new AbortController();
160
+ response.on("close", () => {
161
+ if (!response.writableFinished)
162
+ controller.abort();
163
+ });
164
+ let bodyRead = false;
165
+ const result = await config.registry.plan({
166
+ ecosystem: plan[1],
167
+ token: registryToken(request.headers.authorization),
168
+ readBody: () => {
169
+ bodyRead = true;
170
+ return readPlanBody(request, AbortSignal.any([controller.signal, AbortSignal.timeout(PLAN_UPLOAD_MS)]));
171
+ },
172
+ signal: controller.signal,
173
+ });
174
+ // Refused before the body was read: close the connection rather
175
+ // than read (or keep) what the client is still sending.
176
+ if (!bodyRead)
177
+ response.setHeader("connection", "close");
178
+ if ("body" in result)
179
+ sendRegistry(response, result);
180
+ else {
181
+ void result.stream.cancel().catch(() => undefined);
182
+ sendError(response, 500, "internal_error");
183
+ }
184
+ return;
185
+ }
186
+ if (request.method !== "GET" && request.method !== "HEAD") {
187
+ sendError(response, 405, "method_not_allowed");
188
+ return;
189
+ }
190
+ const match = request.url.match(/^\/registry\/([a-z0-9-]+)\/(.*)$/);
191
+ if (!match) {
192
+ sendError(response, 404, "not_found");
193
+ return;
194
+ }
195
+ const controller = new AbortController();
196
+ response.on("close", () => controller.abort());
197
+ const result = await config.registry.handle({
198
+ method: request.method,
199
+ ecosystem: match[1],
200
+ subpath: match[2].split("?")[0],
201
+ token: registryToken(request.headers.authorization),
202
+ signal: controller.signal,
203
+ });
204
+ response.statusCode = result.status;
205
+ response.setHeader("content-type", result.contentType);
206
+ if ("body" in result) {
207
+ response.end(request.method === "HEAD" ? undefined : result.body);
208
+ return;
209
+ }
210
+ if (request.method === "HEAD") {
211
+ // The registry answers HEAD without starting a download; cancel
212
+ // defensively anyway so a stream can never hold a reservation.
213
+ void result.stream.cancel().catch(() => undefined);
214
+ response.end();
215
+ return;
216
+ }
217
+ // pipeline (not .pipe) destroys the source when the client
218
+ // disconnects or the response errors, which cancels the web stream
219
+ // so the registry releases the run's in-flight reservation.
220
+ pipeline(Readable.fromWeb(result.stream), response, (error) => {
221
+ if (error && !response.destroyed)
222
+ response.destroy();
223
+ });
224
+ return;
225
+ }
63
226
  if (request.method === "HEAD" && request.url === "/api/hello") {
64
227
  response.writeHead(200, { "cache-control": "no-store" }).end();
65
228
  return;
@@ -1,10 +1,24 @@
1
- import type { ModelPricing } from "../llm/pricing.js";
1
+ import { type CatalogEntry } from "../llm/catalog-types.js";
2
+ import type { ModelPricing } from "../llm/pricing-core.js";
2
3
  export type ProxySessionStatus = "active" | "cancelled";
3
4
  export type ProxyRequestStatus = "reserved" | "completed" | "released" | "uncertain";
4
5
  export type ProxyProtocol = "openai-responses" | "anthropic-messages";
5
6
  export interface PricingSnapshot extends ModelPricing {
6
7
  version: string;
7
8
  }
9
+ /** The model terms a coding run was dispatched under: its catalog entry and that entry's price version. */
10
+ export interface ProxyModelTerms {
11
+ version: string;
12
+ entry: CatalogEntry;
13
+ }
14
+ /**
15
+ * Validates and copies model terms, for both ledgers on write and the database ledger on read.
16
+ * Throws invalid_proxy_session_terms: unreadable terms must refuse the session, never fall back.
17
+ */
18
+ export declare function normalizeProxyModelTerms(terms: {
19
+ version: unknown;
20
+ entry: unknown;
21
+ }): ProxyModelTerms;
8
22
  export interface ProxyUsage {
9
23
  inputTokens: number;
10
24
  outputTokens: number;
@@ -22,6 +36,13 @@ export interface ProxySession {
22
36
  deadlineAt: Date;
23
37
  budgetUsd: number;
24
38
  status: ProxySessionStatus;
39
+ registryTokenHash?: string | null;
40
+ /** When the ledger first refused a request of this session for budget. */
41
+ budgetExhaustedAt?: Date | null;
42
+ /** The code of the first upstream failure the proxy relayed for this session. */
43
+ upstreamFailure?: string | null;
44
+ /** The run's catalog entry, copied at session creation; null on sessions from before the catalog. */
45
+ terms?: ProxyModelTerms | null;
25
46
  }
26
47
  export interface ProxyRequest {
27
48
  id: string;
@@ -45,6 +66,8 @@ export interface CreateProxySessionInput {
45
66
  allowedModels: string[];
46
67
  deadlineAt: Date;
47
68
  budgetUsd: number;
69
+ registryTokenHash: string;
70
+ terms?: ProxyModelTerms;
48
71
  }
49
72
  export interface ReserveProxyRequestInput {
50
73
  id: string;
@@ -76,6 +99,12 @@ export interface ProxyLedger {
76
99
  release(requestId: string, upstreamStatus: number): Promise<void>;
77
100
  markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
78
101
  cancelSession(sessionId: string): Promise<void>;
102
+ /** Whether a request of this session was ever refused for budget. */
103
+ budgetExhausted(sessionId: string): Promise<boolean>;
104
+ /** Records an upstream failure code on the session; only the first one is kept. */
105
+ recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
106
+ /** The first upstream failure code relayed for this session, if any. */
107
+ upstreamFailure(sessionId: string): Promise<string | null>;
79
108
  getRequest(requestId: string): Promise<ProxyRequest | null>;
80
109
  }
81
110
  export interface ProxyAuditEvent {
@@ -92,6 +121,9 @@ export interface ProxyAuditEvent {
92
121
  cachedInputTokens?: number;
93
122
  cacheWriteTokens?: number;
94
123
  reasoningTokens?: number;
124
+ /** For a failed stream: the upstream response's content type and encoding headers, for diagnosis. */
125
+ contentType?: string;
126
+ contentEncoding?: string;
95
127
  }
96
128
  export type ProxyAuditSink = (event: ProxyAuditEvent) => void;
97
129
  export interface CredentialResolver {
@@ -1 +1,12 @@
1
- export {};
1
+ import { parseStoredEntry } from "../llm/catalog-types.js";
2
+ /**
3
+ * Validates and copies model terms, for both ledgers on write and the database ledger on read.
4
+ * Throws invalid_proxy_session_terms: unreadable terms must refuse the session, never fall back.
5
+ */
6
+ export function normalizeProxyModelTerms(terms) {
7
+ const entry = parseStoredEntry(terms.entry);
8
+ if (typeof terms.version !== "string" || terms.version.length === 0 || !entry) {
9
+ throw new Error("invalid_proxy_session_terms");
10
+ }
11
+ return { version: terms.version, entry };
12
+ }