@webpresso/agent-kit 3.1.30 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (300) hide show
  1. package/README.md +53 -15
  2. package/bin/_run.js +183 -20
  3. package/catalog/AGENTS.md.tpl +3 -3
  4. package/catalog/agent/agents/implementer.md +45 -0
  5. package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
  6. package/catalog/agent/rules/pre-implementation.md +28 -1
  7. package/catalog/agent/rules/supported-agent-clis.md +9 -0
  8. package/catalog/agent/rules/typescript-version.md +50 -0
  9. package/catalog/agent/skills/codex/SKILL.md +25 -1
  10. package/catalog/agent/skills/verify/SKILL.md +4 -2
  11. package/catalog/docs/templates/blueprint.md +1 -1
  12. package/dist/esm/audit/agents.js +1 -0
  13. package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
  14. package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
  15. package/dist/esm/audit/blueprint-pr-coverage.js +4 -0
  16. package/dist/esm/audit/blueprint-trust.js +14 -10
  17. package/dist/esm/audit/changeset-evidence.d.ts +23 -0
  18. package/dist/esm/audit/changeset-evidence.js +30 -0
  19. package/dist/esm/audit/changeset-required.d.ts +10 -0
  20. package/dist/esm/audit/changeset-required.js +73 -0
  21. package/dist/esm/audit/ci-guardrails-detection.d.ts +27 -0
  22. package/dist/esm/audit/ci-guardrails-detection.js +68 -0
  23. package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
  24. package/dist/esm/audit/ci-guardrails-wiring.js +80 -0
  25. package/dist/esm/audit/ci-test-perf.js +30 -0
  26. package/dist/esm/audit/command-surface.js +4 -2
  27. package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
  28. package/dist/esm/audit/host-substitution-risk.js +256 -0
  29. package/dist/esm/audit/registry.d.ts +4 -4
  30. package/dist/esm/audit/registry.js +13 -1
  31. package/dist/esm/audit/toolchain-isolation.js +1 -2
  32. package/dist/esm/audit/typescript-version.d.ts +2 -0
  33. package/dist/esm/audit/typescript-version.js +123 -0
  34. package/dist/esm/blueprint/core/parser.js +101 -2
  35. package/dist/esm/blueprint/core/schema.d.ts +1 -0
  36. package/dist/esm/blueprint/core/schema.js +26 -0
  37. package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
  38. package/dist/esm/blueprint/core/validation/criteria.js +41 -2
  39. package/dist/esm/blueprint/core/validation/state.js +25 -14
  40. package/dist/esm/blueprint/db/migrations/run.js +4 -2
  41. package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
  42. package/dist/esm/blueprint/lifecycle/audit.js +87 -20
  43. package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
  44. package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
  45. package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
  46. package/dist/esm/blueprint/lifecycle/local.js +19 -3
  47. package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
  48. package/dist/esm/blueprint/lifecycle/review-provenance.js +68 -12
  49. package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +97 -0
  50. package/dist/esm/blueprint/lifecycle/rollout-anchor.js +161 -0
  51. package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
  52. package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
  53. package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
  54. package/dist/esm/blueprint/sync/client.d.ts +2 -1
  55. package/dist/esm/blueprint/sync/client.js +1 -1
  56. package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
  57. package/dist/esm/blueprint/trust/command-runner.js +148 -0
  58. package/dist/esm/blueprint/trust/dossier.d.ts +1 -0
  59. package/dist/esm/blueprint/trust/dossier.js +40 -6
  60. package/dist/esm/blueprint/trust/gates.d.ts +7 -0
  61. package/dist/esm/blueprint/trust/gates.js +20 -0
  62. package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
  63. package/dist/esm/blueprint/trust/promotion.js +74 -112
  64. package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
  65. package/dist/esm/blueprint/trust/scaffold.js +64 -0
  66. package/dist/esm/blueprint/trust/validator.d.ts +1 -0
  67. package/dist/esm/blueprint/trust/validator.js +7 -1
  68. package/dist/esm/blueprint/utils/archive.js +27 -5
  69. package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
  70. package/dist/esm/blueprint/utils/document-paths.js +45 -12
  71. package/dist/esm/build/cli-mcp-parity.js +15 -0
  72. package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
  73. package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
  74. package/dist/esm/cli/cli.d.ts +1 -1
  75. package/dist/esm/cli/cli.js +43 -0
  76. package/dist/esm/cli/commands/agent-launch.d.ts +8 -1
  77. package/dist/esm/cli/commands/agent-launch.js +93 -4
  78. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  79. package/dist/esm/cli/commands/audit-core.js +8 -1
  80. package/dist/esm/cli/commands/audit.js +21 -5
  81. package/dist/esm/cli/commands/blueprint/execution.js +18 -6
  82. package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
  83. package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
  84. package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
  85. package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
  86. package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
  87. package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
  88. package/dist/esm/cli/commands/blueprint/router.js +13 -1
  89. package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
  90. package/dist/esm/cli/commands/ci-preflight.js +30 -6
  91. package/dist/esm/cli/commands/compile.js +5 -31
  92. package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
  93. package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
  94. package/dist/esm/cli/commands/doctor.js +5 -0
  95. package/dist/esm/cli/commands/hook.d.ts +5 -0
  96. package/dist/esm/cli/commands/hook.js +15 -9
  97. package/dist/esm/cli/commands/init/config.js +2 -2
  98. package/dist/esm/cli/commands/init/convergence-apply.d.ts +88 -0
  99. package/dist/esm/cli/commands/init/convergence-apply.js +325 -0
  100. package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
  101. package/dist/esm/cli/commands/init/convergence-state.js +54 -0
  102. package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
  103. package/dist/esm/cli/commands/init/convergence.js +57 -0
  104. package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
  105. package/dist/esm/cli/commands/init/git-convergence.js +168 -0
  106. package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
  107. package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
  108. package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
  109. package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
  110. package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
  111. package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
  112. package/dist/esm/cli/commands/init/host-visibility.js +94 -5
  113. package/dist/esm/cli/commands/init/index.d.ts +3 -0
  114. package/dist/esm/cli/commands/init/index.js +326 -173
  115. package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
  116. package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
  117. package/dist/esm/cli/commands/init/merge.d.ts +1 -0
  118. package/dist/esm/cli/commands/init/merge.js +30 -1
  119. package/dist/esm/cli/commands/init/package-root.d.ts +7 -0
  120. package/dist/esm/cli/commands/init/package-root.js +10 -2
  121. package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
  122. package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
  123. package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
  124. package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
  125. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +20 -0
  126. package/dist/esm/cli/commands/init/scaffold-base-kit.js +61 -5
  127. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
  128. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
  129. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
  130. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +54 -24
  131. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
  132. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +288 -202
  133. package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +22 -0
  134. package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +230 -0
  135. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
  136. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
  137. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
  138. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
  139. package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
  140. package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
  141. package/dist/esm/cli/commands/opencode-probe.d.ts +107 -0
  142. package/dist/esm/cli/commands/opencode-probe.js +323 -0
  143. package/dist/esm/cli/commands/opencode-rotate.d.ts +72 -0
  144. package/dist/esm/cli/commands/opencode-rotate.js +147 -0
  145. package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
  146. package/dist/esm/cli/commands/public-readiness.js +42 -0
  147. package/dist/esm/cli/commands/quality-runner.js +3 -3
  148. package/dist/esm/cli/commands/review.d.ts +35 -3
  149. package/dist/esm/cli/commands/review.js +751 -209
  150. package/dist/esm/cli/commands/run-wait.d.ts +2 -0
  151. package/dist/esm/cli/commands/run-wait.js +122 -0
  152. package/dist/esm/cli/commands/rust-check.d.ts +24 -0
  153. package/dist/esm/cli/commands/rust-check.js +110 -0
  154. package/dist/esm/cli/commands/setup-help.js +1 -1
  155. package/dist/esm/cli/commands/setup-repair-help.js +1 -1
  156. package/dist/esm/cli/commands/typecheck.d.ts +1 -0
  157. package/dist/esm/cli/commands/typecheck.js +30 -1
  158. package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +6 -0
  159. package/dist/esm/cli/commands/worktree/router-dispatch.js +126 -9
  160. package/dist/esm/cli/commands/worktree/router.js +10 -0
  161. package/dist/esm/cli/direct-provider-launch.js +9 -5
  162. package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
  163. package/dist/esm/cli/optional-tool-freshness.js +219 -9
  164. package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
  165. package/dist/esm/daemon/domains/git-actions.js +136 -0
  166. package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
  167. package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
  168. package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
  169. package/dist/esm/daemon/domains/sessions-search.js +29 -0
  170. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
  171. package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
  172. package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
  173. package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
  174. package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
  175. package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
  176. package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
  177. package/dist/esm/daemon/handlers/git-handlers.js +27 -0
  178. package/dist/esm/daemon/handlers/product.d.ts +7 -0
  179. package/dist/esm/daemon/handlers/product.js +10 -119
  180. package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
  181. package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
  182. package/dist/esm/daemon/handlers/shared.d.ts +5 -0
  183. package/dist/esm/daemon/handlers/shared.js +16 -0
  184. package/dist/esm/daemon/methods.d.ts +8 -1
  185. package/dist/esm/daemon/methods.js +7 -0
  186. package/dist/esm/daemon/protocol/contract.d.ts +43 -0
  187. package/dist/esm/daemon/protocol/contract.js +26 -0
  188. package/dist/esm/daemon/protocol/index.d.ts +1 -1
  189. package/dist/esm/daemon/protocol/index.js +1 -1
  190. package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
  191. package/dist/esm/hooks/__conformance__/matrix.js +137 -0
  192. package/dist/esm/hooks/conformance/batch.js +5 -0
  193. package/dist/esm/hooks/doctor.d.ts +5 -3
  194. package/dist/esm/hooks/doctor.js +67 -16
  195. package/dist/esm/hooks/permission-request/index.js +9 -3
  196. package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
  197. package/dist/esm/hooks/permission-request/policy.js +13 -0
  198. package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
  199. package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
  200. package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
  201. package/dist/esm/hooks/pretool-guard/logger.js +16 -0
  202. package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
  203. package/dist/esm/hooks/pretool-guard/runner.js +68 -16
  204. package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
  205. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +54 -0
  206. package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
  207. package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
  208. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
  209. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
  210. package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +6 -1
  211. package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
  212. package/dist/esm/hooks/shared/guard-outcome.js +215 -0
  213. package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
  214. package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
  215. package/dist/esm/hooks/shared/types.d.ts +8 -5
  216. package/dist/esm/hooks/shared/types.js +50 -9
  217. package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
  218. package/dist/esm/hooks/stop/qa-changed-files.js +92 -0
  219. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
  220. package/dist/esm/mcp/blueprint/handlers/document-mutations.d.ts +5 -0
  221. package/dist/esm/mcp/blueprint/handlers/document-mutations.js +109 -11
  222. package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
  223. package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
  224. package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
  225. package/dist/esm/mcp/blueprint/registration.js +3 -2
  226. package/dist/esm/mcp/server.d.ts +1 -0
  227. package/dist/esm/mcp/server.js +27 -0
  228. package/dist/esm/mcp/tools/_names.d.ts +1 -1
  229. package/dist/esm/mcp/tools/_names.js +5 -0
  230. package/dist/esm/mcp/tools/_registry.js +10 -0
  231. package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
  232. package/dist/esm/mcp/tools/_shared/result.js +44 -1
  233. package/dist/esm/mcp/tools/audit.d.ts +5 -1
  234. package/dist/esm/mcp/tools/audit.js +42 -0
  235. package/dist/esm/mcp/tools/audits.d.ts +4 -0
  236. package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
  237. package/dist/esm/mcp/tools/ci-preflight.js +183 -0
  238. package/dist/esm/mcp/tools/pr-upsert.js +39 -1
  239. package/dist/esm/mcp/tools/review-run.d.ts +28 -0
  240. package/dist/esm/mcp/tools/review-run.js +216 -0
  241. package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
  242. package/dist/esm/mcp/tools/run-wait.js +593 -0
  243. package/dist/esm/mcp/tools/session-fetch-and-index.d.ts +1 -1
  244. package/dist/esm/mcp/tools/session-id.d.ts +3 -0
  245. package/dist/esm/mcp/tools/session-id.js +45 -0
  246. package/dist/esm/mcp/tools/session-info.d.ts +3 -0
  247. package/dist/esm/mcp/tools/session-info.js +49 -0
  248. package/dist/esm/output-transforms/audit.d.ts +23 -0
  249. package/dist/esm/output-transforms/audit.js +47 -0
  250. package/dist/esm/output-transforms/index.js +2 -0
  251. package/dist/esm/package.json +2 -0
  252. package/dist/esm/platform/client.d.ts +7 -1
  253. package/dist/esm/platform/github-contract-source.d.ts +2 -1
  254. package/dist/esm/pr-description/contract.js +24 -4
  255. package/dist/esm/review/authority.js +27 -14
  256. package/dist/esm/review/availability.d.ts +33 -0
  257. package/dist/esm/review/availability.js +122 -20
  258. package/dist/esm/review/delivery-verifier.d.ts +27 -0
  259. package/dist/esm/review/delivery-verifier.js +115 -0
  260. package/dist/esm/review/events.d.ts +3 -2
  261. package/dist/esm/review/events.js +23 -3
  262. package/dist/esm/review/execution/adapters.d.ts +11 -1
  263. package/dist/esm/review/execution/adapters.js +36 -10
  264. package/dist/esm/review/execution/artifacts.d.ts +1 -1
  265. package/dist/esm/review/execution/output-policy.d.ts +2 -0
  266. package/dist/esm/review/execution/output-policy.js +12 -0
  267. package/dist/esm/review/execution/review-checkout.js +121 -21
  268. package/dist/esm/review/execution/supervisor.js +36 -4
  269. package/dist/esm/review/execution/types.d.ts +9 -0
  270. package/dist/esm/review/opencode-account.d.ts +24 -0
  271. package/dist/esm/review/opencode-account.js +68 -0
  272. package/dist/esm/review/opencode-auth.d.ts +33 -0
  273. package/dist/esm/review/opencode-auth.js +79 -0
  274. package/dist/esm/review/subject.d.ts +25 -0
  275. package/dist/esm/review/subject.js +116 -26
  276. package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
  277. package/dist/esm/runtime/opencode-account-materializer.js +33 -0
  278. package/dist/esm/rust/affected-manifests.d.ts +38 -0
  279. package/dist/esm/rust/affected-manifests.js +69 -0
  280. package/dist/esm/session-memory/fetch-index.d.ts +1 -1
  281. package/dist/esm/status/snapshot.js +32 -25
  282. package/dist/esm/test/duration-sequencer.d.ts +20 -0
  283. package/dist/esm/test/duration-sequencer.js +54 -0
  284. package/dist/esm/test/shard-durations.json +922 -0
  285. package/dist/esm/test/worker-budget.d.ts +6 -0
  286. package/dist/esm/test/worker-budget.js +59 -1
  287. package/dist/esm/test-helpers/global-setup.d.ts +1 -2
  288. package/dist/esm/test-helpers/global-setup.js +79 -32
  289. package/dist/esm/typecheck/planner.d.ts +9 -1
  290. package/dist/esm/typecheck/planner.js +31 -0
  291. package/dist/esm/ultragoal/service.d.ts +7 -0
  292. package/dist/esm/ultragoal/service.js +42 -2
  293. package/dist/esm/utils/write-json-file.js +3 -1
  294. package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
  295. package/dist/esm/worktrees/codex-project-trust.js +56 -0
  296. package/dist/esm/worktrees/orphan-scan.d.ts +50 -0
  297. package/dist/esm/worktrees/orphan-scan.js +211 -0
  298. package/dist/esm/worktrees/registry.d.ts +8 -0
  299. package/dist/esm/worktrees/registry.js +18 -3
  300. package/package.json +18 -13
