@wardby/cli 0.2.0 → 0.3.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 (491) hide show
  1. package/.env.example +34 -4
  2. package/README.md +183 -71
  3. package/dist/claude-coding-worker/driver.d.ts +7 -1
  4. package/dist/claude-coding-worker/driver.js +31 -2
  5. package/dist/claude-coding-worker/main.js +5 -2
  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 +13 -4
  10. package/dist/cli.d.ts +1 -1
  11. package/dist/cli.js +219 -29
  12. package/dist/coding/collect-exclude.d.ts +25 -0
  13. package/dist/coding/collect-exclude.js +76 -0
  14. package/dist/coding/profile.d.ts +67 -22
  15. package/dist/coding/profile.js +58 -25
  16. package/dist/coding/protected-path-wording.d.ts +24 -0
  17. package/dist/coding/protected-path-wording.js +55 -0
  18. package/dist/coding/protected-paths.d.ts +31 -0
  19. package/dist/coding/protected-paths.js +48 -0
  20. package/dist/coding/protocol.d.ts +99 -3
  21. package/dist/coding/protocol.js +155 -4
  22. package/dist/coding/registry/adapters.d.ts +2 -0
  23. package/dist/coding/registry/adapters.js +9 -0
  24. package/dist/coding/registry/allowlist.d.ts +9 -0
  25. package/dist/coding/registry/allowlist.js +28 -0
  26. package/dist/coding/registry/json-scan.d.ts +55 -0
  27. package/dist/coding/registry/json-scan.js +191 -0
  28. package/dist/coding/registry/lockfiles.d.ts +6 -0
  29. package/dist/coding/registry/lockfiles.js +89 -0
  30. package/dist/coding/registry/npm-lockfile.d.ts +9 -0
  31. package/dist/coding/registry/npm-lockfile.js +73 -0
  32. package/dist/coding/registry/npm-plan.d.ts +29 -0
  33. package/dist/coding/registry/npm-plan.js +289 -0
  34. package/dist/coding/registry/npm.d.ts +7 -0
  35. package/dist/coding/registry/npm.js +252 -0
  36. package/dist/coding/registry/pypi.d.ts +4 -0
  37. package/dist/coding/registry/pypi.js +210 -0
  38. package/dist/coding/registry/report.d.ts +37 -0
  39. package/dist/coding/registry/report.js +31 -0
  40. package/dist/coding/registry/token.d.ts +4 -0
  41. package/dist/coding/registry/token.js +7 -0
  42. package/dist/coding/registry/types.d.ts +286 -0
  43. package/dist/coding/registry/types.js +19 -0
  44. package/dist/coding/registry/worker-config.d.ts +14 -0
  45. package/dist/coding/registry/worker-config.js +31 -0
  46. package/dist/coding/services/builtins.d.ts +22 -0
  47. package/dist/coding/services/builtins.js +85 -0
  48. package/dist/coding/services/catalog.d.ts +443 -0
  49. package/dist/coding/services/catalog.js +159 -0
  50. package/dist/coding/services/declaration.d.ts +11 -0
  51. package/dist/coding/services/declaration.js +114 -0
  52. package/dist/coding/services/note.d.ts +8 -0
  53. package/dist/coding/services/note.js +15 -0
  54. package/dist/coding/services/resolve.d.ts +25 -0
  55. package/dist/coding/services/resolve.js +50 -0
  56. package/dist/coding/services/wording.d.ts +25 -0
  57. package/dist/coding/services/wording.js +70 -0
  58. package/dist/coding-proxy/main.js +24 -4
  59. package/dist/coding-worker/artifact.d.ts +18 -0
  60. package/dist/coding-worker/artifact.js +48 -6
  61. package/dist/coding-worker/debug-trace.d.ts +37 -0
  62. package/dist/coding-worker/debug-trace.js +117 -0
  63. package/dist/coding-worker/driver.d.ts +14 -1
  64. package/dist/coding-worker/driver.js +106 -14
  65. package/dist/coding-worker/errors.d.ts +7 -0
  66. package/dist/coding-worker/errors.js +26 -0
  67. package/dist/coding-worker/main.js +13 -4
  68. package/dist/coding-worker/sdk.d.ts +2 -2
  69. package/dist/coding-worker/sdk.js +7 -2
  70. package/dist/coding-worker/types.d.ts +3 -0
  71. package/dist/config/providers.d.ts +41 -0
  72. package/dist/config/providers.js +66 -0
  73. package/dist/core/budget-groups.d.ts +109 -6
  74. package/dist/core/budget-groups.js +125 -19
  75. package/dist/core/budget-wording.d.ts +22 -0
  76. package/dist/core/budget-wording.js +55 -0
  77. package/dist/core/coding-queue.d.ts +1 -1
  78. package/dist/core/datastores.d.ts +1 -1
  79. package/dist/core/datastores.js +18 -2
  80. package/dist/core/db.d.ts +40 -2
  81. package/dist/core/db.js +75 -2
  82. package/dist/core/dispatch.d.ts +49 -7
  83. package/dist/core/dispatch.js +290 -45
  84. package/dist/core/engine-native.js +27 -10
  85. package/dist/core/grants.d.ts +86 -0
  86. package/dist/core/grants.js +126 -0
  87. package/dist/core/host-events.d.ts +49 -0
  88. package/dist/core/host-events.js +257 -0
  89. package/dist/core/host-identity-links.d.ts +54 -0
  90. package/dist/core/host-identity-links.js +189 -0
  91. package/dist/core/host-status.d.ts +61 -0
  92. package/dist/core/host-status.js +211 -0
  93. package/dist/core/http-runtime.js +3 -4
  94. package/dist/core/in-flight-runs.d.ts +8 -0
  95. package/dist/core/in-flight-runs.js +56 -0
  96. package/dist/core/lease.d.ts +1 -1
  97. package/dist/core/private-directory.d.ts +20 -0
  98. package/dist/core/private-directory.js +36 -0
  99. package/dist/core/provider-wording.d.ts +12 -0
  100. package/dist/core/provider-wording.js +44 -0
  101. package/dist/core/reconciler.d.ts +39 -3
  102. package/dist/core/reconciler.js +86 -2
  103. package/dist/core/repo-access.d.ts +99 -0
  104. package/dist/core/repo-access.js +136 -0
  105. package/dist/core/review-host-checks.d.ts +11 -0
  106. package/dist/core/review-host-checks.js +41 -0
  107. package/dist/core/review-host-tools.d.ts +47 -0
  108. package/dist/core/review-host-tools.js +347 -0
  109. package/dist/core/run-heartbeat.d.ts +27 -0
  110. package/dist/core/run-heartbeat.js +54 -0
  111. package/dist/core/runner.d.ts +31 -9
  112. package/dist/core/runner.js +237 -40
  113. package/dist/core/scheduler.d.ts +1 -1
  114. package/dist/core/secrets.d.ts +12 -3
  115. package/dist/core/secrets.js +25 -6
  116. package/dist/core/subagent-memory-tools.d.ts +2 -2
  117. package/dist/core/subagent-memory-tools.js +16 -3
  118. package/dist/core/tool-admin.d.ts +81 -0
  119. package/dist/core/tool-admin.js +129 -0
  120. package/dist/core/tool-names.d.ts +42 -0
  121. package/dist/core/tool-names.js +64 -0
  122. package/dist/core/untrusted-content.d.ts +32 -0
  123. package/dist/core/untrusted-content.js +72 -0
  124. package/dist/core/webhooks.d.ts +9 -2
  125. package/dist/core/webhooks.js +23 -2
  126. package/dist/generated/prisma/browser.d.ts +328 -0
  127. package/dist/generated/prisma/browser.js +17 -0
  128. package/dist/generated/prisma/client.d.ts +347 -0
  129. package/dist/generated/prisma/client.js +34 -0
  130. package/dist/generated/prisma/commonInputTypes.d.ts +839 -0
  131. package/dist/generated/prisma/commonInputTypes.js +10 -0
  132. package/dist/generated/prisma/enums.d.ts +59 -0
  133. package/dist/generated/prisma/enums.js +59 -0
  134. package/dist/generated/prisma/internal/class.d.ts +605 -0
  135. package/dist/generated/prisma/internal/class.js +49 -0
  136. package/dist/generated/prisma/internal/prismaNamespace.d.ts +4494 -0
  137. package/dist/generated/prisma/internal/prismaNamespace.js +628 -0
  138. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +635 -0
  139. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +599 -0
  140. package/dist/generated/prisma/models/Agent.d.ts +3560 -0
  141. package/dist/generated/prisma/models/Agent.js +1 -0
  142. package/dist/generated/prisma/models/AgentDatastore.d.ts +1210 -0
  143. package/dist/generated/prisma/models/AgentDatastore.js +1 -0
  144. package/dist/generated/prisma/models/AgentMemory.d.ts +986 -0
  145. package/dist/generated/prisma/models/AgentMemory.js +1 -0
  146. package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
  147. package/dist/generated/prisma/models/AgentRepository.js +1 -0
  148. package/dist/generated/prisma/models/AgentSecret.d.ts +1212 -0
  149. package/dist/generated/prisma/models/AgentSecret.js +1 -0
  150. package/dist/generated/prisma/models/AgentSubAgent.d.ts +1217 -0
  151. package/dist/generated/prisma/models/AgentSubAgent.js +1 -0
  152. package/dist/generated/prisma/models/AgentTool.d.ts +1403 -0
  153. package/dist/generated/prisma/models/AgentTool.js +1 -0
  154. package/dist/generated/prisma/models/AuthFormChallenge.d.ts +1298 -0
  155. package/dist/generated/prisma/models/AuthFormChallenge.js +1 -0
  156. package/dist/generated/prisma/models/AuthLoginKey.d.ts +1245 -0
  157. package/dist/generated/prisma/models/AuthLoginKey.js +1 -0
  158. package/dist/generated/prisma/models/AuthRateLimit.d.ts +979 -0
  159. package/dist/generated/prisma/models/AuthRateLimit.js +1 -0
  160. package/dist/generated/prisma/models/AuthSession.d.ts +1376 -0
  161. package/dist/generated/prisma/models/AuthSession.js +1 -0
  162. package/dist/generated/prisma/models/AuthUser.d.ts +1700 -0
  163. package/dist/generated/prisma/models/AuthUser.js +1 -0
  164. package/dist/generated/prisma/models/BudgetGroup.d.ts +1548 -0
  165. package/dist/generated/prisma/models/BudgetGroup.js +1 -0
  166. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +1681 -0
  167. package/dist/generated/prisma/models/CodingAgentProfile.js +1 -0
  168. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +1749 -0
  169. package/dist/generated/prisma/models/CodingProxyRequest.js +1 -0
  170. package/dist/generated/prisma/models/CodingProxySession.d.ts +1626 -0
  171. package/dist/generated/prisma/models/CodingProxySession.js +1 -0
  172. package/dist/generated/prisma/models/CodingRun.d.ts +3583 -0
  173. package/dist/generated/prisma/models/CodingRun.js +1 -0
  174. package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
  175. package/dist/generated/prisma/models/CodingService.js +1 -0
  176. package/dist/generated/prisma/models/Datastore.d.ts +1434 -0
  177. package/dist/generated/prisma/models/Datastore.js +1 -0
  178. package/dist/generated/prisma/models/DatastoreEntry.d.ts +1314 -0
  179. package/dist/generated/prisma/models/DatastoreEntry.js +1 -0
  180. package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
  181. package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
  182. package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
  183. package/dist/generated/prisma/models/HostIdentity.js +1 -0
  184. package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
  185. package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
  186. package/dist/generated/prisma/models/OAuthAuthorizationCode.d.ts +1526 -0
  187. package/dist/generated/prisma/models/OAuthAuthorizationCode.js +1 -0
  188. package/dist/generated/prisma/models/OAuthAuthorizationRequest.d.ts +1350 -0
  189. package/dist/generated/prisma/models/OAuthAuthorizationRequest.js +1 -0
  190. package/dist/generated/prisma/models/OAuthClient.d.ts +1289 -0
  191. package/dist/generated/prisma/models/OAuthClient.js +1 -0
  192. package/dist/generated/prisma/models/OAuthFamily.d.ts +1540 -0
  193. package/dist/generated/prisma/models/OAuthFamily.js +1 -0
  194. package/dist/generated/prisma/models/OAuthGrant.d.ts +1280 -0
  195. package/dist/generated/prisma/models/OAuthGrant.js +1 -0
  196. package/dist/generated/prisma/models/Principal.d.ts +2245 -0
  197. package/dist/generated/prisma/models/Principal.js +1 -0
  198. package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
  199. package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
  200. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
  201. package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
  202. package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
  203. package/dist/generated/prisma/models/RegistryFetch.js +1 -0
  204. package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
  205. package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
  206. package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
  207. package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
  208. package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
  209. package/dist/generated/prisma/models/ResourceGrant.js +1 -0
  210. package/dist/generated/prisma/models/Run.d.ts +2669 -0
  211. package/dist/generated/prisma/models/Run.js +1 -0
  212. package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
  213. package/dist/generated/prisma/models/RunHostCheck.js +1 -0
  214. package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
  215. package/dist/generated/prisma/models/RunHostStatus.js +1 -0
  216. package/dist/generated/prisma/models/SchedulerLease.d.ts +970 -0
  217. package/dist/generated/prisma/models/SchedulerLease.js +1 -0
  218. package/dist/generated/prisma/models/Secret.d.ts +1399 -0
  219. package/dist/generated/prisma/models/Secret.js +1 -0
  220. package/dist/generated/prisma/models/SecretElicitationOutcome.d.ts +973 -0
  221. package/dist/generated/prisma/models/SecretElicitationOutcome.js +1 -0
  222. package/dist/generated/prisma/models/Task.d.ts +1176 -0
  223. package/dist/generated/prisma/models/Task.js +1 -0
  224. package/dist/generated/prisma/models/Tool.d.ts +1490 -0
  225. package/dist/generated/prisma/models/Tool.js +1 -0
  226. package/dist/generated/prisma/models/Webhook.d.ts +1386 -0
  227. package/dist/generated/prisma/models/Webhook.js +1 -0
  228. package/dist/generated/prisma/models.d.ts +45 -0
  229. package/dist/generated/prisma/models.js +1 -0
  230. package/dist/help/build.d.ts +1 -0
  231. package/dist/help/build.js +9 -0
  232. package/dist/help/catalog.d.ts +24 -0
  233. package/dist/help/catalog.js +160 -0
  234. package/dist/help/cli.d.ts +2 -0
  235. package/dist/help/cli.js +65 -0
  236. package/dist/help/runtime.d.ts +3 -0
  237. package/dist/help/runtime.js +44 -0
  238. package/dist/help/search.d.ts +9 -0
  239. package/dist/help/search.js +104 -0
  240. package/dist/help-index.json +660 -0
  241. package/dist/import/cli-args.js +3 -2
  242. package/dist/import/create.d.ts +6 -1
  243. package/dist/import/create.js +68 -14
  244. package/dist/import/index.d.ts +1 -1
  245. package/dist/import/index.js +19 -9
  246. package/dist/import/neutral-schema.d.ts +11 -11
  247. package/dist/mcp/auth/access.d.ts +70 -0
  248. package/dist/mcp/auth/access.js +58 -0
  249. package/dist/mcp/auth/grants-cli.d.ts +149 -0
  250. package/dist/mcp/auth/grants-cli.js +518 -0
  251. package/dist/mcp/auth/host-account-cli.d.ts +2 -0
  252. package/dist/mcp/auth/host-account-cli.js +47 -0
  253. package/dist/mcp/auth/ownership.d.ts +37 -63
  254. package/dist/mcp/auth/ownership.js +19 -14
  255. package/dist/mcp/auth/principal.d.ts +1 -1
  256. package/dist/mcp/auth/repo-authorization.d.ts +22 -0
  257. package/dist/mcp/auth/repo-authorization.js +51 -0
  258. package/dist/mcp/auth/resource-server.d.ts +32 -3
  259. package/dist/mcp/auth/resource-server.js +84 -3
  260. package/dist/mcp/auth/self-hosted/browser.js +22 -8
  261. package/dist/mcp/auth/self-hosted/cli.d.ts +1 -1
  262. package/dist/mcp/auth/self-hosted/cli.js +47 -13
  263. package/dist/mcp/auth/self-hosted/credentials.d.ts +21 -3
  264. package/dist/mcp/auth/self-hosted/credentials.js +62 -4
  265. package/dist/mcp/auth/self-hosted/rate-limit.d.ts +1 -1
  266. package/dist/mcp/auth/self-hosted/session.d.ts +3 -2
  267. package/dist/mcp/context.d.ts +28 -2
  268. package/dist/mcp/errors.d.ts +25 -6
  269. package/dist/mcp/errors.js +98 -0
  270. package/dist/mcp/host-events/github-ingress.d.ts +36 -0
  271. package/dist/mcp/host-events/github-ingress.js +92 -0
  272. package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
  273. package/dist/mcp/host-events/github-user-callback.js +50 -0
  274. package/dist/mcp/index.d.ts +8 -1
  275. package/dist/mcp/index.js +106 -16
  276. package/dist/mcp/server.d.ts +1 -1
  277. package/dist/mcp/server.js +27 -9
  278. package/dist/mcp/shared/page-style.d.ts +16 -0
  279. package/dist/mcp/shared/page-style.js +129 -0
  280. package/dist/mcp/tasks/manager.d.ts +1 -1
  281. package/dist/mcp/tools/agents.js +447 -49
  282. package/dist/mcp/tools/budget-groups.js +3 -3
  283. package/dist/mcp/tools/datastore.js +23 -16
  284. package/dist/mcp/tools/grants.d.ts +2 -0
  285. package/dist/mcp/tools/grants.js +239 -0
  286. package/dist/mcp/tools/help.d.ts +5 -0
  287. package/dist/mcp/tools/help.js +67 -0
  288. package/dist/mcp/tools/host-accounts.d.ts +2 -0
  289. package/dist/mcp/tools/host-accounts.js +114 -0
  290. package/dist/mcp/tools/memory.d.ts +7 -1
  291. package/dist/mcp/tools/memory.js +5 -5
  292. package/dist/mcp/tools/repositories.d.ts +2 -0
  293. package/dist/mcp/tools/repositories.js +181 -0
  294. package/dist/mcp/tools/runs.d.ts +6 -0
  295. package/dist/mcp/tools/runs.js +60 -6
  296. package/dist/mcp/tools/scheduling.js +4 -7
  297. package/dist/mcp/tools/secret-elicitation-form.d.ts +1 -1
  298. package/dist/mcp/tools/secret-elicitation-form.js +10 -28
  299. package/dist/mcp/tools/secret-elicitation.d.ts +1 -1
  300. package/dist/mcp/tools/secrets.js +18 -6
  301. package/dist/mcp/tools/services.d.ts +2 -0
  302. package/dist/mcp/tools/services.js +222 -0
  303. package/dist/mcp/tools/subagents.js +53 -17
  304. package/dist/mcp/tools/tools.d.ts +41 -0
  305. package/dist/mcp/tools/tools.js +202 -41
  306. package/dist/mcp/tools/trigger.js +36 -6
  307. package/dist/mcp/tools/webhooks.js +15 -4
  308. package/dist/mcp/transport/streamable-http.d.ts +11 -1
  309. package/dist/mcp/transport/streamable-http.js +32 -2
  310. package/dist/mcp/unattended-schedules.d.ts +1 -1
  311. package/dist/mcp/webhooks/ingress.d.ts +1 -1
  312. package/dist/providers/auth/delegating.d.ts +19 -0
  313. package/dist/providers/auth/delegating.js +71 -0
  314. package/dist/providers/auth/index.d.ts +3 -1
  315. package/dist/providers/auth/index.js +11 -0
  316. package/dist/providers/auth/self-hosted.d.ts +4 -3
  317. package/dist/providers/auth/self-hosted.js +16 -4
  318. package/dist/providers/auth/types.d.ts +6 -0
  319. package/dist/providers/coding-proxy/memory-ledger.d.ts +3 -0
  320. package/dist/providers/coding-proxy/memory-ledger.js +21 -2
  321. package/dist/providers/coding-proxy/metering.d.ts +4 -0
  322. package/dist/providers/coding-proxy/metering.js +28 -2
  323. package/dist/providers/coding-proxy/prisma-ledger.d.ts +18 -1
  324. package/dist/providers/coding-proxy/prisma-ledger.js +50 -5
  325. package/dist/providers/coding-proxy/proxy.d.ts +13 -0
  326. package/dist/providers/coding-proxy/proxy.js +479 -18
  327. package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
  328. package/dist/providers/coding-proxy/registry/audit.js +380 -0
  329. package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
  330. package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
  331. package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
  332. package/dist/providers/coding-proxy/registry/plan.js +304 -0
  333. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
  334. package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
  335. package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
  336. package/dist/providers/coding-proxy/registry/service.js +1137 -0
  337. package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
  338. package/dist/providers/coding-proxy/registry/store.js +70 -0
  339. package/dist/providers/coding-proxy/runtime.d.ts +18 -1
  340. package/dist/providers/coding-proxy/runtime.js +63 -0
  341. package/dist/providers/coding-proxy/secure-fetch.js +0 -1
  342. package/dist/providers/coding-proxy/server.d.ts +11 -0
  343. package/dist/providers/coding-proxy/server.js +163 -0
  344. package/dist/providers/coding-proxy/types.d.ts +15 -0
  345. package/dist/providers/datastore/postgres.d.ts +1 -1
  346. package/dist/providers/engine/types.d.ts +10 -0
  347. package/dist/providers/executor/build.d.ts +3 -3
  348. package/dist/providers/executor/composition.d.ts +4 -1
  349. package/dist/providers/executor/composition.js +19 -0
  350. package/dist/providers/executor/container.d.ts +106 -4
  351. package/dist/providers/executor/container.js +305 -22
  352. package/dist/providers/executor/dbos.d.ts +3 -4
  353. package/dist/providers/executor/in-process.d.ts +2 -3
  354. package/dist/providers/executor/routing.d.ts +7 -0
  355. package/dist/providers/executor/routing.js +13 -0
  356. package/dist/providers/executor/types.d.ts +22 -0
  357. package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
  358. package/dist/providers/jobs/claude-tool-setup.js +50 -0
  359. package/dist/providers/jobs/collect-prune.d.ts +7 -0
  360. package/dist/providers/jobs/collect-prune.js +27 -0
  361. package/dist/providers/jobs/docker-isolation.d.ts +48 -3
  362. package/dist/providers/jobs/docker-isolation.js +213 -22
  363. package/dist/providers/jobs/docker-services.d.ts +35 -0
  364. package/dist/providers/jobs/docker-services.js +191 -0
  365. package/dist/providers/jobs/docker.d.ts +60 -2
  366. package/dist/providers/jobs/docker.js +313 -50
  367. package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
  368. package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
  369. package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
  370. package/dist/providers/jobs/kubernetes-isolation.js +238 -57
  371. package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
  372. package/dist/providers/jobs/kubernetes-platform.js +11 -5
  373. package/dist/providers/jobs/kubernetes-preflight.js +3 -0
  374. package/dist/providers/jobs/kubernetes.d.ts +21 -2
  375. package/dist/providers/jobs/kubernetes.js +117 -31
  376. package/dist/providers/jobs/types.d.ts +20 -0
  377. package/dist/providers/llm/anthropic.js +6 -2
  378. package/dist/providers/llm/bedrock.js +2 -1
  379. package/dist/providers/llm/claude-messages.d.ts +5 -1
  380. package/dist/providers/llm/claude-messages.js +1 -0
  381. package/dist/providers/llm/claude-provider.d.ts +3 -1
  382. package/dist/providers/llm/claude-provider.js +5 -1
  383. package/dist/providers/llm/index.d.ts +1 -1
  384. package/dist/providers/llm/index.js +1 -1
  385. package/dist/providers/llm/pricing-anthropic.d.ts +10 -0
  386. package/dist/providers/llm/pricing-anthropic.js +32 -14
  387. package/dist/providers/llm/pricing-bedrock-claude.d.ts +8 -0
  388. package/dist/providers/llm/pricing-bedrock-claude.js +9 -0
  389. package/dist/providers/llm/routing.d.ts +10 -1
  390. package/dist/providers/llm/routing.js +18 -0
  391. package/dist/providers/llm/types.d.ts +12 -0
  392. package/dist/providers/llm/types.js +8 -1
  393. package/dist/providers/memory/postgres.d.ts +1 -1
  394. package/dist/providers/review-host/diff-lines.d.ts +16 -0
  395. package/dist/providers/review-host/diff-lines.js +59 -0
  396. package/dist/providers/review-host/github-events.d.ts +6 -0
  397. package/dist/providers/review-host/github-events.js +180 -0
  398. package/dist/providers/review-host/github-user-auth.d.ts +38 -0
  399. package/dist/providers/review-host/github-user-auth.js +128 -0
  400. package/dist/providers/review-host/github.d.ts +57 -0
  401. package/dist/providers/review-host/github.js +567 -0
  402. package/dist/providers/review-host/index.d.ts +12 -0
  403. package/dist/providers/review-host/index.js +30 -0
  404. package/dist/providers/review-host/review-format.d.ts +19 -0
  405. package/dist/providers/review-host/review-format.js +59 -0
  406. package/dist/providers/review-host/types.d.ts +284 -0
  407. package/dist/providers/review-host/types.js +24 -0
  408. package/dist/providers/vcs/git.d.ts +16 -6
  409. package/dist/providers/vcs/git.js +79 -14
  410. package/dist/providers/vcs/github.d.ts +74 -3
  411. package/dist/providers/vcs/github.js +195 -15
  412. package/dist/providers/vcs/types.d.ts +42 -4
  413. package/dist/quickstart/index.js +34 -32
  414. package/dist/quickstart/migrate.d.ts +23 -0
  415. package/dist/quickstart/migrate.js +125 -0
  416. package/dist/sandbox/fetch-policy.d.ts +20 -2
  417. package/dist/sandbox/fetch-policy.js +64 -3
  418. package/dist/sandbox/host-functions.d.ts +9 -1
  419. package/dist/sandbox/host-functions.js +12 -5
  420. package/dist/serve.js +1 -1
  421. package/dist/wardby-bin.js +6 -0
  422. package/docs/README.md +30 -0
  423. package/docs/architecture-runtime.md +90 -0
  424. package/docs/assets/brand/wardby-icon-512.png +0 -0
  425. package/docs/assets/brand/wardby-icon.svg +16 -0
  426. package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
  427. package/docs/assets/brand/wardby-mascot.png +0 -0
  428. package/docs/assets/brand/wardby-mascot.svg +5 -0
  429. package/docs/assets/wardby-workflow.svg +106 -0
  430. package/docs/code-review-agents.md +481 -0
  431. package/docs/coding-agent-setup.md +172 -0
  432. package/docs/coding-packages.md +455 -0
  433. package/docs/coding-services.md +300 -0
  434. package/docs/coding-worker-byo-images.md +98 -0
  435. package/docs/coding-worker-isolation.md +1061 -0
  436. package/docs/getting-started-gke.md +615 -0
  437. package/docs/getting-started-identity-provider.md +308 -0
  438. package/docs/getting-started.md +133 -0
  439. package/docs/observability.md +53 -0
  440. package/docs/release-verification.md +66 -0
  441. package/docs/security-deployment.md +657 -0
  442. package/help/code-review-agents.md +31 -0
  443. package/help/coding-packages.md +31 -0
  444. package/help/coding-services.md +71 -0
  445. package/help/creating-agents.md +68 -0
  446. package/help/deploy-gke.md +39 -0
  447. package/help/deployment-targets.md +39 -0
  448. package/help/errors/budget-group-exhausted.md +25 -0
  449. package/help/errors/docker-isolation-unsupported.md +26 -0
  450. package/help/errors/protected-path.md +45 -0
  451. package/help/errors/repo-access.md +27 -0
  452. package/help/errors/service-declaration-invalid.md +27 -0
  453. package/help/errors/service-declaration-unavailable.md +25 -0
  454. package/help/errors/service-launcher-unsupported.md +30 -0
  455. package/help/errors/service-not-allowed.md +27 -0
  456. package/help/errors/service-unknown.md +23 -0
  457. package/help/errors/service-unready.md +49 -0
  458. package/help/getting-started.md +31 -0
  459. package/help/github.md +30 -0
  460. package/help/identity-and-access.md +39 -0
  461. package/help/mcp.md +30 -0
  462. package/help/native-capabilities.md +30 -0
  463. package/help/observability.md +41 -0
  464. package/help/operating-agents.md +30 -0
  465. package/help/security.md +27 -0
  466. package/help/troubleshooting/budgets.md +26 -0
  467. package/help/troubleshooting/coding-workers.md +47 -0
  468. package/help/troubleshooting/repository-access.md +27 -0
  469. package/package.json +30 -11
  470. package/prisma/migrate.config.mjs +20 -0
  471. package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
  472. package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
  473. package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
  474. package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
  475. package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
  476. package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
  477. package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
  478. package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
  479. package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
  480. package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
  481. package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
  482. package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
  483. package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
  484. package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
  485. package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
  486. package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
  487. package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
  488. package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
  489. package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
  490. package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
  491. package/prisma/schema.prisma +417 -23
