@webpresso/agent-kit 3.1.30 → 3.3.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 (300) hide show
  1. package/README.md +53 -15
  2. package/bin/_run.js +183 -20
  3. package/catalog/AGENTS.md.tpl +3 -3
  4. package/catalog/agent/agents/implementer.md +45 -0
  5. package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
  6. package/catalog/agent/rules/pre-implementation.md +28 -1
  7. package/catalog/agent/rules/supported-agent-clis.md +9 -0
  8. package/catalog/agent/rules/typescript-version.md +50 -0
  9. package/catalog/agent/skills/codex/SKILL.md +25 -1
  10. package/catalog/agent/skills/verify/SKILL.md +4 -2
  11. package/catalog/docs/templates/blueprint.md +1 -1
  12. package/dist/esm/audit/agents.js +1 -0
  13. package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
  14. package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
  15. package/dist/esm/audit/blueprint-pr-coverage.js +4 -0
  16. package/dist/esm/audit/blueprint-trust.js +14 -10
  17. package/dist/esm/audit/changeset-evidence.d.ts +23 -0
  18. package/dist/esm/audit/changeset-evidence.js +30 -0
  19. package/dist/esm/audit/changeset-required.d.ts +10 -0
  20. package/dist/esm/audit/changeset-required.js +73 -0
  21. package/dist/esm/audit/ci-guardrails-detection.d.ts +27 -0
  22. package/dist/esm/audit/ci-guardrails-detection.js +68 -0
  23. package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
  24. package/dist/esm/audit/ci-guardrails-wiring.js +80 -0
  25. package/dist/esm/audit/ci-test-perf.js +30 -0
  26. package/dist/esm/audit/command-surface.js +4 -2
  27. package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
  28. package/dist/esm/audit/host-substitution-risk.js +256 -0
  29. package/dist/esm/audit/registry.d.ts +4 -4
  30. package/dist/esm/audit/registry.js +13 -1
  31. package/dist/esm/audit/toolchain-isolation.js +1 -2
  32. package/dist/esm/audit/typescript-version.d.ts +2 -0
  33. package/dist/esm/audit/typescript-version.js +123 -0
  34. package/dist/esm/blueprint/core/parser.js +101 -2
  35. package/dist/esm/blueprint/core/schema.d.ts +1 -0
  36. package/dist/esm/blueprint/core/schema.js +26 -0
  37. package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
  38. package/dist/esm/blueprint/core/validation/criteria.js +41 -2
  39. package/dist/esm/blueprint/core/validation/state.js +25 -14
  40. package/dist/esm/blueprint/db/migrations/run.js +4 -2
  41. package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
  42. package/dist/esm/blueprint/lifecycle/audit.js +87 -20
  43. package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
  44. package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
  45. package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
  46. package/dist/esm/blueprint/lifecycle/local.js +19 -3
  47. package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
  48. package/dist/esm/blueprint/lifecycle/review-provenance.js +68 -12
  49. package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +97 -0
  50. package/dist/esm/blueprint/lifecycle/rollout-anchor.js +161 -0
  51. package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
  52. package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
  53. package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
  54. package/dist/esm/blueprint/sync/client.d.ts +2 -1
  55. package/dist/esm/blueprint/sync/client.js +1 -1
  56. package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
  57. package/dist/esm/blueprint/trust/command-runner.js +148 -0
  58. package/dist/esm/blueprint/trust/dossier.d.ts +1 -0
  59. package/dist/esm/blueprint/trust/dossier.js +40 -6
  60. package/dist/esm/blueprint/trust/gates.d.ts +7 -0
  61. package/dist/esm/blueprint/trust/gates.js +20 -0
  62. package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
  63. package/dist/esm/blueprint/trust/promotion.js +74 -112
  64. package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
  65. package/dist/esm/blueprint/trust/scaffold.js +64 -0
  66. package/dist/esm/blueprint/trust/validator.d.ts +1 -0
  67. package/dist/esm/blueprint/trust/validator.js +7 -1
  68. package/dist/esm/blueprint/utils/archive.js +27 -5
  69. package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
  70. package/dist/esm/blueprint/utils/document-paths.js +45 -12
  71. package/dist/esm/build/cli-mcp-parity.js +15 -0
  72. package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
  73. package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
  74. package/dist/esm/cli/cli.d.ts +1 -1
  75. package/dist/esm/cli/cli.js +43 -0
  76. package/dist/esm/cli/commands/agent-launch.d.ts +8 -1
  77. package/dist/esm/cli/commands/agent-launch.js +93 -4
  78. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  79. package/dist/esm/cli/commands/audit-core.js +8 -1
  80. package/dist/esm/cli/commands/audit.js +21 -5
  81. package/dist/esm/cli/commands/blueprint/execution.js +18 -6
  82. package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
  83. package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
  84. package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
  85. package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
  86. package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
  87. package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
  88. package/dist/esm/cli/commands/blueprint/router.js +13 -1
  89. package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
  90. package/dist/esm/cli/commands/ci-preflight.js +30 -6
  91. package/dist/esm/cli/commands/compile.js +5 -31
  92. package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
  93. package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
  94. package/dist/esm/cli/commands/doctor.js +5 -0
  95. package/dist/esm/cli/commands/hook.d.ts +5 -0
  96. package/dist/esm/cli/commands/hook.js +15 -9
  97. package/dist/esm/cli/commands/init/config.js +2 -2
  98. package/dist/esm/cli/commands/init/convergence-apply.d.ts +88 -0
  99. package/dist/esm/cli/commands/init/convergence-apply.js +325 -0
  100. package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
  101. package/dist/esm/cli/commands/init/convergence-state.js +54 -0
  102. package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
  103. package/dist/esm/cli/commands/init/convergence.js +57 -0
  104. package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
  105. package/dist/esm/cli/commands/init/git-convergence.js +168 -0
  106. package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
  107. package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
  108. package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
  109. package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
  110. package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
  111. package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
  112. package/dist/esm/cli/commands/init/host-visibility.js +94 -5
  113. package/dist/esm/cli/commands/init/index.d.ts +3 -0
  114. package/dist/esm/cli/commands/init/index.js +326 -173
  115. package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
  116. package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
  117. package/dist/esm/cli/commands/init/merge.d.ts +1 -0
  118. package/dist/esm/cli/commands/init/merge.js +30 -1
  119. package/dist/esm/cli/commands/init/package-root.d.ts +7 -0
  120. package/dist/esm/cli/commands/init/package-root.js +10 -2
  121. package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
  122. package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
  123. package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
  124. package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
  125. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +20 -0
  126. package/dist/esm/cli/commands/init/scaffold-base-kit.js +61 -5
  127. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
  128. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
  129. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
  130. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +54 -24
  131. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
  132. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +288 -202
  133. package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +22 -0
  134. package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +230 -0
  135. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
  136. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
  137. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
  138. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
  139. package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
  140. package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
  141. package/dist/esm/cli/commands/opencode-probe.d.ts +107 -0
  142. package/dist/esm/cli/commands/opencode-probe.js +323 -0
  143. package/dist/esm/cli/commands/opencode-rotate.d.ts +72 -0
  144. package/dist/esm/cli/commands/opencode-rotate.js +147 -0
  145. package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
  146. package/dist/esm/cli/commands/public-readiness.js +42 -0
  147. package/dist/esm/cli/commands/quality-runner.js +3 -3
  148. package/dist/esm/cli/commands/review.d.ts +35 -3
  149. package/dist/esm/cli/commands/review.js +751 -209
  150. package/dist/esm/cli/commands/run-wait.d.ts +2 -0
  151. package/dist/esm/cli/commands/run-wait.js +122 -0
  152. package/dist/esm/cli/commands/rust-check.d.ts +24 -0
  153. package/dist/esm/cli/commands/rust-check.js +110 -0
  154. package/dist/esm/cli/commands/setup-help.js +1 -1
  155. package/dist/esm/cli/commands/setup-repair-help.js +1 -1
  156. package/dist/esm/cli/commands/typecheck.d.ts +1 -0
  157. package/dist/esm/cli/commands/typecheck.js +30 -1
  158. package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +6 -0
  159. package/dist/esm/cli/commands/worktree/router-dispatch.js +126 -9
  160. package/dist/esm/cli/commands/worktree/router.js +10 -0
  161. package/dist/esm/cli/direct-provider-launch.js +9 -5
  162. package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
  163. package/dist/esm/cli/optional-tool-freshness.js +219 -9
  164. package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
  165. package/dist/esm/daemon/domains/git-actions.js +136 -0
  166. package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
  167. package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
  168. package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
  169. package/dist/esm/daemon/domains/sessions-search.js +29 -0
  170. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
  171. package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
  172. package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
  173. package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
  174. package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
  175. package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
  176. package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
  177. package/dist/esm/daemon/handlers/git-handlers.js +27 -0
  178. package/dist/esm/daemon/handlers/product.d.ts +7 -0
  179. package/dist/esm/daemon/handlers/product.js +10 -119
  180. package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
  181. package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
  182. package/dist/esm/daemon/handlers/shared.d.ts +5 -0
  183. package/dist/esm/daemon/handlers/shared.js +16 -0
  184. package/dist/esm/daemon/methods.d.ts +8 -1
  185. package/dist/esm/daemon/methods.js +7 -0
  186. package/dist/esm/daemon/protocol/contract.d.ts +43 -0
  187. package/dist/esm/daemon/protocol/contract.js +26 -0
  188. package/dist/esm/daemon/protocol/index.d.ts +1 -1
  189. package/dist/esm/daemon/protocol/index.js +1 -1
  190. package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
  191. package/dist/esm/hooks/__conformance__/matrix.js +137 -0
  192. package/dist/esm/hooks/conformance/batch.js +5 -0
  193. package/dist/esm/hooks/doctor.d.ts +5 -3
  194. package/dist/esm/hooks/doctor.js +67 -16
  195. package/dist/esm/hooks/permission-request/index.js +9 -3
  196. package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
  197. package/dist/esm/hooks/permission-request/policy.js +13 -0
  198. package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
  199. package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
  200. package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
  201. package/dist/esm/hooks/pretool-guard/logger.js +16 -0
  202. package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
  203. package/dist/esm/hooks/pretool-guard/runner.js +68 -16
  204. package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
  205. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +54 -0
  206. package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
  207. package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
  208. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
  209. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
  210. package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +6 -1
  211. package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
  212. package/dist/esm/hooks/shared/guard-outcome.js +215 -0
  213. package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
  214. package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
  215. package/dist/esm/hooks/shared/types.d.ts +8 -5
  216. package/dist/esm/hooks/shared/types.js +50 -9
  217. package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
  218. package/dist/esm/hooks/stop/qa-changed-files.js +92 -0
  219. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
  220. package/dist/esm/mcp/blueprint/handlers/document-mutations.d.ts +5 -0
  221. package/dist/esm/mcp/blueprint/handlers/document-mutations.js +109 -11
  222. package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
  223. package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
  224. package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
  225. package/dist/esm/mcp/blueprint/registration.js +3 -2
  226. package/dist/esm/mcp/server.d.ts +1 -0
  227. package/dist/esm/mcp/server.js +27 -0
  228. package/dist/esm/mcp/tools/_names.d.ts +1 -1
  229. package/dist/esm/mcp/tools/_names.js +5 -0
  230. package/dist/esm/mcp/tools/_registry.js +10 -0
  231. package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
  232. package/dist/esm/mcp/tools/_shared/result.js +44 -1
  233. package/dist/esm/mcp/tools/audit.d.ts +5 -1
  234. package/dist/esm/mcp/tools/audit.js +42 -0
  235. package/dist/esm/mcp/tools/audits.d.ts +4 -0
  236. package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
  237. package/dist/esm/mcp/tools/ci-preflight.js +183 -0
  238. package/dist/esm/mcp/tools/pr-upsert.js +39 -1
  239. package/dist/esm/mcp/tools/review-run.d.ts +28 -0
  240. package/dist/esm/mcp/tools/review-run.js +216 -0
  241. package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
  242. package/dist/esm/mcp/tools/run-wait.js +593 -0
  243. package/dist/esm/mcp/tools/session-fetch-and-index.d.ts +1 -1
  244. package/dist/esm/mcp/tools/session-id.d.ts +3 -0
  245. package/dist/esm/mcp/tools/session-id.js +45 -0
  246. package/dist/esm/mcp/tools/session-info.d.ts +3 -0
  247. package/dist/esm/mcp/tools/session-info.js +49 -0
  248. package/dist/esm/output-transforms/audit.d.ts +23 -0
  249. package/dist/esm/output-transforms/audit.js +47 -0
  250. package/dist/esm/output-transforms/index.js +2 -0
  251. package/dist/esm/package.json +2 -0
  252. package/dist/esm/platform/client.d.ts +7 -1
  253. package/dist/esm/platform/github-contract-source.d.ts +2 -1
  254. package/dist/esm/pr-description/contract.js +24 -4
  255. package/dist/esm/review/authority.js +27 -14
  256. package/dist/esm/review/availability.d.ts +33 -0
  257. package/dist/esm/review/availability.js +122 -20
  258. package/dist/esm/review/delivery-verifier.d.ts +27 -0
  259. package/dist/esm/review/delivery-verifier.js +115 -0
  260. package/dist/esm/review/events.d.ts +3 -2
  261. package/dist/esm/review/events.js +23 -3
  262. package/dist/esm/review/execution/adapters.d.ts +11 -1
  263. package/dist/esm/review/execution/adapters.js +36 -10
  264. package/dist/esm/review/execution/artifacts.d.ts +1 -1
  265. package/dist/esm/review/execution/output-policy.d.ts +2 -0
  266. package/dist/esm/review/execution/output-policy.js +12 -0
  267. package/dist/esm/review/execution/review-checkout.js +121 -21
  268. package/dist/esm/review/execution/supervisor.js +36 -4
  269. package/dist/esm/review/execution/types.d.ts +9 -0
  270. package/dist/esm/review/opencode-account.d.ts +24 -0
  271. package/dist/esm/review/opencode-account.js +68 -0
  272. package/dist/esm/review/opencode-auth.d.ts +33 -0
  273. package/dist/esm/review/opencode-auth.js +79 -0
  274. package/dist/esm/review/subject.d.ts +25 -0
  275. package/dist/esm/review/subject.js +116 -26
  276. package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
  277. package/dist/esm/runtime/opencode-account-materializer.js +33 -0
  278. package/dist/esm/rust/affected-manifests.d.ts +38 -0
  279. package/dist/esm/rust/affected-manifests.js +69 -0
  280. package/dist/esm/session-memory/fetch-index.d.ts +1 -1
  281. package/dist/esm/status/snapshot.js +32 -25
  282. package/dist/esm/test/duration-sequencer.d.ts +20 -0
  283. package/dist/esm/test/duration-sequencer.js +54 -0
  284. package/dist/esm/test/shard-durations.json +922 -0
  285. package/dist/esm/test/worker-budget.d.ts +6 -0
  286. package/dist/esm/test/worker-budget.js +59 -1
  287. package/dist/esm/test-helpers/global-setup.d.ts +1 -2
  288. package/dist/esm/test-helpers/global-setup.js +79 -32
  289. package/dist/esm/typecheck/planner.d.ts +9 -1
  290. package/dist/esm/typecheck/planner.js +31 -0
  291. package/dist/esm/ultragoal/service.d.ts +7 -0
  292. package/dist/esm/ultragoal/service.js +42 -2
  293. package/dist/esm/utils/write-json-file.js +3 -1
  294. package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
  295. package/dist/esm/worktrees/codex-project-trust.js +56 -0
  296. package/dist/esm/worktrees/orphan-scan.d.ts +50 -0
  297. package/dist/esm/worktrees/orphan-scan.js +211 -0
  298. package/dist/esm/worktrees/registry.d.ts +8 -0
  299. package/dist/esm/worktrees/registry.js +18 -3
  300. package/package.json +18 -13
