@webpresso/agent-kit 3.1.28 → 3.2.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.

Potentially problematic release.


This version of @webpresso/agent-kit might be problematic. Click here for more details.

Files changed (329) hide show
  1. package/README.md +53 -15
  2. package/bin/_run.js +179 -19
  3. package/catalog/AGENTS.md.tpl +6 -6
  4. package/catalog/agent/agents/implementer.md +45 -0
  5. package/catalog/agent/rules/ci-cost-local-first.md +139 -0
  6. package/catalog/agent/rules/ci-test-perf.md +5 -1
  7. package/catalog/agent/rules/cmd-execution.md +9 -0
  8. package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
  9. package/catalog/agent/rules/pre-implementation.md +30 -2
  10. package/catalog/agent/rules/supported-agent-clis.md +9 -0
  11. package/catalog/agent/rules/test-scan-perf.md +80 -0
  12. package/catalog/agent/rules/typescript-version.md +50 -0
  13. package/catalog/agent/rules/workflow-skills-routing.md +4 -2
  14. package/catalog/agent/skills/codex/SKILL.md +25 -1
  15. package/catalog/agent/skills/fix/SKILL.md +3 -0
  16. package/catalog/agent/skills/verify/SKILL.md +22 -2
  17. package/catalog/docs/templates/blueprint.md +1 -1
  18. package/dist/esm/audit/agents.js +1 -0
  19. package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
  20. package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
  21. package/dist/esm/audit/blueprint-pr-coverage.js +72 -7
  22. package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
  23. package/dist/esm/audit/ci-guardrails-wiring.js +90 -0
  24. package/dist/esm/audit/ci-test-perf.js +30 -0
  25. package/dist/esm/audit/command-surface.js +4 -2
  26. package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
  27. package/dist/esm/audit/host-substitution-risk.js +256 -0
  28. package/dist/esm/audit/registry.d.ts +4 -4
  29. package/dist/esm/audit/registry.js +11 -1
  30. package/dist/esm/audit/roadmap-links.js +6 -0
  31. package/dist/esm/audit/test-scan-perf.d.ts +18 -0
  32. package/dist/esm/audit/test-scan-perf.js +275 -0
  33. package/dist/esm/audit/toolchain-isolation.js +1 -2
  34. package/dist/esm/audit/typescript-version.d.ts +2 -0
  35. package/dist/esm/audit/typescript-version.js +123 -0
  36. package/dist/esm/blueprint/core/parser.js +43 -1
  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 +65 -10
  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/engine.d.ts +9 -0
  46. package/dist/esm/blueprint/lifecycle/engine.js +53 -6
  47. package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
  48. package/dist/esm/blueprint/lifecycle/local.js +19 -3
  49. package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
  50. package/dist/esm/blueprint/lifecycle/review-provenance.js +118 -12
  51. package/dist/esm/blueprint/markdown/helpers.js +6 -2
  52. package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
  53. package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
  54. package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
  55. package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
  56. package/dist/esm/blueprint/trust/command-runner.js +148 -0
  57. package/dist/esm/blueprint/trust/gates.d.ts +7 -0
  58. package/dist/esm/blueprint/trust/gates.js +20 -0
  59. package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
  60. package/dist/esm/blueprint/trust/promotion.js +62 -112
  61. package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
  62. package/dist/esm/blueprint/trust/scaffold.js +64 -0
  63. package/dist/esm/blueprint/trust/validator.d.ts +1 -0
  64. package/dist/esm/blueprint/trust/validator.js +7 -1
  65. package/dist/esm/blueprint/utils/archive.js +27 -5
  66. package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
  67. package/dist/esm/blueprint/utils/document-paths.js +45 -12
  68. package/dist/esm/build/cli-mcp-parity.js +10 -0
  69. package/dist/esm/ci/act-replay.js +110 -7
  70. package/dist/esm/ci/act-runner.d.ts +4 -0
  71. package/dist/esm/ci/act-runner.js +85 -26
  72. package/dist/esm/ci/act-worktree-git.d.ts +11 -0
  73. package/dist/esm/ci/act-worktree-git.js +219 -0
  74. package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
  75. package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
  76. package/dist/esm/cli/cli.d.ts +1 -1
  77. package/dist/esm/cli/cli.js +34 -0
  78. package/dist/esm/cli/commands/agent-launch.d.ts +6 -1
  79. package/dist/esm/cli/commands/agent-launch.js +82 -4
  80. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  81. package/dist/esm/cli/commands/audit-core.js +8 -1
  82. package/dist/esm/cli/commands/audit.js +20 -5
  83. package/dist/esm/cli/commands/blueprint/execution.js +18 -6
  84. package/dist/esm/cli/commands/blueprint/mutations.js +83 -47
  85. package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
  86. package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
  87. package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
  88. package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
  89. package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
  90. package/dist/esm/cli/commands/blueprint/router.js +40 -3
  91. package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
  92. package/dist/esm/cli/commands/ci-preflight.js +6 -3
  93. package/dist/esm/cli/commands/ci.d.ts +8 -1
  94. package/dist/esm/cli/commands/ci.js +80 -21
  95. package/dist/esm/cli/commands/compile.js +5 -31
  96. package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
  97. package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
  98. package/dist/esm/cli/commands/dash/keymap.js +1 -0
  99. package/dist/esm/cli/commands/dash/launch-preferences.d.ts +15 -0
  100. package/dist/esm/cli/commands/dash/launch-preferences.js +46 -17
  101. package/dist/esm/cli/commands/dash/plan-once-label.d.ts +7 -0
  102. package/dist/esm/cli/commands/dash/plan-once-label.js +5 -0
  103. package/dist/esm/cli/commands/dash/plan-once-membership.d.ts +67 -0
  104. package/dist/esm/cli/commands/dash/plan-once-membership.js +151 -0
  105. package/dist/esm/cli/commands/dash/plan-once-merge.d.ts +143 -0
  106. package/dist/esm/cli/commands/dash/plan-once-merge.js +238 -0
  107. package/dist/esm/cli/commands/dash/plan-once.d.ts +22 -2
  108. package/dist/esm/cli/commands/dash/plan-once.js +41 -4
  109. package/dist/esm/cli/commands/dash/tui/attention-hud.d.ts +9 -0
  110. package/dist/esm/cli/commands/dash/tui/attention-hud.js +9 -0
  111. package/dist/esm/cli/commands/dash/tui/chat-bridge.d.ts +41 -0
  112. package/dist/esm/cli/commands/dash/tui/chat-bridge.js +73 -0
  113. package/dist/esm/cli/commands/dash/tui/chat-mode.d.ts +47 -0
  114. package/dist/esm/cli/commands/dash/tui/chat-mode.js +98 -0
  115. package/dist/esm/cli/commands/dash/tui/frame.d.ts +3 -0
  116. package/dist/esm/cli/commands/dash/tui/frame.js +3 -1
  117. package/dist/esm/cli/commands/dash/tui/palette.d.ts +1 -1
  118. package/dist/esm/cli/commands/dash/tui/palette.js +14 -0
  119. package/dist/esm/cli/commands/dash/tui/runtime.js +239 -4
  120. package/dist/esm/cli/commands/dash/tui/state.d.ts +41 -0
  121. package/dist/esm/cli/commands/dash/tui/state.js +257 -4
  122. package/dist/esm/cli/commands/doctor.js +5 -0
  123. package/dist/esm/cli/commands/format.js +0 -2
  124. package/dist/esm/cli/commands/hook.d.ts +5 -0
  125. package/dist/esm/cli/commands/hook.js +15 -9
  126. package/dist/esm/cli/commands/init/config.d.ts +0 -1
  127. package/dist/esm/cli/commands/init/config.js +3 -6
  128. package/dist/esm/cli/commands/init/convergence-apply.d.ts +24 -0
  129. package/dist/esm/cli/commands/init/convergence-apply.js +221 -0
  130. package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
  131. package/dist/esm/cli/commands/init/convergence-state.js +54 -0
  132. package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
  133. package/dist/esm/cli/commands/init/convergence.js +57 -0
  134. package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
  135. package/dist/esm/cli/commands/init/git-convergence.js +168 -0
  136. package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
  137. package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
  138. package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
  139. package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
  140. package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
  141. package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
  142. package/dist/esm/cli/commands/init/host-visibility.js +94 -5
  143. package/dist/esm/cli/commands/init/index.d.ts +1 -0
  144. package/dist/esm/cli/commands/init/index.js +326 -173
  145. package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
  146. package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
  147. package/dist/esm/cli/commands/init/merge.d.ts +1 -0
  148. package/dist/esm/cli/commands/init/merge.js +30 -1
  149. package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
  150. package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
  151. package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
  152. package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
  153. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +11 -0
  154. package/dist/esm/cli/commands/init/scaffold-base-kit.js +56 -1
  155. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/claude.d.ts +5 -6
  156. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/claude.js +6 -13
  157. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
  158. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
  159. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
  160. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +51 -23
  161. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/ir.d.ts +0 -2
  162. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/ir.js +0 -2
  163. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/merge.d.ts +6 -3
  164. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/merge.js +39 -26
  165. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
  166. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +297 -173
  167. package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +7 -0
  168. package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +58 -0
  169. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
  170. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
  171. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
  172. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
  173. package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
  174. package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
  175. package/dist/esm/cli/commands/logs.d.ts +15 -0
  176. package/dist/esm/cli/commands/logs.js +192 -3
  177. package/dist/esm/cli/commands/opencode-rotate.d.ts +49 -0
  178. package/dist/esm/cli/commands/opencode-rotate.js +135 -0
  179. package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
  180. package/dist/esm/cli/commands/public-readiness.js +42 -0
  181. package/dist/esm/cli/commands/quality-log-store.d.ts +1 -0
  182. package/dist/esm/cli/commands/quality-log-store.js +187 -51
  183. package/dist/esm/cli/commands/review.d.ts +35 -3
  184. package/dist/esm/cli/commands/review.js +734 -217
  185. package/dist/esm/cli/commands/run-wait.d.ts +2 -0
  186. package/dist/esm/cli/commands/run-wait.js +122 -0
  187. package/dist/esm/cli/commands/secrets.d.ts +1 -0
  188. package/dist/esm/cli/commands/secrets.js +4 -1
  189. package/dist/esm/cli/commands/setup-help.js +1 -1
  190. package/dist/esm/cli/commands/setup-repair-help.js +1 -1
  191. package/dist/esm/cli/commands/worktree/router-dispatch.js +13 -8
  192. package/dist/esm/cli/direct-provider-launch.js +31 -3
  193. package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
  194. package/dist/esm/cli/optional-tool-freshness.js +219 -9
  195. package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
  196. package/dist/esm/daemon/domains/git-actions.js +136 -0
  197. package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
  198. package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
  199. package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
  200. package/dist/esm/daemon/domains/sessions-search.js +29 -0
  201. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
  202. package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
  203. package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
  204. package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
  205. package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
  206. package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
  207. package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
  208. package/dist/esm/daemon/handlers/git-handlers.js +27 -0
  209. package/dist/esm/daemon/handlers/product.d.ts +7 -0
  210. package/dist/esm/daemon/handlers/product.js +10 -119
  211. package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
  212. package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
  213. package/dist/esm/daemon/handlers/shared.d.ts +5 -0
  214. package/dist/esm/daemon/handlers/shared.js +16 -0
  215. package/dist/esm/daemon/methods.d.ts +8 -1
  216. package/dist/esm/daemon/methods.js +7 -0
  217. package/dist/esm/daemon/protocol/contract.d.ts +43 -0
  218. package/dist/esm/daemon/protocol/contract.js +26 -0
  219. package/dist/esm/daemon/protocol/index.d.ts +1 -1
  220. package/dist/esm/daemon/protocol/index.js +1 -1
  221. package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
  222. package/dist/esm/hooks/__conformance__/matrix.js +137 -0
  223. package/dist/esm/hooks/conformance/batch.js +5 -0
  224. package/dist/esm/hooks/doctor.d.ts +15 -0
  225. package/dist/esm/hooks/doctor.js +79 -8
  226. package/dist/esm/hooks/permission-request/index.js +9 -3
  227. package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
  228. package/dist/esm/hooks/permission-request/policy.js +13 -0
  229. package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
  230. package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
  231. package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
  232. package/dist/esm/hooks/pretool-guard/logger.js +16 -0
  233. package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
  234. package/dist/esm/hooks/pretool-guard/runner.js +68 -16
  235. package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
  236. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +58 -4
  237. package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
  238. package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
  239. package/dist/esm/hooks/pretool-guard/validators/mcp-redirect.d.ts +0 -1
  240. package/dist/esm/hooks/pretool-guard/validators/mcp-redirect.js +8 -5
  241. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
  242. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
  243. package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.d.ts +9 -7
  244. package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +126 -14
  245. package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
  246. package/dist/esm/hooks/shared/guard-outcome.js +215 -0
  247. package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
  248. package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
  249. package/dist/esm/hooks/shared/types.d.ts +8 -5
  250. package/dist/esm/hooks/shared/types.js +23 -8
  251. package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
  252. package/dist/esm/hooks/stop/qa-changed-files.js +74 -0
  253. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
  254. package/dist/esm/mcp/blueprint/handlers/document-mutations.js +78 -4
  255. package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
  256. package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
  257. package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
  258. package/dist/esm/mcp/blueprint/registration.js +3 -2
  259. package/dist/esm/mcp/server.d.ts +1 -0
  260. package/dist/esm/mcp/server.js +27 -0
  261. package/dist/esm/mcp/tools/_names.d.ts +1 -1
  262. package/dist/esm/mcp/tools/_names.js +5 -0
  263. package/dist/esm/mcp/tools/_registry.js +10 -0
  264. package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
  265. package/dist/esm/mcp/tools/_shared/result.js +44 -1
  266. package/dist/esm/mcp/tools/audit.d.ts +5 -1
  267. package/dist/esm/mcp/tools/audit.js +40 -0
  268. package/dist/esm/mcp/tools/audits.d.ts +4 -0
  269. package/dist/esm/mcp/tools/ci-act.js +9 -11
  270. package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
  271. package/dist/esm/mcp/tools/ci-preflight.js +183 -0
  272. package/dist/esm/mcp/tools/pr-upsert.js +39 -1
  273. package/dist/esm/mcp/tools/review-run.d.ts +28 -0
  274. package/dist/esm/mcp/tools/review-run.js +216 -0
  275. package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
  276. package/dist/esm/mcp/tools/run-wait.js +593 -0
  277. package/dist/esm/mcp/tools/session-id.d.ts +3 -0
  278. package/dist/esm/mcp/tools/session-id.js +45 -0
  279. package/dist/esm/mcp/tools/session-info.d.ts +3 -0
  280. package/dist/esm/mcp/tools/session-info.js +49 -0
  281. package/dist/esm/output-transforms/audit.d.ts +23 -0
  282. package/dist/esm/output-transforms/audit.js +47 -0
  283. package/dist/esm/output-transforms/index.js +2 -0
  284. package/dist/esm/paths/state-root.js +3 -0
  285. package/dist/esm/review/authority.js +30 -7
  286. package/dist/esm/review/availability.d.ts +22 -0
  287. package/dist/esm/review/availability.js +123 -23
  288. package/dist/esm/review/delivery-verifier.d.ts +27 -0
  289. package/dist/esm/review/delivery-verifier.js +115 -0
  290. package/dist/esm/review/events.d.ts +3 -2
  291. package/dist/esm/review/events.js +23 -3
  292. package/dist/esm/review/execution/adapters.js +26 -9
  293. package/dist/esm/review/execution/output-policy.d.ts +2 -0
  294. package/dist/esm/review/execution/output-policy.js +12 -0
  295. package/dist/esm/review/execution/review-checkout.js +87 -6
  296. package/dist/esm/review/execution/supervisor.js +5 -0
  297. package/dist/esm/review/execution/types.d.ts +8 -0
  298. package/dist/esm/review/opencode-account.d.ts +24 -0
  299. package/dist/esm/review/opencode-account.js +68 -0
  300. package/dist/esm/review/opencode-auth.d.ts +33 -0
  301. package/dist/esm/review/opencode-auth.js +79 -0
  302. package/dist/esm/review/subject.d.ts +27 -0
  303. package/dist/esm/review/subject.js +179 -32
  304. package/dist/esm/runtime/executor.d.ts +1 -0
  305. package/dist/esm/runtime/executor.js +2 -1
  306. package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
  307. package/dist/esm/runtime/opencode-account-materializer.js +33 -0
  308. package/dist/esm/secret-gate/runner.d.ts +1 -0
  309. package/dist/esm/secret-gate/runner.js +4 -1
  310. package/dist/esm/status/snapshot.js +30 -19
  311. package/dist/esm/test/duration-sequencer.d.ts +20 -0
  312. package/dist/esm/test/duration-sequencer.js +54 -0
  313. package/dist/esm/test/shard-durations.json +922 -0
  314. package/dist/esm/test/worker-budget.d.ts +6 -0
  315. package/dist/esm/test/worker-budget.js +59 -1
  316. package/dist/esm/test-helpers/global-setup.d.ts +1 -1
  317. package/dist/esm/test-helpers/global-setup.js +68 -24
  318. package/dist/esm/ultragoal/service.d.ts +7 -0
  319. package/dist/esm/ultragoal/service.js +42 -2
  320. package/dist/esm/utils/write-json-file.js +3 -1
  321. package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
  322. package/dist/esm/worktrees/codex-project-trust.js +56 -0
  323. package/dist/esm/worktrees/current.d.ts +1 -0
  324. package/dist/esm/worktrees/current.js +1 -0
  325. package/dist/esm/worktrees/project-agent-surfaces.d.ts +1 -0
  326. package/dist/esm/worktrees/project-agent-surfaces.js +2 -1
  327. package/dist/esm/worktrees/registry.d.ts +8 -0
  328. package/dist/esm/worktrees/registry.js +18 -3
  329. package/package.json +18 -15