@@ -6,6 +6,26 @@ export const MAX_CODING_SUMMARY_BYTES = 8 * 1024;
6
6
  export const MAX_CODING_TESTS = 64;
7
7
  export const MAX_CODING_TEST_COMMAND_BYTES = 2 * 1024;
8
8
  export const MAX_TAG_BYTES = 32;
9
+ /**
10
+ * Coding-run services (docs/coding-services.md): the catalog name and version
11
+ * grammar, shared by the repository's .wardby/services.yaml, the catalog, and
12
+ * the worker input.
13
+ */
14
+ export const CODING_SERVICE_NAME = /^[a-z][a-z0-9-]{0,39}$/;
15
+ export const CODING_SERVICE_VERSION = /^[0-9A-Za-z][0-9A-Za-z._-]{0,19}$/;
16
+ export const MAX_CODING_SERVICES = 5;
17
+ /** A variable a service hands the agent's shells (DATABASE_URL, PGHOST, REDIS_URL, ...). */
18
+ export const CODING_SERVICE_ENV_NAME = /^[A-Z][A-Z0-9_]{0,63}$/;
19
+ export const MAX_CODING_SERVICE_ENV = 16;
20
+ export const MAX_CODING_SERVICE_ENV_VALUE_BYTES = 1024;
21
+ /**
22
+ * A worker's output-schema failure, reduced to where and how it failed, never
23
+ * what the model wrote: `<path>:<zod issue code>`, where the path is dot-joined
24
+ * schema keys and array indices (`$` for the root). Unrecognized keys the model
25
+ * invented are carried only as the `unrecognized_keys` code, never by name.
26
+ */
27
+ export const MAX_CODING_OUTPUT_ISSUES = 8;
28
+ export const SAFE_CODING_OUTPUT_ISSUE = /^(?:\$|[a-z][A-Za-z]{0,31}(?:\.(?:[a-z][A-Za-z]{0,31}|\d{1,3})){0,7}):[a-z_]{1,32}$/;
9
29
  const MAX_REPOSITORY_INPUT_BYTES = 512;
