@wardby/cli 0.6.0 → 0.7.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 (576) hide show
  1. package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
  2. package/dist/claude-coding-worker/driver.d.ts +21 -3
  3. package/dist/claude-coding-worker/driver.js +125 -17
  4. package/dist/claude-coding-worker/main.js +34 -6
  5. package/dist/claude-coding-worker/sdk.js +12 -1
  6. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  7. package/dist/claude-coding-worker/tool-socket.js +111 -0
  8. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  9. package/dist/claude-coding-worker/transcript.js +77 -0
  10. package/dist/cli-help.d.ts +1 -1
  11. package/dist/cli-help.js +1 -0
  12. package/dist/cli.js +24 -10
  13. package/dist/coding/continuation-wording.d.ts +35 -0
  14. package/dist/coding/continuation-wording.js +73 -0
  15. package/dist/coding/linked-issue-note.d.ts +23 -0
  16. package/dist/coding/linked-issue-note.js +47 -0
  17. package/dist/coding/merge-wording.d.ts +28 -0
  18. package/dist/coding/merge-wording.js +78 -0
  19. package/dist/coding/pr-description-note.d.ts +9 -0
  20. package/dist/coding/pr-description-note.js +32 -0
  21. package/dist/coding/profile.d.ts +46 -126
  22. package/dist/coding/profile.js +45 -4
  23. package/dist/coding/protected-path-wording.d.ts +8 -0
  24. package/dist/coding/protected-path-wording.js +1 -1
  25. package/dist/coding/protocol.d.ts +264 -346
  26. package/dist/coding/protocol.js +235 -12
  27. package/dist/coding/redact.d.ts +3 -0
  28. package/dist/coding/redact.js +12 -0
  29. package/dist/coding/registry/allowlist.d.ts +12 -0
  30. package/dist/coding/registry/allowlist.js +14 -1
  31. package/dist/coding/registry/audit-mode.d.ts +153 -0
  32. package/dist/coding/registry/audit-mode.js +304 -0
  33. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  34. package/dist/coding/registry/lockfile-shared.js +128 -0
  35. package/dist/coding/registry/lockfiles.js +1 -1
  36. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  37. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  38. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  39. package/dist/coding/registry/npm-lockfile.js +4 -6
  40. package/dist/coding/registry/npm.js +78 -8
  41. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  42. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  43. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  44. package/dist/coding/registry/pypi-plan.js +406 -0
  45. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  46. package/dist/coding/registry/pypi-requirements.js +155 -0
  47. package/dist/coding/registry/pypi.d.ts +3 -27
  48. package/dist/coding/registry/pypi.js +40 -154
  49. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  50. package/dist/coding/registry/refusal-hints.js +61 -0
  51. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  52. package/dist/coding/registry/refusal-wording.js +56 -0
  53. package/dist/coding/registry/report.d.ts +70 -8
  54. package/dist/coding/registry/report.js +112 -5
  55. package/dist/coding/registry/types.d.ts +58 -8
  56. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  57. package/dist/coding/registry/yarn-lockfile.js +367 -0
  58. package/dist/coding/services/catalog.d.ts +37 -351
  59. package/dist/coding/transcript/claude-code.d.ts +13 -0
  60. package/dist/coding/transcript/claude-code.js +273 -0
  61. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  62. package/dist/coding/transcript/download-protocol.js +18 -0
  63. package/dist/coding/transcript/format.d.ts +20 -0
  64. package/dist/coding/transcript/format.js +32 -0
  65. package/dist/coding/transcript/recorder.d.ts +51 -0
  66. package/dist/coding/transcript/recorder.js +225 -0
  67. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  68. package/dist/coding/transcript/resume/checkout.js +203 -0
  69. package/dist/coding/transcript/resume/command.d.ts +17 -0
  70. package/dist/coding/transcript/resume/command.js +176 -0
  71. package/dist/coding/transcript/resume/download.d.ts +20 -0
  72. package/dist/coding/transcript/resume/download.js +153 -0
  73. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  74. package/dist/coding/transcript/resume/launch.js +128 -0
  75. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  76. package/dist/coding/transcript/resume/session-file.js +79 -0
  77. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  78. package/dist/coding/transcript/resume/stand-in.js +49 -0
  79. package/dist/coding-worker/artifact.d.ts +8 -3
  80. package/dist/coding-worker/artifact.js +3 -1
  81. package/dist/coding-worker/debug-trace.d.ts +6 -5
  82. package/dist/coding-worker/debug-trace.js +13 -18
  83. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  84. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  85. package/dist/coding-worker/driver.d.ts +4 -3
  86. package/dist/coding-worker/driver.js +116 -38
  87. package/dist/coding-worker/errors.d.ts +1 -0
  88. package/dist/coding-worker/errors.js +32 -0
  89. package/dist/coding-worker/task-note.d.ts +11 -0
  90. package/dist/coding-worker/task-note.js +13 -0
  91. package/dist/coding-worker/types.d.ts +11 -0
  92. package/dist/config/dependency-cache.d.ts +23 -0
  93. package/dist/config/dependency-cache.js +32 -0
  94. package/dist/config/providers.d.ts +12 -3
  95. package/dist/config/providers.js +55 -5
  96. package/dist/config/test-simulators.d.ts +82 -0
  97. package/dist/config/test-simulators.js +305 -0
  98. package/dist/core/async-context.d.ts +2 -0
  99. package/dist/core/async-context.js +12 -0
  100. package/dist/core/budget-events.d.ts +108 -0
  101. package/dist/core/budget-events.js +346 -0
  102. package/dist/core/budget-groups.d.ts +50 -1
  103. package/dist/core/budget-groups.js +236 -27
  104. package/dist/core/budget-stopped-head.d.ts +46 -0
  105. package/dist/core/budget-stopped-head.js +81 -0
  106. package/dist/core/budget-topup.d.ts +51 -0
  107. package/dist/core/budget-topup.js +156 -0
  108. package/dist/core/budget-wording.d.ts +16 -2
  109. package/dist/core/budget-wording.js +40 -2
  110. package/dist/core/coding-queue.d.ts +2 -1
  111. package/dist/core/coding-queue.js +7 -0
  112. package/dist/core/cron.d.ts +19 -1
  113. package/dist/core/cron.js +17 -0
  114. package/dist/core/datastores.js +1 -1
  115. package/dist/core/deferred-coding.d.ts +14 -0
  116. package/dist/core/deferred-coding.js +62 -0
  117. package/dist/core/delegation-child.d.ts +25 -0
  118. package/dist/core/delegation-child.js +37 -0
  119. package/dist/core/dispatch.d.ts +42 -0
  120. package/dist/core/dispatch.js +131 -56
  121. package/dist/core/engine-native.js +1 -1
  122. package/dist/core/error-code.d.ts +38 -0
  123. package/dist/core/error-code.js +168 -0
  124. package/dist/core/grants.d.ts +19 -6
  125. package/dist/core/grants.js +55 -6
  126. package/dist/core/host-events.d.ts +18 -2
  127. package/dist/core/host-events.js +284 -24
  128. package/dist/core/host-status.d.ts +85 -3
  129. package/dist/core/host-status.js +298 -20
  130. package/dist/core/issue-bridge.d.ts +50 -6
  131. package/dist/core/issue-bridge.js +124 -33
  132. package/dist/core/issue-events.d.ts +1 -1
  133. package/dist/core/issue-events.js +4 -10
  134. package/dist/core/issue-status.d.ts +1 -1
  135. package/dist/core/issue-status.js +54 -26
  136. package/dist/core/logger.d.ts +5 -0
  137. package/dist/core/logger.js +14 -1
  138. package/dist/core/lost-run-children.d.ts +6 -0
  139. package/dist/core/lost-run-children.js +32 -0
  140. package/dist/core/mark-ready.d.ts +34 -0
  141. package/dist/core/mark-ready.js +152 -0
  142. package/dist/core/markdown-code.d.ts +8 -0
  143. package/dist/core/markdown-code.js +107 -0
  144. package/dist/core/memory-tools.js +7 -0
  145. package/dist/core/merge-order-check.d.ts +2 -1
  146. package/dist/core/merge-order-check.js +8 -1
  147. package/dist/core/notification-templates.d.ts +1 -7
  148. package/dist/core/notification-templates.js +36 -2
  149. package/dist/core/pull-request-state-sync.js +2 -2
  150. package/dist/core/reconciler.d.ts +4 -3
  151. package/dist/core/reconciler.js +8 -1
  152. package/dist/core/related-pull-requests.d.ts +11 -3
  153. package/dist/core/related-pull-requests.js +27 -14
  154. package/dist/core/reply-parts.d.ts +21 -0
  155. package/dist/core/reply-parts.js +73 -0
  156. package/dist/core/review-fix.d.ts +1 -1
  157. package/dist/core/review-fix.js +2 -1
  158. package/dist/core/review-host-checks.d.ts +1 -1
  159. package/dist/core/review-host-tools.d.ts +3 -0
  160. package/dist/core/review-host-tools.js +99 -13
  161. package/dist/core/review-reads.d.ts +55 -0
  162. package/dist/core/review-reads.js +233 -0
  163. package/dist/core/run-status.d.ts +12 -0
  164. package/dist/core/run-status.js +12 -0
  165. package/dist/core/runner.d.ts +80 -34
  166. package/dist/core/runner.js +439 -144
  167. package/dist/core/schedule-start.d.ts +12 -0
  168. package/dist/core/schedule-start.js +14 -0
  169. package/dist/core/secret-broker-config.d.ts +10 -74
  170. package/dist/core/secret-guard.d.ts +46 -0
  171. package/dist/core/secret-guard.js +104 -0
  172. package/dist/core/secret-guarded-stores.d.ts +12 -0
  173. package/dist/core/secret-guarded-stores.js +41 -0
  174. package/dist/core/secret-spans.d.ts +50 -0
  175. package/dist/core/secret-spans.js +94 -0
  176. package/dist/core/stop-run.d.ts +46 -0
  177. package/dist/core/stop-run.js +61 -0
  178. package/dist/core/workflow-events.d.ts +14 -2
  179. package/dist/core/workflow-events.js +4 -0
  180. package/dist/core/workflow-run-events.d.ts +5 -3
  181. package/dist/core/workflow-run-events.js +43 -8
  182. package/dist/core/zod-json-schema.d.ts +4 -0
  183. package/dist/core/zod-json-schema.js +39 -0
  184. package/dist/core/zod3-window.d.ts +35 -0
  185. package/dist/core/zod3-window.js +124 -0
  186. package/dist/generated/prisma/browser.d.ts +34 -3
  187. package/dist/generated/prisma/client.d.ts +34 -3
  188. package/dist/generated/prisma/commonInputTypes.d.ts +220 -60
  189. package/dist/generated/prisma/enums.d.ts +10 -0
  190. package/dist/generated/prisma/enums.js +8 -0
  191. package/dist/generated/prisma/internal/class.d.ts +44 -0
  192. package/dist/generated/prisma/internal/class.js +4 -4
  193. package/dist/generated/prisma/internal/prismaNamespace.d.ts +428 -9
  194. package/dist/generated/prisma/internal/prismaNamespace.js +92 -1
  195. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +95 -0
  196. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +92 -1
  197. package/dist/generated/prisma/models/Agent.d.ts +106 -8
  198. package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
  199. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +229 -1
  200. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  201. package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
  202. package/dist/generated/prisma/models/CodingRun.d.ts +1637 -1
  203. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  204. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  205. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  206. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  207. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
  208. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
  209. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  210. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  211. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  212. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  213. package/dist/generated/prisma/models/Run.d.ts +738 -2
  214. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  215. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  216. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  217. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  218. package/dist/generated/prisma/models.d.ts +4 -0
  219. package/dist/help-index.json +1320 -69
  220. package/dist/import/create.js +32 -3
  221. package/dist/import/neutral-schema.d.ts +50 -281
  222. package/dist/import/neutral-schema.js +5 -4
  223. package/dist/knowledge/check.d.ts +1 -1
  224. package/dist/knowledge/cli.d.ts +11 -1
  225. package/dist/knowledge/cli.js +37 -4
  226. package/dist/knowledge/concept.d.ts +3 -19
  227. package/dist/knowledge/location.d.ts +31 -0
  228. package/dist/knowledge/location.js +78 -0
  229. package/dist/mcp/auth/access.d.ts +10 -2
  230. package/dist/mcp/auth/access.js +15 -1
  231. package/dist/mcp/auth/ownership.d.ts +7 -7
  232. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  233. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  234. package/dist/mcp/host-events/github-ingress.d.ts +2 -0
  235. package/dist/mcp/host-events/github-ingress.js +2 -1
  236. package/dist/mcp/index.d.ts +6 -0
  237. package/dist/mcp/index.js +58 -10
  238. package/dist/mcp/server.d.ts +13 -0
  239. package/dist/mcp/server.js +33 -14
  240. package/dist/mcp/tools/agents.d.ts +4 -0
  241. package/dist/mcp/tools/agents.js +198 -16
  242. package/dist/mcp/tools/datastore.js +17 -8
  243. package/dist/mcp/tools/grants.js +9 -3
  244. package/dist/mcp/tools/memory.js +11 -1
  245. package/dist/mcp/tools/notification-channels.js +2 -2
  246. package/dist/mcp/tools/packages.d.ts +2 -0
  247. package/dist/mcp/tools/packages.js +195 -0
  248. package/dist/mcp/tools/repositories.js +18 -5
  249. package/dist/mcp/tools/run-access.d.ts +16 -0
  250. package/dist/mcp/tools/run-access.js +25 -0
  251. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  252. package/dist/mcp/tools/run-transcript-download.js +129 -0
  253. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  254. package/dist/mcp/tools/run-transcript.js +70 -0
  255. package/dist/mcp/tools/runs.js +34 -12
  256. package/dist/mcp/tools/scheduling.js +3 -1
  257. package/dist/mcp/tools/secret-elicitation-form.js +5 -0
  258. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  259. package/dist/mcp/tools/secret-elicitation-server.js +10 -61
  260. package/dist/mcp/tools/secrets.js +2 -2
  261. package/dist/mcp/tools/stop-run.d.ts +2 -0
  262. package/dist/mcp/tools/stop-run.js +82 -0
  263. package/dist/mcp/tools/subagents.js +2 -2
  264. package/dist/mcp/tools/tools.d.ts +1 -1
  265. package/dist/mcp/tools/tools.js +25 -9
  266. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  267. package/dist/mcp/transport/stdio-link-host.js +67 -0
  268. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  269. package/dist/mcp/transport/streamable-http.js +41 -1
  270. package/dist/native-worker/docker-launcher.d.ts +38 -2
  271. package/dist/native-worker/docker-launcher.js +65 -5
  272. package/dist/native-worker/gateway-server.d.ts +41 -3
  273. package/dist/native-worker/gateway-server.js +124 -27
  274. package/dist/native-worker/gateway.d.ts +27 -1
  275. package/dist/native-worker/gateway.js +70 -4
  276. package/dist/native-worker/http-server.d.ts +3 -1
  277. package/dist/native-worker/http-server.js +11 -7
  278. package/dist/native-worker/http-transport.js +1 -1
  279. package/dist/native-worker/kubernetes-launcher.d.ts +7 -3
  280. package/dist/native-worker/kubernetes-launcher.js +43 -3
  281. package/dist/native-worker/launch.d.ts +18 -1
  282. package/dist/native-worker/launch.js +6 -1
  283. package/dist/native-worker/ledger.d.ts +18 -2
  284. package/dist/native-worker/ledger.js +57 -4
  285. package/dist/native-worker/loopback.js +3 -8
  286. package/dist/native-worker/main.d.ts +2 -1
  287. package/dist/native-worker/main.js +14 -3
  288. package/dist/native-worker/protocol.d.ts +129 -577
  289. package/dist/native-worker/protocol.js +47 -1
  290. package/dist/native-worker/sandbox-executor.d.ts +17 -2
  291. package/dist/native-worker/sandbox-executor.js +78 -4
  292. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  293. package/dist/native-worker/stderr-redaction.js +237 -0
  294. package/dist/native-worker/stdio.d.ts +1 -1
  295. package/dist/native-worker/stdio.js +6 -5
  296. package/dist/native-worker/warm-pool.d.ts +2 -2
  297. package/dist/native-worker/warm-pool.js +4 -4
  298. package/dist/native-worker/worker.js +28 -2
  299. package/dist/observability/metrics.js +6 -1
  300. package/dist/providers/auth/self-hosted.d.ts +1 -1
  301. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  302. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  303. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  304. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  305. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  306. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  307. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  308. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  309. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  310. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  311. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  312. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  313. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  314. package/dist/providers/coding-proxy/hold.js +86 -0
  315. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  316. package/dist/providers/coding-proxy/interrupted.js +104 -0
  317. package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
  318. package/dist/providers/coding-proxy/memory-ledger.js +84 -8
  319. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  320. package/dist/providers/coding-proxy/metering.js +27 -4
  321. package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
  322. package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
  323. package/dist/providers/coding-proxy/proxy.d.ts +14 -1
  324. package/dist/providers/coding-proxy/proxy.js +166 -14
  325. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  326. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  327. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  328. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  329. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  330. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  331. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  332. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  333. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  334. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  335. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  336. package/dist/providers/coding-proxy/registry/service.js +579 -112
  337. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  338. package/dist/providers/coding-proxy/registry/store.js +54 -1
  339. package/dist/providers/coding-proxy/runtime.d.ts +4 -0
  340. package/dist/providers/coding-proxy/runtime.js +78 -16
  341. package/dist/providers/coding-proxy/server.d.ts +6 -1
  342. package/dist/providers/coding-proxy/server.js +45 -1
  343. package/dist/providers/coding-proxy/types.d.ts +65 -1
  344. package/dist/providers/datastore/types.d.ts +5 -0
  345. package/dist/providers/engine/types.d.ts +17 -2
  346. package/dist/providers/engine/types.js +17 -0
  347. package/dist/providers/executor/composition.d.ts +10 -3
  348. package/dist/providers/executor/composition.js +47 -7
  349. package/dist/providers/executor/container.d.ts +361 -8
  350. package/dist/providers/executor/container.js +1136 -91
  351. package/dist/providers/executor/dbos-status.d.ts +31 -0
  352. package/dist/providers/executor/dbos-status.js +64 -0
  353. package/dist/providers/executor/dbos.d.ts +50 -1
  354. package/dist/providers/executor/dbos.js +207 -20
  355. package/dist/providers/executor/deferred.d.ts +12 -24
  356. package/dist/providers/executor/deferred.js +10 -29
  357. package/dist/providers/executor/in-process.d.ts +9 -1
  358. package/dist/providers/executor/in-process.js +14 -4
  359. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  360. package/dist/providers/executor/linked-issue-reader.js +30 -0
  361. package/dist/providers/executor/routing.d.ts +2 -0
  362. package/dist/providers/executor/routing.js +4 -0
  363. package/dist/providers/executor/types.d.ts +13 -0
  364. package/dist/providers/index.d.ts +2 -1
  365. package/dist/providers/issue-tracker/types.d.ts +17 -0
  366. package/dist/providers/issue-tracker/types.js +39 -1
  367. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  368. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  369. package/dist/providers/jobs/docker-isolation.d.ts +8 -0
  370. package/dist/providers/jobs/docker-isolation.js +17 -0
  371. package/dist/providers/jobs/docker.d.ts +1 -0
  372. package/dist/providers/jobs/docker.js +27 -2
  373. package/dist/providers/jobs/fake-kubernetes-api.d.ts +2 -0
  374. package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
  375. package/dist/providers/jobs/kubernetes-api.d.ts +8 -0
  376. package/dist/providers/jobs/kubernetes-api.js +10 -0
  377. package/dist/providers/jobs/kubernetes-client.js +10 -1
  378. package/dist/providers/jobs/kubernetes-isolation.d.ts +2 -0
  379. package/dist/providers/jobs/kubernetes-isolation.js +17 -1
  380. package/dist/providers/jobs/kubernetes.d.ts +6 -1
  381. package/dist/providers/jobs/kubernetes.js +105 -16
  382. package/dist/providers/jobs/types.d.ts +33 -0
  383. package/dist/providers/jobs/types.js +13 -1
  384. package/dist/providers/llm/anthropic.js +5 -1
  385. package/dist/providers/llm/bedrock.d.ts +0 -12
  386. package/dist/providers/llm/bedrock.js +4 -0
  387. package/dist/providers/llm/claude-messages.d.ts +3 -1
  388. package/dist/providers/llm/claude-messages.js +4 -1
  389. package/dist/providers/llm/claude-provider.d.ts +2 -2
  390. package/dist/providers/llm/claude-provider.js +2 -2
  391. package/dist/providers/llm/openai.d.ts +2 -2
  392. package/dist/providers/llm/openai.js +6 -2
  393. package/dist/providers/llm/routing.d.ts +2 -2
  394. package/dist/providers/llm/routing.js +2 -2
  395. package/dist/providers/llm/types.d.ts +12 -2
  396. package/dist/providers/review-host/github-events.d.ts +9 -1
  397. package/dist/providers/review-host/github-events.js +34 -12
  398. package/dist/providers/review-host/github.d.ts +29 -2
  399. package/dist/providers/review-host/github.js +224 -29
  400. package/dist/providers/review-host/local.d.ts +8 -4
  401. package/dist/providers/review-host/local.js +49 -31
  402. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  403. package/dist/providers/review-host/patch-pages.js +176 -0
  404. package/dist/providers/review-host/review-format.d.ts +19 -1
  405. package/dist/providers/review-host/review-format.js +38 -7
  406. package/dist/providers/review-host/types.d.ts +134 -2
  407. package/dist/providers/review-host/types.js +8 -0
  408. package/dist/providers/storage/gcs.d.ts +63 -0
  409. package/dist/providers/storage/gcs.js +69 -0
  410. package/dist/providers/storage/index.d.ts +15 -0
  411. package/dist/providers/storage/index.js +14 -0
  412. package/dist/providers/storage/local.d.ts +24 -0
  413. package/dist/providers/storage/local.js +92 -0
  414. package/dist/providers/storage/meter.d.ts +14 -0
  415. package/dist/providers/storage/meter.js +34 -0
  416. package/dist/providers/storage/s3.d.ts +41 -0
  417. package/dist/providers/storage/s3.js +107 -0
  418. package/dist/providers/storage/types.d.ts +37 -3
  419. package/dist/providers/storage/types.js +21 -4
  420. package/dist/providers/vcs/git.d.ts +33 -2
  421. package/dist/providers/vcs/git.js +324 -22
  422. package/dist/providers/vcs/github-remote.d.ts +26 -3
  423. package/dist/providers/vcs/github-remote.js +124 -14
  424. package/dist/providers/vcs/github.d.ts +214 -6
  425. package/dist/providers/vcs/github.js +447 -45
  426. package/dist/providers/vcs/index.js +8 -1
  427. package/dist/providers/vcs/pr-description.d.ts +127 -0
  428. package/dist/providers/vcs/pr-description.js +270 -0
  429. package/dist/providers/vcs/remote.d.ts +33 -1
  430. package/dist/providers/vcs/routing.d.ts +4 -2
  431. package/dist/providers/vcs/routing.js +6 -0
  432. package/dist/providers/vcs/types.d.ts +80 -3
  433. package/dist/quickstart/coding-seed.d.ts +14 -3
  434. package/dist/quickstart/coding-seed.js +213 -4
  435. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  436. package/dist/quickstart/reviewer-prompt.js +6 -6
  437. package/dist/quickstart-images.json +1 -1
  438. package/dist/sandbox/generated/zod.bundle.js +62 -1
  439. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  440. package/dist/sandbox/host-functions.d.ts +1 -0
  441. package/dist/sandbox/host-functions.js +6 -11
  442. package/dist/sandbox/secret-broker.js +3 -4
  443. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  444. package/dist/sandbox/zod-params.d.ts +37 -5
  445. package/dist/sandbox/zod-params.js +181 -26
  446. package/dist/serve.js +8 -1
  447. package/dist/viewer/api-schema.d.ts +349 -2627
  448. package/dist/viewer/api-schema.js +7 -0
  449. package/dist/viewer/build-schemas.js +6 -2
  450. package/dist/viewer/openapi.js +2 -4
  451. package/dist/wardby-bin.js +10 -0
  452. package/docs/agent-recipes.md +58 -20
  453. package/docs/code-review-agents.md +551 -41
  454. package/docs/coding-agent-setup.md +489 -7
  455. package/docs/coding-packages.md +1033 -90
  456. package/docs/coding-services.md +27 -12
  457. package/docs/coding-worker-byo-images.md +20 -0
  458. package/docs/coding-worker-isolation.md +105 -30
  459. package/docs/getting-started-gke.md +124 -137
  460. package/docs/getting-started-identity-provider.md +10 -1
  461. package/docs/getting-started.md +9 -0
  462. package/docs/jira-agents.md +17 -8
  463. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  464. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  465. package/docs/knowledge/delegation-admission-slots.md +52 -0
  466. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  467. package/docs/knowledge/import-rename-target.md +52 -0
  468. package/docs/knowledge/index.md +57 -0
  469. package/docs/knowledge/log.md +9 -0
  470. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  471. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  472. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  473. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  474. package/docs/knowledge/overview-cli.md +74 -0
  475. package/docs/knowledge/overview-coding-proxy.md +72 -0
  476. package/docs/knowledge/overview-coding.md +72 -0
  477. package/docs/knowledge/overview-config.md +60 -0
  478. package/docs/knowledge/overview-core.md +72 -0
  479. package/docs/knowledge/overview-deploy.md +83 -0
  480. package/docs/knowledge/overview-mcp.md +61 -0
  481. package/docs/knowledge/overview-prisma.md +72 -0
  482. package/docs/knowledge/overview-providers.md +89 -0
  483. package/docs/knowledge/overview-sandbox.md +83 -0
  484. package/docs/knowledge/overview-surfaces.md +83 -0
  485. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  486. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  487. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  488. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  489. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  490. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  491. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  492. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  493. package/docs/knowledge/warm-input-publication.md +30 -0
  494. package/docs/knowledge/workspace-staging-failure.md +54 -0
  495. package/docs/knowledge.md +54 -14
  496. package/docs/native-sandbox.md +119 -23
  497. package/docs/observability.md +4 -0
  498. package/docs/security-deployment.md +33 -2
  499. package/docs/slack-notifications.md +35 -19
  500. package/docs/tool-secrets.md +42 -10
  501. package/docs/viewer-api.openapi.yml +1 -1
  502. package/help/admin-viewer.md +24 -2
  503. package/help/architecture-agent.md +11 -6
  504. package/help/build-worker-image.md +3 -1
  505. package/help/builder-agent.md +19 -6
  506. package/help/code-review-agents.md +177 -6
  507. package/help/coding-packages.md +156 -6
  508. package/help/cost-attribution.md +9 -5
  509. package/help/creating-agents.md +14 -1
  510. package/help/dependency-cache.md +143 -0
  511. package/help/deploy-gke.md +15 -8
  512. package/help/errors/budget-exhausted.md +187 -0
  513. package/help/errors/budget-group-exhausted.md +5 -1
  514. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  515. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  516. package/help/errors/continuation-closed.md +9 -12
  517. package/help/errors/delegation-conflict.md +24 -0
  518. package/help/errors/file-list-truncated.md +45 -0
  519. package/help/errors/full-read-required.md +49 -0
  520. package/help/errors/github-account-not-allowed.md +4 -0
  521. package/help/errors/graph-incomplete.md +43 -0
  522. package/help/errors/graph-limit.md +43 -0
  523. package/help/errors/merge-conflict.md +49 -0
  524. package/help/errors/native-sandbox-gateway-error.md +20 -0
  525. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  526. package/help/errors/native-sandbox-worker-exited.md +3 -2
  527. package/help/errors/package-not-allowed-pending.md +52 -0
  528. package/help/errors/package-not-allowed.md +51 -0
  529. package/help/errors/package-refusals.md +43 -0
  530. package/help/errors/patch-cursor-malformed.md +31 -0
  531. package/help/errors/run-lost.md +39 -0
  532. package/help/errors/run-transcript-download.md +44 -0
  533. package/help/errors/secret-in-value.md +69 -0
  534. package/help/errors/target-merge.md +40 -0
  535. package/help/fix-merge-conflicts.md +73 -0
  536. package/help/github-app-setup.md +132 -0
  537. package/help/github.md +22 -0
  538. package/help/identity-and-access.md +2 -0
  539. package/help/jira.md +23 -6
  540. package/help/knowledge.md +16 -7
  541. package/help/local-repositories.md +1 -1
  542. package/help/low-power-mode.md +7 -1
  543. package/help/merge-order-check.md +5 -0
  544. package/help/native-capabilities.md +29 -1
  545. package/help/native-sandbox.md +15 -1
  546. package/help/operating-agents.md +5 -0
  547. package/help/package-audit-mode.md +91 -0
  548. package/help/related-pull-requests.md +10 -7
  549. package/help/resume-runs-locally.md +131 -0
  550. package/help/review-fix-rounds.md +33 -1
  551. package/help/sharing-agents.md +59 -0
  552. package/help/slack-notifications.md +19 -5
  553. package/help/status-comments.md +31 -0
  554. package/help/stop-run.md +58 -0
  555. package/help/troubleshooting/budgets.md +28 -0
  556. package/help/troubleshooting/coding-workers.md +78 -7
  557. package/package.json +17 -10
  558. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  559. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  560. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  561. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  562. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  563. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  564. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  565. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  566. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  567. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  568. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  569. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  570. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  571. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  572. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  573. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  574. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  575. package/prisma/schema.prisma +311 -97
  576. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -30,10 +30,10 @@ import { createHash } from "node:crypto";
