@wardby/cli 0.5.3 → 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 (763) hide show
  1. package/.env.example +33 -0
  2. package/README.md +25 -14
  3. package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
  4. package/dist/claude-coding-worker/context.d.ts +22 -0
  5. package/dist/claude-coding-worker/context.js +92 -0
  6. package/dist/claude-coding-worker/driver.d.ts +27 -3
  7. package/dist/claude-coding-worker/driver.js +161 -20
  8. package/dist/claude-coding-worker/main.js +34 -6
  9. package/dist/claude-coding-worker/sdk.js +25 -5
  10. package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
  11. package/dist/claude-coding-worker/tool-socket.js +111 -0
  12. package/dist/claude-coding-worker/transcript.d.ts +18 -0
  13. package/dist/claude-coding-worker/transcript.js +77 -0
  14. package/dist/cli-help.d.ts +1 -1
  15. package/dist/cli-help.js +6 -2
  16. package/dist/cli-native-mode.d.ts +9 -0
  17. package/dist/cli-native-mode.js +20 -0
  18. package/dist/cli.d.ts +3 -1
  19. package/dist/cli.js +161 -11
  20. package/dist/coding/claude-context.d.ts +45 -0
  21. package/dist/coding/claude-context.js +434 -0
  22. package/dist/coding/continuation-wording.d.ts +35 -0
  23. package/dist/coding/continuation-wording.js +73 -0
  24. package/dist/coding/linked-issue-note.d.ts +23 -0
  25. package/dist/coding/linked-issue-note.js +47 -0
  26. package/dist/coding/merge-wording.d.ts +28 -0
  27. package/dist/coding/merge-wording.js +78 -0
  28. package/dist/coding/pr-description-note.d.ts +9 -0
  29. package/dist/coding/pr-description-note.js +32 -0
  30. package/dist/coding/profile.d.ts +50 -118
  31. package/dist/coding/profile.js +51 -4
  32. package/dist/coding/protected-path-wording.d.ts +8 -0
  33. package/dist/coding/protected-path-wording.js +1 -1
  34. package/dist/coding/protocol.d.ts +292 -270
  35. package/dist/coding/protocol.js +322 -15
  36. package/dist/coding/redact.d.ts +3 -0
  37. package/dist/coding/redact.js +12 -0
  38. package/dist/coding/registry/allowlist.d.ts +12 -0
  39. package/dist/coding/registry/allowlist.js +14 -1
  40. package/dist/coding/registry/audit-mode.d.ts +153 -0
  41. package/dist/coding/registry/audit-mode.js +304 -0
  42. package/dist/coding/registry/lockfile-shared.d.ts +36 -0
  43. package/dist/coding/registry/lockfile-shared.js +128 -0
  44. package/dist/coding/registry/lockfiles.js +1 -1
  45. package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
  46. package/dist/coding/registry/npm-lockfile-formats.js +41 -0
  47. package/dist/coding/registry/npm-lockfile.d.ts +8 -4
  48. package/dist/coding/registry/npm-lockfile.js +4 -6
  49. package/dist/coding/registry/npm.js +78 -8
  50. package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
  51. package/dist/coding/registry/pnpm-lockfile.js +189 -0
  52. package/dist/coding/registry/pypi-plan.d.ts +50 -0
  53. package/dist/coding/registry/pypi-plan.js +406 -0
  54. package/dist/coding/registry/pypi-requirements.d.ts +58 -0
  55. package/dist/coding/registry/pypi-requirements.js +155 -0
  56. package/dist/coding/registry/pypi.d.ts +3 -27
  57. package/dist/coding/registry/pypi.js +40 -154
  58. package/dist/coding/registry/refusal-hints.d.ts +20 -0
  59. package/dist/coding/registry/refusal-hints.js +61 -0
  60. package/dist/coding/registry/refusal-wording.d.ts +11 -0
  61. package/dist/coding/registry/refusal-wording.js +56 -0
  62. package/dist/coding/registry/report.d.ts +70 -8
  63. package/dist/coding/registry/report.js +112 -5
  64. package/dist/coding/registry/types.d.ts +58 -8
  65. package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
  66. package/dist/coding/registry/yarn-lockfile.js +367 -0
  67. package/dist/coding/services/catalog.d.ts +37 -351
  68. package/dist/coding/transcript/claude-code.d.ts +13 -0
  69. package/dist/coding/transcript/claude-code.js +273 -0
  70. package/dist/coding/transcript/download-protocol.d.ts +30 -0
  71. package/dist/coding/transcript/download-protocol.js +18 -0
  72. package/dist/coding/transcript/format.d.ts +20 -0
  73. package/dist/coding/transcript/format.js +32 -0
  74. package/dist/coding/transcript/recorder.d.ts +51 -0
  75. package/dist/coding/transcript/recorder.js +225 -0
  76. package/dist/coding/transcript/resume/checkout.d.ts +31 -0
  77. package/dist/coding/transcript/resume/checkout.js +203 -0
  78. package/dist/coding/transcript/resume/command.d.ts +17 -0
  79. package/dist/coding/transcript/resume/command.js +176 -0
  80. package/dist/coding/transcript/resume/download.d.ts +20 -0
  81. package/dist/coding/transcript/resume/download.js +153 -0
  82. package/dist/coding/transcript/resume/launch.d.ts +38 -0
  83. package/dist/coding/transcript/resume/launch.js +128 -0
  84. package/dist/coding/transcript/resume/session-file.d.ts +13 -0
  85. package/dist/coding/transcript/resume/session-file.js +79 -0
  86. package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
  87. package/dist/coding/transcript/resume/stand-in.js +49 -0
  88. package/dist/coding-worker/artifact.d.ts +16 -3
  89. package/dist/coding-worker/artifact.js +5 -3
  90. package/dist/coding-worker/debug-trace.d.ts +6 -5
  91. package/dist/coding-worker/debug-trace.js +13 -18
  92. package/dist/coding-worker/dependency-cache.d.mts +229 -0
  93. package/dist/coding-worker/dependency-cache.mjs +2123 -0
  94. package/dist/coding-worker/driver.d.ts +4 -3
  95. package/dist/coding-worker/driver.js +118 -38
  96. package/dist/coding-worker/errors.d.ts +1 -0
  97. package/dist/coding-worker/errors.js +32 -0
  98. package/dist/coding-worker/sdk.d.ts +6 -0
  99. package/dist/coding-worker/sdk.js +1 -0
  100. package/dist/coding-worker/skills.d.ts +23 -0
  101. package/dist/coding-worker/skills.js +117 -0
  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 +13 -0
  105. package/dist/config/dependency-cache.d.ts +23 -0
  106. package/dist/config/dependency-cache.js +32 -0
  107. package/dist/config/github-allowed-accounts.d.ts +15 -0
  108. package/dist/config/github-allowed-accounts.js +36 -0
  109. package/dist/config/low-power.d.ts +12 -0
  110. package/dist/config/low-power.js +18 -0
  111. package/dist/config/mobile.d.ts +12 -0
  112. package/dist/config/mobile.js +18 -0
  113. package/dist/config/providers.d.ts +65 -3
  114. package/dist/config/providers.js +147 -11
  115. package/dist/config/test-simulators.d.ts +82 -0
  116. package/dist/config/test-simulators.js +305 -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-queue.d.ts +2 -1
  130. package/dist/core/coding-queue.js +7 -0
  131. package/dist/core/cron.d.ts +19 -1
  132. package/dist/core/cron.js +17 -0
  133. package/dist/core/datastores.js +1 -1
  134. package/dist/core/db.d.ts +16 -6
  135. package/dist/core/db.js +12 -10
  136. package/dist/core/deferred-coding.d.ts +14 -0
  137. package/dist/core/deferred-coding.js +62 -0
  138. package/dist/core/delegation-child.d.ts +25 -0
  139. package/dist/core/delegation-child.js +37 -0
  140. package/dist/core/dispatch.d.ts +53 -0
  141. package/dist/core/dispatch.js +167 -57
  142. package/dist/core/engine-native.js +10 -6
  143. package/dist/core/error-code.d.ts +38 -0
  144. package/dist/core/error-code.js +168 -0
  145. package/dist/core/grants.d.ts +19 -6
  146. package/dist/core/grants.js +55 -6
  147. package/dist/core/host-events.d.ts +67 -5
  148. package/dist/core/host-events.js +571 -37
  149. package/dist/core/host-status.d.ts +85 -3
  150. package/dist/core/host-status.js +298 -20
  151. package/dist/core/issue-bridge.d.ts +50 -6
  152. package/dist/core/issue-bridge.js +151 -20
  153. package/dist/core/issue-events.d.ts +1 -1
  154. package/dist/core/issue-events.js +16 -11
  155. package/dist/core/issue-status.d.ts +1 -1
  156. package/dist/core/issue-status.js +68 -29
  157. package/dist/core/logger.d.ts +5 -0
  158. package/dist/core/logger.js +14 -1
  159. package/dist/core/lost-run-children.d.ts +6 -0
  160. package/dist/core/lost-run-children.js +32 -0
  161. package/dist/core/mark-ready.d.ts +34 -0
  162. package/dist/core/mark-ready.js +152 -0
  163. package/dist/core/markdown-code.d.ts +8 -0
  164. package/dist/core/markdown-code.js +107 -0
  165. package/dist/core/memory-tools.js +7 -0
  166. package/dist/core/merge-order-check.d.ts +130 -0
  167. package/dist/core/merge-order-check.js +343 -0
  168. package/dist/core/notification-dispatcher.d.ts +70 -0
  169. package/dist/core/notification-dispatcher.js +368 -0
  170. package/dist/core/notification-templates.d.ts +19 -0
  171. package/dist/core/notification-templates.js +139 -0
  172. package/dist/core/notifications.d.ts +10 -0
  173. package/dist/core/notifications.js +38 -0
  174. package/dist/core/pg-auth.d.ts +22 -0
  175. package/dist/core/pg-auth.js +152 -0
  176. package/dist/core/power-composition.d.ts +16 -0
  177. package/dist/core/power-composition.js +37 -0
  178. package/dist/core/power-idle.d.ts +14 -0
  179. package/dist/core/power-idle.js +30 -0
  180. package/dist/core/power.d.ts +71 -0
  181. package/dist/core/power.js +202 -0
  182. package/dist/core/pull-request-state-sync.js +2 -2
  183. package/dist/core/reconciler.d.ts +8 -5
  184. package/dist/core/reconciler.js +37 -6
  185. package/dist/core/related-pull-requests.d.ts +59 -7
  186. package/dist/core/related-pull-requests.js +140 -25
  187. package/dist/core/reply-parts.d.ts +21 -0
  188. package/dist/core/reply-parts.js +73 -0
  189. package/dist/core/repo-access.d.ts +15 -0
  190. package/dist/core/repo-access.js +66 -0
  191. package/dist/core/review-fix.d.ts +38 -1
  192. package/dist/core/review-fix.js +209 -7
  193. package/dist/core/review-host-checks.d.ts +1 -1
  194. package/dist/core/review-host-tools.d.ts +23 -0
  195. package/dist/core/review-host-tools.js +156 -14
  196. package/dist/core/review-reads.d.ts +55 -0
  197. package/dist/core/review-reads.js +233 -0
  198. package/dist/core/run-status.d.ts +12 -0
  199. package/dist/core/run-status.js +12 -0
  200. package/dist/core/runner.d.ts +384 -5
  201. package/dist/core/runner.js +1244 -372
  202. package/dist/core/schedule-start.d.ts +12 -0
  203. package/dist/core/schedule-start.js +14 -0
  204. package/dist/core/secret-broker-config.d.ts +39 -0
  205. package/dist/core/secret-broker-config.js +112 -0
  206. package/dist/core/secret-guard.d.ts +46 -0
  207. package/dist/core/secret-guard.js +104 -0
  208. package/dist/core/secret-guarded-stores.d.ts +12 -0
  209. package/dist/core/secret-guarded-stores.js +41 -0
  210. package/dist/core/secret-spans.d.ts +50 -0
  211. package/dist/core/secret-spans.js +94 -0
  212. package/dist/core/secrets.d.ts +39 -4
  213. package/dist/core/secrets.js +148 -40
  214. package/dist/core/stop-run.d.ts +46 -0
  215. package/dist/core/stop-run.js +61 -0
  216. package/dist/core/workflow-event-recorder.d.ts +14 -0
  217. package/dist/core/workflow-event-recorder.js +120 -0
  218. package/dist/core/workflow-events.d.ts +94 -0
  219. package/dist/core/workflow-events.js +48 -0
  220. package/dist/core/workflow-run-events.d.ts +18 -0
  221. package/dist/core/workflow-run-events.js +75 -0
  222. package/dist/core/zod-json-schema.d.ts +4 -0
  223. package/dist/core/zod-json-schema.js +39 -0
  224. package/dist/core/zod3-window.d.ts +35 -0
  225. package/dist/core/zod3-window.js +124 -0
  226. package/dist/generated/prisma/browser.d.ts +92 -3
  227. package/dist/generated/prisma/client.d.ts +92 -3
  228. package/dist/generated/prisma/commonInputTypes.d.ts +364 -54
  229. package/dist/generated/prisma/enums.d.ts +37 -0
  230. package/dist/generated/prisma/enums.js +31 -0
  231. package/dist/generated/prisma/internal/class.d.ts +132 -0
  232. package/dist/generated/prisma/internal/class.js +4 -4
  233. package/dist/generated/prisma/internal/prismaNamespace.d.ts +1332 -142
  234. package/dist/generated/prisma/internal/prismaNamespace.js +227 -5
  235. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +234 -0
  236. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +227 -5
  237. package/dist/generated/prisma/models/Agent.d.ts +464 -7
  238. package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
  239. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +301 -1
  240. package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
  241. package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
  242. package/dist/generated/prisma/models/CodingRun.d.ts +1841 -1
  243. package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
  244. package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
  245. package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
  246. package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
  247. package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
  248. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1713 -0
  249. package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
  250. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1551 -0
  251. package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
  252. package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
  253. package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
  254. package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
  255. package/dist/generated/prisma/models/NotificationChannel.js +1 -0
  256. package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
  257. package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
  258. package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
  259. package/dist/generated/prisma/models/NotificationThread.js +1 -0
  260. package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
  261. package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
  262. package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
  263. package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
  264. package/dist/generated/prisma/models/Run.d.ts +1619 -58
  265. package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
  266. package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
  267. package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
  268. package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
  269. package/dist/generated/prisma/models/RunTranscript.js +1 -0
  270. package/dist/generated/prisma/models/Secret.d.ts +37 -1
  271. package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
  272. package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
  273. package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
  274. package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
  275. package/dist/generated/prisma/models.d.ts +12 -0
  276. package/dist/help/build.js +4 -2
  277. package/dist/help/catalog.d.ts +1 -1
  278. package/dist/help/catalog.js +31 -6
  279. package/dist/help-index.json +2584 -146
  280. package/dist/import/create.js +49 -3
  281. package/dist/import/neutral-schema.d.ts +50 -277
  282. package/dist/import/neutral-schema.js +7 -4
  283. package/dist/knowledge/check.d.ts +1 -1
  284. package/dist/knowledge/cli.d.ts +11 -1
  285. package/dist/knowledge/cli.js +37 -4
  286. package/dist/knowledge/concept.d.ts +3 -19
  287. package/dist/knowledge/location.d.ts +31 -0
  288. package/dist/knowledge/location.js +78 -0
  289. package/dist/mcp/auth/access.d.ts +11 -2
  290. package/dist/mcp/auth/access.js +15 -1
  291. package/dist/mcp/auth/ownership.d.ts +7 -7
  292. package/dist/mcp/auth/repo-authorization.js +14 -0
  293. package/dist/mcp/auth/resource-server.d.ts +2 -1
  294. package/dist/mcp/auth/resource-server.js +7 -2
  295. package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
  296. package/dist/mcp/auth/self-hosted/browser.js +19 -6
  297. package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
  298. package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
  299. package/dist/mcp/context.d.ts +6 -0
  300. package/dist/mcp/host-events/github-ingress.d.ts +25 -1
  301. package/dist/mcp/host-events/github-ingress.js +70 -1
  302. package/dist/mcp/index.d.ts +19 -0
  303. package/dist/mcp/index.js +117 -20
  304. package/dist/mcp/server.d.ts +13 -0
  305. package/dist/mcp/server.js +33 -14
  306. package/dist/mcp/tools/agents.d.ts +4 -0
  307. package/dist/mcp/tools/agents.js +277 -24
  308. package/dist/mcp/tools/datastore.js +17 -8
  309. package/dist/mcp/tools/grants.js +9 -3
  310. package/dist/mcp/tools/memory.js +11 -1
  311. package/dist/mcp/tools/notification-channels.d.ts +2 -0
  312. package/dist/mcp/tools/notification-channels.js +293 -0
  313. package/dist/mcp/tools/packages.d.ts +2 -0
  314. package/dist/mcp/tools/packages.js +195 -0
  315. package/dist/mcp/tools/power.d.ts +2 -0
  316. package/dist/mcp/tools/power.js +77 -0
  317. package/dist/mcp/tools/repositories.js +18 -5
  318. package/dist/mcp/tools/run-access.d.ts +16 -0
  319. package/dist/mcp/tools/run-access.js +25 -0
  320. package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
  321. package/dist/mcp/tools/run-transcript-download.js +129 -0
  322. package/dist/mcp/tools/run-transcript.d.ts +19 -0
  323. package/dist/mcp/tools/run-transcript.js +70 -0
  324. package/dist/mcp/tools/runs.d.ts +0 -6
  325. package/dist/mcp/tools/runs.js +41 -14
  326. package/dist/mcp/tools/scheduling.js +3 -1
  327. package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
  328. package/dist/mcp/tools/secret-broker-compat.js +23 -0
  329. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
  330. package/dist/mcp/tools/secret-elicitation-form.js +205 -10
  331. package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
  332. package/dist/mcp/tools/secret-elicitation-server.js +10 -54
  333. package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
  334. package/dist/mcp/tools/secret-elicitation.js +110 -12
  335. package/dist/mcp/tools/secrets.js +186 -9
  336. package/dist/mcp/tools/stop-run.d.ts +2 -0
  337. package/dist/mcp/tools/stop-run.js +82 -0
  338. package/dist/mcp/tools/subagents.js +2 -2
  339. package/dist/mcp/tools/tools.d.ts +2 -2
  340. package/dist/mcp/tools/tools.js +47 -11
  341. package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
  342. package/dist/mcp/transport/stdio-link-host.js +67 -0
  343. package/dist/mcp/transport/streamable-http.d.ts +13 -0
  344. package/dist/mcp/transport/streamable-http.js +41 -1
  345. package/dist/native-worker/composition.d.ts +23 -0
  346. package/dist/native-worker/composition.js +77 -0
  347. package/dist/native-worker/docker-isolation.d.ts +65 -0
  348. package/dist/native-worker/docker-isolation.js +183 -0
  349. package/dist/native-worker/docker-launcher.d.ts +110 -0
  350. package/dist/native-worker/docker-launcher.js +297 -0
  351. package/dist/native-worker/gateway-server.d.ts +77 -0
  352. package/dist/native-worker/gateway-server.js +412 -0
  353. package/dist/native-worker/gateway.d.ts +70 -0
  354. package/dist/native-worker/gateway.js +263 -0
  355. package/dist/native-worker/http-server.d.ts +24 -0
  356. package/dist/native-worker/http-server.js +113 -0
  357. package/dist/native-worker/http-transport.d.ts +17 -0
  358. package/dist/native-worker/http-transport.js +88 -0
  359. package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
  360. package/dist/native-worker/kubernetes-isolation.js +218 -0
  361. package/dist/native-worker/kubernetes-launcher.d.ts +106 -0
  362. package/dist/native-worker/kubernetes-launcher.js +375 -0
  363. package/dist/native-worker/launch.d.ts +62 -0
  364. package/dist/native-worker/launch.js +49 -0
  365. package/dist/native-worker/ledger.d.ts +125 -0
  366. package/dist/native-worker/ledger.js +245 -0
  367. package/dist/native-worker/loopback.d.ts +12 -0
  368. package/dist/native-worker/loopback.js +44 -0
  369. package/dist/native-worker/main.d.ts +8 -0
  370. package/dist/native-worker/main.js +85 -0
  371. package/dist/native-worker/protocol.d.ts +296 -0
  372. package/dist/native-worker/protocol.js +246 -0
  373. package/dist/native-worker/sandbox-executor.d.ts +83 -0
  374. package/dist/native-worker/sandbox-executor.js +284 -0
  375. package/dist/native-worker/stderr-redaction.d.ts +77 -0
  376. package/dist/native-worker/stderr-redaction.js +237 -0
  377. package/dist/native-worker/stdio.d.ts +29 -0
  378. package/dist/native-worker/stdio.js +189 -0
  379. package/dist/native-worker/warm-delivery.d.ts +16 -0
  380. package/dist/native-worker/warm-delivery.js +33 -0
  381. package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
  382. package/dist/native-worker/warm-pool-ledger.js +73 -0
  383. package/dist/native-worker/warm-pool.d.ts +107 -0
  384. package/dist/native-worker/warm-pool.js +283 -0
  385. package/dist/native-worker/worker.d.ts +17 -0
  386. package/dist/native-worker/worker.js +141 -0
  387. package/dist/observability/metrics.js +6 -1
  388. package/dist/providers/auth/authorization-server.d.ts +3 -0
  389. package/dist/providers/auth/index.js +2 -0
  390. package/dist/providers/auth/self-hosted.d.ts +14 -2
  391. package/dist/providers/auth/self-hosted.js +54 -4
  392. package/dist/providers/chat/fake.d.ts +46 -0
  393. package/dist/providers/chat/fake.js +39 -0
  394. package/dist/providers/chat/index.d.ts +4 -0
  395. package/dist/providers/chat/index.js +8 -0
  396. package/dist/providers/chat/slack.d.ts +37 -0
  397. package/dist/providers/chat/slack.js +105 -0
  398. package/dist/providers/chat/types.d.ts +42 -0
  399. package/dist/providers/chat/types.js +19 -0
  400. package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
  401. package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
  402. package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
  403. package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
  404. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
  405. package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
  406. package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
  407. package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
  408. package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
  409. package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
  410. package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
  411. package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
  412. package/dist/providers/coding-proxy/hold.d.ts +32 -0
  413. package/dist/providers/coding-proxy/hold.js +86 -0
  414. package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
  415. package/dist/providers/coding-proxy/interrupted.js +104 -0
  416. package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
  417. package/dist/providers/coding-proxy/memory-ledger.js +84 -8
  418. package/dist/providers/coding-proxy/metering.d.ts +16 -0
  419. package/dist/providers/coding-proxy/metering.js +27 -4
  420. package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
  421. package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
  422. package/dist/providers/coding-proxy/proxy.d.ts +14 -1
  423. package/dist/providers/coding-proxy/proxy.js +166 -14
  424. package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
  425. package/dist/providers/coding-proxy/registry/audit.js +94 -17
  426. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
  427. package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
  428. package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
  429. package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
  430. package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
  431. package/dist/providers/coding-proxy/registry/plan.js +201 -48
  432. package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
  433. package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
  434. package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
  435. package/dist/providers/coding-proxy/registry/service.js +579 -112
  436. package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
  437. package/dist/providers/coding-proxy/registry/store.js +54 -1
  438. package/dist/providers/coding-proxy/runtime.d.ts +4 -0
  439. package/dist/providers/coding-proxy/runtime.js +78 -16
  440. package/dist/providers/coding-proxy/server.d.ts +6 -1
  441. package/dist/providers/coding-proxy/server.js +45 -1
  442. package/dist/providers/coding-proxy/types.d.ts +65 -1
  443. package/dist/providers/datastore/types.d.ts +5 -0
  444. package/dist/providers/engine/types.d.ts +36 -2
  445. package/dist/providers/engine/types.js +39 -0
  446. package/dist/providers/executor/composition.d.ts +31 -1
  447. package/dist/providers/executor/composition.js +81 -8
  448. package/dist/providers/executor/container.d.ts +385 -9
  449. package/dist/providers/executor/container.js +1234 -99
  450. package/dist/providers/executor/dbos-status.d.ts +31 -0
  451. package/dist/providers/executor/dbos-status.js +64 -0
  452. package/dist/providers/executor/dbos.d.ts +91 -0
  453. package/dist/providers/executor/dbos.js +319 -26
  454. package/dist/providers/executor/deferred.d.ts +44 -0
  455. package/dist/providers/executor/deferred.js +100 -0
  456. package/dist/providers/executor/in-process.d.ts +9 -1
  457. package/dist/providers/executor/in-process.js +14 -4
  458. package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
  459. package/dist/providers/executor/linked-issue-reader.js +30 -0
  460. package/dist/providers/executor/routing.d.ts +39 -10
  461. package/dist/providers/executor/routing.js +77 -32
  462. package/dist/providers/executor/types.d.ts +25 -0
  463. package/dist/providers/index.d.ts +2 -1
  464. package/dist/providers/issue-tracker/types.d.ts +17 -0
  465. package/dist/providers/issue-tracker/types.js +39 -1
  466. package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
  467. package/dist/providers/jobs/claude-tool-setup.js +5 -2
  468. package/dist/providers/jobs/docker-isolation.d.ts +8 -0
  469. package/dist/providers/jobs/docker-isolation.js +17 -0
  470. package/dist/providers/jobs/docker.d.ts +1 -0
  471. package/dist/providers/jobs/docker.js +29 -4
  472. package/dist/providers/jobs/fake-kubernetes-api.d.ts +23 -2
  473. package/dist/providers/jobs/fake-kubernetes-api.js +45 -1
  474. package/dist/providers/jobs/kubernetes-api.d.ts +25 -1
  475. package/dist/providers/jobs/kubernetes-api.js +17 -0
  476. package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
  477. package/dist/providers/jobs/kubernetes-client.js +61 -3
  478. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
  479. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
  480. package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
  481. package/dist/providers/jobs/kubernetes-isolation.js +23 -1
  482. package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
  483. package/dist/providers/jobs/kubernetes-platform.js +38 -1
  484. package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
  485. package/dist/providers/jobs/kubernetes-preflight.js +4 -2
  486. package/dist/providers/jobs/kubernetes.d.ts +42 -2
  487. package/dist/providers/jobs/kubernetes.js +178 -19
  488. package/dist/providers/jobs/metadata-probes.d.ts +11 -0
  489. package/dist/providers/jobs/metadata-probes.js +13 -0
  490. package/dist/providers/jobs/types.d.ts +42 -0
  491. package/dist/providers/jobs/types.js +13 -1
  492. package/dist/providers/llm/anthropic.js +5 -1
  493. package/dist/providers/llm/bedrock.d.ts +0 -12
  494. package/dist/providers/llm/bedrock.js +4 -0
  495. package/dist/providers/llm/claude-messages.d.ts +3 -1
  496. package/dist/providers/llm/claude-messages.js +4 -1
  497. package/dist/providers/llm/claude-provider.d.ts +2 -2
  498. package/dist/providers/llm/claude-provider.js +2 -2
  499. package/dist/providers/llm/openai.d.ts +2 -2
  500. package/dist/providers/llm/openai.js +6 -2
  501. package/dist/providers/llm/routing.d.ts +2 -2
  502. package/dist/providers/llm/routing.js +2 -2
  503. package/dist/providers/llm/types.d.ts +12 -2
  504. package/dist/providers/review-host/github-events.d.ts +9 -1
  505. package/dist/providers/review-host/github-events.js +34 -12
  506. package/dist/providers/review-host/github.d.ts +39 -2
  507. package/dist/providers/review-host/github.js +274 -29
  508. package/dist/providers/review-host/local.d.ts +8 -4
  509. package/dist/providers/review-host/local.js +49 -31
  510. package/dist/providers/review-host/patch-pages.d.ts +41 -0
  511. package/dist/providers/review-host/patch-pages.js +176 -0
  512. package/dist/providers/review-host/review-format.d.ts +19 -1
  513. package/dist/providers/review-host/review-format.js +38 -7
  514. package/dist/providers/review-host/types.d.ts +157 -2
  515. package/dist/providers/review-host/types.js +8 -0
  516. package/dist/providers/storage/gcs.d.ts +63 -0
  517. package/dist/providers/storage/gcs.js +69 -0
  518. package/dist/providers/storage/index.d.ts +15 -0
  519. package/dist/providers/storage/index.js +14 -0
  520. package/dist/providers/storage/local.d.ts +24 -0
  521. package/dist/providers/storage/local.js +92 -0
  522. package/dist/providers/storage/meter.d.ts +14 -0
  523. package/dist/providers/storage/meter.js +34 -0
  524. package/dist/providers/storage/s3.d.ts +41 -0
  525. package/dist/providers/storage/s3.js +107 -0
  526. package/dist/providers/storage/types.d.ts +37 -3
  527. package/dist/providers/storage/types.js +21 -4
  528. package/dist/providers/vcs/git.d.ts +33 -2
  529. package/dist/providers/vcs/git.js +324 -22
  530. package/dist/providers/vcs/github-remote.d.ts +26 -3
  531. package/dist/providers/vcs/github-remote.js +124 -14
  532. package/dist/providers/vcs/github.d.ts +246 -12
  533. package/dist/providers/vcs/github.js +521 -61
  534. package/dist/providers/vcs/index.js +8 -1
  535. package/dist/providers/vcs/pr-description.d.ts +127 -0
  536. package/dist/providers/vcs/pr-description.js +270 -0
  537. package/dist/providers/vcs/remote.d.ts +33 -1
  538. package/dist/providers/vcs/routing.d.ts +4 -2
  539. package/dist/providers/vcs/routing.js +6 -0
  540. package/dist/providers/vcs/types.d.ts +80 -3
  541. package/dist/quickstart/coding-seed.d.ts +21 -3
  542. package/dist/quickstart/coding-seed.js +283 -3
  543. package/dist/quickstart/images.d.ts +2 -0
  544. package/dist/quickstart/images.js +7 -1
  545. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  546. package/dist/quickstart/reviewer-prompt.js +6 -6
  547. package/dist/quickstart-images.json +1 -1
  548. package/dist/sandbox/brokered-fetch.d.ts +23 -0
  549. package/dist/sandbox/brokered-fetch.js +37 -0
  550. package/dist/sandbox/generated/zod.bundle.js +62 -1
  551. package/dist/sandbox/generated/zod3.bundle.js +5 -0
  552. package/dist/sandbox/host-functions.d.ts +35 -0
  553. package/dist/sandbox/host-functions.js +150 -91
  554. package/dist/sandbox/prelude.js +7 -1
  555. package/dist/sandbox/run-in-sandbox.d.ts +19 -0
  556. package/dist/sandbox/run-in-sandbox.js +28 -10
  557. package/dist/sandbox/safe-fetch.d.ts +2 -0
  558. package/dist/sandbox/safe-fetch.js +3 -1
  559. package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
  560. package/dist/sandbox/secret-broker-sigv4.js +49 -0
  561. package/dist/sandbox/secret-broker.d.ts +34 -0
  562. package/dist/sandbox/secret-broker.js +161 -0
  563. package/dist/sandbox/tool-capabilities.d.ts +10 -30
  564. package/dist/sandbox/user-tool.d.ts +14 -0
  565. package/dist/sandbox/user-tool.js +32 -0
  566. package/dist/sandbox/zod-params.d.ts +37 -5
  567. package/dist/sandbox/zod-params.js +181 -26
  568. package/dist/serve.js +25 -0
  569. package/dist/viewer/api-schema.d.ts +372 -2454
  570. package/dist/viewer/api-schema.js +29 -0
  571. package/dist/viewer/build-schemas.js +10 -3
  572. package/dist/viewer/event-bus.d.ts +6 -0
  573. package/dist/viewer/event-bus.js +16 -7
  574. package/dist/viewer/graph.d.ts +5 -2
  575. package/dist/viewer/graph.js +7 -2
  576. package/dist/viewer/http.d.ts +0 -1
  577. package/dist/viewer/http.js +2 -2
  578. package/dist/viewer/infra.js +25 -2
  579. package/dist/viewer/limits.d.ts +4 -0
  580. package/dist/viewer/limits.js +4 -0
  581. package/dist/viewer/openapi.d.ts +15 -0
  582. package/dist/viewer/openapi.js +170 -0
  583. package/dist/wardby-bin.js +10 -0
  584. package/docs/README.md +7 -0
  585. package/docs/agent-recipes.md +114 -27
  586. package/docs/architecture-runtime.md +16 -1
  587. package/docs/code-review-agents.md +689 -45
  588. package/docs/coding-agent-setup.md +602 -12
  589. package/docs/coding-packages.md +1037 -92
  590. package/docs/coding-services.md +30 -13
  591. package/docs/coding-worker-byo-images.md +218 -6
  592. package/docs/coding-worker-isolation.md +173 -44
  593. package/docs/getting-started-gke.md +332 -129
  594. package/docs/getting-started-identity-provider.md +31 -11
  595. package/docs/getting-started.md +14 -4
  596. package/docs/jira-agents.md +22 -9
  597. package/docs/knowledge/blob-not-found-semantics.md +41 -0
  598. package/docs/knowledge/bounded-file-descriptor.md +52 -0
  599. package/docs/knowledge/delegation-admission-slots.md +52 -0
  600. package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
  601. package/docs/knowledge/import-rename-target.md +52 -0
  602. package/docs/knowledge/index.md +57 -0
  603. package/docs/knowledge/log.md +9 -0
  604. package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
  605. package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
  606. package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
  607. package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
  608. package/docs/knowledge/overview-cli.md +74 -0
  609. package/docs/knowledge/overview-coding-proxy.md +72 -0
  610. package/docs/knowledge/overview-coding.md +72 -0
  611. package/docs/knowledge/overview-config.md +60 -0
  612. package/docs/knowledge/overview-core.md +72 -0
  613. package/docs/knowledge/overview-deploy.md +83 -0
  614. package/docs/knowledge/overview-mcp.md +61 -0
  615. package/docs/knowledge/overview-prisma.md +72 -0
  616. package/docs/knowledge/overview-providers.md +89 -0
  617. package/docs/knowledge/overview-sandbox.md +83 -0
  618. package/docs/knowledge/overview-surfaces.md +83 -0
  619. package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
  620. package/docs/knowledge/proxy-settlement-projections.md +41 -0
  621. package/docs/knowledge/run-pricing-first-writer.md +43 -0
  622. package/docs/knowledge/schedule-claim-transaction.md +41 -0
  623. package/docs/knowledge/secret-entry-replica-contract.md +52 -0
  624. package/docs/knowledge/terminal-run-first-writer.md +41 -0
  625. package/docs/knowledge/transactional-agent-authorization.md +52 -0
  626. package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
  627. package/docs/knowledge/warm-input-publication.md +30 -0
  628. package/docs/knowledge/workspace-staging-failure.md +54 -0
  629. package/docs/knowledge.md +54 -14
  630. package/docs/native-sandbox.md +731 -0
  631. package/docs/observability.md +4 -0
  632. package/docs/release-verification.md +9 -0
  633. package/docs/security-deployment.md +146 -14
  634. package/docs/slack-notifications.md +268 -0
  635. package/docs/tool-secrets.md +284 -0
  636. package/docs/viewer-api.md +46 -5
  637. package/docs/viewer-api.openapi.yml +1404 -0
  638. package/help/admin-viewer.md +29 -3
  639. package/help/agent-recipes.md +27 -0
  640. package/help/architecture-agent.md +11 -6
  641. package/help/brokered-secrets.md +79 -0
  642. package/help/build-claude-code-image.md +131 -0
  643. package/help/build-worker-image.md +6 -7
  644. package/help/builder-agent.md +19 -6
  645. package/help/code-review-agents.md +243 -10
  646. package/help/coding-packages.md +156 -6
  647. package/help/cost-attribution.md +9 -5
  648. package/help/creating-agents.md +14 -1
  649. package/help/dependency-cache.md +143 -0
  650. package/help/deploy-gke.md +23 -9
  651. package/help/deployment-targets.md +25 -14
  652. package/help/errors/budget-exhausted.md +187 -0
  653. package/help/errors/budget-group-exhausted.md +5 -1
  654. package/help/errors/coding-provider-not-configured.md +2 -2
  655. package/help/errors/coding-stream-quota-exceeded.md +33 -0
  656. package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
  657. package/help/errors/continuation-closed.md +9 -12
  658. package/help/errors/database-auth-invalid.md +28 -0
  659. package/help/errors/delegation-conflict.md +24 -0
  660. package/help/errors/file-list-truncated.md +45 -0
  661. package/help/errors/full-read-required.md +49 -0
  662. package/help/errors/github-account-not-allowed.md +29 -0
  663. package/help/errors/graph-incomplete.md +43 -0
  664. package/help/errors/graph-limit.md +43 -0
  665. package/help/errors/low-power-disabled.md +29 -0
  666. package/help/errors/low-power-scale-forbidden.md +35 -0
  667. package/help/errors/low-power-wake-timeout.md +30 -0
  668. package/help/errors/merge-conflict.md +49 -0
  669. package/help/errors/mobile-disabled.md +31 -0
  670. package/help/errors/native-sandbox-capacity.md +22 -0
  671. package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
  672. package/help/errors/native-sandbox-docker-failed.md +20 -0
  673. package/help/errors/native-sandbox-gateway-error.md +20 -0
  674. package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
  675. package/help/errors/native-sandbox-image-not-pinned.md +19 -0
  676. package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
  677. package/help/errors/native-sandbox-launch-abandoned.md +21 -0
  678. package/help/errors/native-sandbox-network-unenforced.md +22 -0
  679. package/help/errors/native-sandbox-requires-catalog.md +31 -0
  680. package/help/errors/native-sandbox-unavailable.md +19 -0
  681. package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
  682. package/help/errors/native-sandbox-worker-exited.md +21 -0
  683. package/help/errors/native-sandbox-worker-lost.md +20 -0
  684. package/help/errors/native-sandbox-worker-unready.md +22 -0
  685. package/help/errors/package-not-allowed-pending.md +52 -0
  686. package/help/errors/package-not-allowed.md +51 -0
  687. package/help/errors/package-refusals.md +43 -0
  688. package/help/errors/patch-cursor-malformed.md +31 -0
  689. package/help/errors/run-lost.md +39 -0
  690. package/help/errors/run-transcript-download.md +44 -0
  691. package/help/errors/secret-broker-body-invalid.md +26 -0
  692. package/help/errors/secret-broker-changed.md +20 -0
  693. package/help/errors/secret-broker-config-invalid.md +30 -0
  694. package/help/errors/secret-broker-conflict.md +27 -0
  695. package/help/errors/secret-broker-destination-denied.md +28 -0
  696. package/help/errors/secret-broker-value-invalid.md +28 -0
  697. package/help/errors/secret-brokered.md +24 -0
  698. package/help/errors/secret-in-value.md +69 -0
  699. package/help/errors/secret-not-brokered.md +25 -0
  700. package/help/errors/slack-auth-failed.md +48 -0
  701. package/help/errors/slack-channel-unreachable.md +39 -0
  702. package/help/errors/slack-not-configured.md +33 -0
  703. package/help/errors/target-merge.md +40 -0
  704. package/help/fix-merge-conflicts.md +73 -0
  705. package/help/getting-started.md +4 -5
  706. package/help/github-app-setup.md +132 -0
  707. package/help/github.md +40 -1
  708. package/help/identity-and-access.md +7 -1
  709. package/help/jira.md +23 -6
  710. package/help/knowledge.md +16 -7
  711. package/help/local-repositories.md +3 -4
  712. package/help/low-power-mode.md +131 -0
  713. package/help/merge-order-check.md +122 -0
  714. package/help/mobile-app.md +54 -0
  715. package/help/native-capabilities.md +29 -1
  716. package/help/native-sandbox.md +150 -0
  717. package/help/observability.md +8 -0
  718. package/help/operating-agents.md +5 -0
  719. package/help/package-audit-mode.md +91 -0
  720. package/help/related-pull-requests.md +80 -16
  721. package/help/repo-instructions-and-skills.md +91 -0
  722. package/help/resume-runs-locally.md +131 -0
  723. package/help/review-fix-rounds.md +43 -1
  724. package/help/sharing-agents.md +59 -0
  725. package/help/slack-notifications.md +76 -0
  726. package/help/status-comments.md +31 -0
  727. package/help/stop-run.md +58 -0
  728. package/help/troubleshooting/budgets.md +28 -0
  729. package/help/troubleshooting/coding-workers.md +99 -7
  730. package/package.json +27 -13
  731. package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
  732. package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
  733. package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
  734. package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
  735. package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
  736. package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
  737. package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
  738. package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
  739. package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
  740. package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
  741. package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
  742. package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
  743. package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
  744. package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
  745. package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
  746. package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
  747. package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
  748. package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
  749. package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
  750. package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
  751. package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
  752. package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
  753. package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
  754. package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
  755. package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
  756. package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
  757. package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
  758. package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
  759. package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
  760. package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
  761. package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
  762. package/prisma/schema.prisma +631 -146
  763. package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