10
30
  const MAX_REF_BYTES = 255;
11
31
  const MAX_MODEL_BYTES = 128;
@@ -13,8 +33,8 @@ const MAX_RUN_ID_BYTES = 128;
13
33
  const MAX_COST_USD = 1_000_000;
14
34
  const MAX_JSON_NESTING_DEPTH = 64;
15
35
  const INVALID_MULTILINE_CONTROL = /[\u0000\u000B\u000C\u000E-\u001F\u007F]/;
16
- const INVALID_SINGLE_LINE_CONTROL = /[\u0000-\u001F\u007F]/;
17
- function byteLength(value) {
36
+ export const INVALID_SINGLE_LINE_CONTROL = /[\u0000-\u001F\u007F]/;
37
+ export function byteLength(value) {
18
38
  return Buffer.byteLength(value, "utf8");
19
39
  }
20
40
  function boundedText(maxBytes, singleLine = false) {
@@ -25,6 +45,72 @@ function boundedText(maxBytes, singleLine = false) {
25
45
  .refine((value) => !invalidControl.test(value), "must not contain control characters")
26
46
  .refine((value) => value.trim().length > 0, "must not be blank");
27
47
  }
48
+ /**
49
+ * Names the worker owns: its shell basics, anything that would redirect a
50
+ * process's loader or network proxy, and the registry proxy's and Wardby's own
51
+ * settings. No service may set one, whatever its catalog entry says.
52
+ */
53
+ const RESERVED_SERVICE_ENV_NAMES = new Set([
54
+ "HOME",
55
+ "LANG",
56
+ "LC_ALL",
57
+ "PATH",
58
+ "SHELL",
59
+ "TMPDIR",
60
+ "USER",
61
+ "LD_PRELOAD",
62
+ "LD_LIBRARY_PATH",
63
+ "NODE_OPTIONS",
64
+ "NODE_PATH",
65
+ "PYTHONPATH",
66
+ "PYTHONHOME",
67
+ "HTTP_PROXY",
68
+ "HTTPS_PROXY",
69
+ "NO_PROXY",
70
+ "ALL_PROXY",
71
+ "SSL_CERT_FILE",
72
+ "SSL_CERT_DIR",
73
+ ]);
74
+ const RESERVED_SERVICE_ENV_PREFIXES = [
75
+ "WARDBY_",
76
+ "CODEX_",
77
+ "OPENAI_",
78
+ "ANTHROPIC_",
79
+ "PIP_",
80
+ "NPM_CONFIG_",
81
+ "UV_",
82
+ "GIT_",
83
+ ];
84
+ export function isReservedServiceEnvName(name) {
85
+ return (RESERVED_SERVICE_ENV_NAMES.has(name) || RESERVED_SERVICE_ENV_PREFIXES.some((prefix) => name.startsWith(prefix)));
86
+ }
87
+ const serviceEnvValueSchema = z
88
+ .string()
89
+ .refine((value) => byteLength(value) <= MAX_CODING_SERVICE_ENV_VALUE_BYTES, `must be at most ${MAX_CODING_SERVICE_ENV_VALUE_BYTES} UTF-8 bytes`)
90
+ .refine((value) => !INVALID_SINGLE_LINE_CONTROL.test(value), "must not contain control characters");
91
+ /** The variables one service hands the agent's shells: upper-case names wardby does not reserve. */
92
+ export const CodingServiceTestEnvSchema = z.record(z.string(), serviceEnvValueSchema).superRefine((env, ctx) => {
93
+ const names = Object.keys(env);
94
+ if (names.length > MAX_CODING_SERVICE_ENV) {
95
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: `must have at most ${MAX_CODING_SERVICE_ENV} variables` });
96
+ }
97
+ for (const name of names) {
98
+ if (!CODING_SERVICE_ENV_NAME.test(name) || isReservedServiceEnvName(name)) {
99
+ ctx.addIssue({
100
+ code: z.ZodIssueCode.custom,
101
+ path: [name],
102
+ message: "must be an upper-case variable name wardby does not reserve",
103
+ });
104
+ }
105
+ }
106
+ });
107
+ const workerServiceSchema = z
108
+ .object({
109
+ name: z.string().regex(CODING_SERVICE_NAME),
110
+ version: z.string().regex(CODING_SERVICE_VERSION),
111
+ testEnv: CodingServiceTestEnvSchema,
112
+ })
113
+ .strict();
28
114
  function repositoryParts(value) {
29
115
  if (byteLength(value) > MAX_REPOSITORY_INPUT_BYTES || INVALID_SINGLE_LINE_CONTROL.test(value)) {
30
116
  throw new Error("invalid GitHub repository");
@@ -108,6 +194,25 @@ const repositorySchema = z
108
194
  .transform(normalizeGitHubRepository);
109
195
  export const CodingBaseRefSchema = z.string().refine(isGitRef, "must be a safe branch ref").transform(normalizeGitRef);
110
196
  export const CodingTaskOverrideSchema = boundedText(MAX_CODING_TASK_BYTES);
197
+ /**
198
+ * A coding worker receives only its task text, so a coding agent's own
199
+ * instructions (its systemPrompt) travel inside that text, ahead of the
200
+ * request, followed by any note wardby generates for the run (the services it
201
+ * started: src/coding/services/note.ts). Blank instructions and no note leave
202
+ * the task unchanged. The combination must still fit MAX_CODING_TASK_BYTES;
203
+ * exceeding it is an error naming both parts rather than a silent truncation.
204
+ */
205
+ export function composeCodingTask(instructions, task, note) {
206
+ const standing = [instructions?.trim(), note?.trim()].filter((part) => Boolean(part)).join("\n\n");
207
+ if (!standing)
208
+ return task;
209
+ const composed = `Standing instructions for this coding agent:\n${standing}\n\nRequest:\n${task}`;
210
+ if (byteLength(composed) > MAX_CODING_TASK_BYTES) {
211
+ throw new Error(`The coding agent's instructions (${byteLength(standing)} bytes) plus this task (${byteLength(task)} bytes) ` +
212
+ `exceed the ${MAX_CODING_TASK_BYTES}-byte coding task limit; shorten one of them.`);
213
+ }
214
+ return composed;
215
+ }
111
216
  const runIdSchema = boundedText(MAX_RUN_ID_BYTES, true).refine((value) => /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value), "must be an opaque identifier");
112
217
  const modelSchema = boundedText(MAX_MODEL_BYTES, true).refine((value) => /^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(value), "must be a model identifier");
113
218
  const usageSchema = z
@@ -117,6 +222,30 @@ const usageSchema = z
117
222
  costUsd: z.number().finite().nonnegative().max(MAX_COST_USD),
118
223
  })
