@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
@@ -8,6 +8,18 @@ export interface PullRequestTestResult {
8
8
  command: string;
9
9
  outcome: "passed" | "failed" | "skipped";
10
10
  }
11
+ /** One package the registry proxy served during the run (RegistryFetch outcome "served"). */
12
+ export interface PackageReport {
13
+ ecosystem: string;
14
+ name: string;
15
+ version: string;
16
+ }
17
+ /** One package the registry proxy refused during the run (RegistryFetch outcome "refused"). */
18
+ export interface PackageRefusal {
19
+ ecosystem: string;
20
+ name: string;
21
+ reason: string;
22
+ }
11
23
  export interface PullRequestInput {
12
24
  runId: string;
13
25
  repository: string;
@@ -17,6 +29,30 @@ export interface PullRequestInput {
17
29
  summary?: string;
18
30
  tests?: readonly PullRequestTestResult[];
19
31
  tag?: string;
32
+ /** Deduplicated by the caller isn't required — pullRequestBody dedupes itself (ecosystem+name+version / +reason). */
33
+ packages?: readonly PackageReport[];
34
+ packageRefusals?: readonly PackageRefusal[];
35
+ /**
36
+ * A continuation re-finds the PR its root run opened, and a person may
37
+ * have marked that PR ready for review since. The push has already updated
38
+ * it, so it is accepted as found instead of failing the run as
39
+ * `github_pull_request_not_draft`. A PR this client creates is always a
40
+ * draft either way; unset (a fresh run), only a draft PR is accepted.
41
+ */
42
+ acceptReadyForReview?: boolean;
43
+ /**
44
+ * The originating issue-tracker issue (control-plane data, never model
45
+ * output). Provider-neutral: the title gets a `[KEY] ` prefix and the body a
46
+ * first line linking it ("Resolves <trackerName> issue …"). The key is
47
+ * re-validated here, a non-https `url` is dropped, and so is a `trackerName`
48
+ * that isn't a short plain name. The PR lookup keys on the hidden run
49
+ * marker, never the title.
50
+ */
51
+ issue?: {
52
+ key: string;
53
+ url?: string;
54
+ trackerName?: string;
55
+ };
20
56
  }
21
57
  export interface PullRequestResult {
22
58
  number: number;
@@ -42,6 +78,15 @@ export interface ContinuationCheckRunInput {
42
78
  export interface ContinuationCheckRunCompleteInput extends ContinuationCheckRunInput {
43
79
  outcome: "succeeded" | "failed";
44
80
  }
81
+ /** One file at one ref, read through the API without a clone. */
82
+ export interface RepositoryFileInput {
83
+ repository: string;
84
+ ref: string;
85
+ /** Repository-relative POSIX path. */
86
+ path: string;
87
+ /** Refused above this many bytes. */
88
+ maxBytes: number;
89
+ }
45
90
  export interface GitHubRepositoryAccess {
46
91
  withRepositoryToken<T>(repository: string, action: (token: string) => Promise<T>): Promise<T>;
47
92
  createOrFindDraftPullRequest(input: PullRequestInput): Promise<PullRequestResult>;
@@ -53,10 +98,29 @@ export interface GitHubRepositoryAccess {
53
98
  createContinuationCheckRun(input: ContinuationCheckRunInput): Promise<void>;
54
99
  /** Completes the check run if one exists for this run+commit; a no-op otherwise (never creates). */
55
100
  completeContinuationCheckRun(input: ContinuationCheckRunCompleteInput): Promise<void>;
101
+ /**
102
+ * The raw text of one file at a ref, or null when it does not exist (a
103
+ * Contents: read token). Optional so test doubles and non-GitHub providers
104
+ * can omit it: coding-run services then read no declaration.
105
+ */
106
+ readFileAtRef?(input: RepositoryFileInput): Promise<string | null>;
56
107
  }
57
108
  type Fetch = typeof globalThis.fetch;
58
109
  /** Accepts bounded opaque installation tokens without allowing control characters. */
59
110
  export declare function isSafeGitHubInstallationToken(value: unknown): value is string;
111
+ /**
112
+ * Same shape as ISSUE_KEY (issue-tracker/types.ts); duplicated so the VCS layer
113
+ * stays free of issue-tracker imports (a test keeps the two in step). The
114
+ * executor validates with the shared one.
115
+ */
116
+ export declare const PR_ISSUE_KEY: RegExp;
117
+ export declare function pullRequestTitle(input: PullRequestInput): string;
118
+ /** At most this many packages, and separately this many refusals, are listed
119
+ * in a PR body; the rest are counted in a "…and N more" line pointing at
120
+ * get_run, which returns the full list. */
121
+ export declare const MAX_PR_PACKAGE_LINES = 100;
122
+ /** The hidden run marker stays first and unconditional: createOrFindDraftPullRequest's idempotent lookup depends on it. */
123
+ export declare function pullRequestBody(input: PullRequestInput): string;
60
124
  export declare class GitHubAppClient implements GitHubRepositoryAccess {
61
125
  private readonly config;
62
126
  private readonly fetchImpl;
@@ -78,6 +142,28 @@ export declare class GitHubAppClient implements GitHubRepositoryAccess {
78
142
  * apparently isn't gated the same way a genuine issue comment might be.)
79
143
  */
80
144
  private withChecksToken;
145
+ /**
146
+ * Mints an installation token for exactly `permissions` on one repository,
147
+ * runs `action`, and always revokes. The building block for the
148
+ * code-review host (providers/review-host/github.ts), whose calls each
149
+ * request only what they need.
150
+ */
151
+ withScopedToken<T>(repository: string, permissions: Record<string, "read" | "write">, action: (token: string) => Promise<T>): Promise<T>;
152
+ /**
153
+ * One file's raw text at a ref, without a clone (a Contents: read token).
154
+ * Requests the raw media type; GitHub honors it for an ordinary file but
155
+ * falls back to a JSON metadata response for anything else the raw type
156
+ * doesn't apply to -- a directory listing (a JSON array) or a symlink /
157
+ * submodule (a JSON object whose `type` isn't "file"). Either of those, or
158
+ * a 404, means there's no file text to return.
159
+ */
160
+ readFileAtRef(input: RepositoryFileInput): Promise<string | null>;
161
+ private identity?;
162
+ /** The App's id and slug (its @-mention handle), read once with the App JWT. */
163
+ appIdentity(): Promise<{
164
+ id: number;
165
+ slug: string;
166
+ }>;
81
167
  upsertContinuationStatusComment(input: ContinuationStatusCommentInput): Promise<void>;
82
168
  updateContinuationStatusComment(input: ContinuationStatusCommentInput): Promise<void>;
83
169
  createContinuationCheckRun(input: ContinuationCheckRunInput): Promise<void>;
@@ -85,13 +171,12 @@ export declare class GitHubAppClient implements GitHubRepositoryAccess {
85
171
  createOrFindDraftPullRequest(input: PullRequestInput): Promise<PullRequestResult>;
86
172
  private appJwt;
87
173
  private mintRepositoryToken;
88
- private mintChecksToken;
89
174
  /**
90
175
  * Shared installation-token mint: requests exactly `permissions`, then
91
176
  * verifies the response granted exactly that (no more, no less, modulo
92
177
  * the always-implicit `metadata: read`) before trusting the token. Each
93
178
  * caller requests the narrowest permission set it needs — see
94
- * withIssuesToken/withChecksToken for why these are minted separately
179
+ * withScopedToken/withChecksToken for why these are minted separately
95
180
  * from withRepositoryToken rather than requesting a union of everything.
96
181
  */
97
182
  private mintScopedToken;
@@ -100,6 +185,12 @@ export declare class GitHubAppClient implements GitHubRepositoryAccess {
100
185
  private parsePullRequest;
101
186
  private findStatusComment;
102
187
  private findCheckRun;
103
- private requestJson;
188
+ /** Public for the code-review host, which issues its own REST calls with tokens minted here. */
189
+ requestJson(path: string, bearer: string, init?: RequestInit, expectedStatuses?: number[]): Promise<Response>;
190
+ /**
191
+ * Public for the code-review host: one GraphQL request, for what REST lacks
192
+ * (review threads). A response carrying `errors` fails like a REST error.
193
+ */
194
+ graphql(bearer: string, query: string, variables: Record<string, unknown>): Promise<Record<string, unknown>>;
104
195
  }
105
196
  export {};
@@ -11,6 +11,7 @@ const SAFE_PULL_REQUEST_TAG = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,31}$/;
11
11
  /** Mirrors the runId shape validated elsewhere (coding/protocol.ts, git.ts) — validated independently here too. */
12
12
  const SAFE_RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
13
13
  const SAFE_COMMIT_SHA = /^[0-9a-f]{40}$/;
14
+ const SAFE_FILE_PATH = /^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/;
14
15
  function record(value) {
15
16
  if (!value || typeof value !== "object" || Array.isArray(value))
16
17
  throw new Error("github_api_invalid_response");
@@ -32,17 +33,117 @@ export function isSafeGitHubInstallationToken(value) {
32
33
  Buffer.byteLength(value, "utf8") <= 512 &&
33
34
  /^[A-Za-z0-9._-]+$/.test(value));
34
35
  }
35
- function pullRequestTitle(input) {
36
- return input.tag ? `[${input.tag}] Wardby run ${input.runId}` : `Wardby run ${input.runId}`;
36
+ /**
37
+ * Same shape as ISSUE_KEY (issue-tracker/types.ts); duplicated so the VCS layer
38
+ * stays free of issue-tracker imports (a test keeps the two in step). The
39
+ * executor validates with the shared one.
40
+ */
41
+ export const PR_ISSUE_KEY = /^[A-Z][A-Z0-9_]{0,254}-[1-9]\d{0,9}$/;
42
+ /** The issue key when it is well-formed; a malformed one is dropped everywhere it would be rendered. */
43
+ function validIssueKey(input) {
44
+ const key = input.issue?.key;
45
+ return typeof key === "string" && PR_ISSUE_KEY.test(key) ? key : undefined;
46
+ }
47
+ export function pullRequestTitle(input) {
48
+ const base = input.tag ? `[${input.tag}] Wardby run ${input.runId}` : `Wardby run ${input.runId}`;
49
+ const key = validIssueKey(input);
50
+ return key ? `[${key}] ${base}` : base;
51
+ }
52
+ function issueLine(input) {
53
+ const key = validIssueKey(input);
54
+ const url = input.issue?.url;
55
+ if (!key || typeof url !== "string" || !url.startsWith("https://") || /[\s<>()]/.test(url))
56
+ return undefined;
57
+ const name = input.issue?.trackerName;
58
+ const tracker = typeof name === "string" && /^[A-Za-z][A-Za-z0-9 .-]{0,39}$/.test(name) ? `${name.trim()} ` : "";
59
+ return `Resolves ${tracker}issue [${key}](${url})`;
60
+ }
61
+ /**
62
+ * Package names/versions/reasons come from registry metadata, not from
63
+ * anything Wardby validated, and land inside inline code spans in the PR
64
+ * body. A backtick or newline in one of those fields could break out of the
65
+ * span or the line structure, so any entry containing either is dropped
66
+ * rather than escaped (npm/PyPI names can't contain backticks in practice,
67
+ * so this should never trigger — it's a cheap belt-and-suspenders guard).
68
+ */
69
+ function isSafeMarkdownFragment(value) {
70
+ return !value.includes("`") && !value.includes("\n") && !value.includes("\r");
71
+ }
72
+ /** At most this many packages, and separately this many refusals, are listed
73
+ * in a PR body; the rest are counted in a "…and N more" line pointing at
74
+ * get_run, which returns the full list. */
75
+ export const MAX_PR_PACKAGE_LINES = 100;
76
+ /** A hard ceiling on each list's rendered size, whatever the entries
77
+ * contain, so the section can never push the body past GitHub's limit. */
78
+ const MAX_PR_PACKAGE_LIST_CHARS = 16 * 1024;
79
+ /** Renders at most MAX_PR_PACKAGE_LINES lines (and at most
80
+ * MAX_PR_PACKAGE_LIST_CHARS characters) of `lines`, then a count of the rest. */
81
+ function cappedList(lines) {
82
+ const shown = [];
83
+ let chars = 0;
84
+ for (const line of lines.slice(0, MAX_PR_PACKAGE_LINES)) {
85
+ if (chars + line.length + 1 > MAX_PR_PACKAGE_LIST_CHARS)
86
+ break;
87
+ shown.push(line);
88
+ chars += line.length + 1;
89
+ }
90
+ const more = lines.length - shown.length;
91
+ return more > 0 ? [...shown, `- …and ${more} more — see get_run for the full list`] : shown;
92
+ }
93
+ function packagesSection(input) {
94
+ const packages = [
95
+ ...new Map((input.packages ?? [])
96
+ .filter((pkg) => isSafeMarkdownFragment(pkg.ecosystem) &&
97
+ isSafeMarkdownFragment(pkg.name) &&
98
+ isSafeMarkdownFragment(pkg.version))
99
+ .map((pkg) => [`${pkg.ecosystem}\0${pkg.name}\0${pkg.version}`, pkg])).values(),
100
+ ];
101
+ const refusals = [
102
+ ...new Map((input.packageRefusals ?? [])
103
+ .filter((refusal) => isSafeMarkdownFragment(refusal.ecosystem) &&
104
+ isSafeMarkdownFragment(refusal.name) &&
105
+ isSafeMarkdownFragment(refusal.reason))
106
+ .map((refusal) => [`${refusal.ecosystem}\0${refusal.name}\0${refusal.reason}`, refusal])).values(),
107
+ ];
108
+ if (packages.length === 0 && refusals.length === 0)
109
+ return undefined;
110
+ return [
111
+ "<details>",
112
+ `<summary>Packages installed during this run (${packages.length})</summary>`,
113
+ "",
114
+ ...cappedList(packages.map((pkg) => `- ${pkg.ecosystem} \`${pkg.name}@${pkg.version}\``)),
115
+ ...(refusals.length > 0
116
+ ? [
117
+ "",
118
+ "**Refused:**",
119
+ ...cappedList(refusals.map((refusal) => `- ${refusal.ecosystem} \`${refusal.name}\`: ${refusal.reason}`)),
120
+ ]
121
+ : []),
122
+ "</details>",
123
+ ].join("\n");
37
124
  }
38
125
  /** The hidden run marker stays first and unconditional: createOrFindDraftPullRequest's idempotent lookup depends on it. */
39
- function pullRequestBody(input) {
126
+ export function pullRequestBody(input) {
40
127
  const sections = [`${RUN_MARKER_PREFIX}${input.runId} -->`];
128
+ // Hidden marker stays first; the issue link is the first visible line.
129
+ const issue = issueLine(input);
130
+ if (issue)
131
+ sections.push(issue);
41
132
  if (input.summary)
42
133
  sections.push(input.summary);
43
134
  if (input.tests?.length) {
44
135
  sections.push(["**Tests:**", ...input.tests.map((test) => `- \`${test.command}\`: ${test.outcome}`)].join("\n"));
45
136
  }
137
+ // The packages section is informational: a failure rendering it (e.g. a
138
+ // malformed report) omits the section and never fails finalization.
139
+ try {
140
+ const packages = packagesSection(input);
141
+ if (packages)
142
+ sections.push(packages);
143
+ }
144
+ catch {
145
+ // omitted
146
+ }
46
147
  return sections.join("\n\n");
47
148
  }
48
149
  /** The hidden marker stays first and unconditional: findStatusComment's lookup depends on it. */
@@ -108,8 +209,17 @@ export class GitHubAppClient {
108
209
  * apparently isn't gated the same way a genuine issue comment might be.)
109
210
  */
110
211
  async withChecksToken(repository, action) {
212
+ return this.withScopedToken(repository, { checks: "write" }, action);
213
+ }
214
+ /**
215
+ * Mints an installation token for exactly `permissions` on one repository,
216
+ * runs `action`, and always revokes. The building block for the
217
+ * code-review host (providers/review-host/github.ts), whose calls each
218
+ * request only what they need.
219
+ */
220
+ async withScopedToken(repository, permissions, action) {
111
221
  const normalized = normalizeGitHubRepository(repository);
112
- const token = await this.mintChecksToken(normalized);
222
+ const token = await this.mintScopedToken(normalized, permissions, (name, level) => (name === "metadata" && level === "read") || permissions[name] === level);
113
223
  try {
114
224
  return await action(token);
115
225
  }
@@ -117,6 +227,74 @@ export class GitHubAppClient {
117
227
  await this.revokeToken(token).catch(() => undefined);
118
228
  }
119
229
  }
230
+ /**
231
+ * One file's raw text at a ref, without a clone (a Contents: read token).
232
+ * Requests the raw media type; GitHub honors it for an ordinary file but
233
+ * falls back to a JSON metadata response for anything else the raw type
234
+ * doesn't apply to -- a directory listing (a JSON array) or a symlink /
235
+ * submodule (a JSON object whose `type` isn't "file"). Either of those, or
236
+ * a 404, means there's no file text to return.
237
+ */
238
+ async readFileAtRef(input) {
239
+ if (!SAFE_FILE_PATH.test(input.path) || input.path.split("/").some((part) => part === "." || part === "..")) {
240
+ throw new Error("github_file_path_invalid");
241
+ }
242
+ const repository = normalizeGitHubRepository(input.repository);
243
+ const ref = normalizeGitRef(input.ref);
244
+ const [owner, name] = repository.split("/");
245
+ const path = input.path.split("/").map(encodeURIComponent).join("/");
246
+ return this.withScopedToken(repository, { contents: "read" }, async (token) => {
247
+ const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/contents/${path}?ref=${encodeURIComponent(ref)}`, token, { headers: { accept: "application/vnd.github.raw+json" } }, [200, 404]);
248
+ if (response.status === 404)
249
+ return null;
250
+ const declared = Number(response.headers.get("content-length") ?? Number.NaN);
251
+ if (Number.isFinite(declared) && declared > input.maxBytes)
252
+ throw new Error("github_file_too_large");
253
+ const bytes = new Uint8Array(await response.arrayBuffer());
254
+ if (bytes.byteLength > input.maxBytes)
255
+ throw new Error("github_file_too_large");
256
+ let text;
257
+ try {
258
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
259
+ }
260
+ catch {
261
+ throw new Error("github_file_not_utf8");
262
+ }
263
+ // Not raw content check: try to read the body as GitHub's own
264
+ // metadata shape rather than trusting the content-type header, since
265
+ // the raw media type itself is "application/vnd.github.raw+json" --
266
+ // a substring check for "json" would misfire on every real file.
267
+ let metadata;
268
+ try {
269
+ metadata = JSON.parse(text);
270
+ }
271
+ catch {
272
+ return text;
273
+ }
274
+ if (Array.isArray(metadata))
275
+ throw new Error("github_file_not_a_file");
276
+ if (metadata && typeof metadata === "object" && "type" in metadata && metadata.type !== "file") {
277
+ throw new Error("github_file_not_a_file");
278
+ }
279
+ return text;
280
+ });
281
+ }
282
+ identity;
283
+ /** The App's id and slug (its @-mention handle), read once with the App JWT. */
284
+ appIdentity() {
285
+ this.identity ??= (async () => {
286
+ const response = await this.requestJson("/app", await this.appJwt());
287
+ const payload = record(await response.json());
288
+ if (typeof payload.slug !== "string" || !/^[a-z0-9-]{1,64}$/.test(payload.slug)) {
289
+ throw new Error("github_api_invalid_response");
290
+ }
291
+ return { id: positiveInteger(payload.id), slug: payload.slug };
292
+ })().catch((err) => {
293
+ this.identity = undefined;
294
+ throw err;
295
+ });
296
+ return this.identity;
297
+ }
120
298
  async upsertContinuationStatusComment(input) {
121
299
  const repository = normalizeGitHubRepository(input.repository);
122
300
  const baseRef = normalizeGitRef(input.baseRef);
@@ -125,7 +303,13 @@ export class GitHubAppClient {
125
303
  throw new Error("github_status_comment_input_invalid");
126
304
  }
127
305
  await this.withRepositoryToken(repository, async (token) => {
128
- const pr = await this.findPullRequest(token, { runId: input.rootRunId, repository, baseRef, headRef });
306
+ const pr = await this.findPullRequest(token, {
307
+ runId: input.rootRunId,
308
+ repository,
309
+ baseRef,
310
+ headRef,
311
+ acceptReadyForReview: true,
312
+ });
129
313
  if (!pr)
130
314
  return;
131
315
  const existing = await this.findStatusComment(token, repository, pr.number, input.runId);
@@ -147,7 +331,13 @@ export class GitHubAppClient {
147
331
  throw new Error("github_status_comment_input_invalid");
148
332
  }
149
333
  await this.withRepositoryToken(repository, async (token) => {
150
- const pr = await this.findPullRequest(token, { runId: input.rootRunId, repository, baseRef, headRef });
334
+ const pr = await this.findPullRequest(token, {
335
+ runId: input.rootRunId,
336
+ repository,
337
+ baseRef,
338
+ headRef,
339
+ acceptReadyForReview: true,
340
+ });
151
341
  if (!pr)
152
342
  return;
153
343
  const existing = await this.findStatusComment(token, repository, pr.number, input.runId);
@@ -253,24 +443,27 @@ export class GitHubAppClient {
253
443
  (name === "pull_requests" && level === "write") ||
254
444
  (name === "metadata" && level === "read"));
255
445
  }
256
- async mintChecksToken(repository) {
257
- return this.mintScopedToken(repository, { checks: "write" }, (name, level) => (name === "checks" && level === "write") || (name === "metadata" && level === "read"));
258
- }
259
446
  /**
260
447
  * Shared installation-token mint: requests exactly `permissions`, then
261
448
  * verifies the response granted exactly that (no more, no less, modulo
262
449
  * the always-implicit `metadata: read`) before trusting the token. Each
263
450
  * caller requests the narrowest permission set it needs — see
264
- * withIssuesToken/withChecksToken for why these are minted separately
451
+ * withScopedToken/withChecksToken for why these are minted separately
265
452
  * from withRepositoryToken rather than requesting a union of everything.
266
453
  */
267
454
  async mintScopedToken(repository, permissions, isAllowedPermission) {
268
455
  const [owner, name] = repository.split("/");
269
456
  const appJwt = await this.appJwt();
270
- const installationResponse = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/installation`, appJwt);
457
+ const installationResponse = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/installation`, appJwt, {}, [200, 404]);
458
+ if (installationResponse.status === 404)
459
+ throw new Error("github_app_not_installed");
271
460
  const installation = record(await installationResponse.json());
272
461
  const installationId = positiveInteger(installation.id);
273
- const tokenResponse = await this.requestJson(`/app/installations/${installationId}/access_tokens`, appJwt, { method: "POST", body: JSON.stringify({ repositories: [name], permissions }) }, [201]);
462
+ const tokenResponse = await this.requestJson(`/app/installations/${installationId}/access_tokens`, appJwt, { method: "POST", body: JSON.stringify({ repositories: [name], permissions }) }, [201, 422]);
463
+ // 422: the installation has not granted a requested permission (e.g. a
464
+ // new permission the owner has not accepted yet).
465
+ if (tokenResponse.status === 422)
466
+ throw new Error("github_installation_token_scope_invalid");
274
467
  const payload = record(await tokenResponse.json());
275
468
  const grantedPermissions = record(payload.permissions);
276
469
  const repositories = Array.isArray(payload.repositories) ? payload.repositories.map(record) : [];
@@ -307,17 +500,15 @@ export class GitHubAppClient {
307
500
  for (const item of payload) {
308
501
  const candidate = record(item);
309
502
  if (typeof candidate.body === "string" && candidate.body.includes(marker)) {
310
- if (candidate.draft !== true)
311
- throw new Error("github_pull_request_not_draft");
312
- return this.parsePullRequest(candidate, input.repository);
503
+ return this.parsePullRequest(candidate, input.repository, input.acceptReadyForReview === true);
313
504
  }
314
505
  }
315
506
  return null;
316
507
  }
317
- parsePullRequest(value, repository) {
508
+ parsePullRequest(value, repository, acceptReadyForReview = false) {
318
509
  const payload = record(value);
319
510
  const number = positiveInteger(payload.number);
320
- if (payload.draft !== true)
511
+ if (payload.draft !== true && !acceptReadyForReview)
321
512
  throw new Error("github_pull_request_not_draft");
322
513
  const expectedUrl = `https://github.com/${repository}/pull/${number}`;
323
514
  if (typeof payload.html_url !== "string")
@@ -367,6 +558,7 @@ export class GitHubAppClient {
367
558
  }
368
559
  return null;
369
560
  }
561
+ /** Public for the code-review host, which issues its own REST calls with tokens minted here. */
370
562
  async requestJson(path, bearer, init = {}, expectedStatuses = [200]) {
371
563
  let response;
372
564
  try {
@@ -391,4 +583,18 @@ export class GitHubAppClient {
391
583
  throw safeApiError(response);
392
584
  return response;
393
585
  }
586
+ /**
587
+ * Public for the code-review host: one GraphQL request, for what REST lacks
588
+ * (review threads). A response carrying `errors` fails like a REST error.
589
+ */
590
+ async graphql(bearer, query, variables) {
591
+ const response = await this.requestJson("/graphql", bearer, {
592
+ method: "POST",
593
+ body: JSON.stringify({ query, variables }),
594
+ });
595
+ const payload = record(await response.json());
596
+ if (Array.isArray(payload.errors) && payload.errors.length > 0)
597
+ throw new Error("github_graphql_error");
598
+ return record(payload.data);
599
+ }
394
600
  }
@@ -1,9 +1,12 @@
1
+ import type { RepositoryFileInput } from "./github.js";
1
2
  export interface VcsPrepareInput {
2
3
  runId: string;
3
4
  repository: string;
4
5
  baseRef: string;
5
6
  headRef: string;
6
7
  protectedPaths: string[];
8
+ /** Repository-relative paths never collected, in addition to the built-in names. */
9
+ collectExclude?: string[];
7
10
  /**
8
11
  * Revision-in-place: set when headRef is an EXISTING branch to continue
9
12
  * rather than a fresh one
@@ -38,6 +41,7 @@ export interface PreparedWorkspace {
38
41
  workspacePath: string;
39
42
  gitMetadataPath: string;
40
43
  protectedPaths: string[];
44
+ collectExclude: string[];
41
45
  continuation?: {
42
46
  rootRunId: string;
43
47
  };
@@ -50,6 +54,23 @@ export interface FinalizeChangesDetails {
50
54
  outcome: "passed" | "failed" | "skipped";
51
55
  }[];
52
56
  tag?: string;
57
+ /** Packages the registry proxy served/refused during this run (RegistryFetch), for the PR body. */
58
+ packages?: readonly {
59
+ ecosystem: string;
60
+ name: string;
61
+ version: string;
62
+ }[];
63
+ packageRefusals?: readonly {
64
+ ecosystem: string;
65
+ name: string;
66
+ reason: string;
67
+ }[];
68
+ /** Originating issue (control-plane data): named in the PR title and body. Provider-neutral. */
69
+ issue?: {
70
+ key: string;
71
+ url?: string;
72
+ trackerName?: string;
73
+ };
53
74
  }
54
75
  export type FinalizeChangesResult = {
55
76
  outcome: "no_changes";
@@ -110,9 +131,32 @@ export interface VcsProvider {
110
131
  * (the same text that goes in the PR body -- see
111
132
  * `FinalizeChangesDetails.summary`) so the "done" status reflects what
112
133
  * actually happened instead of a caller having to go find out.
134
+ * `budget_exhausted` is a failure that ran out of budget;
135
+ * `details.budgetSentence` then says how (see core/budget-wording.ts).
136
+ * A `failed` run the model provider refused carries `details.providerSentence`.
137
+ * A `failed` run whose changes touched a protected path carries
138
+ * `details.protectedPathSentence` (see coding/protected-path-wording.ts).
113
139
  */
114
- notifyContinuationFinished?(workspace: PreparedWorkspace, outcome: "succeeded" | "failed", details?: {
115
- summary?: string;
116
- agentName?: string;
117
- }): Promise<void>;
140
+ notifyContinuationFinished?(workspace: PreparedWorkspace, outcome: ContinuationOutcome, details?: ContinuationFinishedDetails): Promise<void>;
141
+ /**
142
+ * The raw text of one repository file at a ref, read through the host's API
143
+ * without a clone, or null when it does not exist. Dispatch reads a coding
144
+ * run's .wardby/services.yaml from its base branch with it
145
+ * (docs/coding-services.md). Optional, mirroring notifyContinuationStarted: a
146
+ * provider (or test double) without it gives runs no services.
147
+ */
148
+ readRepositoryFile?(input: RepositoryFileInput): Promise<string | null>;
149
+ }
150
+ export type ContinuationOutcome = "succeeded" | "failed" | "budget_exhausted";
151
+ export interface ContinuationFinishedDetails {
152
+ summary?: string;
153
+ agentName?: string;
154
+ /** Host-safe sentence naming the run's budget; used with `budget_exhausted`. */
155
+ budgetSentence?: string;
156
+ /** Host-safe sentence naming a model-provider refusal (see core/provider-wording.ts); used with `failed`. */
157
+ providerSentence?: string;
158
+ /** Host-safe sentence naming a coding-run service that never became ready (coding/services/wording.ts); used with `failed`. */
159
+ serviceSentence?: string;
160
+ /** Host-safe sentence naming a protected path the run's changes touched (coding/protected-path-wording.ts); used with `failed`. */
161
+ protectedPathSentence?: string;
118
162
  }
@@ -1,4 +1,6 @@
1
1
  export declare function quickstartCommand(args: string[]): Promise<void>;
2
+ /** The closing "build your first agent" hint; the assistant prompts only make sense once an MCP client is configured. */
3
+ export declare function nextStepLines(mcpConfigured: boolean): string[];
2
4
  export declare function doctorCommand(args: string[]): Promise<void>;
3
5
  export declare function statusCommand(args: string[]): Promise<void>;
4
6
  export declare function logsCommand(args: string[]): Promise<void>;
@@ -212,8 +212,13 @@ function applyMigrations(paths) {
212
212
  }
213
213
  async function seedDemo(paths, state, budget) {
214
214
  const { createPrismaClient } = await import("../core/db.js");
215
- const db = createPrismaClient(readQuickstartEnv(paths).DATABASE_URL);
215
+ const { resolvePrincipal } = await import("../mcp/auth/principal.js");
216
+ const env = readQuickstartEnv(paths);
217
+ const db = createPrismaClient(env.DATABASE_URL);
216
218
  try {
219
+ // The demo agent belongs to the local operator (LOCAL_PRINCIPAL) and is
220
+ // private: agents are never owner-less (resource-sharing grants).
221
+ const owner = await resolvePrincipal(env.LOCAL_PRINCIPAL || "local", db);
217
222
  const existing = await db.agent.findUnique({ where: { name: DEMO_AGENT } });
218
223
  if (existing && existing.systemPrompt !== DEMO_PROMPT) {
219
224
  throw new Error(`An agent named "${DEMO_AGENT}" already exists and was not created by quickstart; rename it or use --skip-demo.`);
@@ -221,7 +226,12 @@ async function seedDemo(paths, state, budget) {
221
226
  if (existing) {
222
227
  await db.agent.update({
223
228
  where: { name: DEMO_AGENT },
224
- data: { model: state.model, budgetUsd: budget, maxTurns: 2 },
229
+ data: {
230
+ model: state.model,
231
+ budgetUsd: budget,
232
+ maxTurns: 2,
233
+ ...(existing.ownerId ? {} : { ownerId: owner.id }),
234
+ },
225
235
  });
226
236
  }
227
237
  else {
@@ -232,6 +242,7 @@ async function seedDemo(paths, state, budget) {
232
242
  budgetUsd: budget,
233
243
  maxTurns: 2,
234
244
  systemPrompt: DEMO_PROMPT,
245
+ ownerId: owner.id,
235
246
  },
236
247
  });
237
248
  }
@@ -255,12 +266,12 @@ function clientInstalled(command) {
255
266
  function configureOneMcpClient(client, paths) {
256
267
  if (!clientInstalled(client)) {
257
268
  console.warn(`! ${client} is not installed; skipped its MCP configuration.`);
258
- return;
269
+ return false;
259
270
  }
260
271
  const existing = runCommand(client, ["mcp", "get", "wardby"], { cwd: paths.projectDir });
261
272
  if (existing.status === 0) {
262
273
  console.log(`✓ ${client} already has an MCP server named wardby.`);
263
- return;
274
+ return true;
264
275
  }
265
276
  const packageSpec = `@wardby/cli@${packageJson.version}`;
266
277
  const args = client === "codex"
@@ -294,12 +305,16 @@ function configureOneMcpClient(client, paths) {
294
305
  if (result.status !== 0)
295
306
  commandFailure(`${client} MCP configuration`, result);
296
307
  console.log(`✓ Configured Wardby MCP for ${client}.`);
308
+ return true;
297
309
  }
310
+ /** True when at least one requested client ended up with the wardby MCP server. */
298
311
  function configureMcpClients(client, paths) {
312
+ const results = [];
299
313
  if (client === "codex" || client === "both")
300
- configureOneMcpClient("codex", paths);
314
+ results.push(configureOneMcpClient("codex", paths));
301
315
  if (client === "claude" || client === "both")
302
- configureOneMcpClient("claude", paths);
316
+ results.push(configureOneMcpClient("claude", paths));
317
+ return results.some(Boolean);
303
318
  }
304
319
  async function chooseClient(nonInteractive) {
305
320
  if (nonInteractive)
@@ -401,12 +416,25 @@ export async function quickstartCommand(args) {
401
416
  console.log(`Skipped the billed run. Start it later with: npx @wardby/cli@latest run ${DEMO_AGENT}`);
402
417
  }
403
418
  const client = parseClient(values.client) ?? (await chooseClient(nonInteractive));
404
- if (client !== "none")
405
- configureMcpClients(client, paths);
419
+ const mcpConfigured = client !== "none" && configureMcpClients(client, paths);
406
420
  console.log("\nWardby is ready.");
407
421
  console.log(" npx @wardby/cli@latest status");
408
422
  console.log(" npx @wardby/cli@latest doctor");
409
423
  console.log(" npx @wardby/cli@latest down");
424
+ for (const line of nextStepLines(mcpConfigured))
425
+ console.log(line);
426
+ }
427
+ /** The closing "build your first agent" hint; the assistant prompts only make sense once an MCP client is configured. */
428
+ export function nextStepLines(mcpConfigured) {
429
+ const guide = "the guide: npx @wardby/cli@latest help open agent-recipes";
430
+ const lines = ["", "Next: build your first agent."];
431
+ if (mcpConfigured) {
432
+ lines.push("Ask your assistant one of:", ' "Set up the Wardby architecture keeper for this repository"', ' "Set up a Wardby builder for this repository"', `Or read ${guide}`);
433
+ }
434
+ else {
435
+ lines.push(`Read ${guide}`);
436
+ }
437
+ return lines;
410
438
  }
411
439
  async function databaseHealthy(paths) {
412
440
  const env = readQuickstartEnv(paths);