@@ -0,0 +1,147 @@
1
+ import { loadOpencodeAccountAvailability, pruneExpiredOpencodeAccountSuppressions, recordOpencodeAccountAvailabilityWithLock, } from "#review/availability.js";
2
+ import { opencodeAccountCanonicalId, selectActiveOpencodeAccount, } from "#review/opencode-account.js";
3
+ import { materializeOpencodeGoAuth, readOpencodeGoKey } from "#review/opencode-auth.js";
4
+ import { resolveOpencodeAccountsGracefully } from "#runtime/opencode-account-materializer.js";
5
+ /** The `--wp-rotate` flag, namespaced like `--wp-permission-mode`. */
6
+ export const OPENCODE_ROTATE_FLAG = "--wp-rotate";
7
+ /**
8
+ * Cooldown to record when an account is known to be capped but the real reset
9
+ * window is unknown: it assumes the shortest real OpenCode Go window (5 hours).
10
+ *
11
+ * A manual `--wp-rotate` has no provider response at all, so it always lands
12
+ * here. The launch-time health probe (`#cli/commands/opencode-probe.js`) uses it
13
+ * only as a fallback, because that path *does* have a provider response and
14
+ * normally records the true parsed window instead.
15
+ *
16
+ * Recording no window at all would leave the record permanently suppressed —
17
+ * `suppressionExpired` only clears a record that carries `retryAfterMs` — so
18
+ * every rotated account would be cooled forever and selection would degrade to
19
+ * "first account" again. A too-short guess is self-correcting: the account is
20
+ * retried, and if it is still capped the gate (or the next probe/rotation)
21
+ * simply cools it again.
22
+ */
23
+ export const OPENCODE_UNKNOWN_LIMIT_COOLDOWN_MS = 5 * 60 * 60 * 1_000;
24
+ function coolActiveAccount(canonicalId, deps) {
25
+ if (deps.recordCooldown)
26
+ return deps.recordCooldown(canonicalId);
27
+ // Same event shape the review gate records on an in-flight usage limit, so
28
+ // both writers produce identical, mutually-readable cooldown records.
29
+ return recordOpencodeAccountAvailabilityWithLock(canonicalId, {
30
+ failureCode: "opencode-go-usage-limit",
31
+ terminalClassification: "provider-limit-reached",
32
+ limitWindow: "unknown",
33
+ retryAfterMs: OPENCODE_UNKNOWN_LIMIT_COOLDOWN_MS,
34
+ });
35
+ }
36
+ /**
37
+ * Pick the account to make active next.
38
+ *
39
+ * `excludeId` is the account we just cooled. It is filtered out here rather
40
+ * than relied upon coming back suppressed from the store: that keeps rotation
41
+ * correct even if the cooldown write is slow, contended, or fails outright, and
42
+ * removes a read-after-write dependency from the hot path.
43
+ */
44
+ function selectNextAccount(accounts, excludeId) {
45
+ const pruned = pruneExpiredOpencodeAccountSuppressions(loadOpencodeAccountAvailability());
46
+ const candidates = excludeId === undefined ? accounts : accounts.filter((account) => account.id !== excludeId);
47
+ // Callers guarantee at least one candidate: rotation needs >= 2 accounts, and
48
+ // the no-exclude path is only reached with a non-empty list.
49
+ const pool = candidates.length > 0 ? candidates : accounts;
50
+ const selection = selectActiveOpencodeAccount(pool, pruned.state);
51
+ return selection ?? { account: pool[0], cooled: false };
52
+ }
53
+ /**
54
+ * Cool the currently-materialized opencode-go account and materialize the next
55
+ * usable one into the global `auth.json`.
56
+ *
57
+ * The active account is identified by reading the global store back and matching
58
+ * its key against the resolved accounts — `wp` wrote that value itself, so this
59
+ * stays correct without persisting a separate "last launched" record. When the
60
+ * key matches nothing (a hand-edited store, or a fresh machine), the rotation
61
+ * degrades to a plain reselect and cools nothing, because cooling an account we
62
+ * cannot identify would suppress the wrong one.
63
+ *
64
+ * Never throws: the caller launches the TUI regardless of the outcome.
65
+ */
66
+ export async function rotateActiveOpencodeAccount(cwd, secretProfile, deps = {}) {
67
+ try {
68
+ return await rotateOrThrow(cwd, secretProfile, deps);
69
+ }
70
+ catch (error) {
71
+ // The cooldown write takes the user-scope lock the review gate also holds
72
+ // (contention rejects after a few short retries) and the auth write can fail
73
+ // with EACCES/ENOSPC. Neither may abort the launch, so both degrade to the
74
+ // same "carry on and launch" outcome the sibling select path uses.
75
+ return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
76
+ }
77
+ }
78
+ async function rotateOrThrow(cwd, secretProfile, deps) {
79
+ const resolution = (deps.resolveOpencodeAccounts ?? resolveOpencodeAccountsGracefully)({
80
+ cwd,
81
+ secretProfile,
82
+ });
83
+ if (!resolution.ok)
84
+ return { kind: "unavailable", reason: resolution.reason };
85
+ const accounts = resolution.accounts;
86
+ if (accounts.length < 2)
87
+ return { kind: "single-account" };
88
+ const activeKey = (deps.readActiveKey ?? (() => readOpencodeGoKey()))();
89
+ const current = accounts.find((account) => account.key === activeKey);
90
+ const materialize = deps.materializeGlobalOpencodeAuth ?? ((key) => void materializeOpencodeGoAuth(key));
91
+ if (!current) {
92
+ const next = selectNextAccount(accounts);
93
+ materialize(next.account.key);
94
+ return { kind: "reselected", activeAccountId: next.account.id, activeIsCooled: next.cooled };
95
+ }
96
+ await coolActiveAccount(opencodeAccountCanonicalId(current.id), deps);
97
+ const next = selectNextAccount(accounts, current.id);
98
+ materialize(next.account.key);
99
+ return {
100
+ kind: "rotated",
101
+ cooledAccountId: current.id,
102
+ activeAccountId: next.account.id,
103
+ activeIsCooled: next.cooled,
104
+ ...(next.waitMs === undefined ? {} : { waitMs: next.waitMs }),
105
+ };
106
+ }
107
+ /**
108
+ * Render a cooldown remainder as a short ` (resets in ~Xd)` suffix, or the empty
109
+ * string when the window is unknown. Shared with the launch-time health probe so
110
+ * rotation and probe output cannot drift apart.
111
+ */
112
+ export function formatOpencodeResetWait(waitMs) {
113
+ if (waitMs === undefined)
114
+ return "";
115
+ const hours = waitMs / 3_600_000;
116
+ if (hours >= 24)
117
+ return ` (resets in ~${Math.ceil(hours / 24)}d)`;
118
+ if (hours >= 1)
119
+ return ` (resets in ~${Math.ceil(hours)}h)`;
120
+ return ` (resets in ~${Math.max(1, Math.ceil(waitMs / 60_000))}m)`;
121
+ }
122
+ /** Human-readable lines describing a rotation outcome, in print order. */
123
+ export function describeOpencodeRotate(outcome) {
124
+ switch (outcome.kind) {
125
+ case "unavailable":
126
+ return [`wp opencode: could not resolve OpenCode Go accounts (${outcome.reason}).`];
127
+ case "single-account":
128
+ return [
129
+ "wp opencode: only one OpenCode Go account is configured; nothing to rotate to. Add OPENCODE_GO_KEY_<ID> secrets to enable rotation.",
130
+ ];
131
+ case "reselected":
132
+ return [
133
+ "wp opencode: the active key matches no configured account, so nothing was cooled.",
134
+ `wp opencode: now active -> opencode-go:${outcome.activeAccountId}`,
135
+ ];
136
+ case "rotated": {
137
+ const lines = [
138
+ `wp opencode: cooled opencode-go:${outcome.cooledAccountId} (usage limit)`,
139
+ `wp opencode: now active -> opencode-go:${outcome.activeAccountId}`,
140
+ ];
141
+ if (outcome.activeIsCooled) {
142
+ lines.push(`wp opencode: every account is within its cooldown; using the soonest-expiring one${formatOpencodeResetWait(outcome.waitMs)}. Run again after it resets, or add another OPENCODE_GO_KEY_<ID>.`);
143
+ }
144
+ return lines;
145
+ }
146
+ }
147
+ }
@@ -0,0 +1,11 @@
1
+ import type { CAC } from "cac";
2
+ export declare const PUBLIC_READINESS_COMMAND_HELP: string;
3
+ export interface PublicReadinessDeps {
4
+ readonly cwd?: string;
5
+ readonly resolveRepoRoot?: (cwd: string) => string | null;
6
+ readonly hasReadinessScript?: (repoRoot: string) => boolean;
7
+ readonly run?: (repoRoot: string) => number;
8
+ readonly stderr?: Pick<typeof process.stderr, "write">;
9
+ }
10
+ export declare function runPublicReadiness(deps?: PublicReadinessDeps): number;
11
+ export declare function registerPublicReadinessCommand(cli: CAC): void;
@@ -0,0 +1,42 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { getGitTopLevel } from "#git/changed-files";
5
+ export const PUBLIC_READINESS_COMMAND_HELP = [
6
+ "Run the public package readiness gate.",
7
+ "",
8
+ "Delegates to scripts/public-readiness.ts, preserving that script as the",
9
+ "single owner of package and repository visibility readiness checks.",
10
+ "",
11
+ "Examples:",
12
+ " wp public:readiness",
13
+ ].join("\n");
14
+ function defaultRunPublicReadiness(repoRoot) {
15
+ const result = spawnSync("bun", ["scripts/public-readiness.ts"], {
16
+ cwd: repoRoot,
17
+ stdio: "inherit",
18
+ env: process.env,
19
+ });
20
+ if (result.error) {
21
+ process.stderr.write(`${result.error.message}\n`);
22
+ return 1;
23
+ }
24
+ return typeof result.status === "number" ? result.status : 1;
25
+ }
26
+ export function runPublicReadiness(deps = {}) {
27
+ const cwd = deps.cwd ?? process.cwd();
28
+ const stderr = deps.stderr ?? process.stderr;
29
+ const resolveRepoRoot = deps.resolveRepoRoot ?? ((current) => getGitTopLevel(current));
30
+ const hasReadinessScript = deps.hasReadinessScript ??
31
+ ((repoRoot) => existsSync(path.join(repoRoot, "scripts", "public-readiness.ts")));
32
+ const run = deps.run ?? defaultRunPublicReadiness;
33
+ const repoRoot = resolveRepoRoot(cwd) ?? cwd;
34
+ if (!hasReadinessScript(repoRoot)) {
35
+ stderr.write(`wp public:readiness: scripts/public-readiness.ts is missing at ${repoRoot}.\n`);
36
+ return 1;
37
+ }
38
+ return run(repoRoot);
39
+ }
40
+ export function registerPublicReadinessCommand(cli) {
41
+ cli.command("public:readiness", PUBLIC_READINESS_COMMAND_HELP).action(() => runPublicReadiness());
42
+ }
@@ -147,9 +147,9 @@ function renderSummaryLines(summary, transformed, entry, passed) {
147
147
  }