119
224
  .strict();
225
+ const SAFE_TAG = new RegExp(`^[A-Za-z0-9][A-Za-z0-9._/-]{0,${MAX_TAG_BYTES - 1}}$`);
226
+ /**
227
+ * The tag only labels a pull request title, so a model's malformed tag must not
228
+ * sink an otherwise finished run. A tag that already passes is kept as-is; any
229
+ * other string becomes a lowercase slug (runs of disallowed characters to "-",
230
+ * no leading or trailing punctuation, at most MAX_TAG_BYTES), and one with
231
+ * nothing usable left, or a non-string, becomes null. GitHub finalization still
232
+ * re-validates whatever survives.
233
+ */
234
+ export function normalizeCodingTag(value) {
235
+ if (value === undefined || value === null)
236
+ return value;
237
+ if (typeof value !== "string")
238
+ return null;
239
+ if (SAFE_TAG.test(value))
240
+ return value;
241
+ const slug = value
242
+ .toLowerCase()
243
+ .replace(/[^a-z0-9._/-]+/g, "-")
244
+ .replace(/^[^a-z0-9]+/, "")
245
+ .slice(0, MAX_TAG_BYTES)
246
+ .replace(/[^a-z0-9]+$/, "");
247
+ return SAFE_TAG.test(slug) ? slug : null;
248
+ }
120
249
  /**
121
250
  * A short, caller-visible reference (e.g. a ticket ID) surfaced in the PR title. Never free text.
122
251
  * Accepts null as well as undefined: OpenAI's strict Structured Outputs mode requires every
@@ -126,7 +255,7 @@ const usageSchema = z
126
255
  */
