@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
@@ -1,11 +1,107 @@
1
- import { fulfillSecretElicitation } from "./secret-elicitation.js";
1
+ import { fulfillSecretElicitation, fulfillUnbrokerElicitation, } from "./secret-elicitation.js";
2
+ import { listSecrets } from "../../core/secrets.js";
3
+ import { parseSecretBrokerConfig } from "../../core/secret-broker-config.js";
2
4
  import { PAGE_STYLE } from "../shared/page-style.js";
3
5
  /** The HTTP-transport route path this form is mounted at (see streamable-http.ts). */
4
6
  export const SECRET_ELICITATION_PATH = "/elicit/secret";
5
7
  function escape(value) {
6
8
  return value.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
7
9
  }
8
- function html(res, status, body) {
10
+ const BROKER_WARNING = "If this is not brokered, any tool attached with this secret can read its value and send it anywhere that tool can fetch — including when a prompt-injected agent tells it to.";
11
+ const BROKER_COMPAT = 'Brokered secrets only work with tools that call <code>fetch(url, { secrets: ["NAME"] })</code>. A tool that reads the value with <code>secrets.get()</code> will fail with <code>secret_brokered</code>.';
12
+ /** Script-free toggle: the fields after the checkbox show only while it is checked. */
13
+ const BROKER_STYLE = `
14
+ .broker-toggle { display: inline-block; margin: 0 0 12px 6px; color: var(--ink); }
15
+ .broker-fields { display: none; }
16
+ #brokered:checked ~ .broker-fields { display: block; }
17
+ .warning { border-left: 3px solid #b45309; padding-left: 8px; color: var(--ink); }
18
+ .broker-fields input, .broker-fields textarea, .broker-fields select, input[name="confirm"] {
19
+ display: block;
20
+ width: 100%;
21
+ margin-top: 8px;
22
+ padding: 10px 12px;
23
+ font: inherit;
24
+ font-size: 14px;
25
+ color: var(--ink);
26
+ background: var(--paper);
27
+ border: 1px solid var(--line);
28
+ border-radius: 10px;
29
+ }
30
+ code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }
31
+ code { overflow-wrap: anywhere; }
32
+ pre { white-space: pre-wrap; overflow-wrap: anywhere; padding: 10px; background: var(--paper); border: 1px solid var(--line); border-radius: 10px; }
33
+ .hint { margin: 4px 0 12px; }
34
+ .broker-summary { margin: 0 0 12px; padding: 10px 10px 10px 28px; background: var(--paper); border: 1px solid var(--line); border-radius: 10px; color: var(--ink); }
35
+ .broker-summary li { margin: 2px 0; }
36
+ /* Show only the selected placement's fields; browsers without :has() show them all. */
37
+ @supports selector(:has(*)) {
38
+ .placement { display: none; }
39
+ .broker-fields:has(option[value="header"]:checked) .placement-header,
40
+ .broker-fields:has(option[value="query"]:checked) .placement-query,
41
+ .broker-fields:has(option[value="body"]:checked) .placement-body,
42
+ .broker-fields:has(option[value="aws-sigv4"]:checked) .placement-aws-sigv4 { display: block; }
43
+ }
44
+ `;
45
+ /** The "Brokered (recommended)" checkbox, warning, compatibility note, and broker fields, pre-filled from `prefill`. */
46
+ export function brokerFieldset(prefill) {
47
+ const p = prefill?.placement;
48
+ const sel = (kind) => (p?.kind === kind ? " selected" : "");
49
+ return (`<input type="checkbox" id="brokered" name="brokered" value="1"${prefill ? " checked" : ""}>` +
50
+ `<label class="broker-toggle" for="brokered">Brokered (recommended)</label>` +
51
+ `<p class="warning">${escape(BROKER_WARNING)}</p>` +
52
+ `<p>${BROKER_COMPAT}</p>` +
53
+ `<div class="broker-fields">` +
54
+ `<label>Allowed hosts (one per line)<textarea name="hosts" rows="2">${escape(prefill?.hosts.join("\n") ?? "")}</textarea></label>` +
55
+ `<label>Path prefixes (optional, one per line)<textarea name="pathPrefixes" rows="2">${escape(prefill?.pathPrefixes?.join("\n") ?? "")}</textarea></label>` +
56
+ `<label>Placement<select name="placement">` +
57
+ `<option value="header"${sel("header")}>Header</option><option value="query"${sel("query")}>Query parameter</option>` +
58
+ `<option value="body"${sel("body")}>Body field</option><option value="aws-sigv4"${sel("aws-sigv4")}>AWS SigV4</option></select></label>` +
59
+ `<div class="placement placement-header">` +
60
+ `<label>Header name<input name="headerName" value="${escape(p?.kind === "header" ? p.name : "Authorization")}"></label>` +
61
+ `<label>Header format<input name="headerFormat" value="${escape(p?.kind === "header" ? p.format : "Bearer {value}")}"></label>` +
62
+ `<p class="hint"><code>{value}</code> is replaced with the secret.</p>` +
63
+ `</div>` +
64
+ `<div class="placement placement-query">` +
65
+ `<label>Query parameter name<input name="queryName" value="${escape(p?.kind === "query" ? p.name : "")}"></label>` +
66
+ `</div>` +
67
+ `<div class="placement placement-body">` +
68
+ `<label>Body field name<input name="bodyField" value="${escape(p?.kind === "body" ? p.field : "")}"></label>` +
69
+ `<p class="hint">A top-level field of a JSON-object or form-encoded body.</p>` +
70
+ `</div>` +
71
+ `<div class="placement placement-aws-sigv4">` +
72
+ `<label>AWS region<input name="awsRegion" value="${escape(p?.kind === "aws-sigv4" ? p.region : "")}"></label>` +
73
+ `<label>AWS service<input name="awsService" value="${escape(p?.kind === "aws-sigv4" ? p.service : "")}"></label>` +
74
+ `<p class="hint">For AWS SigV4 the secret value is JSON (session token optional):</p>` +
75
+ `<pre>{\n "accessKeyId": "…",\n "secretAccessKey": "…",\n "sessionToken": "…"\n}</pre>` +
76
+ `</div>` +
77
+ `</div>`);
78
+ }
79
+ const lines = (v) => (v ?? "")
80
+ .split(/\r?\n/)
81
+ .map((s) => s.trim())
82
+ .filter(Boolean);
83
+ /** The form's broker config: null when the box is unchecked; throws secret_broker_config_invalid when it doesn't validate. */
84
+ export function brokerConfigFromForm(body) {
85
+ if (body.get("brokered") !== "1")
86
+ return null;
87
+ const kind = body.get("placement");
88
+ const placement = kind === "header"
89
+ ? { kind, name: body.get("headerName") ?? "", format: body.get("headerFormat") ?? "" }
90
+ : kind === "query"
91
+ ? { kind, name: body.get("queryName") ?? "" }
92
+ : kind === "body"
93
+ ? { kind, field: body.get("bodyField") ?? "" }
94
+ : kind === "aws-sigv4"
95
+ ? { kind, region: body.get("awsRegion") ?? "", service: body.get("awsService") ?? "" }
96
+ : { kind };
97
+ const prefixes = lines(body.get("pathPrefixes"));
98
+ return parseSecretBrokerConfig({
99
+ hosts: lines(body.get("hosts")),
100
+ ...(prefixes.length > 0 && { pathPrefixes: prefixes }),
101
+ placement,
102
+ });
103
+ }
104
+ function html(res, status, body, extraStyle = "") {
9
105
  res.setHeader("content-security-policy", "default-src 'none'; script-src 'none'; style-src 'unsafe-inline'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'");
10
106
  res.setHeader("cache-control", "no-store");
11
107
  res.setHeader("x-content-type-options", "nosniff");
@@ -18,7 +114,7 @@ function html(res, status, body) {
18
114
  res
19
115
  .writeHead(status, { "content-type": "text/html; charset=utf-8" })
20
116
  .end(`<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">` +
21
- `<title>wardby secret entry</title><style>${PAGE_STYLE}</style><body><div class="card"><div class="kicker">wardby</div>${body}</div></body></html>`);
117
+ `<title>wardby secret entry</title><style>${PAGE_STYLE}${extraStyle}</style><body><div class="card"><div class="kicker">wardby</div>${body}</div></body></html>`);
22
118
  }
23
119
  /** Handles one GET (render) or POST (submit) for the secret-entry form at the given token. */
24
120
  export async function handleSecretElicitationForm(method, token, readFormBody, res, deps) {
@@ -27,26 +123,46 @@ export async function handleSecretElicitationForm(method, token, readFormBody, r
27
123
  if (!token)
28
124
  throw new Error("missing token");
29
125
  payload = await deps.verify(token);
126
+ // Other links share the signing key (a run transcript download, a tool's
127
+ // requestState): only a secret link's kind opens this form.
128
+ if (payload.kind !== undefined && payload.kind !== "create" && payload.kind !== "unbroker") {
129
+ throw new Error("not a secret link");
130
+ }
30
131
  }
31
132
  catch {
32
133
  html(res, 400, "<h1>Link expired</h1><p>This link is invalid or has expired. Return to your MCP client and try again.</p>");
33
134
  return;
34
135
  }
136
+ if ((payload.kind ?? "create") === "unbroker") {
137
+ await handleUnbroker(method, payload, readFormBody, res, deps);
138
+ return;
139
+ }
35
140
  if (method === "GET") {
36
141
  html(res, 200, `<h1>Enter secret value</h1><p>Name: <strong>${escape(payload.secretName)}</strong></p>` +
37
142
  `<form method="post"><label>Secret value` +
38
143
  `<input type="password" name="value" autocomplete="off" required autofocus placeholder="Paste the value here"></label>` +
39
- `<button type="submit">Save</button></form>`);
144
+ brokerFieldset(payload.broker) +
145
+ `<button type="submit">Save</button></form>`, BROKER_STYLE);
40
146
  return;
41
147
  }
42
148
  if (method === "POST") {
43
- const body = await readFormBody();
149
+ const body = await readBodyOr413(readFormBody, res);
150
+ if (!body)
151
+ return;
44
152
  const value = body.get("value") ?? "";
45
153
  if (!value) {
46
154
  html(res, 400, "<h1>A value is required.</h1>");
47
155
  return;
48
156
  }
49
- const outcome = await fulfillSecretElicitation(payload, value, deps.secrets, deps.db);
157
+ let broker;
158
+ try {
159
+ broker = brokerConfigFromForm(body);
160
+ }
161
+ catch (err) {
162
+ html(res, 400, `<h1>Could not save</h1><p>${escape(err instanceof Error ? err.message : String(err))}</p>`);
163
+ return;
164
+ }
165
+ const outcome = await fulfillSecretElicitation(payload, value, deps.secrets, deps.db, broker);
50
166
  if (outcome.ok)
51
167
  html(res, 200, "<h1>Saved</h1><p>You can close this tab and return to your MCP client.</p>");
52
168
  else
@@ -55,21 +171,100 @@ export async function handleSecretElicitationForm(method, token, readFormBody, r
55
171
  }
56
172
  res.writeHead(405).end();
57
173
  }
58
- /** Reads a small `application/x-www-form-urlencoded` body (8 KiB cap — a secret value, nothing more). */
174
+ /** Reads the POST body, or answers 413 (over the cap) and returns undefined. */
175
+ async function readBodyOr413(readFormBody, res) {
176
+ try {
177
+ return await readFormBody();
178
+ }
179
+ catch (err) {
180
+ if (!(err instanceof Error && err.message === "body_too_large"))
181
+ throw err;
182
+ res.setHeader("connection", "close");
183
+ html(res, 413, "<h1>Value too large</h1><p>The form was larger than this page accepts.</p>");
184
+ return undefined;
185
+ }
186
+ }
187
+ /** A readable, escaped summary of a broker config for the unbroker page. */
188
+ function describeBroker(broker) {
189
+ if (!broker)
190
+ return "<p>(not brokered)</p>";
191
+ const p = broker.placement;
192
+ const placement = p.kind === "header"
193
+ ? `header <code>${escape(p.name)}: ${escape(p.format)}</code>`
194
+ : p.kind === "query"
195
+ ? `query parameter <code>${escape(p.name)}</code>`
196
+ : p.kind === "body"
197
+ ? `body field <code>${escape(p.field)}</code>`
198
+ : `AWS SigV4 (region <code>${escape(p.region)}</code>, service <code>${escape(p.service)}</code>)`;
199
+ const list = (items) => items.map((item) => `<code>${escape(item)}</code>`).join(", ");
200
+ return (`<ul class="broker-summary">` +
201
+ `<li>Hosts: ${list(broker.hosts)}</li>` +
202
+ (broker.pathPrefixes?.length ? `<li>Paths: ${list(broker.pathPrefixes)}</li>` : "") +
203
+ `<li>Sent as: ${placement}</li>` +
204
+ `</ul>`);
205
+ }
206
+ /** The unbroker link's page: show what is brokered now, and remove it only when the person types the secret's name. */
207
+ async function handleUnbroker(method, payload, readFormBody, res, deps) {
208
+ if (method === "GET") {
209
+ const current = (await listSecrets(payload.ownerId, deps.db)).find((s) => s.name === payload.secretName);
210
+ html(res, 200, `<h1>Remove brokering</h1><p>Name: <strong>${escape(payload.secretName)}</strong></p>` +
211
+ `<p>Currently brokered as:</p>${describeBroker(current?.broker ?? null)}` +
212
+ `<p class="warning">${escape(BROKER_WARNING)}</p>` +
213
+ `<form method="post"><label>Type the secret's name to confirm` +
214
+ `<input name="confirm" autocomplete="off" required autofocus></label>` +
215
+ `<button type="submit">Remove brokering</button></form>`, BROKER_STYLE);
216
+ return;
217
+ }
218
+ if (method === "POST") {
219
+ const body = await readBodyOr413(readFormBody, res);
220
+ if (!body)
221
+ return;
222
+ if (body.get("confirm") !== payload.secretName) {
223
+ html(res, 400, `<h1>${escape("Type the secret's name to confirm.")}</h1>`);
224
+ return;
225
+ }
226
+ const outcome = await fulfillUnbrokerElicitation(payload, deps.secrets, deps.db);
227
+ if (outcome.ok) {
228
+ html(res, 200, "<h1>Brokering removed</h1><p>You can close this tab and return to your MCP client.</p>");
229
+ }
230
+ else {
231
+ html(res, 400, `<h1>Could not remove brokering</h1><p>${escape(outcome.error)}</p>`);
232
+ }
233
+ return;
234
+ }
235
+ res.writeHead(405).end();
236
+ }
237
+ /**
238
+ * The largest form body accepted: room for the largest valid AWS SigV4 value
239
+ * (an 8 KiB session token, up to 3x after URL encoding) plus the broker fields.
240
+ */
241
+ export const FORM_BODY_LIMIT = 32 * 1024;
242
+ /**
243
+ * Reads a small `application/x-www-form-urlencoded` body. Over FORM_BODY_LIMIT it
244
+ * rejects with `body_too_large` and discards the rest of the upload, so the
245
+ * handler can still answer 413 on the same connection.
246
+ */
59
247
  export function readFormBody(req) {
60
248
  return new Promise((resolve, reject) => {
61
249
  let size = 0;
250
+ let tooLarge = false;
62
251
  const chunks = [];
63
252
  req.on("data", (chunk) => {
253
+ if (tooLarge)
254
+ return;
64
255
  size += chunk.length;
65
- if (size > 8192) {
256
+ if (size > FORM_BODY_LIMIT) {
257
+ tooLarge = true;
258
+ chunks.length = 0;
66
259
  reject(new Error("body_too_large"));
67
- req.destroy();
68
260
  return;
69
261
  }
70
262
  chunks.push(chunk);
71
263
  });
72
- req.on("end", () => resolve(new URLSearchParams(Buffer.concat(chunks).toString("utf8"))));
264
+ req.on("end", () => {
265
+ if (!tooLarge)
266
+ resolve(new URLSearchParams(Buffer.concat(chunks).toString("utf8")));
267
+ });
73
268
  req.on("error", reject);
74
269
  });
75
270
  }
@@ -1,5 +1,11 @@
1
1
  import type { SecretFormDeps } from "./secret-elicitation-form.js";
2
+ import { type StdioLinkHandler } from "../transport/stdio-link-host.js";
3
+ /** The loopback path the form is served at on stdio. */
4
+ export declare const STDIO_SECRET_PATH = "/secret";
2
5
  export interface StdioSecretElicitationHost {
3
6
  urlFor(token: string): Promise<string>;
4
7
  }
8
+ /** The secret form as a link-host route. */
9
+ export declare function secretFormRoute(deps: SecretFormDeps): StdioLinkHandler;
10
+ /** A link host serving only the secret form (the composition root shares one host across routes). */
5
11
  export declare function createStdioSecretElicitationHost(deps: SecretFormDeps): StdioSecretElicitationHost;
@@ -1,57 +1,13 @@
1
- /**
2
- * stdio-only host for the secret-entry form: an ephemeral, loopback-only
3
- * HTTP server, started lazily on the first pending elicitation and closed
4
- * after a period of inactivity. stdio's MCP process has no other listener
5
- * (see mcp/transport/stdio.ts) — this one exists only while a secret entry
6
- * is actually pending, consistent with stdio's "no token; the operator is
7
- * trusted" model: reachable only from this same machine, and only a holder
8
- * of the one-time signed URL can do anything with it.
9
- */
10
- import { createServer } from "node:http";
11
1
  import { handleSecretElicitationForm, readFormBody } from "./secret-elicitation-form.js";
12
- /** Matches the requestState codec's own TTL (server.ts) — no point outliving the tokens it serves. */
13
- const IDLE_SHUTDOWN_MS = 10 * 60_000;
2
+ import { createStdioLinkHost } from "../transport/stdio-link-host.js";
3
+ /** The loopback path the form is served at on stdio. */
4
+ export const STDIO_SECRET_PATH = "/secret";
5
+ /** The secret form as a link-host route. */
6
+ export function secretFormRoute(deps) {
7
+ return (req, res, token) => handleSecretElicitationForm(req.method, token, () => readFormBody(req), res, deps);
8
+ }
9
+ /** A link host serving only the secret form (the composition root shares one host across routes). */
14
10
  export function createStdioSecretElicitationHost(deps) {
15
- let server;
16
- let port = 0;
17
- let idleTimer;
18
- function scheduleIdleShutdown() {
19
- if (idleTimer)
20
- clearTimeout(idleTimer);
21
- idleTimer = setTimeout(() => {
22
- server?.close();
23
- server = undefined;
24
- }, IDLE_SHUTDOWN_MS);
25
- idleTimer.unref();
26
- }
27
- async function ensureServer() {
28
- if (server) {
29
- scheduleIdleShutdown();
30
- return port;
31
- }
32
- const s = createServer((req, res) => {
33
- scheduleIdleShutdown();
34
- const url = new URL(req.url ?? "/", "http://127.0.0.1");
35
- if (url.pathname !== "/secret") {
36
- res.writeHead(404).end();
37
- return;
38
- }
39
- void handleSecretElicitationForm(req.method, url.searchParams.get("t"), () => readFormBody(req), res, deps);
40
- });
41
- server = s;
42
- await new Promise((resolve, reject) => {
43
- s.once("error", reject);
44
- s.listen(0, "127.0.0.1", resolve);
45
- });
46
- const address = s.address();
47
- port = typeof address === "object" && address ? address.port : 0;
48
- scheduleIdleShutdown();
49
- return port;
50
- }
51
- return {
52
- async urlFor(token) {
53
- const p = await ensureServer();
54
- return `http://127.0.0.1:${p}/secret?t=${encodeURIComponent(token)}`;
55
- },
56
- };
11
+ const host = createStdioLinkHost({ [STDIO_SECRET_PATH]: secretFormRoute(deps) });
12
+ return { urlFor: (token) => host.urlFor(STDIO_SECRET_PATH, token) };
57
13
  }
@@ -14,25 +14,60 @@
14
14
  * elicitation nobody completes or polls within that window is abandoned).
15
15
  * Expiry is swept lazily on every read and write via a `deleteMany` rather
16
16
  * than a timer, so an idle process holds no interval.
17
+ *
18
+ * Two kinds share the table: "create" (enter a secret's value, optionally
19
+ * brokered) and "unbroker" (a person confirms removing a secret's broker
20
+ * config: `set_secret_broker { broker: null }` never removes it directly).
21
+ * Payloads and outcomes written before `kind` existed have none and count as
22
+ * "create".
17
23
  */
18
24
  import type { PrismaClient } from "#prisma";
19
25
  import { type SecretMetadata } from "../../core/secrets.js";
26
+ import { type SecretBrokerConfig } from "../../core/secret-broker-config.js";
20
27
  import type { SecretCipher } from "../../providers/secrets/types.js";
28
+ export type SecretElicitationKind = "create" | "unbroker";
21
29
  export interface SecretElicitationPayload {
22
30
  ownerId: string;
23
31
  secretName: string;
32
+ /** Missing on links minted before brokered secrets: those are "create". */
33
+ kind?: SecretElicitationKind;
34
+ /** "create" only: the broker config to save with the value (the form pre-fills it). */
35
+ broker?: SecretBrokerConfig;
36
+ /**
37
+ * "unbroker" only: brokerConfigHash of the config the link was minted for. The
38
+ * removal is refused if the secret's config has changed since (or the link has none).
39
+ */
40
+ brokerHash?: string;
24
41
  }
25
42
  export type SecretElicitationOutcome = {
26
43
  ok: true;
44
+ kind: SecretElicitationKind;
27
45
  secret: SecretMetadata;
28
46
  } | {
29
47
  ok: false;
48
+ kind: SecretElicitationKind;
30
49
  error: string;
31
50
  };
32
- export declare function getSecretElicitationOutcome(ownerId: string, secretName: string, db: PrismaClient): Promise<SecretElicitationOutcome | undefined>;
51
+ export declare function getSecretElicitationOutcome(ownerId: string, secretName: string, db: PrismaClient, kind?: SecretElicitationKind): Promise<SecretElicitationOutcome | undefined>;
33
52
  /**
34
53
  * Called by the browser form's POST handler. Idempotent — a resubmit for
35
54
  * the same (ownerId, secretName) that's already fulfilled returns the
36
- * recorded outcome rather than writing again.
55
+ * recorded outcome rather than writing again. A value or broker config that
56
+ * fails validation is returned but not recorded, so the person can correct it. `broker` (the form's,
57
+ * pre-filled from the payload) makes the new secret brokered.
58
+ */
59
+ export declare function fulfillSecretElicitation(payload: SecretElicitationPayload, value: string, cipher: SecretCipher, db: PrismaClient, broker?: SecretBrokerConfig | null): Promise<SecretElicitationOutcome>;
60
+ /**
61
+ * Called by the unbroker form's POST: removes brokering (audited, via
62
+ * "browser", the owner as actor). Idempotent like fulfillSecretElicitation.
63
+ * A link only removes the config it was minted for: if brokering changed
64
+ * since (or the link carries no brokerHash) it is refused without recording
65
+ * an outcome, so a fresh link for the current config still works.
66
+ */
67
+ export declare function fulfillUnbrokerElicitation(payload: SecretElicitationPayload, cipher: SecretCipher, db: PrismaClient): Promise<SecretElicitationOutcome>;
68
+ /**
69
+ * Forgets a recorded unbroker outcome for this secret: called when brokering
70
+ * is set again, so a removal confirmed earlier can't answer (or short-circuit)
71
+ * a later removal request.
37
72
  */
38
- export declare function fulfillSecretElicitation(payload: SecretElicitationPayload, value: string, cipher: SecretCipher, db: PrismaClient): Promise<SecretElicitationOutcome>;
73
+ export declare function clearUnbrokerOutcome(ownerId: string, secretName: string, db: PrismaClient): Promise<void>;
@@ -1,34 +1,72 @@
1
- import { createSecret } from "../../core/secrets.js";
1
+ import { createSecret, listSecrets, setSecretBroker } from "../../core/secrets.js";
2
+ import { parseSecretBrokerConfig, SECRET_BROKER_CHANGED, } from "../../core/secret-broker-config.js";
3
+ /**
4
+ * A link only does what it was minted for: a create link can't confirm an
5
+ * unbroker, nor the reverse. Refused without recording an outcome.
6
+ */
7
+ function kindMismatch(payload, expected) {
8
+ const actual = payload.kind ?? "create";
9
+ if (actual === expected)
10
+ return undefined;
11
+ return {
12
+ ok: false,
13
+ kind: expected,
14
+ error: `elicitation_kind_mismatch: this link is for a "${actual}" request, not "${expected}"`,
15
+ };
16
+ }
17
+ /** A stored outcome's kind; one written before `kind` existed is a "create". */
18
+ function kindOf(outcome) {
19
+ return outcome.kind ?? "create";
20
+ }
2
21
  const ELICITATION_TTL_MS = 600_000;
3
22
  /** Sweeps every expired entry, not just the one being looked up, so a set-and-never-polled-again entry doesn't linger forever. */
4
23
  async function pruneExpired(db, now) {
5
24
  await db.secretElicitationOutcome.deleteMany({ where: { expiresAt: { lte: now } } });
6
25
  }
7
- export async function getSecretElicitationOutcome(ownerId, secretName, db) {
26
+ export async function getSecretElicitationOutcome(ownerId, secretName, db, kind = "create") {
8
27
  const now = new Date();
9
28
  await pruneExpired(db, now);
10
29
  const row = await db.secretElicitationOutcome.findUnique({ where: { ownerId_secretName: { ownerId, secretName } } });
11
- return row?.outcome;
30
+ if (!row || kindOf(row.outcome) !== kind)
31
+ return undefined;
32
+ return row.outcome;
33
+ }
34
+ async function recordOutcome(db, ownerId, secretName, outcome, now) {
35
+ const expiresAt = new Date(now.getTime() + ELICITATION_TTL_MS);
36
+ await db.secretElicitationOutcome.upsert({
37
+ where: { ownerId_secretName: { ownerId, secretName } },
38
+ create: { ownerId, secretName, outcome, expiresAt },
39
+ update: { outcome, expiresAt },
40
+ });
12
41
  }
13
42
  /**
14
43
  * Called by the browser form's POST handler. Idempotent — a resubmit for
15
44
  * the same (ownerId, secretName) that's already fulfilled returns the
16
- * recorded outcome rather than writing again.
45
+ * recorded outcome rather than writing again. A value or broker config that
46
+ * fails validation is returned but not recorded, so the person can correct it. `broker` (the form's,
47
+ * pre-filled from the payload) makes the new secret brokered.
17
48
  */
18
- export async function fulfillSecretElicitation(payload, value, cipher, db) {
49
+ export async function fulfillSecretElicitation(payload, value, cipher, db, broker) {
50
+ const mismatch = kindMismatch(payload, "create");
51
+ if (mismatch)
52
+ return mismatch;
19
53
  const now = new Date();
20
54
  await pruneExpired(db, now);
21
55
  const { ownerId, secretName } = payload;
22
56
  const existing = await db.secretElicitationOutcome.findUnique({
23
57
  where: { ownerId_secretName: { ownerId, secretName } },
24
58
  });
25
- if (existing)
59
+ if (existing && kindOf(existing.outcome) === "create")
26
60
  return existing.outcome;
27
61
  let outcome;
28
62
  try {
29
- const secret = await createSecret(secretName, value, ownerId, cipher, db);
63
+ const secret = await createSecret(secretName, value, ownerId, cipher, db, {
64
+ broker: broker ?? undefined,
65
+ via: "browser",
66
+ });
30
67
  outcome = {
31
68
  ok: true,
69
+ kind: "create",
32
70
  secret: {
33
71
  id: secret.id,
34
72
  name: secret.name,
@@ -36,17 +74,77 @@ export async function fulfillSecretElicitation(payload, value, cipher, db) {
36
74
  ownerId: secret.ownerId,
37
75
  createdAt: secret.createdAt,
38
76
  updatedAt: secret.updatedAt,
77
+ // A rotation without a broker keeps the stored config, so report what was saved.
78
+ broker: secret.broker === null || secret.broker === undefined ? null : parseSecretBrokerConfig(secret.broker),
39
79
  },
40
80
  };
41
81
  }
42
82
  catch (err) {
43
- outcome = { ok: false, error: err instanceof Error ? err.message : String(err) };
83
+ outcome = { ok: false, kind: "create", error: err instanceof Error ? err.message : String(err) };
84
+ // A value or config the person can fix: not recorded, so the same link takes a corrected
85
+ // submission and create_secret keeps waiting rather than replaying this error.
86
+ if (isCorrectableInput(outcome.error))
87
+ return outcome;
44
88
  }
45
- const expiresAt = new Date(now.getTime() + ELICITATION_TTL_MS);
46
- await db.secretElicitationOutcome.upsert({
89
+ await recordOutcome(db, ownerId, secretName, outcome, now);
90
+ return outcome;
91
+ }
92
+ const CORRECTABLE_ERRORS = ["secret_broker_value_invalid", "secret_broker_config_invalid", "bridge_input_limit"];
93
+ function isCorrectableInput(message) {
94
+ return CORRECTABLE_ERRORS.some((code) => message.startsWith(code));
95
+ }
96
+ /**
97
+ * Called by the unbroker form's POST: removes brokering (audited, via
98
+ * "browser", the owner as actor). Idempotent like fulfillSecretElicitation.
99
+ * A link only removes the config it was minted for: if brokering changed
100
+ * since (or the link carries no brokerHash) it is refused without recording
101
+ * an outcome, so a fresh link for the current config still works.
102
+ */
103
+ export async function fulfillUnbrokerElicitation(payload, cipher, db) {
104
+ const mismatch = kindMismatch(payload, "unbroker");
105
+ if (mismatch)
106
+ return mismatch;
107
+ const changed = { ok: false, kind: "unbroker", error: SECRET_BROKER_CHANGED };
108
+ if (!payload.brokerHash)
109
+ return changed;
110
+ const now = new Date();
111
+ await pruneExpired(db, now);
112
+ const { ownerId, secretName } = payload;
113
+ const existing = await db.secretElicitationOutcome.findUnique({
47
114
  where: { ownerId_secretName: { ownerId, secretName } },
48
- create: { ownerId, secretName, outcome, expiresAt },
49
- update: { outcome, expiresAt },
50
115
  });
116
+ if (existing && kindOf(existing.outcome) === "unbroker")
117
+ return existing.outcome;
118
+ let outcome;
119
+ try {
120
+ await setSecretBroker(db, cipher, {
121
+ ownerId,
122
+ name: secretName,
123
+ broker: null,
124
+ actorId: ownerId,
125
+ via: "browser",
126
+ expectedBrokerHash: payload.brokerHash,
127
+ });
128
+ const secret = (await listSecrets(ownerId, db)).find((s) => s.name === secretName);
129
+ if (!secret)
130
+ throw new Error(`secret_not_found: no secret named "${secretName}"`);
131
+ outcome = { ok: true, kind: "unbroker", secret };
132
+ }
133
+ catch (err) {
134
+ if (err instanceof Error && err.message === SECRET_BROKER_CHANGED)
135
+ return changed;
136
+ outcome = { ok: false, kind: "unbroker", error: err instanceof Error ? err.message : String(err) };
137
+ }
138
+ await recordOutcome(db, ownerId, secretName, outcome, now);
51
139
  return outcome;
52
140
  }
141
+ /**
142
+ * Forgets a recorded unbroker outcome for this secret: called when brokering
143
+ * is set again, so a removal confirmed earlier can't answer (or short-circuit)
144
+ * a later removal request.
145
+ */
146
+ export async function clearUnbrokerOutcome(ownerId, secretName, db) {
147
+ await db.secretElicitationOutcome.deleteMany({
148
+ where: { ownerId, secretName, outcome: { path: ["kind"], equals: "unbroker" } },
149
+ });
150
+ }