@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,64 @@
1
+ /**
2
+ * Trust Dossier authoring scaffold.
3
+ *
4
+ * `dossier.ts` / `evidence.ts` / `gates.ts` / `ambiguity.ts` define strict
5
+ * validation for a blueprint's `## Trust Dossier` section, but nothing
6
+ * generates a starting template. `TRUST_DOSSIER_SCAFFOLD` is a complete,
7
+ * already-valid worked example — proven by `scaffold.test.ts` to pass
8
+ * `validateBlueprintTrust` under both the strict configuration
9
+ * `wp audit blueprint-trust` uses and the draft-preflight configuration
10
+ * `wp_blueprint_put` / `preparePromotionTrustGate` use — so an author can
11
+ * paste it in and edit the example values instead of hand-deriving the
12
+ * contract from source.
13
+ *
14
+ * `verified-at` / `verified-head` stay as inert, obviously-fake placeholders:
15
+ * `preparePromotionTrustGate` (./promotion.ts) overwrites both with the real
16
+ * timestamp/HEAD on every promotion attempt, so there is no need for this
17
+ * pure, dependency-free module to shell out to git.
18
+ */
19
+ const PLACEHOLDER_HEAD = "0".repeat(40);
20
+ export const TRUST_DOSSIER_SCAFFOLD = `## Trust Dossier
21
+
22
+ <!-- Trust Dossier scaffold — generated by \`wp blueprint trust-dossier\`. -->
23
+ <!-- Replace every example value below, then delete these comment lines before promotion. -->
24
+ <!-- Constraints enforced by \`wp audit blueprint-trust\` / \`wp_blueprint_put\`: -->
25
+ <!-- - All 5 "###" subsections below are required, verbatim, exactly once each. -->
26
+ <!-- - Material Claims "repo:<path>" evidence must be a bare, existing repo-relative path -->
27
+ <!-- (no ":line" suffix, no leading "/", no "../"). -->
28
+ <!-- - "Residual Unknowns" must render exactly \`None.\` when nothing is outstanding. -->
29
+ <!-- - Promotion Gates "Command" must be a \`wp\` facade call: \`wp typecheck\`, \`wp lint\` -->
30
+ <!-- (no extra args), \`wp test --file <path>\` (repeatable), or -->
31
+ <!-- \`wp audit <kind> [--json|--affected|--branch|--base <val>]\`. -->
32
+ <!-- - No TBD, TODO, "decide during implementation", "open question", or <placeholder> tokens -->
33
+ <!-- anywhere in the 5 subsections below. -->
34
+
35
+ ### Readiness Verdict
36
+
37
+ - promotion-ready: true
38
+ - unresolved-count: 0
39
+ - verified-at: 1970-01-01T00:00:00.000Z
40
+ - verified-head: ${PLACEHOLDER_HEAD}
41
+ - trust-gate-version: v1
42
+
43
+ ### Material Claims
44
+
45
+ | ID | Claim | Evidence |
46
+ | --- | --- | --- |
47
+ | C1 | Example material claim — replace with a real, falsifiable claim this blueprint depends on. | repo:README.md |
48
+
49
+ ### Material Decisions
50
+
51
+ | ID | Decision | Chosen option | Rejected alternatives | Rationale |
52
+ | --- | --- | --- | --- | --- |
53
+ | D1 | Example material decision — replace with a real decision this blueprint locks in. | Example chosen option. | Example rejected alternative and why it lost. | Example rationale for the chosen option. |
54
+
55
+ ### Promotion Gates
56
+
57
+ | Gate | Command | Expected outcome | Last result |
58
+ | --- | --- | --- | --- |
59
+ | typecheck | wp typecheck | Typecheck passes with zero errors. | pass (scaffold example — rerun and record the real result before promotion) |
60
+
61
+ ### Residual Unknowns
62
+
63
+ None.
64
+ `;
@@ -8,6 +8,7 @@ export type ValidateBlueprintTrustInput = {
8
8
  promotionCandidate?: boolean;
9
9
  requirePassingGates?: boolean;
10
10
  scanTaskAmbiguity?: boolean;
11
+ allowDeferredGates?: boolean;
11
12
  };