@@ -0,0 +1,219 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, rmSync, symlinkSync, } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join, resolve, sep } from "node:path";
5
+ export function prepareActGitWorkspace(cwd) {
6
+ const sourceCwd = resolve(cwd);
7
+ const linked = readLinkedWorktreeGitMetadata(sourceCwd);
8
+ if (!linked) {
9
+ return {
10
+ cwd: sourceCwd,
11
+ prepared: false,
12
+ cleanup() { },
13
+ };
14
+ }
15
+ assertExistingDirectory(linked.gitDir, "linked-worktree gitdir");
16
+ const commonDir = resolveGitCommonDir(linked.gitDir);
17
+ assertExistingDirectory(commonDir, "linked-worktree commondir");
18
+ const tempRoot = mkdtempSync(join(tmpdir(), "wp-ci-act-worktree-"));
19
+ const preparedCwd = join(tempRoot, "workspace");
20
+ try {
21
+ const head = git(sourceCwd, ["rev-parse", "HEAD"]);
22
+ git(sourceCwd, ["rev-parse", "--is-inside-work-tree"]);
23
+ execFileSync("git", [
24
+ "clone",
25
+ "--local",
26
+ "--no-hardlinks",
27
+ "--dissociate",
28
+ "--no-checkout",
29
+ sourceCwd,
30
+ preparedCwd,
31
+ ], {
32
+ encoding: "utf8",
33
+ stdio: ["ignore", "pipe", "pipe"],
34
+ });
35
+ syncOriginRemote(sourceCwd, preparedCwd);
36
+ git(preparedCwd, ["checkout", "--detach", "--quiet", head]);
37
+ overlayWorkingTreeChanges(sourceCwd, preparedCwd);
38
+ assertPreparedGitMetadataIsSelfContained(preparedCwd);
39
+ return {
40
+ cwd: preparedCwd,
41
+ prepared: true,
42
+ cleanup() {
43
+ rmSync(tempRoot, { recursive: true, force: true });
44
+ },
45
+ };
46
+ }
47
+ catch (error) {
48
+ rmSync(tempRoot, { recursive: true, force: true });
49
+ throw error;
50
+ }
51
+ }
52
+ export function readLinkedWorktreeGitMetadata(cwd) {
53
+ const gitPath = join(cwd, ".git");
54
+ if (!existsSync(gitPath)) {
55
+ return null;
56
+ }
57
+ const stat = lstatSync(gitPath);
58
+ if (stat.isDirectory())
59
+ return null;
60
+ if (!stat.isFile()) {
61
+ throw new Error(`Cannot prepare ci act workspace: ${gitPath} is not a file or directory.`);
62
+ }
63
+ const content = readFileSync(gitPath, "utf8").trim();
64
+ const match = /^gitdir:\s*(.+)$/u.exec(content);
65
+ if (!match?.[1]) {
66
+ throw new Error(`Cannot prepare ci act workspace: ${gitPath} is not a valid gitdir file.`);
67
+ }
68
+ return { gitDir: resolve(cwd, match[1]) };
69
+ }
70
+ function resolveGitCommonDir(gitDir) {
71
+ const commonDirPath = join(gitDir, "commondir");
72
+ if (!existsSync(commonDirPath))
73
+ return gitDir;
74
+ const raw = readFileSync(commonDirPath, "utf8").trim();
75
+ if (!raw)
76
+ throw new Error(`Cannot prepare ci act workspace: ${commonDirPath} is empty.`);
77
+ return resolve(gitDir, raw);
78
+ }
79
+ function overlayWorkingTreeChanges(sourceCwd, preparedCwd) {
80
+ const changed = parseGitDiffNameStatus(splitGitNullOutput(gitRaw(sourceCwd, ["diff", "--name-status", "--find-renames", "-z", "HEAD", "--"])));
81
+ const untracked = splitGitNullOutput(gitRaw(sourceCwd, ["ls-files", "--others", "--exclude-standard", "-z"]));
82
+ const copyPaths = new Set([...changed.copyPaths, ...untracked]);
83
+ for (const relativePath of changed.removePaths) {
84
+ assertSafeGitRelativePath(relativePath);
85
+ rmSync(join(preparedCwd, relativePath), { recursive: true, force: true });
86
+ }
87
+ for (const relativePath of copyPaths) {
88
+ assertSafeGitRelativePath(relativePath);
89
+ const sourcePath = join(sourceCwd, relativePath);
90
+ const preparedPath = join(preparedCwd, relativePath);
91
+ const sourceStat = tryLstat(sourcePath);
92
+ if (!sourceStat) {
93
+ rmSync(preparedPath, { recursive: true, force: true });
94
+ continue;
95
+ }
96
+ mkdirSync(dirname(preparedPath), { recursive: true });
97
+ if (sourceStat.isSymbolicLink()) {
98
+ rmSync(preparedPath, { recursive: true, force: true });
99
+ symlinkSync(readlinkSync(sourcePath), preparedPath);
100
+ continue;
101
+ }
102
+ rmSync(preparedPath, { recursive: true, force: true });
103
+ cpSync(sourcePath, preparedPath, { recursive: true, force: true, errorOnExist: false });
104
+ }
105
+ }
106
+ function tryLstat(path) {
107
+ try {
108
+ return lstatSync(path);
109
+ }
110
+ catch (error) {
111
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
112
+ return null;
113
+ }
114
+ throw error;
115
+ }
116
+ }
117
+ function parseGitDiffNameStatus(entries) {
118
+ const copyPaths = new Set();
119
+ const removePaths = new Set();
120
+ for (let index = 0; index < entries.length;) {
121
+ const status = entries[index++];
122
+ if (!status)
123
+ continue;
124
+ if (status.startsWith("R")) {
125
+ const oldPath = entries[index++];
126
+ const newPath = entries[index++];
127
+ if (oldPath)
128
+ removePaths.add(oldPath);
129
+ if (newPath)
130
+ copyPaths.add(newPath);
131
+ continue;
132
+ }
133
+ if (status.startsWith("C")) {
134
+ index++;
135
+ const newPath = entries[index++];
136
+ if (newPath)
137
+ copyPaths.add(newPath);
138
+ continue;
139
+ }
140
+ const path = entries[index++];
141
+ if (!path)
142
+ continue;
143
+ if (status.startsWith("D")) {
144
+ removePaths.add(path);
145
+ }
146
+ else {
147
+ copyPaths.add(path);
148
+ }
149
+ }
150
+ return { copyPaths, removePaths };
151
+ }
152
+ function syncOriginRemote(sourceCwd, preparedCwd) {
153
+ const originUrl = tryGit(sourceCwd, ["remote", "get-url", "origin"]);
154
+ if (originUrl) {
155
+ git(preparedCwd, ["remote", "set-url", "origin", originUrl]);
156
+ return;
157
+ }
158
+ tryGit(preparedCwd, ["remote", "remove", "origin"]);
159
+ }
160
+ function assertPreparedGitMetadataIsSelfContained(preparedCwd) {
161
+ const gitPath = join(preparedCwd, ".git");
162
+ if (!existsSync(gitPath) || !lstatSync(gitPath).isDirectory()) {
163
+ throw new Error("Cannot prepare ci act workspace: prepared .git metadata is not a directory.");
164
+ }
165
+ const commonDir = resolve(preparedCwd, git(preparedCwd, ["rev-parse", "--git-common-dir"]));
166
+ const relative = commonDirRelativeToPrepared(preparedCwd, commonDir);
167
+ if (relative === null) {
168
+ throw new Error(`Cannot prepare ci act workspace: prepared git common dir escaped the execution workspace (${commonDir}).`);
169
+ }
170
+ const alternatesPath = join(commonDir, "objects", "info", "alternates");
171
+ if (existsSync(alternatesPath) && readFileSync(alternatesPath, "utf8").trim().length > 0) {
172
+ throw new Error(`Cannot prepare ci act workspace: prepared git objects still depend on alternates (${alternatesPath}).`);
173
+ }
174
+ }
175
+ function commonDirRelativeToPrepared(preparedCwd, commonDir) {
176
+ const normalizedRoot = resolve(preparedCwd);
177
+ const normalizedCommon = resolve(commonDir);
178
+ if (normalizedCommon === normalizedRoot)
179
+ return "";
180
+ if (normalizedCommon.startsWith(`${normalizedRoot}${sep}`)) {
181
+ return normalizedCommon.slice(normalizedRoot.length + 1);
182
+ }
183
+ return null;
184
+ }
185
+ function splitGitNullOutput(output) {
186
+ return output.split("\0").filter((entry) => entry.length > 0);
187
+ }
188
+ function assertSafeGitRelativePath(relativePath) {
189
+ if (relativePath.length === 0 ||
190
+ relativePath.startsWith("/") ||
191
+ relativePath === ".." ||
192
+ relativePath.startsWith("../") ||
193
+ relativePath.includes("/../")) {
194
+ throw new Error(`Unsafe git path returned while preparing ci act workspace: ${relativePath}`);
195
+ }
196
+ }
197
+ function assertExistingDirectory(path, label) {
198
+ if (!existsSync(path) || !lstatSync(path).isDirectory()) {
199
+ throw new Error(`Cannot prepare ci act workspace: ${label} is missing or unreadable: ${path}`);
200
+ }
201
+ }
202
+ function git(cwd, args) {
203
+ return gitRaw(cwd, args).trim();
204
+ }
205
+ function tryGit(cwd, args) {
206
+ try {
207
+ return git(cwd, args);
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ }
213
+ function gitRaw(cwd, args) {
214
+ return execFileSync("git", [...args], {
215
+ cwd,
216
+ encoding: "utf8",
217
+ stdio: ["ignore", "pipe", "pipe"],
218
+ });
219
+ }
@@ -1,6 +1,7 @@
1
1
  import type { CliCommand } from "@webpresso/cli-contract";
2
2
  export declare const blueprintCommands: {
3
3
  audit: CliCommand<Record<string, unknown>>;
4
+ canonicalize: CliCommand<Record<string, unknown>>;
4
5
  exec: CliCommand<Record<string, unknown>>;
5
6
  finalize: CliCommand<Record<string, unknown>>;
6
7
  list: CliCommand<Record<string, unknown>>;
@@ -35,6 +35,7 @@ function createBlueprintAuditCommand() {
35
35
  }
36
36
  export const blueprintCommands = {
37
37
  audit: createBlueprintAuditCommand(),
38
+ canonicalize: placeholderCommand(SCOPE, "canonicalize", "Canonicalize a flat blueprint to folder shape"),
38
39
  exec: placeholderGroup(SCOPE, "exec", "Execute a blueprint", {
39
40
  logs: placeholderCommand(SCOPE, "logs", "Show blueprint execution logs"),
40
41
  resume: placeholderCommand(SCOPE, "resume", "Resume blueprint execution"),
@@ -5,7 +5,7 @@
5
5
  * Lazy-loads subcommand modules based on the first argv to keep startup
6
6
  * cheap. Modeled on apps/cli-wp/src/cli.ts.
7
7
  */
8
- declare const SUPPORTED_COMMANDS: readonly ["blueprint", "browser", "dash", "dash-helper-start", "dash-helper-complete", "claude", "codex", "grok", "opencode", "yolo", "config", "secrets", "roadmap", "status", "review", "sync", "audit", "qa", "ultragoal", "compile", "rule", "skill", "skills", "docs", "setup", "init", "dev", "deploy", "preview", "cleanup", "migrate", "doctor", "err", "test", "e2e", "ci", "ci-preflight", "typecheck", "lint", "format", "logs", "session-id", "session-info", "session", "tech-debt", "pr", "fleet", "worktree", "mcp", "hook", "hooks", "self-install-guard", "gain", "bench", "install", "add", "remove", "update", "exec", "run"];
8
+ declare const SUPPORTED_COMMANDS: readonly ["blueprint", "browser", "dash", "dash-helper-start", "dash-helper-complete", "claude", "codex", "grok", "opencode", "yolo", "config", "secrets", "roadmap", "status", "review", "sync", "audit", "qa", "ultragoal", "compile", "rule", "skill", "skills", "docs", "setup", "init", "dev", "deploy", "preview", "cleanup", "migrate", "doctor", "err", "test", "e2e", "ci", "ci-preflight", "public:readiness", "typecheck", "lint", "format", "logs", "session-id", "session-info", "session", "tech-debt", "pr", "fleet", "worktree", "mcp", "hook", "hooks", "self-install-guard", "optional-tool-refresh", "gain", "bench", "install", "add", "remove", "update", "exec", "run"];
9
9
  export type SupportedCommand = (typeof SUPPORTED_COMMANDS)[number];
10
10
  type RootHelpEntry = {
11
11
  readonly command: string;
@@ -55,6 +55,7 @@ const SUPPORTED_COMMANDS = [
55
55
  "e2e",
56
56
  "ci",
57
57
  "ci-preflight",
58
+ "public:readiness",
58
59
  "typecheck",
59
60
  "lint",
60
61
  "format",
@@ -70,6 +71,7 @@ const SUPPORTED_COMMANDS = [
70
71
  "hook",
71
72
  "hooks",
72
73
  "self-install-guard",
74
+ "optional-tool-refresh",
73
75
  "gain",
74
76
  "bench",
75
77
  "install",
@@ -111,6 +113,10 @@ const ROOT_HELP_CORE_ENTRIES = [
111
113
  command: "ci-preflight",
112
114
  description: "Run the locally-runnable required CI checks fail-fast (the pre-push gate)",
113
115
  },
116
+ {
117
+ command: "public:readiness",
118
+ description: "Run the public package readiness gate through the portable wp surface",
119
+ },
114
120
  { command: "logs", description: "Print persisted raw output from recent quality runs" },
115
121
  { command: "dev", description: "Run a manifest-backed development target" },
116
122
  { command: "status", description: "Show unified local readiness and next action" },
@@ -364,6 +370,10 @@ const COMMAND_REGISTRARS = {
364
370
  const { registerCiPreflightCommand } = await import("./commands/ci-preflight.js");
365
371
  registerCiPreflightCommand(cli);
366
372
  },
373
+ "public:readiness": async (cli) => {
374
+ const { registerPublicReadinessCommand } = await import("./commands/public-readiness.js");
375
+ registerPublicReadinessCommand(cli);
376
+ },
367
377
  typecheck: async (cli) => {
368
378
  const { registerTypecheckCommand } = await import("./commands/typecheck.js");
369
379
  registerTypecheckCommand(cli);
@@ -422,6 +432,15 @@ const COMMAND_REGISTRARS = {
422
432
  const { registerSelfInstallGuardCommand } = await import("./commands/self-install-guard.js");
423
433
  registerSelfInstallGuardCommand(cli);
424
434
  },
435
+ "optional-tool-refresh": async (cli) => {
436
+ cli
437
+ .command("optional-tool-refresh <tool> [...args]", "Internal detached optional-tool freshness worker")
438
+ .allowUnknownOptions()
439
+ .action(async (tool, args = []) => {
440
+ const { runOptionalToolRefreshWorker } = await import("./optional-tool-freshness.js");
441
+ process.exitCode = runOptionalToolRefreshWorker([tool, ...args]);
442
+ });
443
+ },
425
444
  gain: async (cli) => {
426
445
  const { registerGainCommand } = await import("./commands/gain/index.js");
427
446
  registerGainCommand(cli);
@@ -636,6 +655,21 @@ export async function main() {
636
655
  console.error(formatUnknownCommandError(command, SUPPORTED_COMMANDS));
637
656
  return 1;
638
657
  }
658
+ // `wp run wait` is the read-only workflow-run waiter, intercepted before the
659
+ // package-manager `run` facade (which maps `wp run <script>` to `vp run
660
+ // <script>`). Without this, `wait` would be treated as a package script name.
661
+ // Errors resolve to an exit code here, mirroring main()'s catch below, so a
662
+ // bad flag never rejects the main() promise.
663
+ if (resolvedCommand === "run" && argv[3] === "wait") {
664
+ const { runRunWaitCommand } = await import("./commands/run-wait.js");
665
+ try {
666
+ return await runRunWaitCommand(argv.slice(4));
667
+ }
668
+ catch (error) {
669
+ console.error(error instanceof Error ? error.message : String(error));
670
+ return 1;
671
+ }
672
+ }
639
673
  await COMMAND_REGISTRARS[resolvedCommand](cli, resolvedCommand);
640
674
  if (resolvedCommand === "session") {
641
675
  const { runSessionCommand } = await import("./commands/session.js");
@@ -2,6 +2,7 @@ import type { CAC } from "cac";
2
2
  import { type DashPermissionMode, type DashProvider } from "#cli/commands/dash/provider-capabilities.js";
3
3
  import { type RuntimeCommandOptions } from "#runtime/executor.js";
4
4
  import { type SecretsConfig } from "#runtime/secrets-config.js";
5
+ import { resolveOpencodeAccountsGracefully } from "#runtime/opencode-account-materializer.js";
5
6
  export declare const AGENT_LAUNCH_COMMANDS: readonly ["claude", "codex", "grok", "opencode"];
6
7
  export type AgentLaunchCommand = DashProvider;
7
8
  export declare const DEFAULT_AGENT_SECRET_PROFILE = "preview";
@@ -18,6 +19,10 @@ export interface AgentLaunchDeps {
18
19
  error?: Error;
19
20
  };
20
21
  readonly ensureCodexSkillSurface?: (cwd: string, env?: NodeJS.ProcessEnv) => string | null;
22
+ readonly resolveOpencodeAccounts?: typeof resolveOpencodeAccountsGracefully;
23
+ readonly materializeGlobalOpencodeAuth?: (key: string) => void;
24
+ readonly readActiveKey?: () => string | undefined;
25
+ readonly recordCooldown?: (canonicalId: string) => Promise<unknown>;
21
26
  }
22
27
  export declare function buildDefaultAgentArgs(command: AgentLaunchCommand, args?: readonly string[], permissionMode?: DashPermissionMode): readonly string[];
23
28
  export declare function isAgentLaunchCommand(command: string | undefined): command is AgentLaunchCommand;
@@ -29,5 +34,5 @@ export declare function buildAgentRuntimeCommandOptions(input: {
29
34
  readonly env?: NodeJS.ProcessEnv;
30
35
  readonly secretsConfig: SecretsConfig | null;
31
36
  }): RuntimeCommandOptions;
32
- export declare function runAgentLaunchCommand(command: AgentLaunchCommand, args?: readonly string[], options?: AgentLaunchOptions, deps?: AgentLaunchDeps): number;
37
+ export declare function runAgentLaunchCommand(command: AgentLaunchCommand, args?: readonly string[], options?: AgentLaunchOptions, deps?: AgentLaunchDeps): Promise<number>;
33
38
  export declare function registerAgentLaunchCommand(cli: CAC, command: AgentLaunchCommand): void;
@@ -7,6 +7,11 @@ import { WP_AGENT_LAUNCHED_VIA_WP_ENV, WP_AGENT_LAUNCHED_VIA_WP_VALUE, } from "#
7
7
  import { readSecretsConfig } from "#runtime/secrets-config.js";
8
8
  import { resolveFreshAgentKitPackageRoot } from "#cli/commands/init/package-root";
9
9
  import { ensureCodexUserPlugin } from "#cli/commands/init/scaffolders/codex-plugin/index.js";
10
+ import { resolveOpencodeAccountsGracefully } from "#runtime/opencode-account-materializer.js";
11
+ import { loadOpencodeAccountAvailability, pruneExpiredOpencodeAccountSuppressions, } from "#review/availability.js";
12
+ import { selectActiveOpencodeAccount } from "#review/opencode-account.js";
13
+ import { materializeOpencodeGoAuth } from "#review/opencode-auth.js";
14
+ import { describeOpencodeRotate, OPENCODE_ROTATE_FLAG, rotateActiveOpencodeAccount, } from "#cli/commands/opencode-rotate.js";
10
15
  export const AGENT_LAUNCH_COMMANDS = DASH_PROVIDERS;
11
16
  export const DEFAULT_AGENT_SECRET_PROFILE = "preview";
12
17
  export const AGENT_SECRET_PROFILE_ENV = "WP_AGENT_SECRET_PROFILE";
@@ -83,7 +88,67 @@ function ensureCodexSkillSurface(cwd, env = process.env) {
83
88
  return `Codex plugin refresh failed (${result.kind}). Run \`wp install codex\` and retry.`;
84
89
  }
85
90
  }
86
- export function runAgentLaunchCommand(command, args = [], options = {}, deps = {}) {
91
+ /**
92
+ * Choose the active opencode-go account and materialize its key into the
93
+ * global opencode `auth.json` before the TUI launches.
94
+ *
95
+ * Honest limitation: interactive opencode is a long-lived TUI — the account is
96
+ * chosen once at launch and a mid-session dollar-cap is NOT auto-swapped. A
97
+ * plain relaunch does NOT rotate either: nothing on this path records a
98
+ * cooldown, so an exhausted account stays "first non-suppressed" and gets
99
+ * re-picked every time. Run `wp opencode --wp-rotate` to cool the current
100
+ * account and launch on the next one. Only the review gate does automatic
101
+ * in-flight failover, because only it can observe the usage-limit response.
102
+ *
103
+ * Never throws: a Doppler outage or materialize failure must not block the
104
+ * TUI from launching, so every failure is logged and swallowed.
105
+ */
106
+ function selectAndMaterializeOpencodeAccount(cwd, deps, secretProfile) {
107
+ try {
108
+ const resolution = (deps.resolveOpencodeAccounts ?? resolveOpencodeAccountsGracefully)({
109
+ cwd,
110
+ secretProfile,
111
+ });
112
+ if (!resolution.ok)
113
+ return;
114
+ const pruned = pruneExpiredOpencodeAccountSuppressions(loadOpencodeAccountAvailability());
115
+ const selection = selectActiveOpencodeAccount(resolution.accounts, pruned.state);
116
+ if (!selection)
117
+ return;
118
+ (deps.materializeGlobalOpencodeAuth ?? ((key) => materializeOpencodeGoAuth(key)))(selection.account.key);
119
+ if (selection.cooled) {
120
+ console.error(`wp opencode: all OpenCode Go accounts are within their usage cooldown; launching on the soonest-expiring account (${selection.account.id}).`);
121
+ }
122
+ }
123
+ catch (error) {
124
+ const message = error instanceof Error ? error.message : String(error);
125
+ console.error(`wp opencode: account selection failed, launching without it (${message}).`);
126
+ }
127
+ }
128
+ /**
129
+ * Run the opencode-only pre-launch credential step and return the args to
130
+ * forward to the binary. `--wp-rotate` is consumed here and must never reach
131
+ * opencode, which would treat it as a prompt.
132
+ */
133
+ async function prepareOpencodeLaunch(cwd, args, secretsConfig, deps, secretProfile) {
134
+ if (!args.includes(OPENCODE_ROTATE_FLAG)) {
135
+ if (secretsConfig !== null)
136
+ selectAndMaterializeOpencodeAccount(cwd, deps, secretProfile);
137
+ return args;
138
+ }
139
+ const outcome = await rotateActiveOpencodeAccount(cwd, secretProfile, deps);
140
+ for (const line of describeOpencodeRotate(outcome))
141
+ console.error(line);
142
+ // A successful rotation already materialized the next account, so the normal
143
+ // launch-time selection is skipped to avoid a second, redundant write. When
144
+ // rotation could not run, fall through to that selection so the launch still
145
+ // gets the best account it can rather than whatever the store happens to hold.
146
+ if (outcome.kind === "unavailable" && secretsConfig !== null) {
147
+ selectAndMaterializeOpencodeAccount(cwd, deps, secretProfile);
148
+ }
149
+ return args.filter((arg) => arg !== OPENCODE_ROTATE_FLAG);
150
+ }
151
+ export async function runAgentLaunchCommand(command, args = [], options = {}, deps = {}) {
87
152
  const cwd = options.cwd ?? process.cwd();
88
153
  if (command === "codex") {
89
154
  const skillSurfaceError = (deps.ensureCodexSkillSurface ?? ensureCodexSkillSurface)(cwd, options.env ?? process.env);
@@ -93,9 +158,19 @@ export function runAgentLaunchCommand(command, args = [], options = {}, deps = {
93
158
  }
94
159
  }
95
160
  const secretsConfig = (deps.readSecretsConfig ?? readSecretsConfig)(cwd);
161
+ // Account discovery must resolve secrets through the same profile the launch
162
+ // itself uses (below, via buildAgentRuntimeCommandOptions). Without it no
163
+ // environment selector reaches the secret manager, which then falls back to
164
+ // its own ambient, path-scoped config — that resolves only in a checkout that
165
+ // happens to sit under the scoped directory and fails in every managed
166
+ // worktree, CI clone, and fresh checkout.
167
+ const secretProfile = resolveAgentSecretProfile(options.env ?? process.env);
168
+ const launchArgs = command === "opencode"
169
+ ? await prepareOpencodeLaunch(cwd, args, secretsConfig, deps, secretProfile)
170
+ : args;
96
171
  const runtimeOptions = buildAgentRuntimeCommandOptions({
97
172
  command,
98
- args,
173
+ args: launchArgs,
99
174
  cwd,
100
175
  env: options.env ?? process.env,
101
176
  secretsConfig,
@@ -108,8 +183,11 @@ export function runAgentLaunchCommand(command, args = [], options = {}, deps = {
108
183
  return result.status ?? 1;
109
184
  }
110
185
  export function registerAgentLaunchCommand(cli, command) {
186
+ const rotateHint = command === "opencode"
187
+ ? ` (pass \`${OPENCODE_ROTATE_FLAG}\` to cool the current OpenCode Go account and launch on the next one)`
188
+ : "";
111
189
  cli
112
- .command(`${command} [...args]`, `Launch ${command} with provider-backed agent secrets and safe-by-default permissions (run \`wp yolo on\` for persistent full-auto)`)
190
+ .command(`${command} [...args]`, `Launch ${command} with provider-backed agent secrets and safe-by-default permissions (run \`wp yolo on\` for persistent full-auto)${rotateHint}`)
113
191
  .allowUnknownOptions()
114
- .action((args = []) => runAgentLaunchCommand(command, args, { cwd: process.cwd() }));
192
+ .action(async (args = []) => await runAgentLaunchCommand(command, args, { cwd: process.cwd() }));
115
193
  }
@@ -1,4 +1,4 @@
1
- import type { AuditKindId } from "#audit/registry";
1
+ import { type AuditKindId } from "#audit/registry";
2
2
  import type { RepoAuditResult } from "#audit/repo-guardrails";
3
3
  export type AuditKind = AuditKindId;
4
4
  export type AuditOutcome = {
@@ -1,3 +1,4 @@
1
+ import { getAuditKindDescriptor } from "#audit/registry";
1
2
  function optionsForCompositeRepoAudit(name, options) {
2
3
  if (name !== "reference-parity-matrix" || options.strict !== true)
3
4
  return options;
@@ -94,7 +95,13 @@ export async function runAuditDispatch(auditKind, targets, options, deps) {
94
95
  let allOk = true;
95
96
  for (const name of deps.knownRepoKinds) {
96
97
  const result = await deps.runRepoAudit(name, root, optionsForCompositeRepoAudit(name, options));
97
- if (!result.ok)
98
+ // Signal-class kinds (registry.ts gateClass) still run and still
99
+ // report their findings via `results` below, but a failing signal
100
+ // kind must not flip the umbrella — only blocking-class failures do.
101
+ // Unclassified kinds default to blocking, matching the registry's
102
+ // own descriptor() default.
103
+ const gateClass = getAuditKindDescriptor(name)?.gateClass ?? "blocking";
104
+ if (!result.ok && gateClass !== "signal")
98
105
  allOk = false;
99
106
  results.push({ name, result });
100
107
  }
@@ -15,6 +15,7 @@ import { createCliLogSink } from "#cli/commands/quality-log-store.js";
15
15
  import { emitCliCommandOutput, runLoggedChildCommand } from "#cli/commands/quality-runner.js";
16
16
  export const REPO_AUDIT_REGISTRY = {
17
17
  "catalog-drift": async (root) => (await import("#audit/repo-guardrails")).auditCatalogDrift(root),
18
+ "typescript-version": async (root) => (await import("#audit/typescript-version")).auditTypescriptVersion(root),
18
19
  "package-surface": async (root) => (await import("#audit/package-surface")).auditPackageSurface(root),
19
20
  "command-surface": async (root) => (await import("#audit/command-surface")).auditCommandSurface(root),
20
21
  "reference-parity-matrix": async (root, options) => (await import("#audit/reference-parity-matrix")).auditReferenceParityMatrix(root, undefined, {
@@ -123,6 +124,10 @@ export const REPO_AUDIT_REGISTRY = {
123
124
  "secrets-config": async (root) => (await import("#audit/secrets-config")).auditSecretsConfig(root),
124
125
  "consumer-agent-kit-dependency": async (root) => (await import("#audit/consumer-agent-kit-dependency")).auditConsumerAgentKitDependency(root),
125
126
  "ci-test-perf": async (root) => (await import("#audit/ci-test-perf")).auditCiTestPerf(root),
127
+ "ci-guardrails-wiring": async (root) => (await import("#audit/ci-guardrails-wiring")).auditCiGuardrailsWiring(root),
128
+ "test-scan-perf": async (root, options) => (await import("#audit/test-scan-perf")).auditTestScanPerf(root, {
129
+ affectedFiles: options.affectedFiles,
130
+ }),
126
131
  "worktree-main-ownership": async (root) => (await import("#audit/worktree-main-ownership")).auditWorktreeMainOwnership(root),
127
132
  sast: async (root, options) => (await import("#audit/sast")).auditSast(root, {
128
133
  bin: options.bin,
@@ -137,6 +142,7 @@ export const REPO_AUDIT_REGISTRY = {
137
142
  draftTechDebt: options.draftTechDebt,
138
143
  }),
139
144
  "harness-overlay-evidence": async (root) => (await import("#audit/harness-overlay-evidence")).auditHarnessOverlayEvidence(root),
145
+ "host-substitution-risk": async (root) => (await import("#audit/host-substitution-risk")).auditHostSubstitutionRisk(root),
140
146
  "legacy-workflow-identity": async (root) => (await import("#audit/legacy-workflow-identity")).auditLegacyWorkflowIdentity(root),
141
147
  rules: async (root) => runContentAudit(root, "rule"),
142
148
  skills: async (root) => runContentAudit(root, "skill"),
@@ -464,22 +470,31 @@ export function registerAuditCommand(cli) {
464
470
  }
465
471
  case "aggregate-result": {
466
472
  const { formatRepoAuditReport } = await import("#audit/repo-guardrails");
473
+ const isSignal = (name) => getAuditKindDescriptor(name)?.gateClass === "signal";
467
474
  for (const { name, result } of outcome.results) {
468
475
  if (result.ok)
469
476
  continue;
470
- sink.write(`\n[${name}]\n${formatRepoAuditReport(result)}\n`);
477
+ const label = isSignal(name) ? `${name} (signal, non-blocking)` : name;
478
+ sink.write(`\n[${label}]\n${formatRepoAuditReport(result)}\n`);
471
479
  }
472
480
  const failed = outcome.results.filter(({ result }) => !result.ok);
481
+ const blockingFailed = failed.filter(({ name }) => !isSignal(name));
482
+ const signalFailed = failed.filter(({ name }) => isSignal(name));
473
483
  if (failed.length > 0) {
474
- sink.write(`\nguardrails: ${failed.length}/${outcome.results.length} audits failed: ${failed
475
- .map(({ name }) => name)
476
- .join(", ")}\n`);
484
+ const parts = [];
485
+ if (blockingFailed.length > 0) {
486
+ parts.push(`${blockingFailed.length} blocking: ${blockingFailed.map(({ name }) => name).join(", ")}`);
487
+ }
488
+ if (signalFailed.length > 0) {
489
+ parts.push(`${signalFailed.length} signal/non-blocking: ${signalFailed.map(({ name }) => name).join(", ")}`);
490
+ }
491
+ sink.write(`\nguardrails: ${failed.length}/${outcome.results.length} audits reported findings (${parts.join("; ")})\n`);
477
492
  }
478
493
  exitCode = outcome.code;
479
494
  summary =
480
495
  outcome.code === 0
481
496
  ? "audit guardrails passed"
482
- : `audit guardrails failed (${failed.length}/${outcome.results.length})`;
497
+ : `audit guardrails failed (${blockingFailed.length}/${outcome.results.length})`;
483
498
  break;
484
499
  }
485
500
  case "quality-exit": {
@@ -9,6 +9,7 @@ import { setTimeout as delay } from "node:timers/promises";
9
9
  import { applyRuntimeProgressSnapshot, buildBlueprintProgressBridgeState, normalizeRuntimeTaskSnapshot, projectBlueprintLifecycleFromRuntime, readBlueprintExecutionArtifacts, runtimeStateSnapshotSchema, writeBlueprintExecutionArtifacts, writeBlueprintExecutionMetadata, } from "#index";
10
10
  import { applyBlueprintLifecycleToFile, parseBlueprint } from "#local";
11
11
  import { resolveBlueprintRoot } from "#utils/blueprint-root";
12
+ import { resolveBlueprintDocumentIdentity } from "#utils/document-paths.js";
12
13
  import { clearBlueprintExecutionState, persistBlueprintExecutionArtifacts, persistBlueprintExecutionMetadata, persistBlueprintProgressBridgeState, readBlueprintExecutionArtifactsState, readBlueprintExecutionState, readBlueprintProgressBridgeState, readBlueprintRuntimeSnapshot, writeBlueprintRuntimeSnapshot, } from "./execution-io.js";
13
14
  import { assertCompletionEvidence, mergeExecutionArtifacts, } from "./execution-state.js";
14
15
  import { buildBlueprintExecutionControlCommand, buildBlueprintExecutionLaunchCommand, buildBlueprintExecutionRuntimePaths, buildBlueprintLaunchSpec, buildListTasksVerificationCommand, isMissingFileError, nowIsoTimestamp, parseRuntimeApiResponse, parseTeamExecutionId, resolveControlStatus, toProjectRelativePath, uniqueStrings, } from "./execution-spec.js";
@@ -114,22 +115,33 @@ export async function reconcileBlueprintRuntimeSnapshot(projectRoot, blueprintPa
114
115
  const currentStatus = currentDir.split(blueprintsRoot + path.sep)[1]?.split(path.sep)[0];
115
116
  const relativeSlug = slug.replace(/^[^/]+\//u, "");
116
117
  const targetDir = path.join(blueprintsRoot, nextStatus, relativeSlug);
117
- const targetPath = path.join(targetDir, "_overview.md");
118
+ // A flat document owns only its own file; renaming its parent directory
119
+ // would move the entire lifecycle state directory. Lifecycle moves are
120
+ // shape-preserving: flat stays flat, folder moves as a folder.
121
+ const isFlatDocument = resolveBlueprintDocumentIdentity(blueprintsRoot, blueprintPath)?.shape === "flat";
122
+ const targetPath = isFlatDocument ? `${targetDir}.md` : path.join(targetDir, "_overview.md");
123
+ const documentMoved = blueprintPath !== targetPath;
118
124
  const nextMarkdown = completionEvidence
119
125
  ? writeBlueprintExecutionArtifacts(result.markdown, completionEvidence)
120
126
  : result.markdown;
121
- if (currentDir !== targetDir && currentStatus && currentStatus !== nextStatus) {
127
+ if (documentMoved && currentStatus && currentStatus !== nextStatus) {
122
128
  const { mkdir, rename } = await import("node:fs/promises");
123
- await mkdir(path.dirname(targetDir), { recursive: true });
124
- await rename(currentDir, targetDir);
129
+ if (isFlatDocument) {
130
+ await mkdir(path.dirname(targetPath), { recursive: true });
131
+ await rename(blueprintPath, targetPath);
132
+ }
133
+ else {
134
+ await mkdir(path.dirname(targetDir), { recursive: true });
135
+ await rename(currentDir, targetDir);
136
+ }
125
137
  await writeFile(targetPath, nextMarkdown, "utf-8");
126
138
  }
127
139
  else {
128
140
  await writeFile(blueprintPath, nextMarkdown, "utf-8");
129
141
  }
130
142
  return {
131
- moved: currentDir !== targetDir,
132
- path: currentDir !== targetDir ? targetPath : blueprintPath,
143
+ moved: documentMoved,
144
+ path: documentMoved ? targetPath : blueprintPath,
133
145
  status: result.execution.status,
134
146
  };
135
147
  }