30
30
  import { isIP } from "node:net";
31
31
  import { logger } from "../../core/logger.js";
32
32
  import { DISABLED_POWER, wakeTimeoutMs } from "../../core/power.js";
33
- import { MAX_CODING_ARTIFACT_BYTES, MAX_CODING_INPUT_BYTES, MAX_DEBUG_TRACE_LINE_BYTES, parseCodingAgentOutputJson, } from "../../coding/protocol.js";
33
+ import { MAX_CODING_ARTIFACT_BYTES, MAX_CODING_INPUT_BYTES, MAX_DEBUG_TRACE_LINE_BYTES, parseCodingWorkerOutputJson, } from "../../coding/protocol.js";
34
34
  import { CODING_PROXY_DENY_PORT, CODING_PROXY_PORT } from "./docker-isolation.js";
35
35
  import { parseWorkerDiagnosticLine } from "./docker.js";
36
- import { KubernetesAlreadyExistsError, KubernetesConflictError } from "./kubernetes-api.js";
36
+ import { KubernetesAlreadyExistsError, KubernetesConflictError, KubernetesQuotaExceededError, } from "./kubernetes-api.js";
37
37
  import { ENFORCEMENT_PROBE_DENY_REACHABLE, ENFORCEMENT_PROBE_PROVEN, ENFORCEMENT_PROBE_DENY_REFUSED, ENFORCEMENT_PROBE_PROXY_UNREACHABLE, KEEPER_CONTAINER, KEEPER_SEEDED_MARKER, KUBERNETES_ISOLATION_ERROR, STORAGE_ROOT, TOOL_RUNNER_CONTAINER, WORKER_CONTAINER, assertRunNetworkPolicyMatches, assertRunPodMatches, buildCapabilitySecret, buildRunNetworkPolicy, buildRunPod, enforcementStreakScript, kubernetesRunNames, kubernetesRunNamesForToken, runLabels, serviceContainerName, validateKubernetesSpec, } from "./kubernetes-isolation.js";
