@wardby/cli 0.6.0 → 0.8.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 (740) hide show
  1. package/.env.example +5 -5
  2. package/README.md +6 -1
  3. package/deploy/local/docker-compose.quickstart-coding.yml +19 -0
  4. package/dist/claude-coding-worker/driver.d.ts +33 -3
  5. package/dist/claude-coding-worker/driver.js +151 -21
  6. package/dist/claude-coding-worker/main.js +38 -6
  7. package/dist/claude-coding-worker/sdk.js +29 -2
  8. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  9. package/dist/claude-coding-worker/tool-socket.js +111 -0
  10. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  11. package/dist/claude-coding-worker/transcript.js +77 -0
  12. package/dist/claude-plugin/command.d.ts +61 -0
  13. package/dist/claude-plugin/command.js +376 -0
  14. package/dist/cli-help.d.ts +1 -1
  15. package/dist/cli-help.js +3 -1
  16. package/dist/cli.js +71 -13
  17. package/dist/coding/code-host.d.ts +16 -0
  18. package/dist/coding/code-host.js +60 -0
  19. package/dist/coding/continuation-wording.d.ts +35 -0
  20. package/dist/coding/continuation-wording.js +73 -0
  21. package/dist/coding/linked-issue-note.d.ts +23 -0
  22. package/dist/coding/linked-issue-note.js +47 -0
  23. package/dist/coding/mcp-token.d.ts +12 -0
  24. package/dist/coding/mcp-token.js +26 -0
  25. package/dist/coding/merge-wording.d.ts +28 -0
  26. package/dist/coding/merge-wording.js +78 -0
  27. package/dist/coding/pr-description-note.d.ts +9 -0
  28. package/dist/coding/pr-description-note.js +32 -0
  29. package/dist/coding/profile.d.ts +46 -126
  30. package/dist/coding/profile.js +45 -4
  31. package/dist/coding/protected-path-wording.d.ts +8 -0
  32. package/dist/coding/protected-path-wording.js +1 -1
  33. package/dist/coding/protocol.d.ts +264 -346
  34. package/dist/coding/protocol.js +237 -12
  35. package/dist/coding/redact.d.ts +3 -0
  36. package/dist/coding/redact.js +17 -0
  37. package/dist/coding/registry/allowlist.d.ts +12 -0
  38. package/dist/coding/registry/allowlist.js +14 -1
  39. package/dist/coding/registry/audit-mode.d.ts +153 -0
  40. package/dist/coding/registry/audit-mode.js +304 -0
  41. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  42. package/dist/coding/registry/lockfile-shared.js +128 -0
  43. package/dist/coding/registry/lockfiles.js +1 -1
  44. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  45. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  46. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  47. package/dist/coding/registry/npm-lockfile.js +4 -6
  48. package/dist/coding/registry/npm.js +78 -8
  49. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  50. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  51. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  52. package/dist/coding/registry/pypi-plan.js +406 -0
  53. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  54. package/dist/coding/registry/pypi-requirements.js +155 -0
  55. package/dist/coding/registry/pypi.d.ts +3 -27
  56. package/dist/coding/registry/pypi.js +40 -154
  57. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  58. package/dist/coding/registry/refusal-hints.js +61 -0
  59. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  60. package/dist/coding/registry/refusal-wording.js +56 -0
  61. package/dist/coding/registry/report.d.ts +70 -8
  62. package/dist/coding/registry/report.js +112 -5
  63. package/dist/coding/registry/types.d.ts +58 -8
  64. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  65. package/dist/coding/registry/yarn-lockfile.js +367 -0
  66. package/dist/coding/services/catalog.d.ts +37 -351
  67. package/dist/coding/transcript/claude-code.d.ts +13 -0
  68. package/dist/coding/transcript/claude-code.js +273 -0
  69. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  70. package/dist/coding/transcript/download-protocol.js +18 -0
  71. package/dist/coding/transcript/format.d.ts +20 -0
  72. package/dist/coding/transcript/format.js +32 -0
  73. package/dist/coding/transcript/recorder.d.ts +52 -0
  74. package/dist/coding/transcript/recorder.js +225 -0
  75. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  76. package/dist/coding/transcript/resume/checkout.js +203 -0
  77. package/dist/coding/transcript/resume/command.d.ts +17 -0
  78. package/dist/coding/transcript/resume/command.js +176 -0
  79. package/dist/coding/transcript/resume/download.d.ts +20 -0
  80. package/dist/coding/transcript/resume/download.js +153 -0
  81. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  82. package/dist/coding/transcript/resume/launch.js +128 -0
  83. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  84. package/dist/coding/transcript/resume/session-file.js +79 -0
  85. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  86. package/dist/coding/transcript/resume/stand-in.js +49 -0
  87. package/dist/coding-worker/artifact.d.ts +8 -3
  88. package/dist/coding-worker/artifact.js +3 -1
  89. package/dist/coding-worker/debug-trace.d.ts +9 -6
  90. package/dist/coding-worker/debug-trace.js +16 -19
  91. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  92. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  93. package/dist/coding-worker/driver.d.ts +4 -3
  94. package/dist/coding-worker/driver.js +124 -39
  95. package/dist/coding-worker/errors.d.ts +1 -0
  96. package/dist/coding-worker/errors.js +32 -0
  97. package/dist/coding-worker/main.js +5 -1
  98. package/dist/coding-worker/mcp-config.d.ts +27 -0
  99. package/dist/coding-worker/mcp-config.js +32 -0
  100. package/dist/coding-worker/sdk.d.ts +36 -0
  101. package/dist/coding-worker/sdk.js +28 -1
  102. package/dist/coding-worker/task-note.d.ts +11 -0
  103. package/dist/coding-worker/task-note.js +13 -0
  104. package/dist/coding-worker/types.d.ts +15 -0
  105. package/dist/config/dependency-cache.d.ts +23 -0
  106. package/dist/config/dependency-cache.js +32 -0
  107. package/dist/config/mcp-call-limit.d.ts +8 -0
  108. package/dist/config/mcp-call-limit.js +18 -0
  109. package/dist/config/mcp-servers.d.ts +8 -0
  110. package/dist/config/mcp-servers.js +12 -0
  111. package/dist/config/providers.d.ts +12 -3
  112. package/dist/config/providers.js +55 -5
  113. package/dist/config/test-simulators.d.ts +92 -0
  114. package/dist/config/test-simulators.js +333 -0
  115. package/dist/config/tool-timeout.d.ts +1 -0
  116. package/dist/config/tool-timeout.js +18 -0
  117. package/dist/core/async-context.d.ts +2 -0
  118. package/dist/core/async-context.js +12 -0
  119. package/dist/core/budget-events.d.ts +108 -0
  120. package/dist/core/budget-events.js +346 -0
  121. package/dist/core/budget-groups.d.ts +50 -1
  122. package/dist/core/budget-groups.js +236 -27
  123. package/dist/core/budget-stopped-head.d.ts +46 -0
  124. package/dist/core/budget-stopped-head.js +81 -0
  125. package/dist/core/budget-topup.d.ts +51 -0
  126. package/dist/core/budget-topup.js +156 -0
  127. package/dist/core/budget-wording.d.ts +16 -2
  128. package/dist/core/budget-wording.js +40 -2
  129. package/dist/core/coding-mcp.d.ts +36 -0
  130. package/dist/core/coding-mcp.js +253 -0
  131. package/dist/core/coding-queue.d.ts +2 -1
  132. package/dist/core/coding-queue.js +7 -0
  133. package/dist/core/coding-repository.d.ts +46 -0
  134. package/dist/core/coding-repository.js +92 -0
  135. package/dist/core/cron.d.ts +19 -1
  136. package/dist/core/cron.js +17 -0
  137. package/dist/core/datastores.js +1 -1
  138. package/dist/core/deferred-coding.d.ts +14 -0
  139. package/dist/core/deferred-coding.js +62 -0
  140. package/dist/core/delegation-child.d.ts +25 -0
  141. package/dist/core/delegation-child.js +37 -0
  142. package/dist/core/delegation-slots.d.ts +27 -0
  143. package/dist/core/delegation-slots.js +44 -0
  144. package/dist/core/dispatch.d.ts +48 -2
  145. package/dist/core/dispatch.js +166 -66
  146. package/dist/core/engine-native.js +1 -1
  147. package/dist/core/error-code.d.ts +38 -0
  148. package/dist/core/error-code.js +169 -0
  149. package/dist/core/grants.d.ts +46 -8
  150. package/dist/core/grants.js +99 -8
  151. package/dist/core/host-events.d.ts +18 -2
  152. package/dist/core/host-events.js +291 -27
  153. package/dist/core/host-status.d.ts +85 -3
  154. package/dist/core/host-status.js +300 -22
  155. package/dist/core/issue-bridge.d.ts +50 -6
  156. package/dist/core/issue-bridge.js +124 -33
  157. package/dist/core/issue-events.d.ts +1 -1
  158. package/dist/core/issue-events.js +4 -10
  159. package/dist/core/issue-status.d.ts +1 -1
  160. package/dist/core/issue-status.js +58 -29
  161. package/dist/core/logger.d.ts +5 -0
  162. package/dist/core/logger.js +14 -1
  163. package/dist/core/lost-run-children.d.ts +6 -0
  164. package/dist/core/lost-run-children.js +32 -0
  165. package/dist/core/mark-ready.d.ts +34 -0
  166. package/dist/core/mark-ready.js +152 -0
  167. package/dist/core/markdown-code.d.ts +8 -0
  168. package/dist/core/markdown-code.js +107 -0
  169. package/dist/core/mcp-client/client.d.ts +47 -0
  170. package/dist/core/mcp-client/client.js +141 -0
  171. package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
  172. package/dist/core/mcp-client/jsonrpc.js +54 -0
  173. package/dist/core/mcp-client/results.d.ts +13 -0
  174. package/dist/core/mcp-client/results.js +42 -0
  175. package/dist/core/mcp-servers.d.ts +90 -0
  176. package/dist/core/mcp-servers.js +230 -0
  177. package/dist/core/mcp-tools.d.ts +108 -0
  178. package/dist/core/mcp-tools.js +287 -0
  179. package/dist/core/memory-tools.js +7 -0
  180. package/dist/core/merge-order-check.d.ts +2 -1
  181. package/dist/core/merge-order-check.js +44 -18
  182. package/dist/core/notification-dispatcher.js +2 -1
  183. package/dist/core/notification-templates.d.ts +1 -7
  184. package/dist/core/notification-templates.js +36 -2
  185. package/dist/core/pull-request-state-sync.js +2 -2
  186. package/dist/core/reconciler.d.ts +4 -3
  187. package/dist/core/reconciler.js +8 -1
  188. package/dist/core/related-pull-requests.d.ts +11 -3
  189. package/dist/core/related-pull-requests.js +49 -20
  190. package/dist/core/reply-parts.d.ts +21 -0
  191. package/dist/core/reply-parts.js +73 -0
  192. package/dist/core/review-fix.d.ts +1 -1
  193. package/dist/core/review-fix.js +4 -3
  194. package/dist/core/review-host-checks.d.ts +1 -1
  195. package/dist/core/review-host-tools.d.ts +3 -0
  196. package/dist/core/review-host-tools.js +102 -14
  197. package/dist/core/review-reads.d.ts +55 -0
  198. package/dist/core/review-reads.js +233 -0
  199. package/dist/core/run-status.d.ts +12 -0
  200. package/dist/core/run-status.js +12 -0
  201. package/dist/core/runner.d.ts +145 -49
  202. package/dist/core/runner.js +719 -216
  203. package/dist/core/schedule-start.d.ts +12 -0
  204. package/dist/core/schedule-start.js +14 -0
  205. package/dist/core/secret-broker-config.d.ts +12 -74
  206. package/dist/core/secret-broker-config.js +1 -1
  207. package/dist/core/secret-guard.d.ts +49 -0
  208. package/dist/core/secret-guard.js +119 -0
  209. package/dist/core/secret-guarded-stores.d.ts +12 -0
  210. package/dist/core/secret-guarded-stores.js +41 -0
  211. package/dist/core/secret-spans.d.ts +50 -0
  212. package/dist/core/secret-spans.js +94 -0
  213. package/dist/core/secrets.d.ts +11 -1
  214. package/dist/core/secrets.js +27 -1
  215. package/dist/core/serializable-retry.d.ts +18 -0
  216. package/dist/core/serializable-retry.js +43 -0
  217. package/dist/core/stop-run.d.ts +46 -0
  218. package/dist/core/stop-run.js +61 -0
  219. package/dist/core/tool-admin.d.ts +5 -1
  220. package/dist/core/tool-admin.js +7 -2
  221. package/dist/core/tool-names.d.ts +13 -0
  222. package/dist/core/tool-names.js +20 -0
  223. package/dist/core/webhooks.d.ts +4 -0
  224. package/dist/core/webhooks.js +68 -49
  225. package/dist/core/workflow-events.d.ts +14 -2
  226. package/dist/core/workflow-events.js +4 -0
  227. package/dist/core/workflow-run-events.d.ts +5 -3
  228. package/dist/core/workflow-run-events.js +45 -9
  229. package/dist/core/zod-json-schema.d.ts +4 -0
  230. package/dist/core/zod-json-schema.js +39 -0
  231. package/dist/core/zod3-window.d.ts +35 -0
  232. package/dist/core/zod3-window.js +124 -0
  233. package/dist/generated/prisma/browser.d.ts +65 -3
  234. package/dist/generated/prisma/client.d.ts +65 -3
  235. package/dist/generated/prisma/commonInputTypes.d.ts +266 -106
  236. package/dist/generated/prisma/enums.d.ts +10 -0
  237. package/dist/generated/prisma/enums.js +8 -0
  238. package/dist/generated/prisma/internal/class.d.ts +110 -0
  239. package/dist/generated/prisma/internal/class.js +4 -4
  240. package/dist/generated/prisma/internal/prismaNamespace.d.ts +957 -9
  241. package/dist/generated/prisma/internal/prismaNamespace.js +166 -2
  242. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +174 -0
  243. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +166 -2
  244. package/dist/generated/prisma/models/Agent.d.ts +377 -8
  245. package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
  246. package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
  247. package/dist/generated/prisma/models/AgentRepository.d.ts +81 -1
  248. package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
  249. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +228 -7
  250. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  251. package/dist/generated/prisma/models/CodingProxySession.d.ts +232 -2
  252. package/dist/generated/prisma/models/CodingRun.d.ts +1712 -1
  253. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  254. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  255. package/dist/generated/prisma/models/HostProvider.d.ts +2176 -0
  256. package/dist/generated/prisma/models/HostProvider.js +1 -0
  257. package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
  258. package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
  259. package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
  260. package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
  261. package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
  262. package/dist/generated/prisma/models/HostProviderTrustedAccount.js +1 -0
  263. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  264. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  265. package/dist/generated/prisma/models/McpServer.d.ts +1500 -0
  266. package/dist/generated/prisma/models/McpServer.js +1 -0
  267. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +77 -1
  268. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
  269. package/dist/generated/prisma/models/Principal.d.ts +167 -0
  270. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  271. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  272. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  273. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  274. package/dist/generated/prisma/models/ResourceGrant.d.ts +1 -1
  275. package/dist/generated/prisma/models/Run.d.ts +738 -2
  276. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  277. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  278. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  279. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  280. package/dist/generated/prisma/models/Secret.d.ts +387 -0
  281. package/dist/generated/prisma/models/Tool.d.ts +223 -1
  282. package/dist/generated/prisma/models.d.ts +10 -0
  283. package/dist/help/search.js +12 -3
  284. package/dist/help-index.json +2033 -110
  285. package/dist/import/create.js +48 -4
  286. package/dist/import/neutral-schema.d.ts +51 -281
  287. package/dist/import/neutral-schema.js +7 -4
  288. package/dist/knowledge/check.d.ts +1 -1
  289. package/dist/knowledge/cli.d.ts +11 -1
  290. package/dist/knowledge/cli.js +37 -4
  291. package/dist/knowledge/concept.d.ts +3 -19
  292. package/dist/knowledge/location.d.ts +31 -0
  293. package/dist/knowledge/location.js +78 -0
  294. package/dist/mcp/auth/access.d.ts +10 -2
  295. package/dist/mcp/auth/access.js +15 -1
  296. package/dist/mcp/auth/grants-cli.d.ts +6 -4
  297. package/dist/mcp/auth/grants-cli.js +42 -3
  298. package/dist/mcp/auth/ownership.d.ts +7 -7
  299. package/dist/mcp/auth/resource-server.d.ts +3 -1
  300. package/dist/mcp/auth/resource-server.js +17 -2
  301. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  302. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  303. package/dist/mcp/context.d.ts +3 -0
  304. package/dist/mcp/host-events/github-ingress.d.ts +2 -0
  305. package/dist/mcp/host-events/github-ingress.js +2 -1
  306. package/dist/mcp/index.d.ts +6 -0
  307. package/dist/mcp/index.js +69 -10
  308. package/dist/mcp/server.d.ts +13 -0
  309. package/dist/mcp/server.js +33 -14
  310. package/dist/mcp/tools/agents.d.ts +4 -0
  311. package/dist/mcp/tools/agents.js +295 -28
  312. package/dist/mcp/tools/datastore.js +17 -8
  313. package/dist/mcp/tools/grants.js +73 -29
  314. package/dist/mcp/tools/host-providers.d.ts +2 -0
  315. package/dist/mcp/tools/host-providers.js +215 -0
  316. package/dist/mcp/tools/mcp-servers.d.ts +26 -0
  317. package/dist/mcp/tools/mcp-servers.js +481 -0
  318. package/dist/mcp/tools/memory.js +11 -1
  319. package/dist/mcp/tools/notification-channels.js +2 -2
  320. package/dist/mcp/tools/packages.d.ts +2 -0
  321. package/dist/mcp/tools/packages.js +195 -0
  322. package/dist/mcp/tools/repositories.js +65 -12
  323. package/dist/mcp/tools/run-access.d.ts +16 -0
  324. package/dist/mcp/tools/run-access.js +25 -0
  325. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  326. package/dist/mcp/tools/run-transcript-download.js +129 -0
  327. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  328. package/dist/mcp/tools/run-transcript.js +70 -0
  329. package/dist/mcp/tools/runs.js +209 -27
  330. package/dist/mcp/tools/scheduling.js +3 -1
  331. package/dist/mcp/tools/secret-elicitation-form.js +5 -0
  332. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  333. package/dist/mcp/tools/secret-elicitation-server.js +10 -61
  334. package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
  335. package/dist/mcp/tools/secret-elicitation.js +25 -2
  336. package/dist/mcp/tools/secrets.js +40 -6
  337. package/dist/mcp/tools/stop-run.d.ts +2 -0
  338. package/dist/mcp/tools/stop-run.js +82 -0
  339. package/dist/mcp/tools/subagents.js +2 -2
  340. package/dist/mcp/tools/tools.d.ts +7 -5
  341. package/dist/mcp/tools/tools.js +64 -16
  342. package/dist/mcp/tools/trigger.js +28 -6
  343. package/dist/mcp/transport/http-limits.d.ts +2 -0
  344. package/dist/mcp/transport/http-limits.js +6 -2
  345. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  346. package/dist/mcp/transport/stdio-link-host.js +67 -0
  347. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  348. package/dist/mcp/transport/streamable-http.js +41 -1
  349. package/dist/mcp/webhooks/ingress.js +10 -0
  350. package/dist/native-worker/docker-launcher.d.ts +38 -2
  351. package/dist/native-worker/docker-launcher.js +65 -5
  352. package/dist/native-worker/gateway-server.d.ts +55 -3
  353. package/dist/native-worker/gateway-server.js +152 -34
  354. package/dist/native-worker/gateway.d.ts +29 -1
  355. package/dist/native-worker/gateway.js +74 -4
  356. package/dist/native-worker/http-server.d.ts +7 -1
  357. package/dist/native-worker/http-server.js +62 -7
  358. package/dist/native-worker/http-transport.js +1 -1
  359. package/dist/native-worker/kubernetes-launcher.d.ts +7 -3
  360. package/dist/native-worker/kubernetes-launcher.js +43 -3
  361. package/dist/native-worker/launch.d.ts +18 -1
  362. package/dist/native-worker/launch.js +6 -1
  363. package/dist/native-worker/ledger.d.ts +24 -4
  364. package/dist/native-worker/ledger.js +62 -8
  365. package/dist/native-worker/loopback.js +3 -8
  366. package/dist/native-worker/main.d.ts +2 -1
  367. package/dist/native-worker/main.js +14 -3
  368. package/dist/native-worker/protocol.d.ts +130 -577
  369. package/dist/native-worker/protocol.js +51 -2
  370. package/dist/native-worker/sandbox-executor.d.ts +17 -2
  371. package/dist/native-worker/sandbox-executor.js +78 -4
  372. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  373. package/dist/native-worker/stderr-redaction.js +237 -0
  374. package/dist/native-worker/stdio.d.ts +1 -1
  375. package/dist/native-worker/stdio.js +6 -5
  376. package/dist/native-worker/warm-pool.d.ts +2 -2
  377. package/dist/native-worker/warm-pool.js +4 -4
  378. package/dist/native-worker/worker.js +28 -2
  379. package/dist/observability/metrics.js +6 -1
  380. package/dist/providers/auth/self-hosted.d.ts +1 -1
  381. package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
  382. package/dist/providers/coding-proxy/capability-hash.js +5 -0
  383. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  384. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  385. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  386. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  387. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  388. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  389. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  390. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  391. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  392. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  393. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  394. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  395. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  396. package/dist/providers/coding-proxy/hold.js +86 -0
  397. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  398. package/dist/providers/coding-proxy/interrupted.js +104 -0
  399. package/dist/providers/coding-proxy/mcp-route.d.ts +34 -0
  400. package/dist/providers/coding-proxy/mcp-route.js +166 -0
  401. package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -2
  402. package/dist/providers/coding-proxy/memory-ledger.js +99 -8
  403. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  404. package/dist/providers/coding-proxy/metering.js +27 -4
  405. package/dist/providers/coding-proxy/prisma-ledger.d.ts +16 -2
  406. package/dist/providers/coding-proxy/prisma-ledger.js +209 -69
  407. package/dist/providers/coding-proxy/proxy.d.ts +21 -2
  408. package/dist/providers/coding-proxy/proxy.js +300 -48
  409. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  410. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  411. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  412. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  413. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  414. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  415. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  416. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  417. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  418. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  419. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  420. package/dist/providers/coding-proxy/registry/service.js +579 -112
  421. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  422. package/dist/providers/coding-proxy/registry/store.js +54 -1
  423. package/dist/providers/coding-proxy/runtime.d.ts +10 -0
  424. package/dist/providers/coding-proxy/runtime.js +109 -16
  425. package/dist/providers/coding-proxy/server.d.ts +9 -1
  426. package/dist/providers/coding-proxy/server.js +55 -1
  427. package/dist/providers/coding-proxy/types.d.ts +78 -1
  428. package/dist/providers/datastore/types.d.ts +5 -0
  429. package/dist/providers/engine/types.d.ts +17 -2
  430. package/dist/providers/engine/types.js +17 -0
  431. package/dist/providers/executor/composition.d.ts +10 -3
  432. package/dist/providers/executor/composition.js +52 -7
  433. package/dist/providers/executor/container.d.ts +394 -9
  434. package/dist/providers/executor/container.js +1210 -96
  435. package/dist/providers/executor/dbos-status.d.ts +31 -0
  436. package/dist/providers/executor/dbos-status.js +64 -0
  437. package/dist/providers/executor/dbos.d.ts +50 -1
  438. package/dist/providers/executor/dbos.js +207 -20
  439. package/dist/providers/executor/deferred.d.ts +12 -24
  440. package/dist/providers/executor/deferred.js +10 -29
  441. package/dist/providers/executor/in-process.d.ts +9 -1
  442. package/dist/providers/executor/in-process.js +14 -4
  443. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  444. package/dist/providers/executor/linked-issue-reader.js +30 -0
  445. package/dist/providers/executor/routing.d.ts +2 -0
  446. package/dist/providers/executor/routing.js +4 -0
  447. package/dist/providers/executor/types.d.ts +13 -0
  448. package/dist/providers/host-tools/invoke.d.ts +37 -0
  449. package/dist/providers/host-tools/invoke.js +117 -0
  450. package/dist/providers/host-tools/operations.d.ts +65 -0
  451. package/dist/providers/host-tools/operations.js +149 -0
  452. package/dist/providers/host-tools/registry.d.ts +79 -0
  453. package/dist/providers/host-tools/registry.js +362 -0
  454. package/dist/providers/host-tools/request-guard.d.ts +17 -0
  455. package/dist/providers/host-tools/request-guard.js +99 -0
  456. package/dist/providers/host-tools/self-test.d.ts +64 -0
  457. package/dist/providers/host-tools/self-test.js +142 -0
  458. package/dist/providers/index.d.ts +2 -1
  459. package/dist/providers/issue-tracker/types.d.ts +17 -0
  460. package/dist/providers/issue-tracker/types.js +39 -1
  461. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  462. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  463. package/dist/providers/jobs/docker-isolation.d.ts +10 -2
  464. package/dist/providers/jobs/docker-isolation.js +47 -8
  465. package/dist/providers/jobs/docker.d.ts +9 -0
  466. package/dist/providers/jobs/docker.js +60 -11
  467. package/dist/providers/jobs/fake-kubernetes-api.d.ts +2 -0
  468. package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
  469. package/dist/providers/jobs/kubernetes-api.d.ts +8 -0
  470. package/dist/providers/jobs/kubernetes-api.js +10 -0
  471. package/dist/providers/jobs/kubernetes-client.js +10 -1
  472. package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
  473. package/dist/providers/jobs/kubernetes-isolation.js +32 -3
  474. package/dist/providers/jobs/kubernetes.d.ts +11 -1
  475. package/dist/providers/jobs/kubernetes.js +111 -17
  476. package/dist/providers/jobs/types.d.ts +39 -0
  477. package/dist/providers/jobs/types.js +13 -1
  478. package/dist/providers/llm/anthropic.js +5 -1
  479. package/dist/providers/llm/bedrock.d.ts +0 -12
  480. package/dist/providers/llm/bedrock.js +4 -0
  481. package/dist/providers/llm/claude-messages.d.ts +3 -1
  482. package/dist/providers/llm/claude-messages.js +4 -1
  483. package/dist/providers/llm/claude-provider.d.ts +2 -2
  484. package/dist/providers/llm/claude-provider.js +2 -2
  485. package/dist/providers/llm/openai.d.ts +2 -2
  486. package/dist/providers/llm/openai.js +6 -2
  487. package/dist/providers/llm/routing.d.ts +2 -2
  488. package/dist/providers/llm/routing.js +2 -2
  489. package/dist/providers/llm/types.d.ts +12 -2
  490. package/dist/providers/review-host/github-events.d.ts +9 -1
  491. package/dist/providers/review-host/github-events.js +34 -12
  492. package/dist/providers/review-host/github.d.ts +29 -2
  493. package/dist/providers/review-host/github.js +224 -29
  494. package/dist/providers/review-host/local.d.ts +8 -4
  495. package/dist/providers/review-host/local.js +49 -31
  496. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  497. package/dist/providers/review-host/patch-pages.js +176 -0
  498. package/dist/providers/review-host/review-format.d.ts +19 -1
  499. package/dist/providers/review-host/review-format.js +38 -7
  500. package/dist/providers/review-host/types.d.ts +140 -6
  501. package/dist/providers/review-host/types.js +9 -1
  502. package/dist/providers/storage/gcs.d.ts +63 -0
  503. package/dist/providers/storage/gcs.js +69 -0
  504. package/dist/providers/storage/index.d.ts +15 -0
  505. package/dist/providers/storage/index.js +14 -0
  506. package/dist/providers/storage/local.d.ts +24 -0
  507. package/dist/providers/storage/local.js +92 -0
  508. package/dist/providers/storage/meter.d.ts +14 -0
  509. package/dist/providers/storage/meter.js +34 -0
  510. package/dist/providers/storage/s3.d.ts +41 -0
  511. package/dist/providers/storage/s3.js +107 -0
  512. package/dist/providers/storage/types.d.ts +37 -3
  513. package/dist/providers/storage/types.js +21 -4
  514. package/dist/providers/vcs/git.d.ts +39 -4
  515. package/dist/providers/vcs/git.js +339 -26
  516. package/dist/providers/vcs/github-remote.d.ts +26 -3
  517. package/dist/providers/vcs/github-remote.js +124 -14
  518. package/dist/providers/vcs/github.d.ts +183 -44
  519. package/dist/providers/vcs/github.js +455 -56
  520. package/dist/providers/vcs/index.d.ts +1 -1
  521. package/dist/providers/vcs/index.js +9 -2
  522. package/dist/providers/vcs/pr-description.d.ts +127 -0
  523. package/dist/providers/vcs/pr-description.js +270 -0
  524. package/dist/providers/vcs/remote.d.ts +37 -1
  525. package/dist/providers/vcs/remote.js +7 -1
  526. package/dist/providers/vcs/routing.d.ts +16 -8
  527. package/dist/providers/vcs/routing.js +27 -6
  528. package/dist/providers/vcs/types.d.ts +150 -5
  529. package/dist/quickstart/coding-seed.d.ts +14 -3
  530. package/dist/quickstart/coding-seed.js +213 -4
  531. package/dist/quickstart/index.d.ts +5 -0
  532. package/dist/quickstart/index.js +21 -0
  533. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  534. package/dist/quickstart/reviewer-prompt.js +6 -6
  535. package/dist/quickstart-images.json +1 -1
  536. package/dist/sandbox/eval-core.d.ts +12 -2
  537. package/dist/sandbox/eval-core.js +20 -4
  538. package/dist/sandbox/generated/zod.bundle.js +62 -1
  539. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  540. package/dist/sandbox/host-functions.d.ts +5 -0
  541. package/dist/sandbox/host-functions.js +13 -13
  542. package/dist/sandbox/limits.d.ts +4 -1
  543. package/dist/sandbox/limits.js +4 -1
  544. package/dist/sandbox/run-in-sandbox.d.ts +6 -0
  545. package/dist/sandbox/run-in-sandbox.js +14 -2
  546. package/dist/sandbox/safe-fetch.d.ts +2 -0
  547. package/dist/sandbox/safe-fetch.js +1 -1
  548. package/dist/sandbox/secret-broker.d.ts +1 -0
  549. package/dist/sandbox/secret-broker.js +4 -5
  550. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  551. package/dist/sandbox/tool-timeout.d.ts +32 -0
  552. package/dist/sandbox/tool-timeout.js +52 -0
  553. package/dist/sandbox/user-tool.d.ts +8 -1
  554. package/dist/sandbox/user-tool.js +9 -3
  555. package/dist/sandbox/zod-params.d.ts +37 -5
  556. package/dist/sandbox/zod-params.js +181 -26
  557. package/dist/serve.js +8 -1
  558. package/dist/viewer/api-schema.d.ts +349 -2627
  559. package/dist/viewer/api-schema.js +7 -0
  560. package/dist/viewer/build-schemas.js +6 -2
  561. package/dist/viewer/graph.js +2 -1
  562. package/dist/viewer/openapi.js +2 -4
  563. package/dist/wardby-bin.js +15 -0
  564. package/docs/README.md +11 -1
  565. package/docs/agent-recipes.md +95 -24
  566. package/docs/architecture-runtime.md +1 -1
  567. package/docs/claude-code-plugin.md +164 -0
  568. package/docs/code-review-agents.md +557 -41
  569. package/docs/coding-agent-setup.md +566 -8
  570. package/docs/coding-packages.md +1033 -90
  571. package/docs/coding-services.md +27 -12
  572. package/docs/coding-worker-byo-images.md +24 -2
  573. package/docs/coding-worker-isolation.md +183 -37
  574. package/docs/debugging-agent-runs.md +242 -0
  575. package/docs/getting-started-gke.md +129 -141
  576. package/docs/getting-started-identity-provider.md +53 -38
  577. package/docs/getting-started.md +17 -0
  578. package/docs/host-providers.md +294 -0
  579. package/docs/jira-agents.md +17 -8
  580. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  581. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  582. package/docs/knowledge/delegation-admission-slots.md +52 -0
  583. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  584. package/docs/knowledge/import-rename-target.md +52 -0
  585. package/docs/knowledge/index.md +57 -0
  586. package/docs/knowledge/log.md +9 -0
  587. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  588. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  589. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  590. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  591. package/docs/knowledge/overview-cli.md +74 -0
  592. package/docs/knowledge/overview-coding-proxy.md +72 -0
  593. package/docs/knowledge/overview-coding.md +72 -0
  594. package/docs/knowledge/overview-config.md +60 -0
  595. package/docs/knowledge/overview-core.md +72 -0
  596. package/docs/knowledge/overview-deploy.md +83 -0
  597. package/docs/knowledge/overview-mcp.md +61 -0
  598. package/docs/knowledge/overview-prisma.md +72 -0
  599. package/docs/knowledge/overview-providers.md +89 -0
  600. package/docs/knowledge/overview-sandbox.md +83 -0
  601. package/docs/knowledge/overview-surfaces.md +83 -0
  602. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  603. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  604. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  605. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  606. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  607. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  608. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  609. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  610. package/docs/knowledge/warm-input-publication.md +30 -0
  611. package/docs/knowledge/workspace-staging-failure.md +54 -0
  612. package/docs/knowledge.md +54 -14
  613. package/docs/mcp-servers.md +254 -0
  614. package/docs/native-sandbox.md +143 -31
  615. package/docs/observability.md +4 -0
  616. package/docs/security-deployment.md +139 -29
  617. package/docs/slack-notifications.md +35 -19
  618. package/docs/tool-secrets.md +45 -10
  619. package/docs/viewer-api.md +6 -0
  620. package/docs/viewer-api.openapi.yml +1 -1
  621. package/help/admin-viewer.md +28 -2
  622. package/help/agent-recipes.md +33 -2
  623. package/help/architecture-agent.md +11 -6
  624. package/help/brokered-secrets.md +3 -0
  625. package/help/build-claude-code-image.md +1 -1
  626. package/help/build-worker-image.md +3 -1
  627. package/help/builder-agent.md +19 -6
  628. package/help/claude-code-run-pane.md +40 -0
  629. package/help/code-review-agents.md +177 -6
  630. package/help/coding-packages.md +156 -6
  631. package/help/cost-attribution.md +9 -5
  632. package/help/creating-agents.md +14 -1
  633. package/help/dependency-cache.md +143 -0
  634. package/help/deploy-gke.md +15 -8
  635. package/help/errors/budget-exhausted.md +187 -0
  636. package/help/errors/budget-group-exhausted.md +5 -1
  637. package/help/errors/coding-mcp-pins-unavailable.md +35 -0
  638. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  639. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  640. package/help/errors/continuation-closed.md +9 -12
  641. package/help/errors/database-auth-invalid.md +1 -1
  642. package/help/errors/delegation-conflict.md +24 -0
  643. package/help/errors/file-list-truncated.md +45 -0
  644. package/help/errors/full-read-required.md +49 -0
  645. package/help/errors/github-account-not-allowed.md +4 -0
  646. package/help/errors/graph-incomplete.md +43 -0
  647. package/help/errors/graph-limit.md +43 -0
  648. package/help/errors/host-provider-error.md +40 -0
  649. package/help/errors/host-tool-failed.md +36 -0
  650. package/help/errors/mcp-call-limit.md +22 -0
  651. package/help/errors/mcp-call-timeout.md +22 -0
  652. package/help/errors/mcp-server-auth-failed.md +22 -0
  653. package/help/errors/mcp-server-credentials-unavailable.md +45 -0
  654. package/help/errors/mcp-server-error.md +28 -0
  655. package/help/errors/mcp-server-unreachable.md +22 -0
  656. package/help/errors/mcp-servers-off.md +21 -0
  657. package/help/errors/mcp-tool-not-allowed.md +26 -0
  658. package/help/errors/mcp-tool-removed.md +22 -0
  659. package/help/errors/mcp-unavailable.md +25 -0
  660. package/help/errors/merge-conflict.md +49 -0
  661. package/help/errors/native-sandbox-capacity.md +1 -1
  662. package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
  663. package/help/errors/native-sandbox-docker-failed.md +1 -1
  664. package/help/errors/native-sandbox-gateway-error.md +20 -0
  665. package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
  666. package/help/errors/native-sandbox-image-not-pinned.md +1 -1
  667. package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
  668. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  669. package/help/errors/native-sandbox-network-unenforced.md +1 -1
  670. package/help/errors/native-sandbox-requires-catalog.md +1 -1
  671. package/help/errors/native-sandbox-unavailable.md +1 -1
  672. package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
  673. package/help/errors/native-sandbox-worker-exited.md +4 -3
  674. package/help/errors/native-sandbox-worker-lost.md +1 -1
  675. package/help/errors/native-sandbox-worker-unready.md +1 -1
  676. package/help/errors/package-not-allowed-pending.md +52 -0
  677. package/help/errors/package-not-allowed.md +51 -0
  678. package/help/errors/package-refusals.md +43 -0
  679. package/help/errors/patch-cursor-malformed.md +31 -0
  680. package/help/errors/repository-not-listed.md +36 -0
  681. package/help/errors/repository-required.md +36 -0
  682. package/help/errors/run-lost.md +39 -0
  683. package/help/errors/run-transcript-download.md +44 -0
  684. package/help/errors/secret-in-value.md +69 -0
  685. package/help/errors/target-merge.md +40 -0
  686. package/help/errors/tool-timeout.md +38 -0
  687. package/help/fix-merge-conflicts.md +73 -0
  688. package/help/github-app-setup.md +132 -0
  689. package/help/github.md +22 -0
  690. package/help/host-providers.md +40 -0
  691. package/help/identity-and-access.md +6 -1
  692. package/help/jira.md +23 -6
  693. package/help/knowledge.md +16 -7
  694. package/help/local-repositories.md +1 -1
  695. package/help/low-power-mode.md +7 -1
  696. package/help/mcp-servers.md +73 -0
  697. package/help/mcp.md +7 -2
  698. package/help/merge-order-check.md +5 -0
  699. package/help/native-capabilities.md +55 -1
  700. package/help/native-sandbox.md +16 -2
  701. package/help/operating-agents.md +21 -0
  702. package/help/package-audit-mode.md +91 -0
  703. package/help/related-pull-requests.md +17 -10
  704. package/help/repo-instructions-and-skills.md +3 -1
  705. package/help/resume-runs-locally.md +134 -0
  706. package/help/review-fix-rounds.md +33 -1
  707. package/help/sharing-agents.md +59 -0
  708. package/help/slack-notifications.md +19 -5
  709. package/help/status-comments.md +31 -0
  710. package/help/stop-run.md +58 -0
  711. package/help/troubleshooting/budgets.md +28 -0
  712. package/help/troubleshooting/coding-workers.md +86 -7
  713. package/help/troubleshooting/debugging-agent-runs.md +29 -0
  714. package/package.json +18 -10
  715. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  716. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  717. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  718. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  719. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  720. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  721. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  722. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  723. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  724. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  725. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  726. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  727. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  728. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  729. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  730. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  731. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  732. package/prisma/migrations/20261102000000_host_providers/migration.sql +56 -0
  733. package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
  734. package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
  735. package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
  736. package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
  737. package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
  738. package/prisma/schema.prisma +468 -109
  739. package/scripts/git-askpass.sh +1 -1
  740. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -1,7 +1,15 @@