127
256
  const tagSchema = z
128
257
  .string()
129
- .regex(new RegExp(`^[A-Za-z0-9][A-Za-z0-9._/-]{0,${MAX_TAG_BYTES - 1}}$`), "must be a short, safe tag")
258
+ .regex(SAFE_TAG, "must be a short, safe tag")
130
259
  .nullable()
131
260
  .optional()
132
261
  .transform((value) => value ?? undefined);
@@ -136,6 +265,8 @@ const testResultSchema = z
136
265
  outcome: z.enum(["passed", "failed", "skipped"]),
137
266
  })
138
267
  .strict();
268
+ /** Longest line a debug-traced worker writes to its log (src/coding-worker/debug-trace.ts). */
269
+ export const MAX_DEBUG_TRACE_LINE_BYTES = 16 * 1024;
139
270
  export const CodingTaskInputSchema = z
140
271
  .object({
141
272
  schemaVersion: z.literal(CODING_PROTOCOL_VERSION),
@@ -156,6 +287,21 @@ export const CodingTaskInputSchema = z
156
287
  * only enforces that headRef is internally consistent with it.
157
288
  */
158
289
  continuationOf: z.object({ runId: runIdSchema }).strict().optional(),
290
+ /**
291
+ * Admin-requested debug trace (CodingAgentProfile.debugTraceUntil): the
292
+ * worker writes its full stream trace to its own log. Absent means off;
293
+ * the control plane writes the key only when true, so an input for an
294
+ * untraced run is unchanged for workers that predate it.
295
+ */
296
+ debugTrace: z.boolean().optional(),
297
+ /**
298
+ * Coding-run services started next to this run (docs/coding-services.md):
299
+ * each one's catalog name and version, and the variables the agent's shells
300
+ * receive. Absent means none; the control plane writes the key only when a
301
+ * run has services, so every other input is unchanged for workers that
302
+ * predate it.
303
+ */
304
+ services: z.array(workerServiceSchema).min(1).max(MAX_CODING_SERVICES).optional(),
159
305
  })