38
38
  import { claudeToolSetup } from "./claude-tool-setup.js";
39
39
  import { podQuotaUsage, quotaShortfall } from "./kubernetes-quota.js";
@@ -41,6 +41,7 @@ import { readProxyWitness } from "./kubernetes-witness.js";
41
41
  import { safeExtract } from "./safe-extract.js";
42
42
  import { reportServiceState, } from "./service-state.js";
43
43
  import { serviceUnreadyError } from "../../coding/services/wording.js";
44
+ import { JobCapacityError, } from "./types.js";
44
45
  import { replaceDirectoryFromStaging } from "./workspace-swap.js";
45
46
  import { collectExclusions, normalizeCollectExclusions, tarExcludeArgs, } from "../../coding/collect-exclude.js";
46
47
  const BACKEND = "kubernetes";
@@ -184,10 +185,22 @@ const TOKEN = /^[a-f0-9]{20}$/;
184
185
  const WORKSPACE_STORAGE = `${STORAGE_ROOT}/workspace`;
185
186
  const INPUT_STORAGE = `${STORAGE_ROOT}/input`;
186
187
  const RESULT_PATH = `${STORAGE_ROOT}/output/result.json`;
188
+ const TRANSCRIPT_PATH = `${STORAGE_ROOT}/output/session.jsonl`;
187
189
  /** Stands in for the proxy ClusterIP when building a pod only to count its resources. */