1
1
  import { createPrivateKey } from "node:crypto";
2
2
  import { importPKCS8, SignJWT } from "jose";
3
3
  import { isGitHubLogin } from "../../config/github-allowed-accounts.js";
4
- import { normalizeGitHubRepository, normalizeGitRef } from "../../coding/protocol.js";
4
+ import { testSimulatorBase } from "../../config/test-simulators.js";
5
+ import { codeProviderOf, normalizeHostedRepository, pullRequestWebUrl } from "../../coding/code-host.js";
6
+ import { ACCEPTED_ADVISORY_ID } from "../../coding/registry/allowlist.js";
7
+ import { packageAuditRows, packageAuditWording, summarizePackageAudit, } from "../../coding/registry/audit-mode.js";
8
+ import { isSafeGitAuthToken } from "./remote.js";
9
+ import { refusalMeaning } from "../../coding/registry/refusal-hints.js";
10
+ import { DEPENDENCY_CACHE_PATH, normalizeGitHubRepository, normalizeGitRef, truncateText, } from "../../coding/protocol.js";
11
+ import { LATEST_RUN_MARKER_PREFIX, RELATED_SECTION_END, RELATED_SECTION_START, assessFinalMessage, descriptionAppliedComment, descriptionFallbackComment, descriptionSha256, extractRelatedBlock, findDescriptionComments, hasClosingKeyword, isUneditedDescription, supersededDescriptionComment, } from "./pr-description.js";
12
+ export { RELATED_SECTION_END, RELATED_SECTION_START };
5
13
  const DEFAULT_API_BASE_URL = "https://api.github.com";