@@ -0,0 +1,183 @@
1
+ /**
2
+ * `wp_ci_preflight` MCP tool.
3
+ *
4
+ * Wraps `runCiPreflight` (the single owner of the pre-push gate — see
5
+ * `src/cli/commands/ci-preflight.ts`) so agents can run the exact fail-fast,
6
+ * branch-scoped sequence CI mirrors — `format → guardrails → typecheck →
7
+ * lint → test` — without shelling out to `wp ci-preflight` via Bash.
8
+ *
9
+ * `runCiPreflight`'s default `runCheck` re-invokes `wp <subcommand>` via
10
+ * `spawnSync(..., {stdio: "inherit"})`. That is correct for a real terminal
11
+ * but unsafe here: `wp mcp` speaks stdio-transport JSON-RPC over the process's
12
+ * real stdout, and an inherited child write would corrupt that stream. This
13
+ * tool substitutes a `runCheck` that spawns each stage asynchronously via the
14
+ * shared `runCommand` helper (captured stdout/stderr, a bounded per-stage
15
+ * timeout, and `extra.signal` cancellation) using the same `wp` launcher
16
+ * resolution (`resolveWpLauncher`) the CLI uses, so behavior stays identical
17
+ * — only the transport of the output changes. `runCiPreflight`'s own
18
+ * `stdout`/`stderr` deps are swallowed for the same reason (they default to
19
+ * `process.stdout`/`process.stderr`); the equivalent progress detail is
20
+ * reconstructed from the per-stage results this tool collects itself.
21
+ *
22
+ * `runCiPreflight` returns only an exit code — there is no structured
23
+ * per-stage payload to "pass through." The `{passed, summary, details:
24
+ * {stages, stoppedAt}}` shape below mirrors `wp_qa`'s aggregate-gate
25
+ * convention (structured pass/fail + per-stage breakdown) since ci-preflight
26
+ * is the same shape of thing: a staged composite gate, just sequential and
27
+ * fail-fast instead of `wp_qa`'s parallel `Promise.all`.
28
+ */
29
+ import { existsSync } from "node:fs";
30
+ import { join } from "node:path";
31
+ import { z } from "zod";
32
+ import { resolveWpLauncher, runCiPreflight, } from "#cli/commands/ci-preflight.js";
33
+ import { formatMcpToolOutput } from "./_shared/full-output.js";
34
+ import { resolveProjectRoot } from "./_shared/project-root.js";
35
+ import { createSummaryOutputSchema, createSummaryResult } from "./_shared/result.js";
36
+ import { isRunFailure, runCommand } from "./_shared/run-command.js";
37
+ const inputSchema = z.object({
38
+ cwd: z.string().optional(),
39
+ full: z.boolean().optional().default(false),
40
+ });
41
+ // Generous but bounded: mirrors `wp_typecheck`'s cap (the heaviest single
42
+ // sibling stage). In normal operation every stage here is branch-scoped
43
+ // (`--affected --branch`) so real runs finish in seconds to low minutes; this
44
+ // cap only exists to convert a hang into a diagnosable `timedOut: true`
45
+ // instead of blocking the MCP transport indefinitely. Applied per-stage (not
46
+ // as one combined budget) so an early hang doesn't eat the time later stages
47
+ // would have needed.
48
+ const CI_PREFLIGHT_STAGE_TIMEOUT_MS = 10 * 60 * 1_000;
49
+ const stageResultSchema = z.object({
50
+ label: z.string(),
51
+ args: z.array(z.string()),
52
+ passed: z.boolean(),
53
+ exitCode: z.number().optional(),
54
+ timedOut: z.boolean().optional(),
55
+ aborted: z.boolean().optional(),
56
+ spawnError: z.string().optional(),
57
+ rawOutput: z.string().optional(),
58
+ truncated: z.boolean().optional(),
59
+ logPath: z.string().optional(),
60
+ });
61
+ const outputSchema = createSummaryOutputSchema({
62
+ details: z.object({
63
+ stages: z.array(stageResultSchema),
64
+ stoppedAt: z.string().optional(),
65
+ bootstrapError: z.string().optional(),
66
+ }),
67
+ });
68
+ const noopWritable = { write: () => true };
69
+ /**
70
+ * Build the `runCheck` substitution: same stages, same launcher, same
71
+ * fail-fast contract as the CLI's `defaultRunCheck` — just async and
72
+ * output-capturing instead of `spawnSync(..., {stdio: "inherit"})`.
73
+ */
74
+ function buildCapturingRunCheck(stages, options) {
75
+ return async (check, repoRoot) => {
76
+ const launcher = resolveWpLauncher(repoRoot);
77
+ const outcome = await runCommand(launcher.command, [...launcher.prefixArgs, ...check.args], {
78
+ timeoutMs: options.timeoutMs,
79
+ signal: options.signal,
80
+ cwd: repoRoot,
81
+ });
82
+ if (isRunFailure(outcome)) {
83
+ const spawnError = `${outcome.error.code ?? "unknown"} ${outcome.error.message}`;
84
+ stages.push({ label: check.label, args: [...check.args], passed: false, spawnError });
85
+ return 1;
86
+ }
87
+ const combined = [outcome.stdout, outcome.stderr].filter(Boolean).join("\n");
88
+ const compact = formatMcpToolOutput(combined, {
89
+ toolName: `wp_ci_preflight-${check.label}`,
90
+ full: options.full,
91
+ cwd: repoRoot,
92
+ });
93
+ stages.push({
94
+ label: check.label,
95
+ args: [...check.args],
96
+ passed: outcome.exitCode === 0,
97
+ exitCode: outcome.exitCode,
98
+ ...(outcome.timedOut ? { timedOut: true } : {}),
99
+ ...(outcome.aborted ? { aborted: true } : {}),
100
+ ...compact,
101
+ });
102
+ return outcome.exitCode;
103
+ };
104
+ }
105
+ function summarizeCiPreflight(stages, bootstrapError) {
106
+ if (bootstrapError)
107
+ return bootstrapError;
108
+ if (stages.length === 0)
109
+ return "ci-preflight did not run any checks";
110
+ const failed = stages.find((stage) => !stage.passed);
111
+ if (!failed)
112
+ return `ci-preflight passed (${stages.map((stage) => stage.label).join(", ")})`;
113
+ if (failed.spawnError)
114
+ return `ci-preflight could not start ${failed.label}: ${failed.spawnError}`;
115
+ if (failed.timedOut)
116
+ return `ci-preflight: ${failed.label} timed out`;
117
+ if (failed.aborted)
118
+ return `ci-preflight: ${failed.label} aborted`;
119
+ return `ci-preflight failed at ${failed.label} (exit ${failed.exitCode ?? "unknown"})`;
120
+ }
121
+ const tool = {
122
+ name: "wp_ci_preflight",
123
+ description: "Run the locally-runnable required CI checks, fail-fast, branch-scoped: `format → audit guardrails → typecheck → lint → test` (mirrors `.husky/pre-push`). Returns `{passed, summary, details: {stages, stoppedAt}}`. Use before push / PR open-update; prefer over `wp_qa` when you need pre-push parity (branch-scoped `--affected --branch`, sequential fail-fast) rather than `wp_qa`'s parallel whole-scope lint+typecheck+test; run `wp ci-preflight` directly only if this tool is unavailable.",
124
+ inputSchema,
125
+ outputSchema,
126
+ annotations: {
127
+ title: "CI preflight (pre-push gate)",
128
+ readOnlyHint: true,
129
+ destructiveHint: false,
130
+ idempotentHint: true,
131
+ openWorldHint: false,
132
+ },
133
+ handler: async (raw, extra) => {
134
+ const input = inputSchema.parse(raw ?? {});
135
+ const cwd = resolveProjectRoot(input.cwd ? { cwd: input.cwd } : {});
136
+ const stages = [];
137
+ let bootstrapError;
138
+ const runCheck = buildCapturingRunCheck(stages, {
139
+ timeoutMs: CI_PREFLIGHT_STAGE_TIMEOUT_MS,
140
+ signal: extra?.signal,
141
+ full: input.full,
142
+ });
143
+ const exitCode = await runCiPreflight({
144
+ cwd,
145
+ // Already resolved via the MCP-safe `resolveProjectRoot` walk above;
146
+ // re-resolving via git-topLevel here would risk landing on a different
147
+ // root than the one we're about to spawn stages in.
148
+ resolveRepoRoot: () => cwd,
149
+ hasNodeModules: (repoRoot) => {
150
+ const ok = existsSync(join(repoRoot, "node_modules"));
151
+ if (!ok) {
152
+ bootstrapError = `wp_ci_preflight: ${repoRoot} is not bootstrapped — node_modules is missing. Run \`vp install\` in this worktree first, then retry.`;
153
+ }
154
+ return ok;
155
+ },
156
+ runCheck,
157
+ // Swallow progress writes — they default to process.stdout/stderr,
158
+ // which on a stdio-transport MCP server IS the JSON-RPC channel. The
159
+ // equivalent detail is already captured per-stage above.
160
+ stdout: noopWritable,
161
+ stderr: noopWritable,
162
+ });
163
+ const passed = exitCode === 0;
164
+ const stoppedAt = passed ? undefined : stages.at(-1)?.label;
165
+ const payload = {
166
+ passed,
167
+ summary: summarizeCiPreflight(stages, bootstrapError),
168
+ exitCode,
169
+ details: {
170
+ stages,
171
+ ...(stoppedAt ? { stoppedAt } : {}),
172
+ ...(bootstrapError ? { bootstrapError } : {}),
173
+ },
174
+ };
175
+ // `isError: true` is reserved for "we couldn't run the gate at all"
176
+ // (not bootstrapped, or a stage's spawn itself failed) — matching
177
+ // `wp_qa`'s convention that a check legitimately reporting `passed: false`
178
+ // is normal output the agent should act on, not a tool-execution error.
179
+ const executionFailed = bootstrapError !== undefined || stages.some((stage) => stage.spawnError !== undefined);
180
+ return createSummaryResult(payload, executionFailed ? { isError: true } : {});
181
+ },
182
+ };
183
+ export default tool;
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { z } from "zod";
3
3
  import { prDescriptionInputSchema, renderAndValidatePrDescription, } from "#pr-description/contract.js";