188
190
  const QUOTA_PROBE_PROXY_IP = "10.0.0.1";
191
+ /** A Kubernetes object name (RFC 1123 subdomain). */
192
+ const DNS_1123_NAME = /^[a-z0-9]([-a-z0-9.]{0,251}[a-z0-9])?$/;
189
193
  const kubernetesLog = logger.child({ module: "kubernetes-jobs" });
190
- const PHASES = new Set(["provisioning", "active", "succeeded", "failed", "stopped", "lost", "removed"]);
194
+ const PHASES = new Set([
195
+ "provisioning",
196
+ "requeued",
197
+ "active",
198
+ "succeeded",
199
+ "failed",
200
+ "stopped",
201
+ "lost",
202
+ "removed",
203
+ ]);
191
204
  const TERMINAL_PHASES = new Set(["succeeded", "failed", "stopped", "lost", "removed"]);
192
205
  // ---------------------------------------------------------------------------
193
206
  // Pure helpers: the lifecycle rules.
@@ -206,6 +219,8 @@ function statusFor(record) {
206
219
  switch (record.phase) {
207
220
  case "provisioning":
208
221
  return { state: "pending" };
222
+ case "requeued":
223
+ return { state: "pending", capacityRefused: true };
209
224
  case "active":
210
225
  return { state: "running" };
211
226
  case "succeeded":
@@ -508,8 +523,9 @@ export class KubernetesJobLauncher {
508
523
  const handle = { backend: BACKEND, id: `${this.namespace}/${names.token}` };
509
524
  const specHash = stableSpecHash(spec);
510
525
  const existing = await this.readRecord(names);
511
- if (existing)
526
+ if (existing && !this.isRequeued(existing, specHash)) {
512
527
  return this.existingLaunch(existing.record, specHash, handle);
528
+ }
513
529
  const createdAt = this.now();
514
530
  const record = {
515
531
  schemaVersion: RECORD_SCHEMA_VERSION,
@@ -521,22 +537,54 @@ export class KubernetesJobLauncher {
521
537
  phase: "provisioning",
522
538
  collectExclude: spec.collectExclude ?? collectExclusions([]),
523
539
  };
524
- try {
525
- // The record is the idempotency fence before any other cluster side effect.
526
- await this.api.createConfigMap(this.namespace, this.recordConfigMap(names, record));
540
+ if (existing) {
541
+ // Replaces the requeued record; a conflict means another replica got there first.
542
+ try {
543
+ await this.api.replaceConfigMap(this.namespace, names.record, this.recordConfigMap(names, record, existing.resourceVersion));
544
+ }
545
+ catch (error) {
546
+ if (!(error instanceof KubernetesConflictError))
547
+ throw error;
548
+ const raced = await this.readRecord(names);
549
+ if (!raced)
550
+ throw error;
551
+ if (!this.isRequeued(raced, specHash))
552
+ return this.existingLaunch(raced.record, specHash, handle);
553
+ // Requeued again by the other replica (its attempt was refused too): start over from that record.
554
+ return this.launch(spec);
555
+ }
527
556
  }
528
- catch (error) {
529
- if (!(error instanceof KubernetesAlreadyExistsError))
530
- throw error;
531
- const raced = await this.readRecord(names);
532
- if (!raced)
533
- throw error;
534
- return this.existingLaunch(raced.record, specHash, handle);
557
+ else {
558
+ try {
559
+ // The record is the idempotency fence before any other cluster side effect. A quota refusing
560
+ // this create itself (a count/configmaps quota) is not a capacity refusal: it fails the run.
561
+ await this.api.createConfigMap(this.namespace, this.recordConfigMap(names, record));
562
+ }
563
+ catch (error) {
564
+ if (!(error instanceof KubernetesAlreadyExistsError))
565
+ throw error;
566
+ const raced = await this.readRecord(names);
567
+ if (!raced)
568
+ throw error;
569
+ if (!this.isRequeued(raced, specHash))
570
+ return this.existingLaunch(raced.record, specHash, handle);
571
+ // Another replica requeued it between our read and create: start over from the requeued record.
572
+ return this.launch(spec);
573
+ }
535
574
  }
536
575
  try {
537
576
  await this.provision(spec, names, record);
538
577
  }
539
578
  catch (error) {
579
+ if (error instanceof KubernetesQuotaExceededError) {
580
+ // Capacity, not failure: leave a record a later launch() provisions afresh.
581
+ await this.updateRecord(names, () => ({ phase: "requeued" })).catch(() => undefined);
582
+ await this.cleanupRun(names, 0);
583
+ this.hintQuotaUnconfigured(error.quotaName);
584
+ throw new JobCapacityError("kubernetes_quota_exceeded: the namespace ResourceQuota has no room for this run", {
585
+ cause: error,
586
+ });
587
+ }
540
588
  // Record the failure before deleting the pod, so a replica that observes "no pod" in between
541
589
  // can't record `lost` first and have this more specific outcome dropped.
542
590
  await this.updateRecord(names, () => ({
@@ -758,6 +806,22 @@ export class KubernetesJobLauncher {
758
806
  await this.sleep(ENFORCEMENT_POLL_MS);
759
807
  }
760
808
  }
809
+ /** True when `found` is a requeued record for this spec, which launch() replaces with a fresh one. */
810
+ isRequeued(found, specHash) {
811
+ if (found.record.phase !== "requeued")
812
+ return false;
813
+ if (found.record.specHash !== specHash)
814
+ throw new Error("job_spec_conflict");
815
+ return true;
816
+ }
817
+ /** Tells the operator once that a quota refused a pod while no quota is configured for the pre-launch check. */
818
+ hintQuotaUnconfigured(refusedQuota) {
819
+ if (this.options.config.resourceQuota)
820
+ return;
821
+ const name = refusedQuota !== undefined && DNS_1123_NAME.test(refusedQuota) ? refusedQuota : undefined;
822
+ this.warnOnce(`kubernetes_resource_quota_unconfigured: a pod was refused by ${name ? `ResourceQuota ${name}` : "a ResourceQuota"}; ` +
823
+ `set KUBERNETES_RESOURCE_QUOTA=${name ?? "<name>"} and grant the launcher get on that ResourceQuota so runs wait before they start`);
824
+ }
761
825
  existingLaunch(record, specHash, handle) {
762
826
  if (record.specHash !== specHash)
763
827
  throw new Error("job_spec_conflict");
@@ -957,7 +1021,8 @@ export class KubernetesJobLauncher {
957
1021
  // Observation and collection
958
1022
  /** Observes a non-terminal run against its pod and persists any transition; returns the stored record. */
959
1023
  async refresh(names, record) {
960
- if (isTerminal(record.phase))
1024
+ // A requeued run has no pod by design; observing it would record it lost.
1025
+ if (isTerminal(record.phase) || record.phase === "requeued")
961
1026
  return record;
962
1027
  const pod = await this.api.readPod(this.namespace, names.pod);
963
1028
  const observed = observePod(pod, record, this.now(), this.readyTimeoutMs);
@@ -985,6 +1050,30 @@ export class KubernetesJobLauncher {
985
1050
  }
986
1051
  return undefined;
987
1052
  }
1053
+ async readTranscript(handle, maxBytes) {
1054
+ const names = this.namesFor(handle);
1055
+ const found = names && (await this.readRecord(names));
1056
+ if (!names || !found)
1057
+ return undefined;
1058
+ const collector = new BoundedCollector(maxBytes);
1059
+ let exitCode;
1060
+ try {
1061
+ exitCode = await this.api.exec(this.namespace, names.pod, KEEPER_CONTAINER, ["head", "-c", String(maxBytes + 1), TRANSCRIPT_PATH], { stdout: collector, timeoutMs: SHORT_EXEC_TIMEOUT_MS });
1062
+ if (!collector.writableEnded)
1063
+ collector.end();
1064
+ await finished(collector);
1065
+ }
1066
+ catch {
1067
+ // The pod is gone (a stopped run) or unreachable: there is nothing to collect.
1068
+ collector.destroy();
1069
+ return undefined;
1070
+ }
1071
+ if (exitCode !== 0)
1072
+ return undefined;
1073
+ if (collector.exceeded)
1074
+ throw new Error("transcript_too_large");
1075
+ return collector.text();
1076
+ }
988
1077
  async readResultArtifact(names, runId) {
989
1078
  const collector = new BoundedCollector(MAX_CODING_ARTIFACT_BYTES);
990
1079
  let raw;
@@ -1005,7 +1094,7 @@ export class KubernetesJobLauncher {
1005
1094
  }
1006
1095
  let output;
1007
1096
  try {
1008
- output = parseCodingAgentOutputJson(raw);
1097
+ output = parseCodingWorkerOutputJson(raw);
1009
1098
  }
1010
1099
  catch (error) {
1011
1100
  throw errorWithCode("kubernetes_result_artifact_invalid", error);
@@ -21,6 +21,14 @@ export interface JobSpec {
21
21
  /** Required only for Claude's credential-free repository tool container. */
22
22
  toolImage?: string;
23
23
  inputArtifact: string;
24
+ /** Set only when the run's dependency cache is on (CodingRun.dependencyCache); absent otherwise, never false. */
25
+ dependencyCache?: true;
26
+ /**
27
+ * Claude Code only, set only when the run keeps its session (CodingRun.sessionResume); absent otherwise,
28
+ * never false. The worker's SDK config dir, where the session file grows, gets its own size-limited
29
+ * scratch so a long session never fills the worker's shared /tmp.
30
+ */
31
+ sessionResume?: true;
24
32
  timeoutSec: number;
25
33
  limits: JobResourceLimits;
26
34
  labels: Record<string, string>;
@@ -42,6 +50,12 @@ export interface JobHandle {
42
50
  }
43
51
  export type JobStatus = {
44
52
  state: "pending" | "running";
53
+ /**
54
+ * Only ever on `pending`: the backend refused this job's launch for capacity (JobCapacityError)
55
+ * and nothing of it is running, nor will it start on its own. A caller that finds its job so
56
+ * may return the run to its queue and later `launch` the same spec again.
57
+ */
58
+ capacityRefused?: true;
45
59
  } | {
46
60
  state: "succeeded";
47
61
  } | {
@@ -61,11 +75,24 @@ export interface JobResult {
61
75
  /** Output-schema failure locations (`path:code`) that passed SAFE_CODING_OUTPUT_ISSUE; never values. */
62
76
  diagnosticIssues?: string[];
63
77
  }
78
+ /**
79
+ * The backend has no room for this job right now (Kubernetes: the namespace ResourceQuota). No
80
+ * workload of the job is left running; the backend may keep a record of the refusal (Kubernetes
81
+ * does: its run record, which `status` then reports as `pending` with `capacityRefused`). The
82
+ * caller may launch the same spec again later.
83
+ */
84
+ export declare class JobCapacityError extends Error {
85
+ readonly code = "coding_capacity_exceeded";
86
+ constructor(message: string, options?: ErrorOptions);
87
+ }
64
88
  /**
65
89
  * Lifecycle invariants implemented by every launcher:
66
90
  *
67
91
  * - `launch` is idempotent by runId for an identical spec and rejects a
68
92
  * different spec for the same runId.
93
+ * - `launch` may reject with JobCapacityError when the backend has no room for
94
+ * the job; nothing of it is then left running, and a later `launch` of the
95
+ * same spec provisions it afresh.
69
96
  * - pending may become running or terminal; running may become terminal;
70
97
  * terminal states never change.
71
98
  * - `collect` is repeatable for a terminal job until `remove` succeeds.
@@ -100,6 +127,12 @@ export interface JobLauncher {
100
127
  launch: (spec: JobSpec) => Promise<JobHandle>;
101
128
  status: (handle: JobHandle) => Promise<JobStatus>;
102
129
  collect: (handle: JobHandle) => Promise<JobResult>;
130
+ /**
131
+ * The run's session transcript file (the worker's session.jsonl), at most `maxBytes`; undefined
132
+ * when there is none or the job's storage is gone (a stopped job). Throws `transcript_too_large`
133
+ * when larger. Never cached in the job record: it is not redacted yet. Call before `remove`.
134
+ */
135
+ readTranscript?: (handle: JobHandle, maxBytes: number) => Promise<string | undefined>;
103
136
  stop: (handle: JobHandle, reason?: string) => Promise<void>;
104
137
  remove: (handle: JobHandle) => Promise<void>;
105
138
  }
@@ -3,4 +3,16 @@
3
3
  * values are carried in a versioned input artifact, never expanded into an
4
4
  * arbitrary environment map or shell command.
5
5
  */
6
- export {};
6
+ /**
7
+ * The backend has no room for this job right now (Kubernetes: the namespace ResourceQuota). No
8
+ * workload of the job is left running; the backend may keep a record of the refusal (Kubernetes
9
+ * does: its run record, which `status` then reports as `pending` with `capacityRefused`). The
10
+ * caller may launch the same spec again later.
11
+ */
12
+ export class JobCapacityError extends Error {
13
+ code = "coding_capacity_exceeded";
14
+ constructor(message, options) {
15
+ super(message, options);
16
+ this.name = "JobCapacityError";
17
+ }
18
+ }
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import Anthropic from "@anthropic-ai/sdk";
8
8
  import { ClaudeLlmProvider } from "./claude-provider.js";
9
+ import { simulatorModelClientOptions } from "../../config/test-simulators.js";
9
10
  export function anthropicCredentialsPresent(env = process.env) {
10
11
  return Boolean(env.ANTHROPIC_API_KEY);
11
12
  }
@@ -14,6 +15,9 @@ export class AnthropicLlmProvider extends ClaudeLlmProvider {
14
15
  if (!client && !apiKey) {
15
16
  throw new Error("ANTHROPIC_API_KEY is not set — required by the Anthropic LlmProvider adapter.");
16
17
  }
17
- super(client ?? new Anthropic({ apiKey }), lookup);
18
+ // WARDBY_TEST_SIMULATORS (test only): the scripted model, with a placeholder key the
19
+ // credential-free fetch drops; the real key never goes there.
20
+ const simulator = client ? null : simulatorModelClientOptions("anthropic");
21
+ super(client ?? new Anthropic(simulator ?? { apiKey }), lookup);
18
22
  }
19
23
  }
@@ -1,15 +1,3 @@
1
- /**
2
- * Bedrock-Claude adapter for the LlmProvider seam. `@anthropic-ai/bedrock-sdk`
3
- * is imported only here; all protocol/pricing-dispatch logic lives in the
4
- * shared ClaudeLlmProvider base class (claude-provider.ts) — AnthropicBedrock
5
- * exposes the identical .messages.stream() surface as @anthropic-ai/sdk, so
6
- * this file's only job is constructing the right client.
7
- *
8
- * Named BedrockClaudeLlmProvider, not BedrockLlmProvider: Bedrock hosts
9
- * multiple model vendors, and this adapter only ever speaks the
10
- * Anthropic-native protocol for Claude models. A future non-Claude Bedrock
11
- * adapter gets its own name, not a rename of this one.
12
- */
13
1
  import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
14
2
  import { ClaudeLlmProvider } from "./claude-provider.js";
15
3
  import type { CatalogLookup } from "./catalog-lookup.js";
@@ -10,6 +10,7 @@
10
10
  * Anthropic-native protocol for Claude models. A future non-Claude Bedrock
11
11
  * adapter gets its own name, not a rename of this one.
12
12
  */
13
+ import { refuseBedrockUnderTestSimulators } from "../../config/test-simulators.js";
13
14
  import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
14
15
  import { ClaudeLlmProvider } from "./claude-provider.js";
15
16
  export function bedrockCredentialsPresent(env = process.env) {
@@ -23,6 +24,9 @@ export class BedrockClaudeLlmProvider extends ClaudeLlmProvider {
23
24
  if (!client && !region) {
24
25
  throw new Error("BEDROCK_REGION (or AWS_REGION) is required by the Bedrock Claude LlmProvider adapter.");
25
26
  }
27
+ // WARDBY_TEST_SIMULATORS (test only) refuses Bedrock: AWS-signed calls cannot go to the simulator.
28
+ if (!client)
29
+ refuseBedrockUnderTestSimulators();
26
30
  super(client ?? new AnthropicBedrock({ awsRegion: region }), lookup);
27
31
  }
28
32
  }
@@ -106,5 +106,7 @@ export type ClaudeStreamEvent = {
106
106
  } | {
107
107
  type: "message_stop";
108
108
  };
109
- export declare function mapClaudeStream(events: AsyncIterable<ClaudeStreamEvent>, priceUsd: (usage: LlmUsage) => number): AsyncIterable<LlmStreamEvent>;
109
+ export declare function mapClaudeStream(events: AsyncIterable<ClaudeStreamEvent>, priceUsd: (usage: LlmUsage) => number,
110
+ /** Called at message_start: the response has started, and output may be billed from here on. */
111
+ onResponseStarted?: () => void): AsyncIterable<LlmStreamEvent>;
110
112
  export {};
@@ -98,7 +98,9 @@ export function withCacheBreakpoints(req) {
98
98
  });
99
99
  return { ...req, ...(system ? { system } : {}), messages };
100
100
  }
101
- export async function* mapClaudeStream(events, priceUsd) {
101
+ export async function* mapClaudeStream(events, priceUsd,
102
+ /** Called at message_start: the response has started, and output may be billed from here on. */
103
+ onResponseStarted) {
102
104
  const toolBuffers = new Map();
103
105
  let start = {};
104
106
  let outputTokens = 0;
@@ -106,6 +108,7 @@ export async function* mapClaudeStream(events, priceUsd) {
106
108
  for await (const ev of events) {
107
109
  switch (ev.type) {
108
110
  case "message_start":
111
+ onResponseStarted?.();
109
112
  start = ev.message.usage ?? {};
110
113
  outputTokens = ev.message.usage?.output_tokens ?? 0;
111
114
  break;
@@ -5,7 +5,7 @@
5
5
  * stays exactly what each concrete adapter (anthropic.ts, bedrock.ts) has in
6
6
  * common, and nothing more.
7
7
  */
8
- import type { LlmMessage, LlmRequest, LlmStreamEvent, LlmToolDef } from "./types.js";
8
+ import type { LlmMessage, LlmRequest, LlmStreamEvent, LlmStreamHooks, LlmToolDef } from "./types.js";
9
9
  import { type CatalogLookup } from "./catalog-lookup.js";
10
10
  import type { CatalogEntry } from "./catalog-types.js";
11
11
  import type { CatalogLlmAdapter } from "./routing.js";
@@ -27,7 +27,7 @@ export declare class ClaudeLlmProvider implements CatalogLlmAdapter {
27
27
  private readonly lookup;
28
28
  constructor(client: ClaudeMessagesClient, lookup?: CatalogLookup);
29
29
  withEntry(entry: CatalogEntry): ClaudeLlmProvider;
30
- stream(req: LlmRequest, signal?: AbortSignal): AsyncIterable<LlmStreamEvent>;
30
+ stream(req: LlmRequest, signal?: AbortSignal, hooks?: LlmStreamHooks): AsyncIterable<LlmStreamEvent>;
31
31
  countTokens(model: string, messages: LlmMessage[], tools?: LlmToolDef[]): Promise<number>;
32
32
  priceUsd(model: string, usage: {
33
33
  inputTokens: number;
@@ -21,14 +21,14 @@ export class ClaudeLlmProvider {
21
21
  withEntry(entry) {
22
22
  return new ClaudeLlmProvider(this.client, pinnedLookup(entry));
23
23
  }
24
- async *stream(req, signal) {
24
+ async *stream(req, signal, hooks) {
25
25
  // Defence in depth behind config-time validation: a level the model
26
26
  // doesn't accept would fail the whole call, so it is dropped here.
27
27
  const { effort, ...rest } = req;
28
28
  const accepted = effort && this.lookup(req.model).efforts.includes(effort);
29
29
  const claudeReq = withCacheBreakpoints(toClaudeRequest(accepted ? { ...rest, effort } : rest, DEFAULT_MAX_TOKENS));
30
30
  const raw = this.client.messages.stream({ model: req.model, ...claudeReq }, { signal });
31
- yield* mapClaudeStream(raw, (usage) => this.priceUsd(req.model, usage));
31
+ yield* mapClaudeStream(raw, (usage) => this.priceUsd(req.model, usage), hooks?.onResponseStarted);
32
32
  }
33
33
  async countTokens(model, messages, tools) {
34
34
  this.lookup(model); // fail-closed on a model the catalog does not serve
@@ -27,7 +27,7 @@
27
27
  * apply.
28
28
  */
29
29
  import OpenAI from "openai";
30
- import type { LlmMessage, LlmRequest, LlmStreamEvent, LlmToolDef } from "./types.js";
30
+ import type { LlmMessage, LlmRequest, LlmStreamEvent, LlmStreamHooks, LlmToolDef } from "./types.js";
31
31
  import { type CatalogLookup } from "./catalog-lookup.js";
32
32
  import type { CatalogEntry } from "./catalog-types.js";
33
33
  import type { CatalogLlmAdapter } from "./routing.js";
@@ -44,7 +44,7 @@ export declare class OpenAiLlmProvider implements CatalogLlmAdapter {
44
44
  */
45
45
  constructor(apiKey?: string, client?: OpenAI, lookup?: CatalogLookup);
46
46
  withEntry(entry: CatalogEntry): OpenAiLlmProvider;
47
- stream(req: LlmRequest, signal?: AbortSignal): AsyncIterable<LlmStreamEvent>;
47
+ stream(req: LlmRequest, signal?: AbortSignal, hooks?: LlmStreamHooks): AsyncIterable<LlmStreamEvent>;
48
48
  /**
49
49
  * OpenAI reports both `cached_tokens` and `cache_write_tokens` as subsets
50
50
  * of `input_tokens`. wardby's LlmUsage convention (claude-messages.ts,
@@ -27,6 +27,7 @@
27
27
  * apply.
28
28
  */
29
29
  import OpenAI from "openai";
30
+ import { simulatorModelClientOptions } from "../../config/test-simulators.js";
30
31
  import { encode as encodeCl100kBase } from "gpt-tokenizer/encoding/cl100k_base";
31
32
  import { encode as encodeO200kBase } from "gpt-tokenizer/encoding/o200k_base";
32
33
  import { computeCost } from "./pricing-core.js";
@@ -133,12 +134,14 @@ export class OpenAiLlmProvider {
133
134
  if (!apiKey) {
134
135
  throw new Error("OPENAI_API_KEY is not set — required by the OpenAI LlmProvider adapter.");
135
136
  }
136
- this.client = new OpenAI({ apiKey });
137
+ // WARDBY_TEST_SIMULATORS (test only): the scripted model, with a placeholder key the
138
+ // credential-free fetch drops; the real key never goes there.
139
+ this.client = new OpenAI(simulatorModelClientOptions("openai") ?? { apiKey });
137
140
  }
138
141
  withEntry(entry) {
139
142
  return new OpenAiLlmProvider("", this.client, pinnedLookup(entry));
140
143
  }
141
- async *stream(req, signal) {
144
+ async *stream(req, signal, hooks) {
142
145
  const entry = this.lookup(req.model);
143
146
  // Effort is sent only at a level the catalog says the model accepts and
144
147
  // dropped otherwise (the LlmRequest.effort contract). Temperature only
@@ -157,6 +160,7 @@ export class OpenAiLlmProvider {
157
160
  ...(sendTemperature ? { temperature: req.temperature } : {}),
158
161
  };
159
162
  const stream = await this.client.responses.create(params, { signal });
163
+ hooks?.onResponseStarted?.();
160
164
  let sawToolCall = false;
161
165
  for await (const event of stream) {
162
166
  switch (event.type) {
@@ -1,6 +1,6 @@
1
1
  import type { ModelCatalog } from "./catalog.js";
2
2
  import { type CatalogEntry, type ModelProvider, type ResolvedCatalogEntry } from "./catalog-types.js";
3
- import type { LlmEffort, LlmMessage, LlmProvider, LlmRequest, LlmStreamEvent, LlmToolDef } from "./types.js";
3
+ import type { LlmEffort, LlmMessage, LlmProvider, LlmRequest, LlmStreamEvent, LlmStreamHooks, LlmToolDef } from "./types.js";
4
4
  /** Effort levels `model` accepts, from the current catalog; no credentials needed (config-time validation). */
5
5
  export declare function modelSupportedEfforts(model: string): readonly LlmEffort[];
6
6
  export declare function modelAcceptsEffort(model: string, effort: LlmEffort): boolean;
@@ -24,7 +24,7 @@ export declare class RoutingLlmProvider implements LlmProvider {
24
24
  /** A provider bound to one run's stored entry: prices and shapes requests from it, never the live catalog. */
25
25
  forRun(entry: CatalogEntry): LlmProvider;
26
26
  private resolve;
27
- stream(req: LlmRequest, signal?: AbortSignal): AsyncIterable<LlmStreamEvent>;
27
+ stream(req: LlmRequest, signal?: AbortSignal, hooks?: LlmStreamHooks): AsyncIterable<LlmStreamEvent>;
28
28
  countTokens(model: string, messages: LlmMessage[], tools?: LlmToolDef[]): Promise<number>;
29
29
  priceUsd(model: string, usage: {
30
30
  inputTokens: number;
@@ -54,8 +54,8 @@ export class RoutingLlmProvider {
54
54
  resolve(model) {
55
55
  return this.byProvider.get(this.entryFor(model).provider);
56
56
  }
57
- stream(req, signal) {
58
- return this.resolve(req.model).stream(req, signal);
57
+ stream(req, signal, hooks) {
58
+ return this.resolve(req.model).stream(req, signal, hooks);
59
59
  }
60
60
  countTokens(model, messages, tools) {
61
61
  return this.resolve(model).countTokens(model, messages, tools);
@@ -68,7 +68,9 @@ export interface LlmUsage {
68
68
  export type LlmStreamEvent = {
69
69
  type: "text";
70
70
  delta: string;
71
- } | {
71
+ }
72
+ /** `id` must be unique within a run, not only within a turn: a delegation keys its child run on it. */
73
+ | {
72
74
  type: "tool_call";
73
75
  id: string;
74
76
  name: string;
@@ -78,8 +80,16 @@ export type LlmStreamEvent = {
78
80
  stopReason: string;
79
81
  usage: LlmUsage;
80
82
  };
83
+ /** Observers of a stream's progress that its events do not show. */
84
+ export interface LlmStreamHooks {
85
+ /**
86
+ * Called once the provider's response has started. From then on the provider
87
+ * may bill output (thinking or reasoning included) before any event is yielded.
88
+ */
89
+ onResponseStarted?: () => void;
90
+ }
81
91
  export interface LlmProvider {
82
- stream(req: LlmRequest, signal?: AbortSignal): AsyncIterable<LlmStreamEvent>;
92
+ stream(req: LlmRequest, signal?: AbortSignal, hooks?: LlmStreamHooks): AsyncIterable<LlmStreamEvent>;
83
93
  /**
84
94
  * Pre-flight token count for budget enforcement. `tools`, when passed,
85
95
  * must be counted too — a provider bills the serialized tool schemas as
@@ -6,8 +6,16 @@ type Json = Record<string, unknown>;
6
6
  * counts: anyone can write the marker into their own PR's description.
7
7
  */
8
8
  export declare function appMarkerRunId(pr: Json | null, slug: string): string | undefined;
9
+ /** Why a mention was dropped before routing; never carries the body. */
10
+ export interface DroppedMention {
11
+ eventName: string;
12
+ repository: string;
13
+ association: string;
14
+ reason: "author_association" | "not_a_user";
15
+ }
16
+ /** `onDropped` hears about a mention the author pre-filter dropped, so the caller can log it. */
9
17
  export declare function normalizeGitHubEvent(eventName: string, payload: unknown, app: {
10
18
  id: number;
11
19
  slug: string;
12
- }): HostEvent | null;
20
+ }, onDropped?: (dropped: DroppedMention) => void): HostEvent | null;
13
21
  export {};
@@ -4,8 +4,14 @@
4
4
  */
5
5
  import { createHmac, timingSafeEqual } from "node:crypto";
6
6
  import { normalizeGitHubRepository } from "../../coding/protocol.js";
7
+ import { withoutMarkdownCode } from "../../core/markdown-code.js";
7
8
  const PR_ACTIONS = new Set(["opened", "synchronize", "reopened", "ready_for_review"]);
8
- const TRUSTED_ASSOCIATIONS = new Set(["OWNER", "MEMBER", "COLLABORATOR"]);
9
+ /**
10
+ * GitHub labels an organization member whose membership is private CONTRIBUTOR
11
+ * or NONE, so both pass; first-time authors and mannequins are drive-by
12
+ * accounts that cannot have access to a repository they never committed to.
13
+ */
14
+ const TRUSTED_ASSOCIATIONS = new Set(["OWNER", "MEMBER", "COLLABORATOR", "CONTRIBUTOR", "NONE"]);
9
15
  const SAFE_SHA = /^[0-9a-f]{40}$/;
10
16
  // GitHub's push payload includes at most 2048 commits.
11
17
  const PUSH_MAX_COMMITS = 2048;
@@ -37,9 +43,10 @@ function repositoryOf(payload) {
37
43
  return null;
38
44
  }
39
45
  }
46
+ /** A mention of the App outside code: a mention quoted in code documents it, not requests a run. */
40
47
  function mentions(body, slug) {
41
48
  const escaped = slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
42
- return new RegExp(`(^|[^\\w@.-])@${escaped}(?![\\w-])`, "i").test(body);
49
+ return new RegExp(`(^|[^\\w@.-])@${escaped}(?![\\w-])`, "i").test(withoutMarkdownCode(body));
43
50
  }
44
51
  const text = (value) => (typeof value === "string" ? value : "");
45
52
  function subjectOf(item) {
@@ -73,20 +80,27 @@ function priorRunIdOf(pr, slug) {
73
80
  * any org member, COLLABORATOR includes read and triage). The real gate is the
74
81
  * author's live repository permission, checked by id in core/host-events.ts.
75
82
  */
76
- function trustedHuman(association, user) {
77
- return (typeof association === "string" &&
78
- TRUSTED_ASSOCIATIONS.has(association) &&
79
- user?.type === "User" &&
80
- typeof user.login === "string" &&
81
- int(user.id) !== null);
83
+ function trustedHuman(association, user, drop) {
84
+ const label = typeof association === "string" ? association : "missing";
85
+ if (typeof association !== "string" || !TRUSTED_ASSOCIATIONS.has(association)) {
86
+ drop("author_association", label);
87
+ return false;
88
+ }
89
+ if (user?.type !== "User" || typeof user.login !== "string" || int(user.id) === null) {
90
+ drop("not_a_user", label);
91
+ return false;
92
+ }
93
+ return true;
82
94
  }
83
- export function normalizeGitHubEvent(eventName, payload, app) {
95
+ /** `onDropped` hears about a mention the author pre-filter dropped, so the caller can log it. */
96
+ export function normalizeGitHubEvent(eventName, payload, app, onDropped) {
84
97
  const p = obj(payload);
85
98
  if (!p)
86
99
  return null;
87
100
  const repository = repositoryOf(p);
88
101
  if (!repository)
89
102
  return null;
103
+ const drop = (reason, association) => onDropped?.({ eventName, repository, association, reason });
90
104
  if (eventName === "push") {
91
105
  const defaultBranch = obj(p.repository)?.default_branch;
92
106
  const { before, after } = p;
@@ -181,10 +195,10 @@ export function normalizeGitHubEvent(eventName, payload, app) {
181
195
  return null;
182
196
  const body = text(issue?.body);
183
197
  const user = obj(issue?.user);
184
- if (!trustedHuman(issue?.author_association, user))
185
- return null;
186
198
  if (!mentions(title, app.slug) && !mentions(body, app.slug))
187
199
  return null;
200
+ if (!trustedHuman(issue?.author_association, user, drop))
201
+ return null;
188
202
  if (p.action === "edited") {
189
203
  // Only the author's own edit, and only one that newly adds the mention — not every later edit.
190
204
  const sender = obj(p.sender);
@@ -209,6 +223,10 @@ export function normalizeGitHubEvent(eventName, payload, app) {
209
223
  body,
210
224
  author: user.login,
211
225
  authorId: String(user.id),
226
+ authorAssociation: String(issue?.author_association),
227
+ ...(typeof obj(p.repository)?.private === "boolean"
228
+ ? { repositoryPrivate: obj(p.repository)?.private }
229
+ : {}),
212
230
  subject: { title, body },
213
231
  };
214
232
  }
@@ -221,7 +239,7 @@ export function normalizeGitHubEvent(eventName, payload, app) {
221
239
  const commentId = int(comment?.id);
222
240
  if (typeof body !== "string" || !commentId || !mentions(body, app.slug))
223
241
  return null;
224
- if (!trustedHuman(comment?.author_association, user))
242
+ if (!trustedHuman(comment?.author_association, user, drop))
225
243
  return null;
226
244
  const isInline = eventName === "pull_request_review_comment";
227
245
  const parent = obj(isInline ? p.pull_request : p.issue);
@@ -242,6 +260,10 @@ export function normalizeGitHubEvent(eventName, payload, app) {
242
260
  body,
243
261
  author: user.login,
244
262
  authorId: String(user.id),
263
+ authorAssociation: String(comment?.author_association),
264
+ ...(typeof obj(p.repository)?.private === "boolean"
265
+ ? { repositoryPrivate: obj(p.repository)?.private }
266
+ : {}),
245
267
  ...(subject ? { subject } : {}),
246
268
  ...(priorRunId ? { priorRunId } : {}),
247
269
  };