6
14
  const DEFAULT_API_VERSION = "2026-03-10";
7
15
  const RUN_MARKER_PREFIX = "<!-- wardby:";
@@ -27,19 +35,14 @@ function safeApiError(response) {
27
35
  const requestId = response.headers.get("x-github-request-id");
28
36
  return new Error(`github_api_error:${response.status}${requestId ? `:${requestId}` : ""}`);
29
37
  }
30
- /** Accepts bounded opaque installation tokens without allowing control characters. */
31
- export function isSafeGitHubInstallationToken(value) {
32
- return (typeof value === "string" &&
33
- value.length >= 20 &&
34
- Buffer.byteLength(value, "utf8") <= 512 &&
35
- /^[A-Za-z0-9._-]+$/.test(value));
36
- }
37
38
  /**
38
39
  * Same shape as ISSUE_KEY (issue-tracker/types.ts); duplicated so the VCS layer
39
40
  * stays free of issue-tracker imports (a test keeps the two in step). The
40
41
  * executor validates with the shared one.
41
42
  */
42
43
  export const PR_ISSUE_KEY = /^[A-Z][A-Z0-9_]{0,254}-[1-9]\d{0,9}$/;
44
+ /** Same shape as GITHUB_ISSUE_KEY (issue-tracker/types.ts), duplicated likewise. Only the Related section shows one. */
45
+ export const PR_GITHUB_ISSUE_KEY = /^[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?\/[a-z0-9._-]{1,100}#[1-9]\d{0,9}$/;
43
46
  /** The issue key when it is well-formed; a malformed one is dropped everywhere it would be rendered. */
44
47
  function validIssueKey(input) {
45
48
  const key = input.issue?.key;
@@ -50,22 +53,29 @@ export function pullRequestTitle(input) {
50
53
  const key = validIssueKey(input);
51
54
  return key ? `[${key}] ${base}` : base;
52
55
  }
53
- /** Validated issue parts; the tracker prefix is "" or "<Name> ". */
54
- function issueParts(issue) {
56
+ /**
57
+ * Validated issue parts; the tracker prefix is "" or "<Name> ". A GitHub issue
58
+ * key is accepted only with `orGitHub` (the Related section): the title and
59
+ * the body's issue line stay tracker-only.
60
+ */
61
+ function issueParts(issue, orGitHub = false) {
55
62
  const key = issue?.key;
56
- if (typeof key !== "string" || !PR_ISSUE_KEY.test(key))
63
+ if (typeof key !== "string" || !(PR_ISSUE_KEY.test(key) || (orGitHub && PR_GITHUB_ISSUE_KEY.test(key)))) {
57
64
  return undefined;
65
+ }
58
66
  const url = issue?.url;
59
67
  const safeUrl = typeof url === "string" && url.startsWith("https://") && !/[\s<>()]/.test(url) ? url : undefined;
60
68
  const name = issue?.trackerName;
61
69
  const tracker = typeof name === "string" && /^[A-Za-z][A-Za-z0-9 .-]{0,39}$/.test(name) ? `${name.trim()} ` : "";
62
70
  return { key, ...(safeUrl ? { url: safeUrl } : {}), tracker };
63
71
  }
72
+ /** The body's issue line: a tracker issue's link, else the same-repository issue the run came from. */
64
73
  function issueLine(input) {
65
74
  const parts = issueParts(input.issue);
66
- if (!parts?.url)
67
- return undefined;
68
- return `Resolves ${parts.tracker}issue [${parts.key}](${parts.url})`;
75
+ if (parts?.url)
76
+ return `Resolves ${parts.tracker}issue [${parts.key}](${parts.url})`;
77
+ const number = input.issueNumber;
78
+ return typeof number === "number" && Number.isSafeInteger(number) && number > 0 ? `From issue #${number}` : undefined;
69
79
  }
70
80
  /**
71
81
  * Package names/versions/reasons come from registry metadata, not from
@@ -78,17 +88,26 @@ function issueLine(input) {
78
88
  function isSafeMarkdownFragment(value) {
79
89
  return !value.includes("`") && !value.includes("\n") && !value.includes("\r");
80
90
  }
81
- export const RELATED_SECTION_START = "<!-- wardby-related:start -->";
82
- export const RELATED_SECTION_END = "<!-- wardby-related:end -->";
91
+ /** Whether a comment was written by this GitHub App (its bot user, through this App's id). */
92
+ function isThisAppsComment(comment, appId) {
93
+ const user = comment.user;
94
+ const app = comment.performed_via_github_app;
95
+ return (!!user &&
96
+ typeof user === "object" &&
97
+ user.type === "Bot" &&
98
+ !!app &&
99
+ typeof app === "object" &&
100
+ app.id === appId);
101
+ }
83
102
  /** At most this many pull requests are listed; the rest are counted. */
84
103
  export const MAX_RELATED_PULL_REQUESTS = 20;
85
104
  /** GitHub rejects a pull request body longer than this. */
86
105
  export const MAX_PULL_REQUEST_BODY_CHARS = 65_536;
87
106
  const RELATED_STATES = new Set(["open", "draft", "merged", "closed"]);
88
- /** The repository normalized, or undefined when it isn't a plain owner/name safe inside a link. */
107
+ /** The repository normalized, or undefined when it isn't a hosted repository id safe inside a link. */
89
108
  function safeRepository(value) {
90
109
  try {
91
- const repository = normalizeGitHubRepository(value);
110
+ const repository = normalizeHostedRepository(value);
92
111
  return isSafeMarkdownFragment(repository) && !/[[\]()<>\s]/.test(repository) ? repository : undefined;
93
112
  }
94
113
  catch {
@@ -105,7 +124,9 @@ function relatedLine(entry, prefix) {
105
124
  return `${prefix} **This pull request**${state}`;
106
125
  if (!Number.isSafeInteger(entry.number) || (entry.number ?? 0) <= 0)
107
126
  return undefined;
108
- return `${prefix} [${repository}#${entry.number}](https://github.com/${repository}/pull/${entry.number})${state}`;
127
+ const label = `${repository}#${entry.number}`;
128
+ const url = pullRequestWebUrl(codeProviderOf(repository), repository, entry.number);
129
+ return `${prefix} ${url ? `[${label}](${url})` : label}${state}`;
109
130
  }
110
131
  const isDone = (entry) => entry.state === "merged" || entry.state === "closed";
111
132
  /**
@@ -128,7 +149,7 @@ export function renderRelatedSection(input) {
128
149
  const valid = input.entries.filter((entry) => relatedLine(entry, "-") !== undefined);
129
150
  if (!valid.some((entry) => !entry.self))
130
151
  return undefined;
131
- const issue = issueParts(input.issue);
152
+ const issue = issueParts(input.issue, true);
132
153
  const issueText = issue ? ` for ${issue.tracker}issue ${issue.url ? `[${issue.key}](${issue.url})` : issue.key}` : "";
133
154
  const open = valid.filter((entry) => !isDone(entry)).slice(0, MAX_RELATED_PULL_REQUESTS);
134
155
  const done = valid.filter(isDone).slice(0, MAX_RELATED_PULL_REQUESTS - open.length);
@@ -185,8 +206,8 @@ export function renderRelatedSection(input) {
185
206
  RELATED_SECTION_END,
186
207
  ].join("\n");
187
208
  }
188
- /** The run marker, then optionally blank lines and the "Resolves …" line: the section goes right after. */
189
- const BODY_HEAD = /^[^\S\n]*<!-- (?:wardby|reevo-run):\S+ -->[^\S\n]*(?:\n|$)(?:[^\S\n]*\n)*(?:Resolves [^\n]*(?:\n|$))?/;
209
+ /** The run marker, then optionally blank lines and the issue line ("Resolves … issue …" or "From issue #N"): the section goes right after. */
210
+ const BODY_HEAD = /^[^\S\n]*<!-- (?:wardby|reevo-run):\S+ -->[^\S\n]*(?:\n|$)(?:[^\S\n]*\n)*(?:(?:Resolves |From issue #\d)[^\n]*(?:\n|$))?/;
190
211
  /**
191
212
  * The body with `block` in place of the existing marked section, or inserted
192
213
  * after the run marker (and the issue line) when there is none. Null — do not
@@ -223,13 +244,16 @@ export const MAX_PR_PACKAGE_LINES = 100;
223
244
  /** A hard ceiling on each list's rendered size, whatever the entries
224
245
  * contain, so the section can never push the body past GitHub's limit. */
225
246
  const MAX_PR_PACKAGE_LIST_CHARS = 16 * 1024;
226
- /** Renders at most MAX_PR_PACKAGE_LINES lines (and at most
227
- * MAX_PR_PACKAGE_LIST_CHARS characters) of `lines`, then a count of the rest. */
228
- function cappedList(lines) {
247
+ /** The accepted-advisories list's ceiling: smaller, so adding it keeps the
248
+ * whole section's worst case well inside the body limit. */
249
+ const MAX_PR_WAIVER_LIST_CHARS = 8 * 1024;
250
+ /** Renders at most MAX_PR_PACKAGE_LINES lines (and at most `maxChars`
251
+ * characters) of `lines`, then a count of the rest. */
252
+ function cappedList(lines, maxChars = MAX_PR_PACKAGE_LIST_CHARS) {
229
253
  const shown = [];
230
254
  let chars = 0;
231
255
  for (const line of lines.slice(0, MAX_PR_PACKAGE_LINES)) {
232
- if (chars + line.length + 1 > MAX_PR_PACKAGE_LIST_CHARS)
256
+ if (chars + line.length + 1 > maxChars)
233
257
  break;
234
258
  shown.push(line);
235
259
  chars += line.length + 1;
@@ -237,6 +261,14 @@ function cappedList(lines) {
237
261
  const more = lines.length - shown.length;
238
262
  return more > 0 ? [...shown, `- …and ${more} more — see get_run for the full list`] : shown;
239
263
  }
264
+ const MAX_DEPENDENCY_CACHE_FOLDERS = 4;
265
+ function dependencyCacheLine(folders) {
266
+ const shown = [...new Set(folders ?? [])]
267
+ .filter((folder) => DEPENDENCY_CACHE_PATH.test(folder))
268
+ .slice(0, MAX_DEPENDENCY_CACHE_FOLDERS)
269
+ .map((folder) => (folder === "." ? "the repo root" : `\`${folder}\``));
270
+ return shown.length > 0 ? `Dependency cache: restored \`node_modules\` for ${shown.join(", ")}.` : undefined;
271
+ }
240
272
  function packagesSection(input) {
241
273
  const packages = [
242
274
  ...new Map((input.packages ?? [])
@@ -252,11 +284,23 @@ function packagesSection(input) {
252
284
  isSafeMarkdownFragment(refusal.reason))
253
285
  .map((refusal) => [`${refusal.ecosystem}\0${refusal.name}\0${refusal.reason}`, refusal])).values(),
254
286
  ];
287
+ const restored = dependencyCacheLine(input.restoredDependencies);
255
288
  if (packages.length === 0 && refusals.length === 0)
256
- return undefined;
289
+ return restored;
290
+ // Only ids safe in a Markdown line; a package whose ids are all unsafe is
291
+ // not listed here (it is still listed as installed).
292
+ const waivers = packages.flatMap((pkg) => {
293
+ // Ids come from OSV (a waiver can match via alias), so keep only the
294
+ // policy id shape and render each in a code span.
295
+ const ids = (pkg.acceptedAdvisories ?? []).filter((id) => ACCEPTED_ADVISORY_ID.test(id));
296
+ return ids.length > 0 ? [`- \`${pkg.name}@${pkg.version}\`: ${ids.map((id) => `\`${id}\``).join(", ")}`] : [];
297
+ });
257
298
  return [
299
+ ...(restored ? [restored, ""] : []),
258
300
  "<details>",
259
- `<summary>Packages installed during this run (${packages.length})</summary>`,
301
+ input.packagesScope === "pull_request"
302
+ ? `<summary>Packages installed by wardby's runs on this pull request (${packages.length})</summary>`
303
+ : `<summary>Packages installed during this run (${packages.length})</summary>`,
260
304
  "",
261
305
  ...cappedList(packages.map((pkg) => `- ${pkg.ecosystem} \`${pkg.name}@${pkg.version}\``)),
262
306
  ...(refusals.length > 0
@@ -266,6 +310,13 @@ function packagesSection(input) {
266
310
  ...cappedList(refusals.map((refusal) => `- ${refusal.ecosystem} \`${refusal.name}\`: ${refusal.reason}`)),
267
311
  ]
268
312
  : []),
313
+ ...(waivers.length > 0
314
+ ? [
315
+ "",
316
+ "**Accepted advisories** (waived by this agent's package policy):",
317
+ ...cappedList(waivers, MAX_PR_WAIVER_LIST_CHARS),
318
+ ]
319
+ : []),
269
320
  "</details>",
270
321
  ].join("\n");
271
322
  }
@@ -282,15 +333,6 @@ const LOCKFILE_NAMES = new Set([
282
333
  export function isLockfilePath(path) {
283
334
  return LOCKFILE_NAMES.has(path.slice(path.lastIndexOf("/") + 1));
284
335
  }
285
- /** What each refusal code means to someone reading the PR, without the registry's internals. */
286
- const REFUSAL_MEANING = {
287
- wardby_package_not_allowed: "not on the allowlist, or only reachable through a refused package",
288
- wardby_version_filtered: "withheld: newer than the release-age limit, or a high-severity advisory",
289
- wardby_graph_incomplete: "its dependencies could not be confirmed (usually transient)",
290
- wardby_lockfile_integrity_mismatch: "the lock file's integrity does not match the registry's",
291
- wardby_upstream_error: "the upstream registry failed (transient)",
292
- wardby_audit_unavailable: "the advisory check was unavailable (transient)",
293
- };
294
336
  /** At most this many refused packages are named in the warning; the full list stays in the details. */
295
337
  const MAX_WARNING_NAMES = 8;
296
338
  /**
@@ -320,7 +362,7 @@ function refusalWarning(input) {
320
362
  const listed = [...names];
321
363
  const shown = listed.slice(0, MAX_WARNING_NAMES).join(", ");
322
364
  const more = listed.length > MAX_WARNING_NAMES ? ` and ${listed.length - MAX_WARNING_NAMES} more` : "";
323
- const meaning = REFUSAL_MEANING[reason];
365
+ const meaning = refusalMeaning(reason);
324
366
  lines.push(`> - ${shown}${more}: \`${reason}\`${meaning ? ` (${meaning})` : ""}`);
325
367
  }
326
368
  const lockfiles = (input.changedLockfiles ?? []).filter(isSafeMarkdownFragment);
@@ -329,8 +371,51 @@ function refusalWarning(input) {
329
371
  }
330
372
  return lines.join("\n");
331
373
  }
374
+ /** The banner when the audit report can't be rendered: fixed text, no record data. */
375
+ const PACKAGE_AUDIT_FALLBACK_BANNER = "> [!CAUTION]\n> **Package audit mode was on for this run.** Wardby's registry may have installed packages outside this agent's allowlist; see `get_run` (`packageAudit`) before merging.";
376
+ /**
377
+ * The package audit block: built only from registry records (names and
378
+ * versions through codeSpan, advisory ids by their policy shape), so neither
379
+ * the model nor a package's metadata can remove or soften it.
380
+ */
381
+ function packageAuditSection(input) {
382
+ if (!input.packageAudit)
383
+ return undefined;
384
+ const summary = summarizePackageAudit(packageAuditRows(input.packageAudit.entries));
385
+ return packageAuditWording(input.packageAudit.mode, summary, { format: "pr" });
386
+ }
387
+ /**
388
+ * The pull request body, within GitHub's MAX_PULL_REQUEST_BODY_CHARS. When it
389
+ * would be longer, the informational Packages section goes first; if that is
390
+ * not enough, the agent's summary is truncated to fit (fitSummary keeps its
391
+ * closing-keyword line). The other sections are bounded and stay whole.
392
+ */
393
+ export function pullRequestBody(input, options = {}) {
394
+ const body = buildPullRequestBody(input, options);
395
+ if (body.length <= MAX_PULL_REQUEST_BODY_CHARS)
396
+ return body;
397
+ const withoutPackages = options.omitPackages ? body : buildPullRequestBody(input, { omitPackages: true });
398
+ if (withoutPackages.length <= MAX_PULL_REQUEST_BODY_CHARS || !input.summary)
399
+ return withoutPackages;
400
+ const room = input.summary.length - (withoutPackages.length - MAX_PULL_REQUEST_BODY_CHARS);
401
+ return buildPullRequestBody({ ...input, summary: fitSummary(input.summary, room) }, { omitPackages: true });
402
+ }
403
+ /**
404
+ * `summary` cut to `max` characters. A last line with a closing keyword
405
+ * (`Resolves #12`) is kept after the cut, so merging still closes the issue.
406
+ */
407
+ function fitSummary(summary, max) {
408
+ const measure = (value) => value.length;
409
+ const lines = summary.trimEnd().split("\n");
410
+ const last = lines[lines.length - 1];
411
+ if (lines.length > 1 && last.length <= 200 && hasClosingKeyword(last)) {
412
+ const kept = truncateText(lines.slice(0, -1).join("\n"), max - last.length - 2, measure);
413
+ return `${kept}\n\n${last}`;
414
+ }
415
+ return truncateText(summary, max, measure);
416
+ }
332
417
  /** The hidden run marker stays first and unconditional: createOrFindDraftPullRequest's idempotent lookup depends on it. */
333
- export function pullRequestBody(input) {
418
+ function buildPullRequestBody(input, options) {
334
419
  const sections = [`${RUN_MARKER_PREFIX}${input.runId} -->`];
335
420
  // Hidden marker stays first; the issue link is the first visible line.
336
421
  const issue = issueLine(input);
@@ -352,6 +437,17 @@ export function pullRequestBody(input) {
352
437
  catch {
353
438
  // omitted, like the packages section
354
439
  }
440
+ try {
441
+ const audit = packageAuditSection(input);
442
+ if (audit)
443
+ sections.push(audit);
444
+ }
445
+ catch {
446
+ // Unlike the packages section, the audit banner fails closed: a report
447
+ // that can't be rendered still says the mode was on.
448
+ if (input.packageAudit)
449
+ sections.push(PACKAGE_AUDIT_FALLBACK_BANNER);
450
+ }
355
451
  if (input.summary)
356
452
  sections.push(input.summary);
357
453
  if (input.tests?.length) {
@@ -360,13 +456,16 @@ export function pullRequestBody(input) {
360
456
  // The packages section is informational: a failure rendering it (e.g. a
361
457
  // malformed report) omits the section and never fails finalization.
362
458
  try {
363
- const packages = packagesSection(input);
459
+ const packages = options.omitPackages ? undefined : packagesSection(input);
364
460
  if (packages)
365
461
  sections.push(packages);
366
462
  }
367
463
  catch {
368
464
  // omitted
369
465
  }
466
+ if (input.latestRunId && SAFE_RUN_ID.test(input.latestRunId)) {
467
+ sections.push(`${LATEST_RUN_MARKER_PREFIX}${input.latestRunId} -->`);
468
+ }
370
469
  return sections.join("\n\n");
371
470
  }
372
471
  /** The hidden marker stays first and unconditional: findStatusComment's lookup depends on it. */
@@ -404,7 +503,9 @@ export class GitHubAppClient {
404
503
  throw new Error("github_app_id_invalid");
405
504
  if (!config.privateKey.trim())
406
505
  throw new Error("github_app_private_key_invalid");
407
- this.apiBaseUrl = normalizeApiBaseUrl(config.apiBaseUrl ?? DEFAULT_API_BASE_URL);
506
+ // WARDBY_TEST_SIMULATORS (test only, refused with production configuration): every call
507
+ // goes to the simulator instead, all or nothing.
508
+ this.apiBaseUrl = testSimulatorBase("github-api") ?? normalizeApiBaseUrl(config.apiBaseUrl ?? DEFAULT_API_BASE_URL);
408
509
  this.apiVersion = config.apiVersion ?? DEFAULT_API_VERSION;
409
510
  if (!/^\d{4}-\d{2}-\d{2}$/.test(this.apiVersion))
410
511
  throw new Error("github_api_version_invalid");
@@ -611,11 +712,14 @@ export class GitHubAppClient {
611
712
  }
612
713
  async completeContinuationCheckRun(input) {
613
714
  const repository = normalizeGitHubRepository(input.repository);
614
- if (!SAFE_RUN_ID.test(input.runId) || !SAFE_COMMIT_SHA.test(input.headSha)) {
715
+ if (!SAFE_RUN_ID.test(input.runId) || (input.headSha !== undefined && !SAFE_COMMIT_SHA.test(input.headSha))) {
615
716
  throw new Error("github_check_run_input_invalid");
616
717
  }
718
+ const ref = input.headSha ?? (input.headRef === undefined ? undefined : normalizeGitRef(input.headRef));
719
+ if (!ref)
720
+ throw new Error("github_check_run_input_invalid");
617
721
  await this.withChecksToken(repository, async (token) => {
618
- const existing = await this.findCheckRun(token, repository, input.headSha, input.runId);
722
+ const existing = await this.findCheckRun(token, repository, ref, input.runId);
619
723
  if (!existing)
620
724
  return;
621
725
  const [owner, name] = repository.split("/");
@@ -653,8 +757,14 @@ export class GitHubAppClient {
653
757
  draft: true,
654
758
  }),
655
759
  }, [201, 422]);
656
- if (response.status === 201)
657
- return this.parsePullRequest(await response.json(), repository);
760
+ if (response.status === 201) {
761
+ const payload = record(await response.json());
762
+ const created = this.parsePullRequest(payload, repository);
763
+ // Hash what GitHub stored, not what was sent.
764
+ return typeof payload.body === "string"
765
+ ? { ...created, descriptionSha256: descriptionSha256(payload.body) }
766
+ : created;
767
+ }
658
768
  const raced = await this.findPullRequest(token, { ...input, repository, baseRef, headRef });
659
769
  if (raced)
660
770
  return raced;
@@ -675,6 +785,270 @@ export class GitHubAppClient {
675
785
  throw new Error("github_pull_request_input_invalid");
676
786
  return this.withRepositoryToken(repository, (token) => this.findPullRequest(token, { runId: input.runId, repository, baseRef, headRef, acceptReadyForReview: true }));
677
787
  }
788
+ /** See GitHubRepositoryAccess.openPullRequestDraft: GitHub's own `draft` flag on the marked open PR. */
789
+ async openPullRequestDraft(input) {
790
+ const repository = normalizeGitHubRepository(input.repository);
791
+ const baseRef = normalizeGitRef(input.baseRef);
792
+ const headRef = normalizeGitRef(input.headRef);
793
+ if (!SAFE_RUN_ID.test(input.runId))
794
+ throw new Error("github_pull_request_input_invalid");
795
+ return this.withRepositoryToken(repository, async (token) => {
796
+ const found = await this.findMarkedPullRequest(token, {
797
+ runId: input.runId,
798
+ repository,
799
+ baseRef,
800
+ headRef,
801
+ acceptReadyForReview: true,
802
+ });
803
+ return found ? found.draft : null;
804
+ });
805
+ }
806
+ /** See GitHubRepositoryAccess.openPullRequestBase: the marked open PR's current base, same repository only. */
807
+ async openPullRequestBase(input) {
808
+ const repository = normalizeGitHubRepository(input.repository);
809
+ const baseRef = normalizeGitRef(input.baseRef);
810
+ const headRef = normalizeGitRef(input.headRef);
811
+ if (!SAFE_RUN_ID.test(input.runId))
812
+ throw new Error("github_pull_request_input_invalid");
813
+ return this.withRepositoryToken(repository, async (token) => {
814
+ const found = await this.findMarkedPullRequest(token, {
815
+ runId: input.runId,
816
+ repository,
817
+ baseRef,
818
+ headRef,
819
+ acceptReadyForReview: true,
820
+ });
821
+ if (!found)
822
+ return null;
823
+ const base = record(found.raw.base);
824
+ const head = record(found.raw.head);
825
+ const sameRepository = (side) => {
826
+ const name = side.repo && typeof side.repo === "object" ? side.repo.full_name : null;
827
+ return typeof name === "string" && name.toLowerCase() === repository.toLowerCase();
828
+ };
829
+ // A fork's branch is never fetched: wardby's own heads live in the PR's repository.
830
+ if (!sameRepository(base) || !sameRepository(head))
831
+ return null;
832
+ if (typeof base.ref !== "string")
833
+ throw new Error("github_api_invalid_response");
834
+ try {
835
+ return { number: found.pr.number, baseRef: normalizeGitRef(base.ref) };
836
+ }
837
+ catch (error) {
838
+ throw new Error("github_api_invalid_response", { cause: error });
839
+ }
840
+ });
841
+ }
842
+ /**
843
+ * A fix round's description update (see GitHubRepositoryAccess). One
844
+ * repository token; every failure becomes `skipped:error`.
845
+ */
846
+ async updatePullRequestDescription(input) {
847
+ try {
848
+ const target = this.descriptionTarget(input);
849
+ return await this.withRepositoryToken(target.repository, async (token) => {
850
+ const state = await this.descriptionState(token, input, target);
851
+ if (!state)
852
+ return { kind: "skipped", reason: "not_open" };
853
+ const { pr, verdict, full, proposed } = state;
854
+ const { repository } = target;
855
+ if (!state.writable) {
856
+ // The comment truncates a body too long for it, so the full one goes in.
857
+ const commentPosted = await this.upsertDescriptionComment(token, repository, pr.number, input, full, state)
858
+ .then(() => true)
859
+ .catch(() => false);
860
+ return { kind: "edited_by_hand", commentPosted };
861
+ }
862
+ if (proposed === undefined)
863
+ return { kind: "skipped", reason: "too_long" };
864
+ const agentTextRunId = verdict.ok ? input.runId : input.baseline.agentTextRunId;
865
+ const outcome = verdict.ok
866
+ ? { kind: "replaced" }
867
+ : { kind: "refreshed", reason: verdict.reason };
868
+ const proposedSha256 = descriptionSha256(proposed);
869
+ if (proposedSha256 === input.baseline.recordedSha256) {
870
+ return { kind: "unchanged", sha256: proposedSha256, agentTextRunId: input.baseline.agentTextRunId };
871
+ }
872
+ const [owner, name] = repository.split("/");
873
+ // Known, accepted race: a person editing between our read and this PATCH is overwritten (GitHub has no If-Match); the store's compare-and-set only covers wardby runs racing each other.
874
+ const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/pulls/${pr.number}`, token, { method: "PATCH", body: JSON.stringify({ body: proposed }) }, [200]);
875
+ const written = record(await response.json()).body;
876
+ if (typeof written !== "string")
877
+ throw new Error("github_api_invalid_response");
878
+ // A proposal left from an earlier round is stale now; a failure here never undoes the write.
879
+ await this.markDescriptionCommentApplied(token, repository, pr.number, input.runId, state).catch(() => undefined);
880
+ return { ...outcome, sha256: descriptionSha256(written), agentTextRunId };
881
+ });
882
+ }
883
+ catch {
884
+ return { kind: "skipped", reason: "error" };
885
+ }
886
+ }
887
+ /** See GitHubRepositoryAccess.proposeDescriptionComment. */
888
+ async proposeDescriptionComment(input) {
889
+ try {
890
+ if (!input.headSha || !/^[0-9a-f]{40}$/.test(input.headSha))
891
+ return false;
892
+ const target = this.descriptionTarget(input);
893
+ return await this.withRepositoryToken(target.repository, async (token) => {
894
+ const state = await this.descriptionState(token, input, target);
895
+ if (!state || state.writable)
896
+ return false;
897
+ await this.upsertDescriptionComment(token, target.repository, state.pr.number, input, state.full, state);
898
+ return true;
899
+ });
900
+ }
901
+ catch {
902
+ return false;
903
+ }
904
+ }
905
+ /** The validated repository and refs; throws unless this is wardby's own pull request branch. */
906
+ descriptionTarget(input) {
907
+ const repository = normalizeGitHubRepository(input.repository);
908
+ const baseRef = normalizeGitRef(input.baseRef);
909
+ const headRef = normalizeGitRef(input.headRef);
910
+ if (!SAFE_RUN_ID.test(input.runId) ||
911
+ !SAFE_RUN_ID.test(input.rootRunId) ||
912
+ !SAFE_RUN_ID.test(input.baseline.agentTextRunId) ||
913
+ (input.headSha !== undefined && !/^[0-9a-f]{40}$/.test(input.headSha)) ||
914
+ // Only wardby's own pull request: its branch is the root run's.
915
+ headRef !== `wardby/run-${input.rootRunId}`) {
916
+ throw new Error("github_pull_request_description_input_invalid");
917
+ }
918
+ return { repository, baseRef, headRef };
919
+ }
920
+ /**
921
+ * The open pull request, the description this run proposes, and whether
922
+ * wardby may write it directly: it is unedited (recorded or rebuilt hash),
923
+ * or a person copied wardby's latest proposal in (taken back). Null when
924
+ * the pull request isn't open. `comments` is set when it was read.
925
+ */
926
+ async descriptionState(token, input, target) {
927
+ const { repository, baseRef, headRef } = target;
928
+ const found = await this.findMarkedPullRequest(token, {
929
+ runId: input.rootRunId,
930
+ repository,
931
+ baseRef,
932
+ headRef,
933
+ acceptReadyForReview: true,
934
+ });
935
+ if (!found)
936
+ return null;
937
+ const { pr, body: currentBody } = found;
938
+ const verdict = assessFinalMessage(input.summary, input.baseline.previousAgentText);
939
+ const summary = verdict.ok ? input.summary : input.baseline.previousAgentText;
940
+ const { full, proposed } = this.proposedDescription(input, repository, baseRef, headRef, summary, currentBody);
941
+ const unedited = isUneditedDescription({
942
+ currentBody,
943
+ rootRunId: input.rootRunId,
944
+ recordedSha256: input.baseline.recordedSha256,
945
+ ...(input.baseline.legacySha256 ? { legacySha256: input.baseline.legacySha256 } : {}),
946
+ previousAgentText: input.baseline.previousAgentText,
947
+ });
948
+ if (unedited)
949
+ return { pr, currentBody, verdict, full, proposed, writable: true };
950
+ const comments = await this.findDescriptionComments(token, repository, pr.number);
951
+ const latest = comments.newest?.parsed.proposed;
952
+ // The author copied wardby's latest proposal in: the description is wardby's again.
953
+ const takenBack = latest !== undefined &&
954
+ isUneditedDescription({
955
+ currentBody,
956
+ rootRunId: input.rootRunId,
957
+ recordedSha256: descriptionSha256(latest),
958
+ });
959
+ return { pr, currentBody, verdict, full, proposed, writable: takenBack, comments };
960
+ }
961
+ /**
962
+ * The rebuilt description: the generated sections from this run with
963
+ * `summary` as the agent text, the latest-run marker last, and the current
964
+ * body's Related block re-inserted verbatim. `proposed` drops the Packages
965
+ * section when `full` exceeds GitHub's limit, and is undefined when it still
966
+ * would.
967
+ */
968
+ proposedDescription(input, repository, baseRef, headRef, summary, currentBody) {
969
+ const related = extractRelatedBlock(currentBody.replace(/\r\n/g, "\n"));
970
+ const build = (omitPackages) => {
971
+ const body = pullRequestBody({
972
+ repository,
973
+ baseRef,
974
+ headRef,
975
+ runId: input.rootRunId,
976
+ latestRunId: input.runId,
977
+ summary,
978
+ tests: input.tests,
979
+ tag: input.tag,
980
+ packages: input.packages,
981
+ packagesScope: "pull_request",
982
+ packageRefusals: input.packageRefusals,
983
+ packageAudit: input.packageAudit,
984
+ restoredDependencies: input.restoredDependencies,
985
+ changedLockfiles: input.changedLockfiles,
986
+ issue: input.issue,
987
+ issueNumber: input.issueNumber,
988
+ }, { omitPackages });
989
+ return related ? (upsertRelatedSection(body, related) ?? body) : body;
990
+ };
991
+ const full = build(false);
992
+ if (full.length <= MAX_PULL_REQUEST_BODY_CHARS)
993
+ return { full, proposed: full };
994
+ const trimmed = build(true);
995
+ return { full, proposed: trimmed.length <= MAX_PULL_REQUEST_BODY_CHARS ? trimmed : undefined };
996
+ }
997
+ /**
998
+ * Creates the pull request's one description comment, or edits the newest
999
+ * one this App wrote (unchanged text is not re-sent); older duplicates are
1000
+ * rewritten to point at it. A comment anyone else wrote is never edited.
1001
+ */
1002
+ async upsertDescriptionComment(token, repository, pullRequestNumber, input, proposedBody, state) {
1003
+ const body = descriptionFallbackComment(input.runId, proposedBody, input.headSha);
1004
+ const { newest, older } = state.comments ?? (await this.findDescriptionComments(token, repository, pullRequestNumber));
1005
+ const [owner, name] = repository.split("/");
1006
+ const commentPath = (id) => `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues/comments/${id}`;
1007
+ let url = newest?.url;
1008
+ if (newest) {
1009
+ if (newest.body.replace(/\r\n/g, "\n") !== body) {
1010
+ await this.requestJson(commentPath(newest.id), token, { method: "PATCH", body: JSON.stringify({ body }) }, [200]);
1011
+ }
1012
+ }
1013
+ else {
1014
+ const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues/${pullRequestNumber}/comments`, token, { method: "POST", body: JSON.stringify({ body }) }, [201]);
1015
+ const created = record(await response.json()).html_url;
1016
+ url = typeof created === "string" ? created : undefined;
1017
+ }
1018
+ await this.supersedeDescriptionComments(token, commentPath, older, url);
1019
+ }
1020
+ /** Once a run applied its description, a pending proposal in the description comment is marked applied. */
1021
+ async markDescriptionCommentApplied(token, repository, pullRequestNumber, runId, state) {
1022
+ const { newest, older } = state.comments ?? (await this.findDescriptionComments(token, repository, pullRequestNumber));
1023
+ if (!newest)
1024
+ return;
1025
+ const [owner, name] = repository.split("/");
1026
+ const commentPath = (id) => `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues/comments/${id}`;
1027
+ if (!newest.parsed.applied) {
1028
+ await this.requestJson(commentPath(newest.id), token, { method: "PATCH", body: JSON.stringify({ body: descriptionAppliedComment(runId) }) }, [200]);
1029
+ }
1030
+ await this.supersedeDescriptionComments(token, commentPath, older, newest.url);
1031
+ }
1032
+ /** Rewrites duplicate description comments to a pointer at the one in use. */
1033
+ async supersedeDescriptionComments(token, commentPath, older, url) {
1034
+ for (const duplicate of older) {
1035
+ await this.requestJson(commentPath(duplicate.id), token, { method: "PATCH", body: JSON.stringify({ body: supersededDescriptionComment(url) }) }, [200]);
1036
+ }
1037
+ }
1038
+ /** The description comments this App wrote (see findDescriptionComments; the reviewer reads them the same way). */
1039
+ async findDescriptionComments(token, repository, pullRequestNumber) {
1040
+ const { id: appId } = await this.appIdentity();
1041
+ const [owner, name] = repository.split("/");
1042
+ return findDescriptionComments(async (page) => {
1043
+ const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues/${pullRequestNumber}/comments?per_page=100&page=${page}`, token);
1044
+ const payload = await response.json();
1045
+ if (!Array.isArray(payload))
1046
+ throw new Error("github_api_invalid_response");
1047
+ return payload;
1048
+ },
1049
+ // Only this App's own comments: never a person's, nor another App's or bot's.
1050
+ (comment) => isThisAppsComment(comment, appId));
1051
+ }
678
1052
  async appJwt() {
679
1053
  let keyObject;
680
1054
  try {
@@ -726,7 +1100,7 @@ export class GitHubAppClient {
726
1100
  const expiresAt = typeof payload.expires_at === "string" ? Date.parse(payload.expires_at) : Number.NaN;
727
1101
  const unexpectedPermission = Object.entries(grantedPermissions).some(([permissionName, level]) => !isAllowedPermission(permissionName, level));
728
1102
  const requestedGranted = Object.entries(permissions).every(([permissionName, level]) => grantedPermissions[permissionName] === level);
729
- if (!isSafeGitHubInstallationToken(payload.token) ||
1103
+ if (!isSafeGitAuthToken(payload.token) ||
730
1104
  !Number.isFinite(expiresAt) ||
731
1105
  expiresAt <= this.now().getTime() + 60_000 ||
732
1106
  !requestedGranted ||
@@ -740,11 +1114,19 @@ export class GitHubAppClient {
740
1114
  await this.requestJson("/installation/token", token, { method: "DELETE" }, [204]);
741
1115
  }
742
1116
  async findPullRequest(token, input) {
1117
+ return (await this.findMarkedPullRequest(token, input))?.pr ?? null;
1118
+ }
1119
+ /**
1120
+ * findPullRequest, plus the matched pull request's raw body and payload. Not
1121
+ * filtered by base: a person may retarget the PR, and the head branch plus the
1122
+ * run marker already identify it. When several open PRs match, the one on
1123
+ * `baseRef` wins.
1124
+ */
1125
+ async findMarkedPullRequest(token, input) {
743
1126
  const [owner, name] = input.repository.split("/");
744
1127
  const query = new URLSearchParams({
745
1128
  state: "open",
746
1129
  head: `${owner}:${input.headRef}`,
747
- base: input.baseRef,
748
1130
  per_page: "100",
749
1131
  });
750
1132
  const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/pulls?${query.toString()}`, token);
@@ -752,13 +1134,26 @@ export class GitHubAppClient {
752
1134
  if (!Array.isArray(payload))
753
1135
  throw new Error("github_api_invalid_response");
754
1136
  const marker = `${RUN_MARKER_PREFIX}${input.runId} -->`;
1137
+ let first;
755
1138
  for (const item of payload) {
756
1139
  const candidate = record(item);
757
- if (typeof candidate.body === "string" && candidate.body.includes(marker)) {
758
- return this.parsePullRequest(candidate, input.repository, input.acceptReadyForReview === true);
1140
+ if (typeof candidate.body !== "string" || !candidate.body.includes(marker))
1141
+ continue;
1142
+ const base = candidate.base && typeof candidate.base === "object" ? candidate.base : {};
1143
+ if (base.ref === input.baseRef) {
1144
+ first = candidate;
1145
+ break;
759
1146
  }
1147
+ first ??= candidate;
760
1148
  }
761
- return null;
1149
+ if (!first)
1150
+ return null;
1151
+ return {
1152
+ pr: this.parsePullRequest(first, input.repository, input.acceptReadyForReview === true),
1153
+ body: first.body,
1154
+ draft: first.draft === true,
1155
+ raw: first,
1156
+ };
762
1157
  }
763
1158
  parsePullRequest(value, repository, acceptReadyForReview = false) {
764
1159
  const payload = record(value);
@@ -788,23 +1183,27 @@ export class GitHubAppClient {
788
1183
  return { number, url: expectedUrl };
789
1184
  }
790
1185
  async findStatusComment(token, repository, pullRequestNumber, runId) {
1186
+ const marker = `${STATUS_COMMENT_MARKER_PREFIX}${runId} -->`;
1187
+ return this.findMarkedComment(token, repository, pullRequestNumber, (body) => body.includes(marker));
1188
+ }
1189
+ /** The first comment on the pull request (first page) whose body `matches`. */
1190
+ async findMarkedComment(token, repository, pullRequestNumber, matches) {
791
1191
  const [owner, name] = repository.split("/");
792
1192
  const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues/${pullRequestNumber}/comments?per_page=100`, token);
793
1193
  const payload = await response.json();
794
1194
  if (!Array.isArray(payload))
795
1195
  throw new Error("github_api_invalid_response");
796
- const marker = `${STATUS_COMMENT_MARKER_PREFIX}${runId} -->`;
797
1196
  for (const item of payload) {
798
1197
  const candidate = record(item);
799
- if (typeof candidate.body === "string" && candidate.body.includes(marker)) {
800
- return { id: positiveInteger(candidate.id) };
801
- }
1198
+ if (typeof candidate.body !== "string" || !matches(candidate.body))
1199
+ continue;
1200
+ return { id: positiveInteger(candidate.id), body: candidate.body };
802
1201
  }
803
1202
  return null;
804
1203
  }
805
- async findCheckRun(token, repository, headSha, runId) {
1204
+ async findCheckRun(token, repository, ref, runId) {
806
1205
  const [owner, name] = repository.split("/");
807
- const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/commits/${headSha}/check-runs?per_page=100`, token);
1206
+ const response = await this.requestJson(`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/commits/${encodeURIComponent(ref)}/check-runs?per_page=100`, token);
808
1207
  const payload = record(await response.json());
809
1208
  const checkRuns = Array.isArray(payload.check_runs) ? payload.check_runs.map(record) : [];
810
1209
  for (const candidate of checkRuns) {