4
+ import { readCurrentSessionId } from "#session-memory/current-session.js";
4
5
  import { createSummaryOutputSchema, createSummaryResult } from "./_shared/result.js";
5
6
  import { resolveProjectRoot } from "./_shared/project-root.js";
6
7
  import { redactText } from "./_shared/redact.js";
@@ -58,6 +59,42 @@ function resolveCwd(input) {
58
59
  function branchFor(input) {
59
60
  return input.branch ?? "HEAD";
60
61
  }
62
+ /**
63
+ * Best-effort fill for an omitted `description.sessionId`, using the same
64
+ * lookup `wp_session_id` wraps. Never overrides an explicit value and never
65
+ * fights an explicit `Session-skip` (a caller who set a skip reason has
66
+ * already made a deliberate choice not to disclose a session id).
67
+ *
68
+ * This DOES change one previously-fail-closed case: an omitted `sessionId`
69
+ * with no `Session-skip` used to fail validation outright; it now silently
70
+ * passes when the current worktree has a resolvable id (which may be a prior,
71
+ * still-accurate-for-this-worktree id when no capture has happened yet in the
72
+ * live session) — this is the intended best-effort automation of the paste a
73
+ * caller would otherwise do by hand. When NO id resolves, the outcome is
74
+ * unchanged: the description is returned as-is and the pre-existing
75
+ * "missing sessionId" validation error still blocks the mutation. So the only
76
+ * new behavior is "fills a real gap"; it never manufactures a fake id and
77
+ * never converts a genuine miss into a silent success.
78
+ */
79
+ function withAutoResolvedSessionId(input) {
80
+ const description = input.description;
81
+ if (description.sessionId?.trim())
82
+ return description;
83
+ if (description.sessionSkipReason?.trim())
84
+ return description;
85
+ try {
86
+ const sessionId = readCurrentSessionId(resolveCwd(input), process.env);
87
+ return sessionId ? { ...description, sessionId } : description;
88
+ }
89
+ catch (error) {
90
+ // Match this module's stderr-breadcrumb philosophy (see current-session.ts):
91
+ // a lookup throw degrades to "leave as-is" (fail-closed — validation then
92
+ // reports the missing sessionId), but is surfaced so a genuine store bug
93
+ // is not silently swallowed.
94
+ process.stderr.write(`[wp_pr_upsert] sessionId auto-resolve failed; leaving description unchanged: ${error instanceof Error ? error.message : String(error)}\n`);
95
+ return description;
96
+ }
97
+ }
61
98
  function clipOutput(value, maxOutputBytes) {
62
99
  const redacted = redactText(value.trim());
63
100
  if (!redacted)
@@ -152,7 +189,8 @@ const tool = {
152
189
  },
153
190
  handler: async (raw, extra) => {
154
191
  const input = inputSchema.parse(raw ?? {});
155
- const { body, validation } = renderAndValidatePrDescription(input.description);
192
+ const description = withAutoResolvedSessionId(input);
193
+ const { body, validation } = renderAndValidatePrDescription(description);
156
194
  const branch = branchFor(input);
157
195
  const bodySha256 = bodyHash(body);
158
196
  const commands = [];
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `wp_review_run` MCP tool.
3
+ *
4
+ * Wraps `runReviewRunCommand` — the exact runtime `wp review run` and
5
+ * `wp review gate` use — so MCP callers get a first-class outside-voice
6
+ * review primitive instead of shelling into a provider CLI directly. Two
7
+ * ergonomic improvements over the raw `wp review run` CLI:
8
+ *
9
+ * 1. Accepts `prompt` directly instead of requiring a `--prompt-file` on
10
+ * disk. The tool writes the prompt to a private temp file under the
11
+ * resolved `artifactRoot` itself (cleaned up after each stage), since
12
+ * `runReviewRunCommand` requires a real file to read over stdin.
13
+ * 2. By default runs a synthesized `probe` stage (cheap liveness check)
14
+ * followed by the `review` stage in ONE call — removing the two-step
15
+ * probe-then-review dance every consumer previously had to hand-roll in
16
+ * bash (see the `codex` skill's pre-fix version). If the probe fails,
17
+ * the review stage is never attempted. Pass `skipProbe: true` to go
18
+ * straight to `review` once a provider is known-warm, or pass an
19
+ * explicit `stage` for CLI-parity manual control.
20
+ *
21
+ * Provider fallback (e.g. Codex out of API credits) is a `provider`
22
+ * parameter change on this SAME tool call — never a raw shell-out to a
23
+ * different provider's CLI. `forbidden-commands.ts`'s
24
+ * `findReviewCliRedirect` enforces that on the Bash-tool side.
25
+ */
26
+ import type { ToolDescriptor } from "#mcp/auto-discover";
27
+ declare const tool: ToolDescriptor;
28
+ export default tool;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * `wp_review_run` MCP tool.
3
+ *
4
+ * Wraps `runReviewRunCommand` — the exact runtime `wp review run` and
5
+ * `wp review gate` use — so MCP callers get a first-class outside-voice
6
+ * review primitive instead of shelling into a provider CLI directly. Two
7
+ * ergonomic improvements over the raw `wp review run` CLI:
8
+ *
9
+ * 1. Accepts `prompt` directly instead of requiring a `--prompt-file` on
10
+ * disk. The tool writes the prompt to a private temp file under the
11
+ * resolved `artifactRoot` itself (cleaned up after each stage), since
12
+ * `runReviewRunCommand` requires a real file to read over stdin.
13
+ * 2. By default runs a synthesized `probe` stage (cheap liveness check)
14
+ * followed by the `review` stage in ONE call — removing the two-step
15
+ * probe-then-review dance every consumer previously had to hand-roll in
16
+ * bash (see the `codex` skill's pre-fix version). If the probe fails,
17
+ * the review stage is never attempted. Pass `skipProbe: true` to go
18
+ * straight to `review` once a provider is known-warm, or pass an
19
+ * explicit `stage` for CLI-parity manual control.
20
+ *
21
+ * Provider fallback (e.g. Codex out of API credits) is a `provider`
22
+ * parameter change on this SAME tool call — never a raw shell-out to a
23
+ * different provider's CLI. `forbidden-commands.ts`'s
24
+ * `findReviewCliRedirect` enforces that on the Bash-tool side.
25
+ */
26
+ import { randomUUID } from "node:crypto";
27
+ import { mkdirSync, unlinkSync, writeFileSync } from "node:fs";
28
+ import path from "node:path";
29
+ import { z } from "zod";
30
+ import { runReviewRunCommand } from "#cli/commands/review.js";
31
+ import { createSummaryOutputSchema, createSummaryResult } from "./_shared/result.js";
32
+ import { resolveProjectRoot } from "./_shared/project-root.js";
33
+ const PROBE_PROMPT = "Reply exactly WP_REVIEW_PROBE_OK.";
34
+ const PROBE_EXPECTED_MARKER = "WP_REVIEW_PROBE_OK";
35
+ const inputSchema = z
36
+ .object({
37
+ prompt: z.string().min(1),
38
+ provider: z.enum(["claude", "codex", "opencode", "grok"]),
39
+ model: z.string().min(1).optional(),
40
+ effort: z.enum(["medium", "high"]).optional().default("medium"),
41
+ stage: z.enum(["probe", "review"]).optional(),
42
+ skipProbe: z.boolean().optional().default(false),
43
+ expectedMarker: z
44
+ .string()
45
+ .min(1)
46
+ .optional()
47
+ .describe("Required substring of the provider's output. Applies to BOTH stages. On a review, ask the prompt for a verdict token (e.g. 'VERDICT:') and pass it here — a provider that announces intent and ends the turn without doing the work then fails loudly as expected-marker-missing instead of reporting a content-free success. On an explicit probe it is the liveness marker; in auto mode the probe uses its own synthesized marker and this value applies to the review stage."),
48
+ artifactRoot: z.string().optional(),
49
+ idleSeconds: z.number().int().positive().optional().default(180),
50
+ cwd: z.string().optional(),
51
+ })
52
+ .strict();
53
+ const reviewRunSummarySchema = z.object({
54
+ schemaVersion: z.literal(1),
55
+ runId: z.string(),
56
+ provider: z.enum(["claude", "codex", "opencode", "grok"]),
57
+ adapterVersion: z.string(),
58
+ model: z.string(),
59
+ effort: z.enum(["medium", "high"]),
60
+ stage: z.enum(["probe", "review"]),
61
+ status: z.string(),
62
+ startedAt: z.string(),
63
+ finishedAt: z.string(),
64
+ lastProgressAt: z.string(),
65
+ semanticProgressCount: z.number(),
66
+ exitCode: z.number().nullable(),
67
+ markerMatched: z.boolean().nullable(),
68
+ result: z.string().optional(),
69
+ failureCode: z.string().optional(),
70
+ limitWindow: z.enum(["five-hour", "weekly", "monthly", "unknown"]).optional(),
71
+ retryAfterMs: z.number().optional(),
72
+ summaryPath: z.string(),
73
+ });
74
+ const outputSchema = createSummaryOutputSchema({
75
+ counts: z.object({ stagesRun: z.number() }),
76
+ details: z.object({
77
+ stages: z.array(reviewRunSummarySchema),
78
+ probeSkipped: z.boolean(),
79
+ }),
80
+ });
81
+ function resolveCwd(input) {
82
+ return resolveProjectRoot(input.cwd ? { cwd: input.cwd } : {});
83
+ }
84
+ function resolveArtifactRoot(projectRoot, input) {
85
+ if (!input.artifactRoot)
86
+ return path.join(projectRoot, ".webpresso", "reviews");
87
+ return path.isAbsolute(input.artifactRoot)
88
+ ? input.artifactRoot
89
+ : path.join(projectRoot, input.artifactRoot);
90
+ }
91
+ function writePromptFile(artifactRoot, prompt) {
92
+ mkdirSync(artifactRoot, { recursive: true });
93
+ const promptFile = path.join(artifactRoot, `mcp-review-prompt-${randomUUID()}.txt`);
94
+ // 0600 matches the CLI fallback's `mktemp` posture: the prompt can carry a
95
+ // diff/context the caller would not want other local users reading, and the
96
+ // file lives under a shared artifactRoot. Owner-only, not just an
97
+ // unpredictable name.
98
+ writeFileSync(promptFile, prompt, { encoding: "utf8", mode: 0o600 });
99
+ return promptFile;
100
+ }
101
+ function cleanupPromptFile(promptFile) {
102
+ try {
103
+ unlinkSync(promptFile);
104
+ }
105
+ catch {
106
+ // Best-effort cleanup: a leftover temp file under the private
107
+ // artifactRoot is harmless and is never treated as review evidence.
108
+ }
109
+ }
110
+ async function runStage(projectRoot, artifactRoot, input, stage, prompt, expectedMarker, signal) {
111
+ const promptFile = writePromptFile(artifactRoot, prompt);
112
+ try {
113
+ const options = {
114
+ provider: input.provider,
115
+ promptFile,
116
+ effort: input.effort,
117
+ stage,
118
+ artifactRoot,
119
+ idleSeconds: String(input.idleSeconds),
120
+ ...(input.model ? { model: input.model } : {}),
121
+ ...(expectedMarker ? { expectedMarker } : {}),
122
+ };
123
+ return await runReviewRunCommand(projectRoot, options, signal ? { signal } : {});
124
+ }
125
+ finally {
126
+ cleanupPromptFile(promptFile);
127
+ }
128
+ }
129
+ /**
130
+ * Execution success, not verdict positivity: a `review` stage that completes
131
+ * with a REJECT verdict is still `status: "complete"` and counts as `passed`
132
+ * here. Only a `probe` stage additionally requires its expected marker to
133
+ * have matched (when one was actually requested — an explicit probe without
134
+ * an `expectedMarker` only needs to complete).
135
+ *
136
+ * Note this check does NOT need a review-stage marker branch: when the caller
137
+ * supplies an `expectedMarker`, the supervisor itself downgrades a run whose
138
+ * output lacks it to `status: "provider-failure"` /
139
+ * `failureCode: "expected-marker-missing"`, so the `status !== "complete"`
140
+ * guard above already rejects it. That is the load-bearing defense against a
141
+ * provider that announces intent and ends the turn without doing the work —
142
+ * observed 2026-07-24, when reviews returned only "I'll compare X against
143
+ * Y..." yet reported `complete`.
144
+ */
145
+ function stageOk(summary, markerRequired) {
146
+ if (summary.status !== "complete")
147
+ return false;
148
+ if (summary.stage !== "probe")
149
+ return true;
150
+ return markerRequired ? summary.markerMatched === true : summary.markerMatched !== false;
151
+ }
152
+ function describeStage(summary) {
153
+ if (summary.stage === "probe") {
154
+ const ok = summary.status === "complete" && summary.markerMatched !== false;
155
+ return ok ? "probe ok" : `probe failed (${summary.failureCode ?? summary.status})`;
156
+ }
157
+ return summary.status === "complete"
158
+ ? "review complete"
159
+ : `review failed (${summary.failureCode ?? summary.status})`;
160
+ }
161
+ function summarize(stages, passed, probeSkipped) {
162
+ const parts = stages.map(describeStage);
163
+ if (probeSkipped)
164
+ parts.unshift("probe skipped");
165
+ return `${passed ? "passed" : "failed"}: ${parts.join("; ")}`;
166
+ }
167
+ function toResult(stages, passed, probeSkipped) {
168
+ return createSummaryResult({
169
+ passed,
170
+ summary: summarize(stages, passed, probeSkipped),
171
+ counts: { stagesRun: stages.length },
172
+ details: { stages, probeSkipped },
173
+ }, { isError: !passed });
174
+ }
175
+ const tool = {
176
+ name: "wp_review_run",
177
+ description: 'Run an outside-voice provider review (claude|codex|opencode|grok) from a `prompt` string — no `--prompt-file` needed. By default runs a synthesized probe stage first, then the review stage, in one call; the review stage is skipped if the probe fails. Pass `stage: "probe"` or `stage: "review"` for single-stage CLI-parity control, or `skipProbe: true` to skip straight to review once a provider is known-warm. To fall back from an unavailable provider (e.g. Codex out of credits), change the `provider` parameter on this SAME tool — never shell into a different provider CLI. IMPORTANT: `passed` means the review EXECUTED to completion, NOT that the reviewer approved — a review that runs and returns REJECT is still `passed: true`. The reviewer\'s actual verdict/findings are in `details.stages[].result`; read that text before reporting approval. To guarantee the reviewer actually did the work, ask the prompt for a verdict token and pass it as `expectedMarker`: a provider that only announces intent then stops will fail as expected-marker-missing rather than returning a content-free success.',
178
+ inputSchema,
179
+ outputSchema,
180
+ annotations: {
181
+ title: "Run outside-voice provider review",
182
+ readOnlyHint: false,
183
+ destructiveHint: false,
184
+ idempotentHint: false,
185
+ openWorldHint: true,
186
+ },
187
+ handler: async (raw, extra) => {
188
+ const input = inputSchema.parse(raw ?? {});
189
+ const projectRoot = resolveCwd(input);
190
+ const artifactRoot = resolveArtifactRoot(projectRoot, input);
191
+ const signal = extra?.signal;
192
+ if (input.stage === "probe") {
193
+ const result = await runStage(projectRoot, artifactRoot, input, "probe", input.prompt, input.expectedMarker, signal);
194
+ return toResult([result], stageOk(result, input.expectedMarker !== undefined), false);
195
+ }
196
+ if (input.stage === "review") {
197
+ const result = await runStage(projectRoot, artifactRoot, input, "review", input.prompt, input.expectedMarker, signal);
198
+ return toResult([result], stageOk(result, false), false);
199
+ }
200
+ // No explicit stage requested: auto probe-then-review.
201
+ const stages = [];
202
+ if (!input.skipProbe) {
203
+ const probeResult = await runStage(projectRoot, artifactRoot, input, "probe", PROBE_PROMPT, PROBE_EXPECTED_MARKER, signal);
204
+ stages.push(probeResult);
205
+ if (!stageOk(probeResult, true)) {
206
+ // Probe failed: do not waste a full review-stage call.
207
+ return toResult(stages, false, false);
208
+ }
209
+ }
210
+ const reviewResult = await runStage(projectRoot, artifactRoot, input, "review", input.prompt, input.expectedMarker, signal);
211
+ stages.push(reviewResult);
212
+ const passed = stages.every((stage) => stageOk(stage, stage.stage === "probe"));
213
+ return toResult(stages, passed, input.skipProbe);
214
+ },
215
+ };
216
+ export default tool;
@@ -0,0 +1,86 @@
1
+ import { z } from "zod";
2
+ import type { ToolDescriptor, ToolHandlerExtra } from "#mcp/auto-discover";
3
+ export declare const RUN_WAIT_UNTIL_VALUES: readonly ["run_terminal", "all_jobs_terminal"];
4
+ export type RunWaitUntil = (typeof RUN_WAIT_UNTIL_VALUES)[number];
5
+ export type RunWaitStatus = "success" | "failed" | "timed_out" | "no_run";
6
+ export type RunWaitVerdict = "passed" | "failed" | "pending";
7
+ export type RunWaitTerminalReason = "run_terminal" | "all_jobs_terminal" | "run_failed" | "timeout" | "no_run" | "command_failed";
8
+ export type WorkflowRunStatus = "queued" | "in_progress" | "completed" | "waiting" | "requested" | "pending" | (string & {});
9
+ export type WorkflowRunConclusion = "success" | "failure" | "cancelled" | "skipped" | "neutral" | "timed_out" | "action_required" | "stale" | "startup_failure" | null;
10
+ export type JobStatus = "queued" | "in_progress" | "completed" | "waiting" | "requested" | "pending" | (string & {});
11
+ export type JobConclusion = "success" | "failure" | "neutral" | "cancelled" | "skipped" | "timed_out" | "action_required" | null;
12
+ export type JobClassification = "blocked_upstream";
13
+ export interface RunWaitJob {
14
+ readonly name: string;
15
+ readonly status: JobStatus;
16
+ readonly conclusion: JobConclusion;
17
+ readonly failedStep?: string;
18
+ readonly errorTail?: string;
19
+ readonly upstreamCulprits?: readonly string[];
20
+ readonly classification?: JobClassification;
21
+ readonly transient?: string;
22
+ }
23
+ /**
24
+ * Slim per-command record: keeps spawn diagnostics (exit code, timedOut,
25
+ * aborted, missingBinary, deadline-skips) without carrying raw output — job
26
+ * logs and JSON payloads never enter the result's command trail.
27
+ */
28
+ interface SlimCommand {
29
+ readonly id: string;
30
+ readonly command: string;
31
+ readonly args: readonly string[];
32
+ readonly passed: boolean;
33
+ readonly exitCode?: number;
34
+ readonly timedOut?: true;
35
+ readonly aborted?: true;
36
+ readonly missingBinary?: true;
37
+ readonly skipped?: true;
38
+ }
39
+ export interface RunWaitResult {
40
+ readonly [key: string]: unknown;
41
+ readonly status: RunWaitStatus;
42
+ readonly passed: boolean;
43
+ readonly summary: string;
44
+ readonly verdict: RunWaitVerdict;
45
+ readonly terminalReason: RunWaitTerminalReason;
46
+ readonly conclusion: WorkflowRunConclusion;
47
+ readonly runId: number | null;
48
+ readonly runUrl?: string;
49
+ readonly workflowName?: string;
50
+ readonly headSha?: string;
51
+ readonly until: RunWaitUntil;
52
+ readonly jobs: readonly RunWaitJob[];
53
+ readonly counts: Record<string, number>;
54
+ readonly details: {
55
+ readonly cwd: string;
56
+ readonly sha?: string;
57
+ readonly runId?: number;
58
+ readonly workflow?: string;
59
+ readonly until: RunWaitUntil;
60
+ readonly timeoutMs: number;
61
+ readonly pollIntervalMs: number;
62
+ readonly pollCount: number;
63
+ readonly elapsedMs: number;
64
+ readonly commands: readonly SlimCommand[];
65
+ };
66
+ readonly warnings?: readonly string[];
67
+ }
68
+ declare const inputSchema: z.ZodObject<{
69
+ cwd: z.ZodOptional<z.ZodString>;
70
+ directory: z.ZodOptional<z.ZodString>;
71
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
72
+ maxOutputBytes: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
73
+ sha: z.ZodOptional<z.ZodString>;
74
+ runId: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
75
+ workflow: z.ZodOptional<z.ZodString>;
76
+ until: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
77
+ all_jobs_terminal: "all_jobs_terminal";
78
+ run_terminal: "run_terminal";
79
+ }>>>;
80
+ pollIntervalMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
81
+ }, z.core.$strict>;
82
+ export type RunWaitInput = z.input<typeof inputSchema>;
83
+ export declare function classifyTransient(text: string): string | undefined;
84
+ export declare function runRunWait(raw: RunWaitInput, extra?: ToolHandlerExtra): Promise<RunWaitResult>;
85
+ declare const tool: ToolDescriptor;
86
+ export default tool;