12
13
  export type BlueprintTrustViolation = TrustDossierViolation & {
13
14
  file: string;
@@ -51,7 +51,8 @@ export function validateBlueprintTrust(input) {
51
51
  message: error instanceof Error ? error.message : String(error),
52
52
  });
53
53
  }
54
- if (input.requirePassingGates !== false && !/^pass\b/iu.test(gate.lastResult))
54
+ if (input.requirePassingGates !== false &&
55
+ !isAcceptableGateResult(gate.lastResult, input.allowDeferredGates))
55
56
  violations.push({
56
57
  section: "Promotion Gates",
57
58
  claimId: gate.gate,
@@ -64,3 +65,8 @@ export function validateBlueprintTrust(input) {
64
65
  violations: violations.map((v) => ({ ...v, file: input.file })),
65
66
  };
66
67
  }
68
+ function isAcceptableGateResult(lastResult, allowDeferredGates) {
69
+ if (/^pass\b/iu.test(lastResult))
70
+ return true;
71
+ return allowDeferredGates === true && /^deferred:/iu.test(lastResult);
72
+ }
@@ -6,6 +6,7 @@
6
6
  import { access, readFile, writeFile } from "node:fs/promises";
7
7
  import path from "node:path";
8
8
  import { parseBlueprint } from "#core/parser";
9
+ import { getBlueprintDocumentCandidates } from "./document-paths.js";
9
10
  import { resolveBlueprintRoot } from "./blueprint-root.js";
10
11
  /**
11
12
  * Validates that all tasks in a plan are complete.
@@ -111,7 +112,13 @@ export async function archiveBlueprint(slug, projectPath) {
111
112
  if (isAlreadyCompleted(slug)) {
112
113
  return { success: false, error: "Plan is already completed" };
113
114
  }
114
- const paths = buildPlanPaths(projectPath, slug);
115
+ const paths = await buildPlanPaths(projectPath, slug);
116
+ if (paths.ambiguousPaths) {
117
+ return {
118
+ success: false,
119
+ error: `Plan ${slug} exists in both flat and folder forms; remove one before archiving: ${paths.ambiguousPaths.join(", ")}`,
120
+ };
121
+ }
115
122
  // Check if plan exists
116
123
  const planExists = await checkPlanExists(paths.sourcePath);
117
124
  if (!planExists) {
@@ -132,16 +139,31 @@ export async function archiveBlueprint(slug, projectPath) {
132
139
  /**
133
140
  * Builds source and target paths for archival.
134
141
  *
142
+ * Resolves the existing flat or folder document via the shared candidates;
143
+ * when neither shape exists, falls back to the canonical folder path so the
144
+ * caller reports the same "Plan not found" error as before.
145
+ *
135
146
  * @param projectPath - Root path of the project
136
147
  * @param slug - Plan slug
137
148
  * @returns Path information
138
149
  */
139
- function buildPlanPaths(projectPath, slug) {
150
+ async function buildPlanPaths(projectPath, slug) {
140
151
  const plansDir = resolveBlueprintRoot(projectPath);
141
- const sourcePath = path.join(plansDir, slug, "_overview.md");
152
+ const candidates = getBlueprintDocumentCandidates(plansDir, slug);
153
+ const existing = [];
154
+ for (const candidate of candidates) {
155
+ if (await checkPlanExists(candidate))
156
+ existing.push(candidate);
157
+ }
158
+ const sourcePath = existing[0] ?? candidates.at(-1) ?? path.join(plansDir, slug, "_overview.md");
142
159
  const sourceDir = path.dirname(sourcePath);
143
- const targetDir = sourceDir;
144
- return { sourcePath, sourceDir, targetDir, planName: slug };
160
+ return {
161
+ sourcePath,
162
+ sourceDir,
163
+ targetDir: sourceDir,
164
+ planName: slug,
165
+ ...(existing.length > 1 ? { ambiguousPaths: existing } : {}),
166
+ };
145
167
  }
146
168
  /**
147
169
  * Extracts plan name from slug (removes status prefix).
@@ -8,6 +8,13 @@ export interface BlueprintDocumentPath {
8
8
  slug: string;
9
9
  state: BlueprintStatus;
10
10
  }
11
+ export interface BlueprintDocumentIdentity extends BlueprintDocumentPath {
12
+ documentPath: string;
13
+ folderDirectory: string;
14
+ folderPath: string;
15
+ lifecycleSlug: string;
16
+ stableSlug: string;
17
+ }
11
18
  export declare function normalizeBlueprintPath(filePath: string): string;
12
19
  export declare function isBlueprintStatus(value: string | undefined): value is BlueprintStatus;
13
20
  export declare function isBlueprintSlugSegment(value: string | undefined): value is string;
@@ -18,5 +25,16 @@ export declare function getBlueprintDocumentPaths(root: string, state: Blueprint
18
25
  flat: string;
19
26
  folder: string;
20
27
  };
28
+ export declare function resolveBlueprintDocumentIdentity(root: string, documentPath: string): BlueprintDocumentIdentity | null;
29
+ export declare function folderBlueprintRequiredMessage(identity: {
30
+ readonly documentPath: string;
31
+ readonly lifecycleSlug: string;
32
+ readonly shape: BlueprintShape;
33
+ }): string;
34
+ export declare function assertFolderBlueprintIdentity(identity: {
35
+ readonly documentPath: string;
36
+ readonly lifecycleSlug: string;
37
+ readonly shape: BlueprintShape;
38
+ }): void;
21
39
  export declare function getBlueprintDocumentCandidates(root: string, slug: string): string[];
22
40
  export declare function getBlueprintAlternateDocumentPath(root: string, filePath: string): string | null;
@@ -22,7 +22,7 @@ export function isBlueprintSlugSegment(value) {
22
22
  export function parseBlueprintDocumentRelativePath(filePath) {
23
23
  const normalized = normalizeBlueprintPath(filePath);
24
24
  const parts = normalized.split("/").filter((segment) => segment.length > 0);
25
- const [state, second, third] = parts;
25
+ const [state, second] = parts;
26
26
  if (!isBlueprintStatus(state)) {
27
27
  return null;
28
28
  }
@@ -38,13 +38,16 @@ export function parseBlueprintDocumentRelativePath(filePath) {
38
38
  state,
39
39
  };
40
40
  }
41
- if (parts.length === 3 &&
42
- isBlueprintSlugSegment(second) &&
43
- third === BLUEPRINT_OVERVIEW_FILENAME) {
41
+ if (parts.length >= 3 && parts.at(-1) === BLUEPRINT_OVERVIEW_FILENAME) {
42
+ const slugSegments = parts.slice(1, -1);
43
+ if (!slugSegments.every((segment) => isBlueprintSlugSegment(segment))) {
44
+ return null;
45
+ }
46
+ const slug = slugSegments.join("/");
44
47
  return {
45
- relativePath: `${state}/${second}/${BLUEPRINT_OVERVIEW_FILENAME}`,
48
+ relativePath: `${state}/${slug}/${BLUEPRINT_OVERVIEW_FILENAME}`,
46
49
  shape: "folder",
47
- slug: second,
50
+ slug,
48
51
  state,
49
52
  };
50
53
  }
@@ -53,13 +56,13 @@ export function parseBlueprintDocumentRelativePath(filePath) {
53
56
  export function isBlueprintSupportingMarkdownRelativePath(filePath) {
54
57
  const normalized = normalizeBlueprintPath(filePath);
55
58
  const parts = normalized.split("/").filter((segment) => segment.length > 0);
56
- const [state, slug, doc] = parts;
57
- return (parts.length === 3 &&
59
+ const [state] = parts;
60
+ return (parts.length >= 3 &&
58
61
  isBlueprintStatus(state) &&
59
- isBlueprintSlugSegment(slug) &&
60
- typeof doc === "string" &&
61
- doc.endsWith(".md") &&
62
- doc !== BLUEPRINT_OVERVIEW_FILENAME);
62
+ parts.slice(1, -1).every((segment) => isBlueprintSlugSegment(segment)) &&
63
+ typeof parts.at(-1) === "string" &&
64
+ parts.at(-1).endsWith(".md") &&
65
+ parts.at(-1) !== BLUEPRINT_OVERVIEW_FILENAME);
63
66
  }
64
67
  export function getBlueprintDocumentPaths(root, state, slug) {
65
68
  const directory = path.join(root, state, slug);
@@ -69,6 +72,36 @@ export function getBlueprintDocumentPaths(root, state, slug) {
69
72
  folder: path.join(directory, BLUEPRINT_OVERVIEW_FILENAME),
70
73
  };
71
74
  }
75
+ export function resolveBlueprintDocumentIdentity(root, documentPath) {
76
+ const relativePath = normalizeBlueprintPath(path.relative(root, documentPath));
77
+ const parsed = parseBlueprintDocumentRelativePath(relativePath);
78
+ if (!parsed)
79
+ return null;
80
+ const paths = getBlueprintDocumentPaths(root, parsed.state, parsed.slug);
81
+ return {
82
+ ...parsed,
83
+ documentPath: parsed.shape === "flat" ? paths.flat : paths.folder,
84
+ folderDirectory: paths.directory,
85
+ folderPath: paths.folder,
86
+ lifecycleSlug: `${parsed.state}/${parsed.slug}`,
87
+ stableSlug: parsed.slug,
88
+ };
89
+ }
90
+ export function folderBlueprintRequiredMessage(identity) {
91
+ if (identity.shape === "folder") {
92
+ return "";
93
+ }
94
+ return [
95
+ `Blueprint evidence requires folder shape; ${identity.documentPath} is a flat blueprint.`,
96
+ `Run: wp blueprint canonicalize ${identity.lifecycleSlug}`,
97
+ "Then commit the canonicalized path and rerun the evidence command.",
98
+ ].join(" ");
99
+ }
100
+ export function assertFolderBlueprintIdentity(identity) {
101
+ const message = folderBlueprintRequiredMessage(identity);
102
+ if (message)
103
+ throw new Error(message);
104
+ }
72
105
  export function getBlueprintDocumentCandidates(root, slug) {
73
106
  const normalized = normalizeBlueprintPath(slug);
74
107
  const segments = normalized.split("/").filter((segment) => segment.length > 0);
@@ -187,6 +187,11 @@ export const CLI_MCP_PARITY_CLASSIFICATION = {
187
187
  classification: "direct-fallback-by-design",
188
188
  reason: "internal serialization wrapper spawned by the auto-update, wp update, and setup lanes; never agent-facing",
189
189
  },
190
+ "optional-tool-refresh": {
191
+ command: "optional-tool-refresh",
192
+ classification: "direct-fallback-by-design",
193
+ reason: "internal detached worker spawned by provider launch freshness; never agent-facing",
194
+ },
190
195
  init: {
191
196
  command: "init",
192
197
  classification: "unsafe-credentialed-destructive",
@@ -229,6 +234,11 @@ export const CLI_MCP_PARITY_CLASSIFICATION = {
229
234
  classification: "direct-fallback-by-design",
230
235
  reason: "long-running local preview server remains a direct CLI workflow",
231
236
  },
237
+ "public:readiness": {
238
+ command: "public:readiness",
239
+ classification: "direct-fallback-by-design",
240
+ reason: "public package readiness performs local package/tarball checks and is intentionally not a read-only MCP workflow",
241
+ },
232
242
  qa: {
233
243
  command: "qa",
234
244
  classification: "existing-mcp",
@@ -31,8 +31,105 @@ export function buildReplayWorkflowSource(sourceYaml, options) {
31
31
  : basename(options.workflowPath);
32
32
  workflow.name = `replay: ${originalName}`;
33
33
  workflow.on = normalizeWorkflowOnSection(workflow.on, options.eventName);
34
+ workflow.jobs = rewriteReplayJobs(workflow.jobs, options.eventName);
34
35
  return stringify(workflow);
35
36
  }
37
+ function rewriteReplayJobs(jobs, eventName) {
38
+ if (typeof jobs !== "object" || jobs === null || Array.isArray(jobs)) {
39
+ return jobs;
40
+ }
41
+ return Object.fromEntries(Object.entries(jobs).map(([jobId, job]) => [
42
+ jobId,
43
+ rewriteReplayJob(job, eventName),
44
+ ]));
45
+ }
46
+ function rewriteReplayJob(job, eventName) {
47
+ if (typeof job !== "object" || job === null || Array.isArray(job)) {
48
+ return job;
49
+ }
50
+ const jobRecord = { ...job };
51
+ if (Array.isArray(jobRecord.steps)) {
52
+ jobRecord.steps = jobRecord.steps.map((step) => rewriteReplayStep(step, eventName));
53
+ }
54
+ return jobRecord;
55
+ }
56
+ function rewriteReplayStep(step, eventName) {
57
+ if (!isRecord(step) || !isSameRepoCheckoutStep(step, eventName)) {
58
+ return step;
59
+ }
60
+ const rewritten = {
61
+ name: typeof step.name === "string" ? step.name : "Use prepared local replay workspace",
62
+ run: [
63
+ 'echo "wp ci act replay: using prepared local workspace instead of actions/checkout"',
64
+ "test -d .git",
65
+ "git rev-parse --is-inside-work-tree",
66
+ "git rev-parse --verify HEAD",
67
+ ].join("\n"),
68
+ "working-directory": "${{ github.workspace }}",
69
+ };
70
+ copyOptionalStepField(step, rewritten, "id");
71
+ copyOptionalStepField(step, rewritten, "if");
72
+ copyOptionalStepField(step, rewritten, "timeout-minutes");
73
+ copyOptionalStepField(step, rewritten, "continue-on-error");
74
+ return rewritten;
75
+ }
76
+ function isSameRepoCheckoutStep(step, eventName) {
77
+ if (typeof step.uses !== "string" || !/^actions\/checkout(?:@|$)/u.test(step.uses)) {
78
+ return false;
79
+ }
80
+ if (step.env !== undefined && step.env !== null) {
81
+ return false;
82
+ }
83
+ const withConfig = step.with;
84
+ if (withConfig === undefined || withConfig === null) {
85
+ return true;
86
+ }
87
+ if (!isRecord(withConfig)) {
88
+ return false;
89
+ }
90
+ if (hasAnyCheckoutInputExcept(withConfig, ["ref"])) {
91
+ return false;
92
+ }
93
+ return isCurrentReplayRef(withConfig.ref, eventName);
94
+ }
95
+ function isCurrentReplayRef(value, eventName) {
96
+ if (value === undefined || value === null || String(value).trim().length === 0) {
97
+ return true;
98
+ }
99
+ const normalized = normalizeGithubExpression(String(value));
100
+ if (normalized === null)
101
+ return false;
102
+ if (normalized === "github.sha") {
103
+ return true;
104
+ }
105
+ if (normalized ===
106
+ "github.event_name=='pull_request'&&github.event.pull_request.base.sha||github.sha") {
107
+ return eventName !== "pull_request";
108
+ }
109
+ return false;
110
+ }
111
+ function normalizeGithubExpression(value) {
112
+ const match = /^\$\{\{\s*([\s\S]*?)\s*\}\}$/u.exec(value.trim());
113
+ if (!match?.[1])
114
+ return null;
115
+ return match[1].replace(/"/gu, "'").replace(/\s+/gu, "");
116
+ }
117
+ function hasAnyCheckoutInputExcept(withConfig, allowedKeys) {
118
+ const allowed = new Set(allowedKeys);
119
+ return Object.entries(withConfig).some(([key, value]) => {
120
+ if (allowed.has(key))
121
+ return false;
122
+ return value !== undefined && value !== null && String(value).trim().length > 0;
123
+ });
124
+ }
125
+ function copyOptionalStepField(source, target, field) {
126
+ if (source[field] !== undefined) {
127
+ target[field] = source[field];
128
+ }
129
+ }
130
+ function isRecord(value) {
131
+ return typeof value === "object" && value !== null && !Array.isArray(value);
132
+ }
36
133
  export function createReplayWorkflow(options) {
37
134
  const sourcePath = resolve(options.cwd, options.workflowPath);
38
135
  const sourceYaml = readFileSync(sourcePath, "utf8");
@@ -42,11 +139,17 @@ export function createReplayWorkflow(options) {
42
139
  });
43
140
  const dir = mkdtempSync(join(tmpdir(), "wp-ci-act-replay-"));
44
141
  const workflowPath = join(dir, "workflow.yml");
45
- writeFileSync(workflowPath, generatedYaml, "utf8");
46
- return {
47
- workflowPath,
48
- cleanup() {
49
- rmSync(dir, { recursive: true, force: true });
50
- },
51
- };
142
+ try {
143
+ writeFileSync(workflowPath, generatedYaml, "utf8");
144
+ return {
145
+ workflowPath,
146
+ cleanup() {
147
+ rmSync(dir, { recursive: true, force: true });
148
+ },
149
+ };
150
+ }
151
+ catch (error) {
152
+ rmSync(dir, { recursive: true, force: true });
153
+ throw error;
154
+ }
52
155
  }
@@ -6,6 +6,7 @@ export interface PublicCiActOptions {
6
6
  readonly workflow?: string;
7
7
  readonly workflowPath?: string;
8
8
  readonly job?: string;
9
+ readonly matrix?: readonly string[];
9
10
  readonly eventName?: CiActEventName;
10
11
  readonly eventPath?: string;
11
12
  readonly envProfile?: string;
@@ -22,6 +23,7 @@ export interface PublicCiActCommand {
22
23
  readonly actArgs: readonly string[];
23
24
  }
24
25
  export interface PreparedPublicCiActExecution {
26
+ readonly cwd: string;
25
27
  readonly command: PublicCiActCommand;
26
28
  readonly mode: CiActExecutionMode;
27
29
  readonly nonSecurityEquivalent: boolean;
@@ -36,5 +38,7 @@ export declare function buildPublicCiActArgs(options?: PublicCiActOptions, workf
36
38
  export declare function buildPublicCiActCommand(options?: PublicCiActOptions): PublicCiActCommand;
37
39
  export declare function preparePublicCiActExecution(options?: PublicCiActOptions): PreparedPublicCiActExecution;
38
40
  export declare function resolveCiActSecretEnvProfile(options?: PublicCiActOptions): string | undefined;
41
+ export declare function shouldForceCiActSecretGate(envProfile: string | undefined): boolean;
39
42
  export declare function sanitizePublicCiActArgv(command: PublicCiActCommand): PublicCiActCommand;
40
43
  export declare function assertNoForbiddenCiActArgs(args: readonly string[]): void;
44
+ export declare function normalizeCiActMatrixSelectors(selectors: readonly string[] | undefined): readonly string[];
@@ -2,6 +2,7 @@ import { resolve } from "node:path";
2
2
  import { buildSecretGateCommand } from "#secret-gate/runner.js";
3
3
  import { resolveSecretsConfigProfileEnvironment } from "#runtime/secrets-config.js";
4
4
  import { createReplayWorkflow, GENERATED_REPLAY_WORKFLOW_PLACEHOLDER, } from "./act-replay.js";
5
+ import { prepareActGitWorkspace } from "./act-worktree-git.js";
5
6
  export { GENERATED_REPLAY_WORKFLOW_PLACEHOLDER } from "./act-replay.js";
6
7
  const DEFAULT_WORKFLOW = "ci-e2e";
7
8
  export const DEFAULT_PLATFORM_IMAGE = "ghcr.io/catthehacker/ubuntu:full-latest";
@@ -43,6 +44,7 @@ export function buildPublicCiActArgs(options = {}, workflowPathOverride) {
43
44
  "--rm",
44
45
  ];
45
46
  pushOption(args, "-j", options.job);
47
+ pushRepeatableOption(args, "--matrix", normalizeCiActMatrixSelectors(options.matrix));
46
48
  pushOption(args, "-e", options.eventPath ? resolve(cwd, options.eventPath) : undefined);
47
49
  pushOption(args, "--container-architecture", containerArchitecture);
48
50
  return args;
@@ -57,7 +59,7 @@ export function buildPublicCiActCommand(options = {}) {
57
59
  sink: "act",
58
60
  profile: secretEnvProfile,
59
61
  envProfile: options.envProfile ?? "secrets-only",
60
- forceSecretGate: true,
62
+ forceSecretGate: shouldForceCiActSecretGate(options.envProfile),
61
63
  command: "act",
62
64
  args: actArgs,
63
65
  });
@@ -65,32 +67,63 @@ export function buildPublicCiActCommand(options = {}) {
65
67
  }
66
68
  export function preparePublicCiActExecution(options = {}) {
67
69
  const cwd = options.cwd ?? process.cwd();
68
- const mode = resolveCiActExecutionMode(options);
69
- const replay = mode === "replay"
70
- ? createReplayWorkflow({
71
- cwd,
72
- workflowPath: resolveCiActWorkflowPath(options),
73
- eventName: options.eventName ?? "pull_request",
74
- })
75
- : null;
76
- const actArgs = buildPublicCiActArgs({ ...options, cwd }, replay ? replay.workflowPath : undefined);
77
- const secretEnvProfile = resolveCiActSecretEnvProfile({ ...options, cwd }) ?? "preview";
78
- const wrapped = buildSecretGateCommand({
79
- sink: "act",
80
- profile: secretEnvProfile,
81
- envProfile: options.envProfile ?? "secrets-only",
82
- forceSecretGate: true,
83
- command: "act",
84
- args: actArgs,
85
- });
86
- return {
87
- command: { command: wrapped.command, args: wrapped.args, actArgs },
88
- mode,
89
- nonSecurityEquivalent: mode === "replay",
90
- cleanup() {
70
+ let gitWorkspace = null;
71
+ let replay = null;
72
+ try {
73
+ gitWorkspace = prepareActGitWorkspace(cwd);
74
+ const executionCwd = gitWorkspace.cwd;
75
+ const mode = resolveCiActExecutionMode(options);
76
+ const sourceWorkflowPath = resolve(cwd, resolveCiActWorkflowPath(options));
77
+ replay =
78
+ mode === "replay"
79
+ ? createReplayWorkflow({
80
+ cwd,
81
+ workflowPath: sourceWorkflowPath,
82
+ eventName: options.eventName ?? "pull_request",
83
+ })
84
+ : null;
85
+ const executionOptions = {
86
+ ...options,
87
+ cwd: executionCwd,
88
+ eventPath: options.eventPath ? resolve(cwd, options.eventPath) : undefined,
89
+ };
90
+ const actArgs = buildPublicCiActArgs(executionOptions, replay ? replay.workflowPath : sourceWorkflowPath);
91
+ if (gitWorkspace.prepared) {
92
+ actArgs.push("--bind");
93
+ }
94
+ const secretEnvProfile = resolveCiActSecretEnvProfile({ ...options, cwd }) ?? "preview";
95
+ const wrapped = buildSecretGateCommand({
96
+ sink: "act",
97
+ profile: secretEnvProfile,
98
+ envProfile: options.envProfile ?? "secrets-only",
99
+ forceSecretGate: shouldForceCiActSecretGate(options.envProfile),
100
+ command: "act",
101
+ args: actArgs,
102
+ });
103
+ return {
104
+ cwd: executionCwd,
105
+ command: { command: wrapped.command, args: wrapped.args, actArgs },
106
+ mode,
107
+ nonSecurityEquivalent: mode === "replay",
108
+ cleanup() {
109
+ try {
110
+ replay?.cleanup();
111
+ }
112
+ finally {
113
+ gitWorkspace?.cleanup();
114
+ }
115
+ },
116
+ };
117
+ }
118
+ catch (error) {
119
+ try {
91
120
  replay?.cleanup();
92
- },
93
- };
121
+ }
122
+ finally {
123
+ gitWorkspace?.cleanup();
124
+ }
125
+ throw error;
126
+ }
94
127
  }
95
128
  export function resolveCiActSecretEnvProfile(options = {}) {
96
129
  const secretEnvProfile = options.secretEnvProfile?.trim();
@@ -103,6 +136,9 @@ export function resolveCiActSecretEnvProfile(options = {}) {
103
136
  }
104
137
  return undefined;
105
138
  }
139
+ export function shouldForceCiActSecretGate(envProfile) {
140
+ return envProfile !== "none" && envProfile !== "public";
141
+ }
106
142
  export function sanitizePublicCiActArgv(command) {
107
143
  return {
108
144
  command: command.command,
@@ -126,11 +162,34 @@ export function assertNoForbiddenCiActArgs(args) {
126
162
  if (found)
127
163
  throw new Error(`Unsupported unsafe ci act argument: ${found}`);
128
164
  }
165
+ export function normalizeCiActMatrixSelectors(selectors) {
166
+ if (!selectors)
167
+ return [];
168
+ return selectors.map((selector) => normalizeCiActMatrixSelector(selector));
169
+ }
129
170
  function pushOption(args, flag, value) {
130
171
  if (value === undefined || value === "")
131
172
  return;
132
173
  args.push(flag, String(value));
133
174
  }
175
+ function pushRepeatableOption(args, flag, values) {
176
+ for (const value of values) {
177
+ args.push(flag, value);
178
+ }
179
+ }
180
+ function normalizeCiActMatrixSelector(selector) {
181
+ const trimmed = selector.trim();
182
+ const delimiter = trimmed.indexOf(":");
183
+ if (trimmed.length === 0 || delimiter <= 0) {
184
+ throw new Error(`Invalid ci act matrix selector "${selector}". Use key:value with non-empty key and value.`);
185
+ }
186
+ const key = trimmed.slice(0, delimiter).trim();
187
+ const value = trimmed.slice(delimiter + 1).trim();
188
+ if (key.length === 0 || value.length === 0) {
189
+ throw new Error(`Invalid ci act matrix selector "${selector}". Use key:value with non-empty key and value.`);
190
+ }
191
+ return `${key}:${value}`;
192
+ }
134
193
  function sanitizeArg(value) {
135
194
  if (/wp-ci-act-[^/\\]+[/\\]secrets\.env$/u.test(value))
136
195
  return "[INTERNAL_SECRET_FILE]";
@@ -0,0 +1,11 @@
1
+ export interface PreparedActGitWorkspace {
2
+ readonly cwd: string;
3
+ readonly prepared: boolean;
4
+ cleanup(): void;
5
+ }
6
+ interface LinkedWorktreeGitMetadata {
7
+ readonly gitDir: string;
8
+ }
9
+ export declare function prepareActGitWorkspace(cwd: string): PreparedActGitWorkspace;
10
+ export declare function readLinkedWorktreeGitMetadata(cwd: string): LinkedWorktreeGitMetadata | null;
11
+ export {};