148
148
  if (!passed || transformed.truncated) {
149
149
  lines.push(`Full log: wp logs ${entry.command}`);
150
- }
151
- if (transformed.elisions && transformed.elisions.length > 0) {
152
- lines.push(...transformed.elisions.map((elision) => `Retrieve elision: ${elision.retrieveTool} id=${elision.id}`));
150
+ if (transformed.elisions && transformed.elisions.length > 0) {
151
+ lines.push(...transformed.elisions.map((elision) => `Retrieve elision: ${elision.retrieveTool} id=${elision.id}`));
152
+ }
153
153
  }
154
154
  if (transformed.warnings && transformed.warnings.length > 0) {
155
155
  lines.push(...transformed.warnings.map((warning) => `Warning: ${warning}`));
@@ -2,8 +2,11 @@ import type { CAC } from "cac";
2
2
  import { runReviewExecution, type ReviewEffort, type ReviewLimitWindow, type ReviewProvider, type ReviewRunSummary, type ReviewStage } from "#review/execution/index.js";
3
3
  import { createReviewTargetCheckout, type ReviewTargetCheckout } from "#review/execution/review-checkout.js";
4
4
  import { type ReviewProcessRecord } from "#review/execution/process-registry.js";
5
+ import { type OpencodeAccount } from "#review/opencode-account.js";
6
+ import { resolveOpencodeAccountsGracefully } from "#runtime/opencode-account-materializer.js";
5
7
  import { evaluateApprovalGate } from "#lifecycle/audit";
6
8
  import { type ReviewEvent } from "#review/events.js";
9
+ import { type ReviewGateVerification } from "#review/delivery-verifier.js";
7
10
  import { runCommand } from "#mcp/tools/_shared/run-command.js";
8
11
  export type ReviewVerdict = "approve" | "approve-with-nits" | "reject" | "no-verdict";
9
12
  export type ReviewStatus = "complete" | "timed-out" | "incomplete" | "unavailable" | "failed";
@@ -77,6 +80,8 @@ export interface ReviewCommandOptions {
77
80
  artifactRoot?: string;
78
81
  idleSeconds?: string;
79
82
  maxProgressEvents?: string;
83
+ reason?: string;
84
+ confirm?: boolean;
80
85
  }
81
86
  interface ReviewGateAttempt {
82
87
  readonly provider: ReviewProvider;
@@ -90,6 +95,7 @@ interface ReviewGateAttempt {
90
95
  readonly verdict: ReviewVerdict;
91
96
  readonly terminalClassification: string;
92
97
  readonly failureCode?: string;
98
+ readonly providerErrorDetail?: string;
93
99
  readonly limitWindow?: ReviewLimitWindow;
94
100
  readonly retryAfterMs?: number;
95
101
  readonly artifact?: string;
@@ -105,7 +111,7 @@ interface ReviewGateResult {
105
111
  readonly targetSha: string;
106
112
  readonly baseSha: string;
107
113
  readonly promptHash: string;
108
- readonly status: "approved" | "needs-review" | "rejected" | "recorded-untracked";
114
+ readonly status: "approved" | "needs-review" | "rejected" | "scope-exhausted" | "recorded-untracked" | "verification-failed";
109
115
  readonly approvalGate: ReturnType<typeof evaluateApprovalGate>;
110
116
  readonly statePath: string;
111
117
  readonly attempts: readonly ReviewGateAttempt[];
@@ -123,6 +129,7 @@ interface ReviewGateResult {
123
129
  readonly rev?: string;
124
130
  }[];
125
131
  readonly issues?: readonly string[];
132
+ readonly verification?: ReviewGateVerification;
126
133
  readonly message: string;
127
134
  }
128
135
  interface ReviewLedger {
@@ -164,6 +171,22 @@ export declare function runReviewRunCommand(projectRoot: string, options: Review
164
171
  export declare function readReviewLedger(projectRoot: string, slug: string): Promise<ReviewLedger>;
165
172
  export declare function logReviewEntry(projectRoot: string, slug: string, input: ReviewCommandOptions): Promise<ReviewEntry>;
166
173
  export declare function logReviewEvent(projectRoot: string, slug: string, input: ReviewCommandOptions): Promise<ReviewEvent>;
174
+ /**
175
+ * `wp review override` — the gated, auditable human escape hatch for the
176
+ * promotion approval gate. It records a `maintainer-override` approval that
177
+ * satisfies the gate distinctly (never as a strong/OpenCode-Go approval).
178
+ *
179
+ * Trust properties:
180
+ * - REFUSES unless a formal strong-reviewer gate has already REJECTED the exact
181
+ * current subject (precondition + target binding are the same lookup).
182
+ * - Requires an explicit `--reason` and `--confirm` — no accidental invocation.
183
+ * - Reviewer id `maintainer-override` is not in the `wp review log` reviewer
184
+ * enum, so neither `wp review log` nor `wp_blueprint_review_log` can mint it;
185
+ * this command is the only writer. The read-time policy in
186
+ * `#review/events` treats it as human-like, so its manual-stage record is a
187
+ * legitimate governance approval rather than a disguised machine approval.
188
+ */
189
+ export declare function runReviewOverride(projectRoot: string, slug: string, input: ReviewCommandOptions): Promise<ReviewEvent>;
167
190
  export declare function classifyProviderOutput(output: string): Pick<ReviewGateAttempt, "status" | "verdict" | "terminalClassification">;
168
191
  export declare function reviewerFamily(model: string): ReviewReviewerId;
169
192
  type GateProviderResultStage = ReviewStage | "approval-gate";
@@ -176,18 +199,26 @@ export declare function invokeProvider(input: {
176
199
  readonly provider: ReviewProvider;
177
200
  readonly targetSha: string;
178
201
  readonly signal?: AbortSignal;
179
- }, executeReview?: typeof runReviewExecution, runCatalogCommand?: typeof runCommand, createTargetCheckout?: typeof createReviewTargetCheckout, existingCheckout?: ReviewTargetCheckout): Promise<{
202
+ readonly authDataDir?: string;
203
+ }, executeReview?: typeof runReviewExecution, runCatalogCommand?: typeof runCommand, createTargetCheckout?: typeof createReviewTargetCheckout, getSharedCheckout?: () => ReviewTargetCheckout | undefined): Promise<{
180
204
  output: string;
181
205
  model: string;
182
206
  reviewer: string;
183
207
  stage?: GateProviderResultStage;
184
- } & Pick<ReviewGateAttempt, "status" | "verdict" | "terminalClassification" | "failureCode" | "limitWindow" | "retryAfterMs">>;
208
+ } & Pick<ReviewGateAttempt, "status" | "verdict" | "terminalClassification" | "failureCode" | "providerErrorDetail" | "limitWindow" | "retryAfterMs">>;
185
209
  export interface ReviewGateDependencies {
186
210
  readonly createTargetCheckout?: typeof createReviewTargetCheckout;
187
211
  readonly invokeProvider?: typeof invokeProvider;
188
212
  readonly runCatalogCommand?: typeof runCommand;
189
213
  readonly runReviewExecution?: typeof runReviewExecution;
190
214
  readonly signal?: AbortSignal;
215
+ /** Test seam: resolve opencode-go accounts from the secret provider. */
216
+ readonly resolveOpencodeAccounts?: typeof resolveOpencodeAccountsGracefully;
217
+ /**
218
+ * Test seam: materialize an account's isolated auth store and return the
219
+ * `XDG_DATA_HOME` directory to inject for that account's spawns.
220
+ */
221
+ readonly prepareOpencodeCredential?: (account: OpencodeAccount) => string;
191
222
  }
192
223
  /**
193
224
  * Sanctioned fallback when `wp review gate` does not reach "approved" — points
@@ -198,6 +229,7 @@ export interface ReviewGateDependencies {
198
229
  export declare function reviewGateNonConvergenceHint(slug: string, context?: {
199
230
  readonly gateId?: string;
200
231
  readonly failureCode?: string;
232
+ readonly status?: ReviewGateResult["status"];
201
233
  }): string;
202
234
  export declare function runReviewGate(projectRoot: string, slug: string, input: ReviewCommandOptions, dependencies?: ReviewGateDependencies): Promise<ReviewGateResult>;
203
235
  export declare function buildReviewScoreboard(entries: readonly ReviewEntry[]): readonly ReviewScoreboardRow[];