160
306
  .strict()
161
307
  .superRefine((value, ctx) => {
@@ -167,6 +313,10 @@ export const CodingTaskInputSchema = z
167
313
  message: "must match wardby/run-<runId> (or wardby/run-<continuationOf.runId>)",
168
314
  });
169
315
  }
316
+ const names = (value.services ?? []).map((service) => service.name);
317
+ if (new Set(names).size !== names.length) {
318
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["services"], message: "must name each service once" });
319
+ }
170
320
  });
171
321
  export const CodingAgentOutputSchema = z
172
322
  .object({
@@ -175,7 +325,8 @@ export const CodingAgentOutputSchema = z
175
325
  outcome: z.enum(["changes_ready", "no_changes", "budget_exhausted"]),
176
326
  summary: boundedText(MAX_CODING_SUMMARY_BYTES),
177
327
  tests: z.array(testResultSchema).max(MAX_CODING_TESTS),
178
- tag: tagSchema,
328
+ // Model-written, so normalized rather than rejected; see normalizeCodingTag.
329
+ tag: z.preprocess(normalizeCodingTag, tagSchema),
179
330
  })
180
331
  .strict()
181
332
  .transform((value) => ({
@@ -0,0 +1,2 @@
1
+ import type { EcosystemId, RegistryAdapter } from "./types.js";
2
+ export declare const REGISTRY_ADAPTERS: ReadonlyMap<EcosystemId, RegistryAdapter>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The registry adapter map: every ecosystem the coding package registry
3
+ * proxies, keyed by its EcosystemId. Adding a new ecosystem means adding it
4
+ * here (and to the allowlist/profile validation that reads this map) --
5
+ * nothing else in the registry core hardcodes "npm" or "pypi".
6
+ */
7
+ import { npmAdapter } from "./npm.js";
8
+ import { pypiAdapter } from "./pypi.js";
9
+ export const REGISTRY_ADAPTERS = new Map([npmAdapter, pypiAdapter].map((adapter) => [adapter.id, adapter]));
@@ -0,0 +1,9 @@
1
+ import type { AllowlistEntry, RegistryAdapter } from "./types.js";
2
+ export type PackageAllowlist = Readonly<Record<string, readonly string[]>>;
3
+ export interface PackagePolicy {
4
+ minReleaseAgeDays: number;
5
+ }
6
+ export declare const DEFAULT_MIN_RELEASE_AGE_DAYS = 3;
7
+ export declare function resolvePolicy(value: unknown): PackagePolicy;
8
+ export declare function parseAllowlist(allowlist: PackageAllowlist, adapters: ReadonlyMap<string, RegistryAdapter>): Map<string, AllowlistEntry[]>;
9
+ export declare function matchRoot(entries: readonly AllowlistEntry[], normalizedName: string): AllowlistEntry | undefined;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The per-agent package allowlist and policy model: parsing raw allowlist
3
+ * strings (via each ecosystem's adapter) into `AllowlistEntry` values, and
4
+ * matching a normalized package name against them.
5
+ */
6
+ import { z } from "zod";
7
+ export const DEFAULT_MIN_RELEASE_AGE_DAYS = 3;
8
+ const PolicySchema = z
9
+ .object({ minReleaseAgeDays: z.number().int().min(0).max(30).default(DEFAULT_MIN_RELEASE_AGE_DAYS) })
10
+ .strict();
11
+ export function resolvePolicy(value) {
12
+ return PolicySchema.parse(value ?? {});
13
+ }
14
+ export function parseAllowlist(allowlist, adapters) {
15
+ const parsed = new Map();
16
+ for (const [ecosystem, entries] of Object.entries(allowlist)) {
17
+ const adapter = adapters.get(ecosystem);
18
+ if (!adapter)
19
+ throw new Error(`unknown package ecosystem "${ecosystem}"`);
20
+ parsed.set(ecosystem, entries.map((entry) => adapter.parseAllowlistEntry(entry)));
21
+ }
22
+ return parsed;
23
+ }
24
+ export function matchRoot(entries, normalizedName) {
25
+ return entries.find((entry) => entry.wildcard
26
+ ? normalizedName.startsWith(entry.name) && normalizedName.length > entry.name.length
27
+ : entry.name === normalizedName);
28
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * A streaming scan for one top-level member of a JSON object document,
3
+ * without ever holding the document: only the wanted member's value text is
4
+ * kept (bounded), and every other value, however large, is skipped as it
5
+ * streams past. Used to read an npm packument's `time` (per-version publish
6
+ * times), which comes after `versions` and can follow tens of MB of it.
7
+ *
8
+ * It is a tokenizer, not a validator: it tracks strings, escapes and
9
+ * nesting depth, which is all that locating a top-level member needs. The
10
+ * captured value is then parsed with JSON.parse, so a malformed value
11
+ * throws there. A document that is not an object, or that ends before the
12
+ * member closes, yields null.
13
+ */
14
+ export declare class JsonMemberTooLarge extends Error {
15
+ }
16
+ export declare class TopLevelMemberScanner {
17
+ private readonly wanted;
18
+ private readonly maxValueLength;
19
+ private depth;
20
+ private inString;
21
+ private escape;
22
+ /** At depth 1, the next string is a key. */
23
+ private expectKey;
24
+ private collectingKey;
25
+ private key;
26
+ private lastKey;
27
+ /** After `"<wanted>":`, waiting for the value's first character. */
28
+ private pending;
29
+ private capturing;
30
+ private captured;
31
+ private capturedLength;
32
+ private finished;
33
+ private result;
34
+ private started;
35
+ constructor(wanted: string, maxValueLength: number);
36
+ /** True once the member was captured (or proven absent or not an
37
+ * object), so the caller may stop reading. */
38
+ get done(): boolean;
39
+ /** The member's value, parsed; undefined while scanning or when absent. */
40
+ get value(): unknown;
41
+ /** Feeds the next decoded text. Throws JsonMemberTooLarge when the
42
+ * member's value exceeds its bound. */
43
+ push(text: string): void;
44
+ private appendKey;
45
+ private capture;
46
+ private finish;
47
+ }
48
+ /** Reads `stream` (UTF-8 JSON) until the top-level member `wanted` has
49
+ * been captured, then cancels the rest. Returns its parsed value, or
50
+ * undefined when the document has no such object-valued member. At most
51
+ * `maxBytes` of the stream are read; more throws JsonMemberTooLarge. */
52
+ export declare function scanTopLevelMember(stream: ReadableStream<Uint8Array>, wanted: string, limits: {
53
+ maxBytes: number;
54
+ maxValueLength: number;
55
+ }): Promise<unknown>;
@@ -0,0 +1,191 @@
1
+ /**
2
+ * A streaming scan for one top-level member of a JSON object document,
3
+ * without ever holding the document: only the wanted member's value text is
4
+ * kept (bounded), and every other value, however large, is skipped as it
5
+ * streams past. Used to read an npm packument's `time` (per-version publish
6
+ * times), which comes after `versions` and can follow tens of MB of it.
7
+ *
8
+ * It is a tokenizer, not a validator: it tracks strings, escapes and
9
+ * nesting depth, which is all that locating a top-level member needs. The
10
+ * captured value is then parsed with JSON.parse, so a malformed value
11
+ * throws there. A document that is not an object, or that ends before the
12
+ * member closes, yields null.
13
+ */
14
+ /** Longest top-level key compared; a longer one cannot be the wanted key. */
15
+ const MAX_KEY_LENGTH = 256;
16
+ export class JsonMemberTooLarge extends Error {
17
+ }
18
+ export class TopLevelMemberScanner {
19
+ wanted;
20
+ maxValueLength;
21
+ depth = 0;
22
+ inString = false;
23
+ escape = false;
24
+ /** At depth 1, the next string is a key. */
25
+ expectKey = false;
26
+ collectingKey = false;
27
+ key = "";
28
+ lastKey;
29
+ /** After `"<wanted>":`, waiting for the value's first character. */
30
+ pending = false;
31
+ capturing = false;
32
+ captured = [];
33
+ capturedLength = 0;
34
+ finished = false;
35
+ result = undefined;
36
+ started = false;
37
+ constructor(wanted, maxValueLength) {
38
+ this.wanted = wanted;
39
+ this.maxValueLength = maxValueLength;
40
+ }
41
+ /** True once the member was captured (or proven absent or not an
42
+ * object), so the caller may stop reading. */
43
+ get done() {
44
+ return this.finished;
45
+ }
46
+ /** The member's value, parsed; undefined while scanning or when absent. */
47
+ get value() {
48
+ return this.result;
49
+ }
50
+ /** Feeds the next decoded text. Throws JsonMemberTooLarge when the
51
+ * member's value exceeds its bound. */
52
+ push(text) {
53
+ if (this.finished)
54
+ return;
55
+ let segmentStart = this.capturing ? 0 : -1;
56
+ const length = text.length;
57
+ let i = 0;
58
+ while (i < length) {
59
+ if (this.inString) {
60
+ if (this.escape) {
61
+ this.escape = false;
62
+ if (this.collectingKey)
63
+ this.appendKey(text[i]);
64
+ i += 1;
65
+ continue;
66
+ }
67
+ // Skip ahead to the next quote or backslash: the bulk of a
68
+ // packument is string content, never looked at char by char.
69
+ const quote = text.indexOf('"', i);
70
+ const backslash = text.indexOf("\\", i);
71
+ const stop = quote < 0 ? backslash : backslash < 0 ? quote : Math.min(quote, backslash);
72
+ if (stop < 0) {
73
+ if (this.collectingKey)
74
+ this.appendKey(text.slice(i));
75
+ break;
76
+ }
77
+ if (this.collectingKey)
78
+ this.appendKey(text.slice(i, stop));
79
+ if (stop === backslash) {
80
+ this.escape = true;
81
+ if (this.collectingKey)
82
+ this.appendKey("\\");
83
+ i = stop + 1;
84
+ continue;
85
+ }
86
+ this.inString = false;
87
+ if (this.collectingKey) {
88
+ this.collectingKey = false;
89
+ this.lastKey = this.key;
90
+ }
91
+ i = stop + 1;
92
+ continue;
93
+ }
94
+ const c = text[i];
95
+ if (c === " " || c === "\n" || c === "\r" || c === "\t") {
96
+ i += 1;
97
+ continue;
98
+ }
99
+ if (!this.started) {
100
+ this.started = true;
101
+ if (c !== "{")
102
+ return this.finish(undefined);
103
+ }
104
+ if (this.pending) {
105
+ this.pending = false;
106
+ if (c !== "{")
107
+ return this.finish(undefined);
108
+ this.capturing = true;
109
+ segmentStart = i;
110
+ }
111
+ if (c === '"') {
112
+ this.inString = true;
113
+ if (this.depth === 1 && this.expectKey) {
114
+ this.collectingKey = true;
115
+ this.key = "";
116
+ this.expectKey = false;
117
+ }
118
+ }
119
+ else if (c === "{" || c === "[") {
120
+ this.depth += 1;
121
+ if (this.depth === 1)
122
+ this.expectKey = true;
123
+ }
124
+ else if (c === "}" || c === "]") {
125
+ this.depth -= 1;
126
+ if (this.capturing && this.depth === 1) {
127
+ this.capture(text.slice(segmentStart, i + 1));
128
+ return this.finish(JSON.parse(this.captured.join("")));
129
+ }
130
+ if (this.depth === 0)
131
+ return this.finish(undefined);
132
+ }
133
+ else if (c === ":") {
134
+ if (this.depth === 1 && this.lastKey === this.wanted)
135
+ this.pending = true;
136
+ }
137
+ else if (c === ",") {
138
+ if (this.depth === 1) {
139
+ this.expectKey = true;
140
+ this.lastKey = undefined;
141
+ }
142
+ }
143
+ i += 1;
144
+ }
145
+ if (this.capturing && segmentStart >= 0)
146
+ this.capture(text.slice(segmentStart));
147
+ }
148
+ appendKey(part) {
149
+ if (this.key.length <= MAX_KEY_LENGTH)
150
+ this.key += part.slice(0, MAX_KEY_LENGTH + 1 - this.key.length);
151
+ }
152
+ capture(part) {
153
+ this.capturedLength += part.length;
154
+ if (this.capturedLength > this.maxValueLength)
155
+ throw new JsonMemberTooLarge(`"${this.wanted}" is too large`);
156
+ this.captured.push(part);
157
+ }
158
+ finish(value) {
159
+ this.finished = true;
160
+ this.result = value;
161
+ this.captured = [];
162
+ }
163
+ }
164
+ /** Reads `stream` (UTF-8 JSON) until the top-level member `wanted` has
165
+ * been captured, then cancels the rest. Returns its parsed value, or
166
+ * undefined when the document has no such object-valued member. At most
167
+ * `maxBytes` of the stream are read; more throws JsonMemberTooLarge. */
168
+ export async function scanTopLevelMember(stream, wanted, limits) {
169
+ const scanner = new TopLevelMemberScanner(wanted, limits.maxValueLength);
170
+ const decoder = new TextDecoder("utf-8");
171
+ const reader = stream.getReader();
172
+ let bytes = 0;
173
+ try {
174
+ for (;;) {
175
+ const { done, value } = await reader.read();
176
+ if (done) {
177
+ scanner.push(decoder.decode());
178
+ return scanner.value;
179
+ }
180
+ bytes += value.byteLength;
181
+ if (bytes > limits.maxBytes)
182
+ throw new JsonMemberTooLarge(`the document is larger than ${limits.maxBytes} bytes`);
183
+ scanner.push(decoder.decode(value, { stream: true }));
184
+ if (scanner.done)
185
+ return scanner.value;
186
+ }
187
+ }
188
+ finally {
189
+ await reader.cancel().catch(() => undefined);
190
+ }
191
+ }
@@ -0,0 +1,6 @@
1
+ /** Normalises every recognised lockfile under `workspace`; returns the
2
+ * workspace-relative paths it rewrote, sorted. */
3
+ export declare function normalizeRegistryLockfiles(input: {
4
+ workspace: string;
5
+ proxyBaseUrl: string;
6
+ }): Promise<string[]>;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Rewrites the proxy download URLs a package manager records in lockfiles
3
+ * back to public ones, for every adapter with a `lockfiles` hook. The driver
4
+ * runs this on the workspace before it is collected, so a committed lockfile
5
+ * never points at the sandbox-only proxy host.
6
+ *
7
+ * Best effort by design: a file that cannot be read or written safely is
8
+ * skipped, never a reason to fail the run. The walk never follows symlinks
9
+ * and skips the folders collection excludes by name (dependency and cache
10
+ * folders), which are never sent back anyway.
11
+ */
12
+ import { constants } from "node:fs";
13
+ import { open, readdir } from "node:fs/promises";
14
+ import { join } from "node:path";
15
+ import { BUILTIN_COLLECT_EXCLUDE_NAMES } from "../collect-exclude.js";
16
+ import { REGISTRY_ADAPTERS } from "./adapters.js";
17
+ import { registryUrlFor } from "./worker-config.js";
18
+ const MAX_LOCKFILE_BYTES = 64 * 1024 * 1024;
19
+ const MAX_DEPTH = 32;
20
+ const SKIPPED_DIRECTORIES = new Set([...BUILTIN_COLLECT_EXCLUDE_NAMES, ".git"]);
21
+ /** Rewrites one file in place through a single descriptor (no symlinks, no
22
+ * path re-resolution between the checks and the write). Returns whether it
23
+ * changed; any failure leaves the file as it was found or skips it. */
24
+ async function normalizeFile(path, normalize) {
25
+ let file;
26
+ try {
27
+ file = await open(path, constants.O_RDWR | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ try {
33
+ const metadata = await file.stat();
34
+ if (!metadata.isFile() || metadata.size > MAX_LOCKFILE_BYTES)
35
+ return false;
36
+ const before = (await file.readFile()).toString("utf8");
37
+ const after = normalize(before);
38
+ if (after === before)
39
+ return false;
40
+ await file.truncate(0);
41
+ await file.write(after, 0, "utf8");
42
+ return true;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ finally {
48
+ await file.close();
49
+ }
50
+ }
51
+ /** Normalises every recognised lockfile under `workspace`; returns the
52
+ * workspace-relative paths it rewrote, sorted. */
53
+ export async function normalizeRegistryLockfiles(input) {
54
+ const byName = new Map();
55
+ for (const adapter of REGISTRY_ADAPTERS.values()) {
56
+ const lockfiles = adapter.lockfiles;
57
+ if (!lockfiles)
58
+ continue;
59
+ const registryUrl = registryUrlFor(input.proxyBaseUrl, adapter.id);
60
+ for (const name of lockfiles.names)
61
+ byName.set(name, (content) => lockfiles.normalize(content, registryUrl));
62
+ }
63
+ const rewritten = [];
64
+ const walk = async (relative, depth) => {
65
+ let entries;
66
+ try {
67
+ entries = await readdir(join(input.workspace, relative), { withFileTypes: true });
68
+ }
69
+ catch {
70
+ return;
71
+ }
72
+ for (const entry of entries) {
73
+ const path = relative ? `${relative}/${entry.name}` : entry.name;
74
+ // Dirent types come from lstat semantics: a symlink is neither a directory nor a file here.
75
+ if (entry.isDirectory()) {
76
+ if (depth < MAX_DEPTH && !SKIPPED_DIRECTORIES.has(entry.name))
77
+ await walk(path, depth + 1);
78
+ }
79
+ else if (entry.isFile()) {
80
+ const normalize = byName.get(entry.name);
81
+ if (normalize && (await normalizeFile(join(input.workspace, path), normalize)))
82
+ rewritten.push(path);
83
+ }
84
+ }
85
+ };
86
+ if (byName.size > 0)
87
+ await walk("", 0);
88
+ return rewritten.sort();
89
+ }
@@ -0,0 +1,9 @@
1
+ /** Same shape as the adapter's allowlist name check (scoped names are lower case). */
2
+ export declare const PACKAGE_NAME: RegExp;
3
+ /** `https://registry.npmjs.org/@scope/pkg/-/pkg-1.0.0.tgz` */
4
+ export declare function publicNpmTarballUrl(name: string, version: string): string;
5
+ export declare function normalizeNpmLockfile(content: string, registryUrl: string): string;
6
+ export declare const npmLockfiles: {
7
+ readonly names: readonly ["package-lock.json", "npm-shrinkwrap.json"];
8
+ readonly normalize: typeof normalizeNpmLockfile;
9
+ };