@@ -0,0 +1,283 @@
1
+ /**
2
+ * The native sandbox warm pool (phase 6, docs/native-sandbox.md): up to NATIVE_SANDBOX_WARM_POOL_SIZE
3
+ * idle workers, each already isolated (on Kubernetes: attested and probed from inside), holding no
4
+ * run data and no capability. A run claims one with a compare-and-swap on its row
5
+ * (warm-pool-ledger.ts), its input arrives by exec only after the claim, and the worker is
6
+ * destroyed after that one run like any other. With no idle worker, or any doubt about the one it
7
+ * claimed, a run cold-launches exactly as without a pool.
8
+ *
9
+ * Maintenance runs in the process that calls the executor's `launch()`: every tick it reaps rows
10
+ * whose runs have ended, retires idle workers that are too old, of another spec, gone, or over the
11
+ * size (only ever unclaimed ones), and replenishes the deficit. Claims work from any process.
12
+ */
13
+ import { randomBytes } from "node:crypto";
14
+ import { logger } from "../core/logger.js";
15
+ import { nativeWarmWorkerName } from "./docker-isolation.js";
16
+ const poolLog = logger.child({ module: "native-warm-pool" });
17
+ export const NATIVE_SANDBOX_WARM_DELIVERY_FAILED = "native_sandbox_warm_delivery_failed";
18
+ /** A pool worker waits this much longer than the max age, so a claim never meets one about to exit. */
19
+ const WAIT_MARGIN_MS = 5 * 60_000;
20
+ /** How long another configuration's idle worker is left alone before it is retired (rolling updates). */
21
+ const OTHER_SPEC_GRACE_MS = 60_000;
22
+ /** How long a removed worker that may hold a capability has to be confirmed gone before a cold launch. */
23
+ const GONE_TIMEOUT_MS = 30_000;
24
+ const runEnded = (status) => status !== "pending" && status !== "running";
25
+ /** A ManagedWorkerLauncher that hands a run a warm worker when it can, and cold-launches otherwise. */
26
+ export class PooledWorkerLauncher {
27
+ options;
28
+ networkReadyAtLaunch;
29
+ waitMs;
30
+ specHash;
31
+ timer;
32
+ ticking;
33
+ /** The one pass queued behind a running one: a tick asked for mid-pass sees state from after the ask. */
34
+ queued;
35
+ warming = new Set();
36
+ /** Tokens this process is still starting: never reaped as abandoned, however slow. */
37
+ warmingHere = new Set();
38
+ /** The first pass (orphan sweep included) has run. */
39
+ swept = false;
40
+ constructor(options) {
41
+ this.options = options;
42
+ this.networkReadyAtLaunch = options.launcher.networkReadyAtLaunch;
43
+ this.waitMs = options.maxAgeMs + WAIT_MARGIN_MS;
44
+ this.specHash = options.launcher.warmSpecHash(this.waitMs);
45
+ }
46
+ get cold() {
47
+ return this.options.launcher;
48
+ }
49
+ now() {
50
+ return this.options.now?.() ?? Date.now();
51
+ }
52
+ sleep(ms) {
53
+ return (this.options.sleep ?? ((t) => new Promise((resolve) => setTimeout(resolve, t))))(ms);
54
+ }
55
+ async launch(input, launchOptions) {
56
+ const runId = input.runId;
57
+ const claimed = this.options.size > 0
58
+ ? await this.options.ledger
59
+ .claim(runId, this.specHash, new Date(this.now() - this.options.maxAgeMs))
60
+ .catch((err) => {
61
+ poolLog.warn({ err, runId }, "warm pool claim failed; launching cold");
62
+ return null;
63
+ })
64
+ : null;
65
+ if (!claimed) {
66
+ if (this.options.size > 0)
67
+ poolLog.info({ runId, event: "miss" }, "no idle warm worker; launching cold");
68
+ this.nudge();
69
+ return this.cold.launch(input, launchOptions);
70
+ }
71
+ const token = claimed.id;
72
+ this.nudge();
73
+ const intact = await this.cold.reattestWarm(token, this.waitMs).catch(() => false);
74
+ if (!intact) {
75
+ poolLog.warn({ runId, worker: claimed.name, event: "fallback" }, "claimed warm worker failed re-attest");
76
+ await this.discard(token);
77
+ return this.cold.launch(input, launchOptions);
78
+ }
79
+ try {
80
+ await this.cold.deliver(token, input);
81
+ }
82
+ catch (err) {
83
+ // The worker may hold the capability now: it must be gone before another worker gets it.
84
+ poolLog.warn({ err, runId, worker: claimed.name, event: "fallback" }, "warm delivery failed");
85
+ await this.cold.removeWarm(token).catch(() => { });
86
+ const gone = await this.confirmGone(token);
87
+ if (!gone) {
88
+ throw new Error(`${NATIVE_SANDBOX_WARM_DELIVERY_FAILED}: the run's input could not be delivered to its warm worker, which could not be confirmed stopped.`, { cause: err });
89
+ }
90
+ await this.options.ledger.remove(token);
91
+ return this.cold.launch(input, launchOptions);
92
+ }
93
+ if (this.networkReadyAtLaunch === false)
94
+ await this.options.onDelivered?.(runId);
95
+ poolLog.info({ runId, worker: claimed.name, event: "claimed" }, "run claimed a warm worker");
96
+ return this.cold.warmHandle(token);
97
+ }
98
+ async confirmGone(token) {
99
+ const until = this.now() + GONE_TIMEOUT_MS;
100
+ for (;;) {
101
+ const state = await this.cold.inspectWarm(token).catch(() => undefined);
102
+ if (state?.state === "missing")
103
+ return true;
104
+ if (this.now() >= until)
105
+ return false;
106
+ await this.sleep(1_000);
107
+ }
108
+ }
109
+ /** Removes a pool worker and its row. */
110
+ async discard(token) {
111
+ await this.cold.removeWarm(token).catch((err) => {
112
+ poolLog.warn({ err, token }, "removing a warm worker failed; the next tick retries");
113
+ });
114
+ await this.options.ledger.remove(token);
115
+ }
116
+ async claimedToken(runId) {
117
+ return (await this.options.ledger.forRun(runId))?.id;
118
+ }
119
+ handle(runId) {
120
+ const token = this.claimedToken(runId);
121
+ const handle = token.then((t) => (t ? this.cold.warmHandle(t) : this.cold.handle(runId)));
122
+ return {
123
+ exited: handle.then((h) => h.exited),
124
+ kill: () => void handle.then((h) => h.kill()),
125
+ };
126
+ }
127
+ async inspect(runId) {
128
+ const token = await this.claimedToken(runId);
129
+ return token ? this.cold.inspectWarm(token) : this.cold.inspect(runId);
130
+ }
131
+ async kill(runId) {
132
+ const token = await this.claimedToken(runId);
133
+ return token ? this.cold.killWarm(token) : this.cold.kill(runId);
134
+ }
135
+ async remove(runId) {
136
+ const token = await this.claimedToken(runId);
137
+ if (!token)
138
+ return this.cold.remove(runId);
139
+ await this.cold.removeWarm(token);
140
+ await this.options.ledger.remove(token);
141
+ }
142
+ listWorkers() {
143
+ return this.cold.listWorkers();
144
+ }
145
+ removeByWorkerName(name) {
146
+ return this.cold.removeByWorkerName(name);
147
+ }
148
+ get resolveGatewayUrl() {
149
+ return this.cold.resolveGatewayUrl?.bind(this.cold);
150
+ }
151
+ /**
152
+ * Starts maintenance: one pass now, then one every interval. At size 0 a pass is a single count
153
+ * of pool rows until one appears: a replica still running a bigger size during a rolling update
154
+ * can refill the pool after this replica's first pass, and only a later pass retires those.
155
+ */
156
+ async start() {
157
+ await this.tick();
158
+ this.swept = true;
159
+ if (!this.timer) {
160
+ this.timer = setInterval(() => this.nudge(), this.options.intervalMs ?? 15_000);
161
+ this.timer.unref?.();
162
+ }
163
+ }
164
+ stop() {
165
+ if (this.timer)
166
+ clearInterval(this.timer);
167
+ this.timer = undefined;
168
+ }
169
+ /** Asks for a pass soon, only in the process running maintenance: a short-lived CLI never warms workers. */
170
+ nudge() {
171
+ if (this.timer)
172
+ void this.tick();
173
+ }
174
+ /** One maintenance pass; resolves once reaping and retiring are done (warming continues behind it). */
175
+ tick() {
176
+ if (this.ticking) {
177
+ this.queued ??= this.ticking.then(() => {
178
+ this.queued = undefined;
179
+ return this.tick();
180
+ });
181
+ return this.queued;
182
+ }
183
+ this.ticking = this.maintain()
184
+ .catch((err) => poolLog.warn({ err }, "warm pool maintenance failed"))
185
+ .finally(() => {
186
+ this.ticking = undefined;
187
+ });
188
+ return this.ticking;
189
+ }
190
+ /** Resolves once every worker this process is warming has settled (tests, shutdown). */
191
+ async settled() {
192
+ while (this.warming.size > 0)
193
+ await Promise.allSettled([...this.warming]);
194
+ }
195
+ async maintain() {
196
+ const { ledger, size } = this.options;
197
+ // With no pool configured, a pass costs one count until another replica leaves rows behind.
198
+ if (size === 0 && this.swept && (await ledger.count()) === 0)
199
+ return;
200
+ // Listed before the rows are read: a row always exists before its worker, so a worker listed
201
+ // here with no row below is an orphan, never one another replica is still creating.
202
+ const live = new Set(await this.cold.listWarm());
203
+ const rows = await ledger.workers();
204
+ const now = this.now();
205
+ const bornAfter = now - this.options.maxAgeMs;
206
+ const keepIdle = [];
207
+ for (const row of rows) {
208
+ live.delete(row.id);
209
+ if (row.status === "claimed") {
210
+ if (!row.run || runEnded(row.run.status))
211
+ await this.discard(row.id);
212
+ }
213
+ else if (row.status === "warming") {
214
+ if (row.createdAt.getTime() < now - this.options.warmTimeoutMs - 60_000 && !this.warmingHere.has(row.id)) {
215
+ await this.discard(row.id);
216
+ poolLog.info({ worker: row.name, event: "reaped" }, "abandoned warming worker removed");
217
+ }
218
+ }
219
+ else if (row.status === "retiring") {
220
+ await this.discard(row.id);
221
+ }
222
+ else if (row.specHash !== this.specHash) {
223
+ // Another configuration's worker is never claimed here. It is retired once it is past the
224
+ // grace, not at once: during a rolling update the old and new replicas would otherwise
225
+ // retire each other's fresh workers and refill their own, over and over.
226
+ if (row.createdAt.getTime() < now - OTHER_SPEC_GRACE_MS)
227
+ await this.retire(row, "stale");
228
+ }
229
+ else {
230
+ const stale = row.createdAt.getTime() <= bornAfter;
231
+ const running = !stale && (await this.cold.inspectWarm(row.id).catch(() => undefined))?.state === "running";
232
+ if (running)
233
+ keepIdle.push(row);
234
+ else
235
+ await this.retire(row, stale ? "stale" : "gone");
236
+ }
237
+ }
238
+ // Over the size (it was lowered): retire the oldest idle workers first.
239
+ keepIdle.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
240
+ for (const row of keepIdle.slice(0, Math.max(0, keepIdle.length - size)))
241
+ await this.retire(row, "excess");
242
+ for (const orphan of live) {
243
+ await this.cold.removeWarm(orphan).catch(() => { });
244
+ poolLog.info({ token: orphan, event: "reaped" }, "orphan warm worker removed");
245
+ }
246
+ if (size > 0)
247
+ await this.replenish();
248
+ }
249
+ async retire(row, reason) {
250
+ // Only an idle worker is retired: the compare-and-swap loses to a claim.
251
+ if (!(await this.options.ledger.retire(row.id)))
252
+ return;
253
+ await this.discard(row.id);
254
+ poolLog.info({ worker: row.name, reason, event: "retired" }, "warm worker retired");
255
+ }
256
+ async replenish() {
257
+ const newToken = this.options.newToken ?? (() => randomBytes(10).toString("hex"));
258
+ const reserved = await this.options.ledger.reserve(this.specHash, this.options.size, newToken, nativeWarmWorkerName);
259
+ for (const { id, name } of reserved) {
260
+ this.warmingHere.add(id);
261
+ const started = this.now();
262
+ const warming = this.cold
263
+ .startWarm(id, this.waitMs)
264
+ .then(async () => {
265
+ if (await this.options.ledger.markIdle(id)) {
266
+ poolLog.info({ worker: name, ms: this.now() - started, event: "warmed" }, "warm worker ready");
267
+ }
268
+ else {
269
+ await this.discard(id);
270
+ }
271
+ })
272
+ .catch(async (err) => {
273
+ poolLog.warn({ err, worker: name }, "starting a warm worker failed");
274
+ await this.options.ledger.remove(id).catch(() => { });
275
+ })
276
+ .finally(() => {
277
+ this.warmingHere.delete(id);
278
+ this.warming.delete(warming);
279
+ });
280
+ this.warming.add(warming);
281
+ }
282
+ }
283
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The worker side of the native sandbox contract: runs the unchanged
3
+ * NativeEngine with an EngineRunContext whose every outside effect is a
4
+ * gateway call. User tools run here, in QuickJS, with their privileged
5
+ * bridges (fetch, datastore, secrets, console) served by the gateway; built-in
6
+ * tools run on the gateway. Worker-safe: no database, provider adapter, or
7
+ * credential is reachable from this module's imports (worker-imports.test.ts).
8
+ */
9
+ import type { LlmStreamEvent } from "../providers/llm/types.js";
10
+ import { type GatewayRequest, type WorkerInput } from "./protocol.js";
11
+ /** How the worker reaches the gateway. Errors arrive as GatewayError. */
12
+ export interface GatewayTransport {
13
+ call(request: GatewayRequest): Promise<unknown>;
14
+ stream(request: GatewayRequest): AsyncIterable<LlmStreamEvent>;
15
+ }
16
+ /** Runs one native run to its result and reports it with `finish`. Resolves when done. */
17
+ export declare function runNativeWorker(input: WorkerInput, transport: GatewayTransport): Promise<void>;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * The worker side of the native sandbox contract: runs the unchanged
3
+ * NativeEngine with an EngineRunContext whose every outside effect is a
4
+ * gateway call. User tools run here, in QuickJS, with their privileged
5
+ * bridges (fetch, datastore, secrets, console) served by the gateway; built-in
6
+ * tools run on the gateway. Worker-safe: no database, provider adapter, or
7
+ * credential is reachable from this module's imports (worker-imports.test.ts).
8
+ */
9
+ import { NativeEngine } from "../core/engine-native.js";
10
+ import { computeCost } from "../providers/llm/pricing-core.js";
11
+ import { PRIVILEGED_BRIDGE_NAMES } from "../sandbox/host-functions.js";
12
+ import { runUserToolCall } from "../sandbox/user-tool.js";
13
+ import { rememberSecretValue } from "./stderr-redaction.js";
14
+ import { GatewayError, NATIVE_WORKER_PROTOCOL_VERSION, } from "./protocol.js";
15
+ const isPending = (value) => typeof value === "object" && value !== null && value.pending === true;
16
+ /** Runs one native run to its result and reports it with `finish`. Resolves when done. */
17
+ export async function runNativeWorker(input, transport) {
18
+ let sequence = 0;
19
+ const nextCallId = (kind) => `${kind}-${++sequence}`;
20
+ const request = (method, params) => ({
21
+ v: NATIVE_WORKER_PROTOCOL_VERSION,
22
+ runId: input.runId,
23
+ callId: nextCallId(method),
24
+ method,
25
+ params,
26
+ });
27
+ const call = (method, params) => transport.call(request(method, params));
28
+ // Set when the gateway refuses a model call for budget: the run ends budget_exhausted, as in
29
+ // process, not failed.
30
+ let budgetRefused = false;
31
+ const llm = {
32
+ stream: (req) => (async function* () {
33
+ try {
34
+ yield* transport.stream(request("llm.stream", { request: req }));
35
+ }
36
+ catch (err) {
37
+ if (err instanceof GatewayError && err.code === "budget_exhausted")
38
+ budgetRefused = true;
39
+ throw err;
40
+ }
41
+ })(),
42
+ countTokens: async (model, messages, tools) => (await call("llm.countTokens", {
43
+ model,
44
+ messages: messages,
45
+ ...(tools ? { tools } : {}),
46
+ })),
47
+ // Local and exact: the run's pinned entry, the same computeCost the gateway's adapters use.
48
+ priceUsd: (_model, usage) => computeCost(input.pricing, usage),
49
+ };
50
+ const builtins = new Set(input.builtinTools);
51
+ let invocations = 0;
52
+ const remoteHost = (tool) => {
53
+ const invocation = `t${++invocations}`;
54
+ return Object.fromEntries(PRIVILEGED_BRIDGE_NAMES.map((bridge) => [
55
+ bridge,
56
+ async (argsJson) => {
57
+ try {
58
+ const result = await call("host.call", { tool, invocation, bridge, argsJson });
59
+ // A secret value now lives in this process: keep it out of everything it writes to stderr.
60
+ if (bridge === "__bridge_secretsGet" && typeof result === "string")
61
+ rememberSecretValue(result);
62
+ return result;
63
+ }
64
+ catch (err) {
65
+ // A bridge failure reaches the tool as the same error message it would see in-process.
66
+ if (err instanceof GatewayError && err.code === "bridge_error")
67
+ throw new Error(err.message, { cause: err });
68
+ throw err;
69
+ }
70
+ },
71
+ ]));
72
+ };
73
+ const runSandboxTool = async (name, argsJson) => {
74
+ if (builtins.has(name)) {
75
+ // A long-running built-in (a delegation) answers `pending`; ask again with the same callId,
76
+ // which the gateway resumes wherever it got to — on any replica.
77
+ const builtinRequest = request("builtin.call", { name, argsJson });
78
+ let result = await transport.call(builtinRequest);
79
+ while (isPending(result))
80
+ result = await transport.call(builtinRequest);
81
+ return result;
82
+ }
83
+ const tool = input.userTools[name];
84
+ if (!tool) {
85
+ return JSON.stringify({ error: "unknown_tool", message: `No tool named "${name}" is attached to this agent.` });
86
+ }
87
+ const host = remoteHost(name);
88
+ return runUserToolCall(tool, argsJson, () => host);
89
+ };
90
+ let textSeq = 0;
91
+ let textSent = Promise.resolve();
92
+ const concurrent = new Set(input.runsConcurrently);
93
+ const ctx = {
94
+ agent: input.agent,
95
+ tools: input.tools,
96
+ providers: { llm },
97
+ runSandboxTool,
98
+ ...(concurrent.size > 0 ? { runsConcurrently: (toolName) => concurrent.has(toolName) } : {}),
99
+ onText: (delta) => {
100
+ // One text call at a time: the gateway admits each call asynchronously, so concurrent ones
101
+ // can arrive out of order, and it drops any delta older than the last one it delivered.
102
+ const seq = textSeq++;
103
+ textSent = textSent.then(() => call("text", { seq, delta }).then(() => { }, () => {
104
+ // Streamed text is for live observers only; the final text travels with `finish`.
105
+ }));
106
+ },
107
+ onProgress: async (progress) => {
108
+ await call("progress", { turns: progress.turns, usage: progress.usage });
109
+ },
110
+ };
111
+ let result;
112
+ try {
113
+ result = await new NativeEngine().run(ctx);
114
+ }
115
+ catch (err) {
116
+ // A gateway failure (a delegation that could not be created, say) ends the run as failed with
117
+ // its code, not as an opaque worker exit. run_not_drivable means the run already ended.
118
+ if (!(err instanceof GatewayError) || err.code === "run_not_drivable")
119
+ throw err;
120
+ await textSent;
121
+ await call("finish", {
122
+ status: "failed",
123
+ finalText: "",
124
+ turns: 0,
125
+ // `internal` wraps raw exception text on some transports, so only its code (and the cause
126
+ // code the gateway carried with it, if any) is persisted, never its message.
127
+ error: err.code === "internal"
128
+ ? `native_sandbox_gateway_error: internal${err.causeCode ? `: ${err.causeCode}` : ""}`
129
+ : `native_sandbox_gateway_error: ${err.code}: ${err.message.slice(0, 1024)}`,
130
+ });
131
+ return;
132
+ }
133
+ // Live text reaches observers before the run is reported finished.
134
+ await textSent;
135
+ await call("finish", {
136
+ status: budgetRefused && result.status === "failed" ? "budget_exhausted" : result.status,
137
+ finalText: result.finalText,
138
+ turns: result.turns,
139
+ ...(result.error !== undefined ? { error: result.error } : {}),
140
+ });
141
+ }
@@ -133,8 +133,13 @@ export class WardbyMetrics {
133
133
  }
134
134
  observeProxyAudit = (event) => {
135
135
  this.proxyAuditEvents.inc({ event: event.type });
136
- if (event.reservationUsd !== undefined)
136
+ // A completed reply repeats its request's hold (for the overshoot audit): count it once, when held.
137
+ // A refused request carries the hold that did not fit, which was never reserved.
138
+ if (event.reservationUsd !== undefined &&
139
+ event.type !== "response.completed" &&
140
+ event.type !== "request.rejected") {
137
141
  this.proxyBudgetReserved.inc(event.reservationUsd);
142
+ }
138
143
  if (event.type !== "response.completed")
139
144
  return;
140
145
  if (event.costUsd !== undefined)
@@ -1,8 +1,11 @@
1
+ import type { MobileConfig } from "../../config/mobile.js";
1
2
  export interface SelfHostedAuthConfig {
2
3
  canonicalUri: string;
3
4
  signingKey: string;
4
5
  credentialHashKey: string;
5
6
  maxClients?: number;
7
+ /** Mobile sign-in: its one private-use redirect is accepted only while enabled. */
8
+ mobile?: MobileConfig;
6
9
  }
7
10
  export interface RegisterClientParams {
8
11
  redirectUris: string[];
@@ -20,11 +20,13 @@ export function buildAuthProvider(kind, config, db) {
20
20
  }
21
21
  if (config.credentialHashKey.toLowerCase() === process.env.SECRET_APP_KEY?.toLowerCase())
22
22
  throw new Error("Credential and encryption keys must be distinct.");
23
+ logger.info({ module: "auth", mobileEnabled: config.mobile.enabled, mobileRedirectUri: config.mobile.redirectUri }, "self-hosted OAuth mobile sign-in");
23
24
  return new SelfHostedAuthProvider({
24
25
  canonicalUri: config.audience,
25
26
  signingKey: config.signingKey,
26
27
  credentialHashKey: config.credentialHashKey,
27
28
  maxClients: config.maxClients,
29
+ mobile: config.mobile,
28
30
  }, db);
29
31
  }
30
32
  return new DelegatingAuthProvider(config);
@@ -11,6 +11,10 @@ export type { AuthorizeParams, RegisterClientParams, SelfHostedAuthConfig, Token
11
11
  * scheme, host, path, query — must match exactly, with no userinfo or fragment.
12
12
  */
13
13
  export declare function redirectMatches(registered: readonly string[], requested: string): boolean;
14
+ /** The mobile app's redirect while WARDBY_MOBILE_ENABLED is off. The message is safe to show to the client. */
15
+ export declare class MobileDisabledError extends Error {
16
+ constructor();
17
+ }
14
18
  export declare class SelfHostedAuthProvider implements AuthProvider {
15
19
  readonly db: PrismaClient;
16
20
  readonly credentials: Credentials;
@@ -49,9 +53,9 @@ export declare class SelfHostedAuthProvider implements AuthProvider {
49
53
  createdAt: Date;
50
54
  id: string;
51
55
  state: string | null;
52
- clientId: string;
53
- expiresAt: Date;
54
56
  resource: string;
57
+ expiresAt: Date;
58
+ clientId: string;
55
59
  consumedAt: Date | null;
56
60
  redirectUri: string;
57
61
  codeChallenge: string;
@@ -74,6 +78,14 @@ export declare class SelfHostedAuthProvider implements AuthProvider {
74
78
  private withinCanonical;
75
79
  private exchange;
76
80
  private rotate;
81
+ /**
82
+ * Whether `redirectUri` is a mobile (non-web, non-loopback) redirect this
83
+ * server refuses now. Only the currently configured mobile redirect, while
84
+ * mobile sign-in is enabled, passes - so a client registered under an earlier
85
+ * WARDBY_MOBILE_REDIRECT_URI is refused whether mobile is on or off.
86
+ * Web and loopback redirects are never affected.
87
+ */
88
+ private refusedRedirect;
77
89
  private issue;
78
90
  private revokeFamily;
79
91
  revoke(token: string, clientId: string): Promise<void>;
@@ -7,6 +7,7 @@ import { SCOPES_SUPPORTED, limitScope } from "../../mcp/auth/resource-server.js"
7
7
  import { canonicalUrl } from "../../mcp/transport/http-limits.js";
8
8
  import { Credentials, DAY, decodeKey, lockUser } from "../../mcp/auth/self-hosted/credentials.js";
9
9
  import { Sessions } from "../../mcp/auth/self-hosted/session.js";
10
+ import { MOBILE_DISABLED } from "../../config/mobile.js";
10
11
  const LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
11
12
  /**
12
13
  * Whether `requested` is one of a client's registered redirect URIs. A native
@@ -43,7 +44,21 @@ export function redirectMatches(registered, requested) {
43
44
  }
44
45
  });
45
46
  }
46
- function validRedirect(value) {
47
+ /** The mobile app's redirect while WARDBY_MOBILE_ENABLED is off. The message is safe to show to the client. */
48
+ export class MobileDisabledError extends Error {
49
+ constructor() {
50
+ super(`${MOBILE_DISABLED}: mobile sign-in is not enabled on this server (WARDBY_MOBILE_ENABLED).`);
51
+ this.name = "MobileDisabledError";
52
+ }
53
+ }
54
+ /**
55
+ * A registrable redirect: https, loopback http, or exactly the configured
56
+ * mobile redirect (RFC 8252 §7.1). This checks format only; whether mobile
57
+ * sign-in is enabled is enforced in each flow.
58
+ */
59
+ function validRedirect(value, mobileRedirect) {
60
+ if (mobileRedirect !== undefined && value === mobileRedirect)
61
+ return true;
47
62
  try {
48
63
  const u = new URL(value);
49
64
  return (!value.includes("#") &&
@@ -55,9 +70,16 @@ function validRedirect(value) {
55
70
  return false;
56
71
  }
57
72
  }
58
- const registration = z
73
+ const registration = (mobileRedirect) => z
59
74
  .object({
60
- redirectUris: z.array(z.string().min(1).max(2048).refine(validRedirect)).min(1).max(10),
75
+ redirectUris: z
76
+ .array(z
77
+ .string()
78
+ .min(1)
79
+ .max(2048)
80
+ .refine((value) => validRedirect(value, mobileRedirect)))
81
+ .min(1)
82
+ .max(10),
61
83
  clientName: z.string().max(100).optional(),
62
84
  grantTypes: z
63
85
  .array(z.enum(["authorization_code", "refresh_token"]))
@@ -114,7 +136,9 @@ export class SelfHostedAuthProvider {
114
136
  };
115
137
  }
116
138
  async registerClient(params) {
117
- const p = registration.parse(params);
139
+ const p = registration(this.config.mobile?.redirectUri).parse(params);
140
+ if (p.redirectUris.some((uri) => this.refusedRedirect(uri)))
141
+ throw new MobileDisabledError();
118
142
  return this.db.$transaction(async (tx) => {
119
143
  await tx.$queryRawUnsafe("SELECT 1 AS locked FROM pg_advisory_xact_lock(7412901)");
120
144
  if ((await tx.oAuthClient.count()) >= (this.config.maxClients ?? 1000))
@@ -143,6 +167,8 @@ export class SelfHostedAuthProvider {
143
167
  if (!redirectMatches(metadata?.redirect_uris ?? [], p.redirectUri) ||
144
168
  !metadata?.grant_types?.includes("authorization_code"))
145
169
  throw new Error("Invalid client or redirect.");
170
+ if (this.refusedRedirect(p.redirectUri))
171
+ throw new MobileDisabledError();
146
172
  const scope = limitScope(p.scope, SCOPES_SUPPORTED);
147
173
  const request = await this.db.oAuthAuthorizationRequest.create({
148
174
  data: {
@@ -258,6 +284,8 @@ export class SelfHostedAuthProvider {
258
284
  if (!/^[A-Za-z0-9._~-]{43,128}$/.test(p.codeVerifier) ||
259
285
  createHash("sha256").update(p.codeVerifier).digest("base64url") !== code.codeChallenge)
260
286
  throw new Error("Invalid grant: PKCE verifier mismatch.");
287
+ if (this.refusedRedirect(code.redirectUri))
288
+ throw new MobileDisabledError();
261
289
  return this.db.$transaction(async (tx) => {
262
290
  const user = await lockUser(tx, code.userId);
263
291
  const consumed = await tx.oAuthAuthorizationCode.updateMany({
@@ -305,6 +333,13 @@ export class SelfHostedAuthProvider {
305
333
  await this.revokeFamily(tx, grant.familyId);
306
334
  return "refresh token reused; family revoked";
307
335
  }
336
+ // Not token reuse: refuse without revoking, so the family works again
337
+ // once mobile sign-in is re-enabled. This checks every redirect the
338
+ // client registered, not just the one its code used: a client registered
339
+ // with both an https and a mobile redirect is refused while mobile is off.
340
+ const redirects = grant.family.client.metadata.redirect_uris ?? [];
341
+ if (redirects.some((uri) => this.refusedRedirect(uri)))
342
+ return MOBILE_DISABLED;
308
343
  const result = await this.issue(tx, grant.family, user.principal.subject);
309
344
  await tx.oAuthGrant.update({
310
345
  where: { id: grant.id },
@@ -312,10 +347,25 @@ export class SelfHostedAuthProvider {
312
347
  });
313
348
  return result;
314
349
  });
350
+ if (result === MOBILE_DISABLED)
351
+ throw new MobileDisabledError();
315
352
  if (typeof result === "string")
316
353
  throw new Error(`Invalid grant: ${result}.`);
317
354
  return result;
318
355
  }
356
+ /**
357
+ * Whether `redirectUri` is a mobile (non-web, non-loopback) redirect this
358
+ * server refuses now. Only the currently configured mobile redirect, while
359
+ * mobile sign-in is enabled, passes - so a client registered under an earlier
360
+ * WARDBY_MOBILE_REDIRECT_URI is refused whether mobile is on or off.
361
+ * Web and loopback redirects are never affected.
362
+ */
363
+ refusedRedirect(redirectUri) {
364
+ if (validRedirect(redirectUri))
365
+ return false;
366
+ const mobile = this.config.mobile;
367
+ return !(mobile?.enabled === true && redirectUri === mobile.redirectUri);
368
+ }
319
369
  async issue(tx, family, subject) {
320
370
  const refresh = this.credentials.create("rvr");
321
371
  await tx.oAuthGrant.create({