@webpresso/agent-kit 3.1.30 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/README.md +53 -15
  2. package/bin/_run.js +183 -20
  3. package/catalog/AGENTS.md.tpl +3 -3
  4. package/catalog/agent/agents/implementer.md +45 -0
  5. package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
  6. package/catalog/agent/rules/pre-implementation.md +28 -1
  7. package/catalog/agent/rules/supported-agent-clis.md +9 -0
  8. package/catalog/agent/rules/typescript-version.md +50 -0
  9. package/catalog/agent/skills/codex/SKILL.md +25 -1
  10. package/catalog/agent/skills/verify/SKILL.md +4 -2
  11. package/catalog/docs/templates/blueprint.md +1 -1
  12. package/dist/esm/audit/agents.js +1 -0
  13. package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
  14. package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
  15. package/dist/esm/audit/blueprint-pr-coverage.js +4 -0
  16. package/dist/esm/audit/blueprint-trust.js +14 -10
  17. package/dist/esm/audit/changeset-evidence.d.ts +23 -0
  18. package/dist/esm/audit/changeset-evidence.js +30 -0
  19. package/dist/esm/audit/changeset-required.d.ts +10 -0
  20. package/dist/esm/audit/changeset-required.js +73 -0
  21. package/dist/esm/audit/ci-guardrails-detection.d.ts +27 -0
  22. package/dist/esm/audit/ci-guardrails-detection.js +68 -0
  23. package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
  24. package/dist/esm/audit/ci-guardrails-wiring.js +80 -0
  25. package/dist/esm/audit/ci-test-perf.js +30 -0
  26. package/dist/esm/audit/command-surface.js +4 -2
  27. package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
  28. package/dist/esm/audit/host-substitution-risk.js +256 -0
  29. package/dist/esm/audit/registry.d.ts +4 -4
  30. package/dist/esm/audit/registry.js +13 -1
  31. package/dist/esm/audit/toolchain-isolation.js +1 -2
  32. package/dist/esm/audit/typescript-version.d.ts +2 -0
  33. package/dist/esm/audit/typescript-version.js +123 -0
  34. package/dist/esm/blueprint/core/parser.js +101 -2
  35. package/dist/esm/blueprint/core/schema.d.ts +1 -0
  36. package/dist/esm/blueprint/core/schema.js +26 -0
  37. package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
  38. package/dist/esm/blueprint/core/validation/criteria.js +41 -2
  39. package/dist/esm/blueprint/core/validation/state.js +25 -14
  40. package/dist/esm/blueprint/db/migrations/run.js +4 -2
  41. package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
  42. package/dist/esm/blueprint/lifecycle/audit.js +87 -20
  43. package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
  44. package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
  45. package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
  46. package/dist/esm/blueprint/lifecycle/local.js +19 -3
  47. package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
  48. package/dist/esm/blueprint/lifecycle/review-provenance.js +68 -12
  49. package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +97 -0
  50. package/dist/esm/blueprint/lifecycle/rollout-anchor.js +161 -0
  51. package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
  52. package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
  53. package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
  54. package/dist/esm/blueprint/sync/client.d.ts +2 -1
  55. package/dist/esm/blueprint/sync/client.js +1 -1
  56. package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
  57. package/dist/esm/blueprint/trust/command-runner.js +148 -0
  58. package/dist/esm/blueprint/trust/dossier.d.ts +1 -0
  59. package/dist/esm/blueprint/trust/dossier.js +40 -6
  60. package/dist/esm/blueprint/trust/gates.d.ts +7 -0
  61. package/dist/esm/blueprint/trust/gates.js +20 -0
  62. package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
  63. package/dist/esm/blueprint/trust/promotion.js +74 -112
  64. package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
  65. package/dist/esm/blueprint/trust/scaffold.js +64 -0
  66. package/dist/esm/blueprint/trust/validator.d.ts +1 -0
  67. package/dist/esm/blueprint/trust/validator.js +7 -1
  68. package/dist/esm/blueprint/utils/archive.js +27 -5
  69. package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
  70. package/dist/esm/blueprint/utils/document-paths.js +45 -12
  71. package/dist/esm/build/cli-mcp-parity.js +15 -0
  72. package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
  73. package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
  74. package/dist/esm/cli/cli.d.ts +1 -1
  75. package/dist/esm/cli/cli.js +43 -0
  76. package/dist/esm/cli/commands/agent-launch.d.ts +8 -1
  77. package/dist/esm/cli/commands/agent-launch.js +93 -4
  78. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  79. package/dist/esm/cli/commands/audit-core.js +8 -1
  80. package/dist/esm/cli/commands/audit.js +21 -5
  81. package/dist/esm/cli/commands/blueprint/execution.js +18 -6
  82. package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
  83. package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
  84. package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
  85. package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
  86. package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
  87. package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
  88. package/dist/esm/cli/commands/blueprint/router.js +13 -1
  89. package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
  90. package/dist/esm/cli/commands/ci-preflight.js +30 -6
  91. package/dist/esm/cli/commands/compile.js +5 -31
  92. package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
  93. package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
  94. package/dist/esm/cli/commands/doctor.js +5 -0
  95. package/dist/esm/cli/commands/hook.d.ts +5 -0
  96. package/dist/esm/cli/commands/hook.js +15 -9
  97. package/dist/esm/cli/commands/init/config.js +2 -2
  98. package/dist/esm/cli/commands/init/convergence-apply.d.ts +88 -0
  99. package/dist/esm/cli/commands/init/convergence-apply.js +325 -0
  100. package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
  101. package/dist/esm/cli/commands/init/convergence-state.js +54 -0
  102. package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
  103. package/dist/esm/cli/commands/init/convergence.js +57 -0
  104. package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
  105. package/dist/esm/cli/commands/init/git-convergence.js +168 -0
  106. package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
  107. package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
  108. package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
  109. package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
  110. package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
  111. package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
  112. package/dist/esm/cli/commands/init/host-visibility.js +94 -5
  113. package/dist/esm/cli/commands/init/index.d.ts +3 -0
  114. package/dist/esm/cli/commands/init/index.js +326 -173
  115. package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
  116. package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
  117. package/dist/esm/cli/commands/init/merge.d.ts +1 -0
  118. package/dist/esm/cli/commands/init/merge.js +30 -1
  119. package/dist/esm/cli/commands/init/package-root.d.ts +7 -0
  120. package/dist/esm/cli/commands/init/package-root.js +10 -2
  121. package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
  122. package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
  123. package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
  124. package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
  125. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +20 -0
  126. package/dist/esm/cli/commands/init/scaffold-base-kit.js +61 -5
  127. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
  128. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
  129. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
  130. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +54 -24
  131. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
  132. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +288 -202
  133. package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +22 -0
  134. package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +230 -0
  135. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
  136. package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
  137. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
  138. package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
  139. package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
  140. package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
  141. package/dist/esm/cli/commands/opencode-probe.d.ts +107 -0
  142. package/dist/esm/cli/commands/opencode-probe.js +323 -0
  143. package/dist/esm/cli/commands/opencode-rotate.d.ts +72 -0
  144. package/dist/esm/cli/commands/opencode-rotate.js +147 -0
  145. package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
  146. package/dist/esm/cli/commands/public-readiness.js +42 -0
  147. package/dist/esm/cli/commands/quality-runner.js +3 -3
  148. package/dist/esm/cli/commands/review.d.ts +35 -3
  149. package/dist/esm/cli/commands/review.js +751 -209
  150. package/dist/esm/cli/commands/run-wait.d.ts +2 -0
  151. package/dist/esm/cli/commands/run-wait.js +122 -0
  152. package/dist/esm/cli/commands/rust-check.d.ts +24 -0
  153. package/dist/esm/cli/commands/rust-check.js +110 -0
  154. package/dist/esm/cli/commands/setup-help.js +1 -1
  155. package/dist/esm/cli/commands/setup-repair-help.js +1 -1
  156. package/dist/esm/cli/commands/typecheck.d.ts +1 -0
  157. package/dist/esm/cli/commands/typecheck.js +30 -1
  158. package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +6 -0
  159. package/dist/esm/cli/commands/worktree/router-dispatch.js +126 -9
  160. package/dist/esm/cli/commands/worktree/router.js +10 -0
  161. package/dist/esm/cli/direct-provider-launch.js +9 -5
  162. package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
  163. package/dist/esm/cli/optional-tool-freshness.js +219 -9
  164. package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
  165. package/dist/esm/daemon/domains/git-actions.js +136 -0
  166. package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
  167. package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
  168. package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
  169. package/dist/esm/daemon/domains/sessions-search.js +29 -0
  170. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
  171. package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
  172. package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
  173. package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
  174. package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
  175. package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
  176. package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
  177. package/dist/esm/daemon/handlers/git-handlers.js +27 -0
  178. package/dist/esm/daemon/handlers/product.d.ts +7 -0
  179. package/dist/esm/daemon/handlers/product.js +10 -119
  180. package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
  181. package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
  182. package/dist/esm/daemon/handlers/shared.d.ts +5 -0
  183. package/dist/esm/daemon/handlers/shared.js +16 -0
  184. package/dist/esm/daemon/methods.d.ts +8 -1
  185. package/dist/esm/daemon/methods.js +7 -0
  186. package/dist/esm/daemon/protocol/contract.d.ts +43 -0
  187. package/dist/esm/daemon/protocol/contract.js +26 -0
  188. package/dist/esm/daemon/protocol/index.d.ts +1 -1
  189. package/dist/esm/daemon/protocol/index.js +1 -1
  190. package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
  191. package/dist/esm/hooks/__conformance__/matrix.js +137 -0
  192. package/dist/esm/hooks/conformance/batch.js +5 -0
  193. package/dist/esm/hooks/doctor.d.ts +5 -3
  194. package/dist/esm/hooks/doctor.js +67 -16
  195. package/dist/esm/hooks/permission-request/index.js +9 -3
  196. package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
  197. package/dist/esm/hooks/permission-request/policy.js +13 -0
  198. package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
  199. package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
  200. package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
  201. package/dist/esm/hooks/pretool-guard/logger.js +16 -0
  202. package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
  203. package/dist/esm/hooks/pretool-guard/runner.js +68 -16
  204. package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
  205. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +54 -0
  206. package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
  207. package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
  208. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
  209. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
  210. package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +6 -1
  211. package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
  212. package/dist/esm/hooks/shared/guard-outcome.js +215 -0
  213. package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
  214. package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
  215. package/dist/esm/hooks/shared/types.d.ts +8 -5
  216. package/dist/esm/hooks/shared/types.js +50 -9
  217. package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
  218. package/dist/esm/hooks/stop/qa-changed-files.js +92 -0
  219. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
  220. package/dist/esm/mcp/blueprint/handlers/document-mutations.d.ts +5 -0
  221. package/dist/esm/mcp/blueprint/handlers/document-mutations.js +109 -11
  222. package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
  223. package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
  224. package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
  225. package/dist/esm/mcp/blueprint/registration.js +3 -2
  226. package/dist/esm/mcp/server.d.ts +1 -0
  227. package/dist/esm/mcp/server.js +27 -0
  228. package/dist/esm/mcp/tools/_names.d.ts +1 -1
  229. package/dist/esm/mcp/tools/_names.js +5 -0
  230. package/dist/esm/mcp/tools/_registry.js +10 -0
  231. package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
  232. package/dist/esm/mcp/tools/_shared/result.js +44 -1
  233. package/dist/esm/mcp/tools/audit.d.ts +5 -1
  234. package/dist/esm/mcp/tools/audit.js +42 -0
  235. package/dist/esm/mcp/tools/audits.d.ts +4 -0
  236. package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
  237. package/dist/esm/mcp/tools/ci-preflight.js +183 -0
  238. package/dist/esm/mcp/tools/pr-upsert.js +39 -1
  239. package/dist/esm/mcp/tools/review-run.d.ts +28 -0
  240. package/dist/esm/mcp/tools/review-run.js +216 -0
  241. package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
  242. package/dist/esm/mcp/tools/run-wait.js +593 -0
  243. package/dist/esm/mcp/tools/session-fetch-and-index.d.ts +1 -1
  244. package/dist/esm/mcp/tools/session-id.d.ts +3 -0
  245. package/dist/esm/mcp/tools/session-id.js +45 -0
  246. package/dist/esm/mcp/tools/session-info.d.ts +3 -0
  247. package/dist/esm/mcp/tools/session-info.js +49 -0
  248. package/dist/esm/output-transforms/audit.d.ts +23 -0
  249. package/dist/esm/output-transforms/audit.js +47 -0
  250. package/dist/esm/output-transforms/index.js +2 -0
  251. package/dist/esm/package.json +2 -0
  252. package/dist/esm/platform/client.d.ts +7 -1
  253. package/dist/esm/platform/github-contract-source.d.ts +2 -1
  254. package/dist/esm/pr-description/contract.js +24 -4
  255. package/dist/esm/review/authority.js +27 -14
  256. package/dist/esm/review/availability.d.ts +33 -0
  257. package/dist/esm/review/availability.js +122 -20
  258. package/dist/esm/review/delivery-verifier.d.ts +27 -0
  259. package/dist/esm/review/delivery-verifier.js +115 -0
  260. package/dist/esm/review/events.d.ts +3 -2
  261. package/dist/esm/review/events.js +23 -3
  262. package/dist/esm/review/execution/adapters.d.ts +11 -1
  263. package/dist/esm/review/execution/adapters.js +36 -10
  264. package/dist/esm/review/execution/artifacts.d.ts +1 -1
  265. package/dist/esm/review/execution/output-policy.d.ts +2 -0
  266. package/dist/esm/review/execution/output-policy.js +12 -0
  267. package/dist/esm/review/execution/review-checkout.js +121 -21
  268. package/dist/esm/review/execution/supervisor.js +36 -4
  269. package/dist/esm/review/execution/types.d.ts +9 -0
  270. package/dist/esm/review/opencode-account.d.ts +24 -0
  271. package/dist/esm/review/opencode-account.js +68 -0
  272. package/dist/esm/review/opencode-auth.d.ts +33 -0
  273. package/dist/esm/review/opencode-auth.js +79 -0
  274. package/dist/esm/review/subject.d.ts +25 -0
  275. package/dist/esm/review/subject.js +116 -26
  276. package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
  277. package/dist/esm/runtime/opencode-account-materializer.js +33 -0
  278. package/dist/esm/rust/affected-manifests.d.ts +38 -0
  279. package/dist/esm/rust/affected-manifests.js +69 -0
  280. package/dist/esm/session-memory/fetch-index.d.ts +1 -1
  281. package/dist/esm/status/snapshot.js +32 -25
  282. package/dist/esm/test/duration-sequencer.d.ts +20 -0
  283. package/dist/esm/test/duration-sequencer.js +54 -0
  284. package/dist/esm/test/shard-durations.json +922 -0
  285. package/dist/esm/test/worker-budget.d.ts +6 -0
  286. package/dist/esm/test/worker-budget.js +59 -1
  287. package/dist/esm/test-helpers/global-setup.d.ts +1 -2
  288. package/dist/esm/test-helpers/global-setup.js +79 -32
  289. package/dist/esm/typecheck/planner.d.ts +9 -1
  290. package/dist/esm/typecheck/planner.js +31 -0
  291. package/dist/esm/ultragoal/service.d.ts +7 -0
  292. package/dist/esm/ultragoal/service.js +42 -2
  293. package/dist/esm/utils/write-json-file.js +3 -1
  294. package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
  295. package/dist/esm/worktrees/codex-project-trust.js +56 -0
  296. package/dist/esm/worktrees/orphan-scan.d.ts +50 -0
  297. package/dist/esm/worktrees/orphan-scan.js +211 -0
  298. package/dist/esm/worktrees/registry.d.ts +8 -0
  299. package/dist/esm/worktrees/registry.js +18 -3
  300. package/package.json +18 -13
@@ -1,33 +1,55 @@
1
1
  /**
2
2
  * Grok Build native project hooks emitter.
3
3
  *
4
- * Writes a project-local `.grok/hooks.json` surface with managed commands
5
- * labeled `WP_HOOK_HOST=grok`. Claude freeload remains the fallback delivery
6
- * path; this is the first-class native project surface for doctor/setup.
4
+ * Grok reads project hook configs from `.grok/hooks/*.json` a near-clone of
5
+ * the Claude Code hook contract (stdin event JSON incl. hookEventName/cwd,
6
+ * regex matchers, exit code 2 = deny, JSON stdout for decisions). We write one
7
+ * managed file, `.grok/hooks/webpresso.json`, with commands labeled
8
+ * `WP_HOOK_HOST=grok`. Hooks are trust-gated: the user must run `/hooks-trust`
9
+ * once in Grok before they fire (fail-open on timeout).
10
+ *
11
+ * Managed events are the intersection of WP_HOOK_SPECS with Grok's documented
12
+ * event set — notably Grok has no PermissionRequest event (it has
13
+ * PermissionDenied instead), so that spec is skipped.
7
14
  */
8
- import { mkdirSync, writeFileSync } from "node:fs";
9
15
  import { join } from "node:path";
10
16
  import { WP_HOOK_SPECS } from "#cli/commands/init/scaffolders/agent-hooks/ir.js";
11
- export const GROK_HOOKS_RELATIVE_PATH = ".grok/hooks.json";
17
+ import { updateScaffolderTextFile } from "#cli/commands/init/scaffolders/file-transaction.js";
18
+ export const GROK_HOOKS_DIR_RELATIVE_PATH = ".grok/hooks";
19
+ export const GROK_HOOKS_RELATIVE_PATH = `${GROK_HOOKS_DIR_RELATIVE_PATH}/webpresso.json`;
20
+ /** Grok's documented lifecycle events. */
21
+ const GROK_HOOK_EVENTS = new Set([
22
+ "SessionStart",
23
+ "SessionEnd",
24
+ "UserPromptSubmit",
25
+ "PreToolUse",
26
+ "PostToolUse",
27
+ "PostToolUseFailure",
28
+ "PermissionDenied",
29
+ "Stop",
30
+ "StopFailure",
31
+ "Notification",
32
+ "SubagentStart",
33
+ "SubagentStop",
34
+ "PreCompact",
35
+ "PostCompact",
36
+ ]);
12
37
  /**
13
- * Build managed Grok hook groups. PreToolUse uses a broad Bash|Write|Edit matcher;
14
- * PermissionRequest and SessionStart are included without matchers.
38
+ * Build the managed Grok hook document (Claude-contract wrapped shape:
39
+ * `{ "hooks": { Event: [ { matcher?, hooks: [...] } ] } }`).
15
40
  */
16
41
  export function buildGrokHookDocument(input) {
17
42
  const { resolveBin } = input;
18
43
  const hooks = {};
19
44
  for (const spec of WP_HOOK_SPECS) {
20
- // Grok managed subset: PreToolUse, PermissionRequest, SessionStart, PostToolUse.
21
- if (spec.event !== "PreToolUse" &&
22
- spec.event !== "PermissionRequest" &&
23
- spec.event !== "SessionStart" &&
24
- spec.event !== "PostToolUse") {
45
+ if (!GROK_HOOK_EVENTS.has(spec.event))
25
46
  continue;
26
- }
27
- // resolveBin (GROK_BIN) already labels WP_HOOK_HOST=grok on each branch of the
28
- // launcher chain. Only prefix when the resolver returns a bare command.
47
+ // resolveBin (GROK_BIN) already labels WP_HOOK_HOST=grok on each branch of
48
+ // the launcher chain with shell quoting (`WP_HOOK_HOST='grok'`), so match
49
+ // the variable name, not one quoting variant. Only prefix a bare command;
50
+ // prefixing a compound `if …` launcher would produce invalid `env … if`.
29
51
  const resolved = resolveBin(spec.bin);
30
- const command = resolved.includes("WP_HOOK_HOST=grok")
52
+ const command = /WP_HOOK_HOST=(['"]?)grok\1/u.test(resolved)
31
53
  ? resolved
32
54
  : `env WP_HOOK_HOST=grok ${resolved}`;
33
55
  const group = {
@@ -41,11 +63,7 @@ export function buildGrokHookDocument(input) {
41
63
  const existing = hooks[spec.event] ?? [];
42
64
  hooks[spec.event] = [...existing, group];
43
65
  }
44
- return {
45
- version: 1,
46
- host: "grok",
47
- hooks,
48
- };
66
+ return { hooks };
49
67
  }
50
68
  export function writeGrokProjectHooks(input) {
51
69
  const path = join(input.repoRoot, GROK_HOOKS_RELATIVE_PATH);
@@ -53,7 +71,6 @@ export function writeGrokProjectHooks(input) {
53
71
  if (input.dryRun) {
54
72
  return { path, written: false };
55
73
  }
56
- mkdirSync(join(input.repoRoot, ".grok"), { recursive: true });
57
- writeFileSync(path, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
58
- return { path, written: true };
74
+ const outcome = updateScaffolderTextFile(path, () => `${JSON.stringify(doc, null, 2)}\n`);
75
+ return { path, written: outcome === "written" };
59
76
  }
@@ -88,6 +88,8 @@ export declare function trustCodexWebpressoHooksForRepo(input: ScaffoldAgentHook
88
88
  export interface ScaffoldAgentHooksInput {
89
89
  repoRoot: string;
90
90
  options: MergeOptions;
91
+ /** Hosts selected by setup. Omitted by direct callers to scaffold every hook host. */
92
+ selectedHosts?: readonly string[];
91
93
  /**
92
94
  * Merge options for the user/home-scope leg (`~/.claude/settings.json`).
93
95
  * Defaults to `options`. The setup consent gate passes a dry-run-forced copy
@@ -36,9 +36,16 @@ import { ensureGroup, mergeAgentKitGroups } from "./merge.js";
36
36
  // - pretool guard: fail-closed (explicit deny JSON) so policy cannot silently
37
37
  // bypass when the guard binary is missing/non-executable.
38
38
  const PRETOOL_GUARD_BIN = "wp-pretool-guard";
39
- const PRETOOL_GUARD_MISSING_DENY_REASON = "wp not found on PATH. Install with vp install -g @webpresso/agent-kit and re-run wp setup.";
40
- // Dual envelope (Grok decision + Claude hookSpecificOutput) and exit 2 so Grok cannot fail-open.
41
- const PRETOOL_GUARD_MISSING_DENY = `printf '%s\\n' '{"decision":"deny","reason":"${PRETOOL_GUARD_MISSING_DENY_REASON}","hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"${PRETOOL_GUARD_MISSING_DENY_REASON}"}}'; exit 2`;
39
+ // GUARD_-coded and within the 80-char permissionDecisionReason budget so the
40
+ // generated fallback honors the same guard-outcome contract as the runtime.
41
+ const PRETOOL_GUARD_MISSING_DENY_REASON = "GUARD_PRETOOL_FAILURE: wp not found on PATH; run wp setup";
42
+ // Claude reads STDERR (not stdout) as the blocking feedback on an exit-2
43
+ // PreToolUse deny, so the coded reason is also echoed to stderr (`>&2`).
44
+ const PRETOOL_GUARD_MISSING_DENY_STDERR = `printf '%s\\n' '${PRETOOL_GUARD_MISSING_DENY_REASON}' >&2`;
45
+ // Codex golden schema forbids a top-level `decision`; emit hookSpecificOutput only.
46
+ const PRETOOL_GUARD_MISSING_DENY_CODEX = `printf '%s\\n' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"${PRETOOL_GUARD_MISSING_DENY_REASON}"}}'; ${PRETOOL_GUARD_MISSING_DENY_STDERR}; exit 2`;
47
+ // Claude/Grok dual envelope (Grok decision + Claude hookSpecificOutput) + exit 2 so Grok cannot fail-open.
48
+ const PRETOOL_GUARD_MISSING_DENY_DUAL = `printf '%s\\n' '{"decision":"deny","reason":"${PRETOOL_GUARD_MISSING_DENY_REASON}","hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"${PRETOOL_GUARD_MISSING_DENY_REASON}"}}'; ${PRETOOL_GUARD_MISSING_DENY_STDERR}; exit 2`;
42
49
  const JSON_ONLY_HOOK_FALLBACK = `printf '%s\\n' '{}'`;
43
50
  function quoteShell(value) {
44
51
  return `'${value.replaceAll("'", "'\\''")}'`;
@@ -58,11 +65,12 @@ const HOOK_SPEC_BY_BIN = new Map(WP_HOOK_SPECS.map((spec) => [spec.bin, spec]));
58
65
  function isJsonOnlyHookBin(name) {
59
66
  return HOOK_SPEC_BY_BIN.get(name)?.jsonOnly === true;
60
67
  }
61
- function missingLauncherFallbackCommand(name) {
68
+ function missingLauncherFallbackCommand(name, host) {
62
69
  if (isJsonOnlyHookBin(name))
63
70
  return JSON_ONLY_HOOK_FALLBACK;
64
- if (name === PRETOOL_GUARD_BIN)
65
- return PRETOOL_GUARD_MISSING_DENY;
71
+ if (name === PRETOOL_GUARD_BIN) {
72
+ return host === "codex" ? PRETOOL_GUARD_MISSING_DENY_CODEX : PRETOOL_GUARD_MISSING_DENY_DUAL;
73
+ }
66
74
  return "true";
67
75
  }
68
76
  function hookSubcommandForRequired(binName) {
@@ -114,7 +122,7 @@ function buildHookStatusGuard(command, fallback) {
114
122
  }
115
123
  function buildSourcePackageDirectHookCommand(input) {
116
124
  const hookName = hookSubcommandForRequired(input.name);
117
- const fallback = missingLauncherFallbackCommand(input.name);
125
+ const fallback = missingLauncherFallbackCommand(input.name, input.host);
118
126
  const hostEnv = `env WP_HOOK_HOST=${quoteShell(input.host)}`;
119
127
  const hookEntrypointPath = quoteShell(join(input.packageRoot, "src", "cli", "hook-entrypoint.ts"));
120
128
  const branches = [];
@@ -146,7 +154,7 @@ function buildConsumerDirectWpHookCommand(name, host) {
146
154
  const wpPath = quoteShell(resolveWpHookLauncherPath());
147
155
  const nodePath = quoteShell(resolveNodeForHookLauncher());
148
156
  const hookName = hookSubcommandForRequired(name);
149
- const fallback = missingLauncherFallbackCommand(name);
157
+ const fallback = missingLauncherFallbackCommand(name, host);
150
158
  return `if [ -x ${nodePath} ] && [ -f ${wpPath} ]; then env WP_HOOK_HOST=${quoteShell(host)} ${nodePath} ${wpPath} hook ${hookName}; hook_status=$?; if [ "$hook_status" -eq 2 ]; then exit 2; elif [ "$hook_status" -ne 0 ]; then ${fallback}; fi; else ${fallback}; fi # ${name}`;
151
159
  }
152
160
  function buildDirectWpHookCommand(repoRoot, name, host) {
@@ -573,7 +581,9 @@ export function disableManagedHooksFromManifest(input, manifest, vendors) {
573
581
  return result;
574
582
  }
575
583
  export function resolvePackageRootForHookLaunchers(options = {}) {
576
- return resolveAgentKitPackageRootOrThrow("wp setup: could not locate @webpresso/agent-kit package root for hook launchers.", options);
584
+ // Default cwd so vitest/bunfs hosts that lose moduleUrl still resolve from
585
+ // the monorepo/package checkout the process is running in (CI flake fix).
586
+ return resolveAgentKitPackageRootOrThrow("wp setup: could not locate @webpresso/agent-kit package root for hook launchers.", { cwd: process.cwd(), ...options });
577
587
  }
578
588
  /**
579
589
  * The `wp hook <sub>` subcommand maps each catalogued `wp-*` hook bin to the
@@ -606,37 +616,57 @@ function pruneLegacyGeneratedHookFiles(repoRoot, directorySegments, fileNames) {
606
616
  }
607
617
  removeDirectoryIfEmpty(directoryPath);
608
618
  }
609
- function pruneLegacyManagedHookDirectories(repoRoot) {
619
+ function pruneLegacyManagedHookDirectories(repoRoot, selectedHosts) {
610
620
  const managedHookFiles = WP_HOOK_BIN_NAMES.map((binName) => `${binName}.sh`);
611
- pruneLegacyGeneratedHookFiles(repoRoot, [".codex", "managed-hooks"], [...managedHookFiles, ...LEGACY_MANAGED_ONLY_HOOK_FILES]);
612
- pruneLegacyGeneratedHookFiles(repoRoot, [".claude", "hooks", "managed"], managedHookFiles);
621
+ if (selectedHosts.has("codex")) {
622
+ pruneLegacyGeneratedHookFiles(repoRoot, [".codex", "managed-hooks"], [...managedHookFiles, ...LEGACY_MANAGED_ONLY_HOOK_FILES]);
623
+ }
624
+ if (selectedHosts.has("claude")) {
625
+ pruneLegacyGeneratedHookFiles(repoRoot, [".claude", "hooks", "managed"], managedHookFiles);
626
+ }
613
627
  }
614
628
  export async function scaffoldAgentHooks(input) {
629
+ const selectedHosts = new Set(input.selectedHosts ?? ["claude", "codex", "grok"]);
615
630
  const manifest = buildManagedHooksManifest(input.repoRoot);
616
631
  const result = {
617
- claude: patchJsonFile(join(input.repoRoot, ".claude", "settings.json"), (existing) => patchClaudeSettings(existing, input.repoRoot), input.options),
618
- codex: patchJsonFile(join(input.repoRoot, ".codex", "hooks.json"), (existing) => patchCodexHooks(existing, input.repoRoot), input.options),
619
- claudeUser: input.skipClaudeUserSettings
620
- ? { targetPath: defaultClaudeUserSettingsPath(), action: "identical" }
632
+ claude: selectedHosts.has("claude")
633
+ ? patchJsonFile(join(input.repoRoot, ".claude", "settings.json"), (existing) => patchClaudeSettings(existing, input.repoRoot), input.options)
634
+ : {
635
+ targetPath: join(input.repoRoot, ".claude", "settings.json"),
636
+ action: "identical",
637
+ },
638
+ codex: selectedHosts.has("codex")
639
+ ? patchJsonFile(join(input.repoRoot, ".codex", "hooks.json"), (existing) => patchCodexHooks(existing, input.repoRoot), input.options)
640
+ : {
641
+ targetPath: join(input.repoRoot, ".codex", "hooks.json"),
642
+ action: "identical",
643
+ },
644
+ claudeUser: input.skipClaudeUserSettings || !selectedHosts.has("claude")
645
+ ? {
646
+ targetPath: defaultClaudeUserSettingsPath(),
647
+ action: "identical",
648
+ }
621
649
  : patchJsonFile(defaultClaudeUserSettingsPath(), (existing) => patchClaudeUserSettings(existing), input.claudeUserOptions ?? input.options),
622
650
  manifest,
623
651
  };
624
652
  // Native Grok project hooks (WP_HOOK_HOST=grok). Freeload via Claude remains fallback.
625
- const { writeGrokProjectHooks } = await import("./emitters/grok.js");
626
- writeGrokProjectHooks({
627
- repoRoot: input.repoRoot,
628
- resolveBin: GROK_BIN(input.repoRoot),
629
- dryRun: input.options.dryRun === true,
630
- });
653
+ if (selectedHosts.has("grok")) {
654
+ const { writeGrokProjectHooks } = await import("./emitters/grok.js");
655
+ writeGrokProjectHooks({
656
+ repoRoot: input.repoRoot,
657
+ resolveBin: GROK_BIN(input.repoRoot),
658
+ dryRun: input.options.dryRun === true,
659
+ });
660
+ }
631
661
  if (!input.options.dryRun) {
632
- pruneLegacyManagedHookDirectories(input.repoRoot);
662
+ pruneLegacyManagedHookDirectories(input.repoRoot, selectedHosts);
633
663
  }
634
664
  // Root-gate: the trust leg runs ONLY when the caller passed an explicit
635
665
  // trust config carrying its own resolved consent. Omission (or `false`)
636
666
  // means no `$CODEX_HOME/config.toml` write and no app-server spawn — this
637
667
  // boundary never manufactures an `apply` consent on the caller's behalf.
638
668
  const trustSync = input.trustCodexHooks;
639
- if (trustSync !== undefined && trustSync !== false) {
669
+ if (selectedHosts.has("codex") && trustSync !== undefined && trustSync !== false) {
640
670
  await trustCodexWebpressoHooksForRepo(input, trustSync.userScope);
641
671
  }
642
672
  return result;
@@ -19,6 +19,9 @@
19
19
  * forwarded through Codex's stdio `env_vars` allow-list.
20
20
  */
21
21
  import { spawnSync } from "node:child_process";
22
+ import { findWebpressoMcpEntry, WEBPRESSO_MCP_SERVER_NAME, type WebpressoInstallProbe } from "#cli/commands/init/mcp-spec.js";
23
+ export { findWebpressoMcpEntry, WEBPRESSO_MCP_SERVER_NAME };
24
+ export type { WebpressoInstallProbe };
22
25
  import type { MergeOptions } from "#cli/commands/init/merge";
23
26
  import { type PinnedCodexMcpDefinition } from "#hooks/host-config-contract.js";
24
27
  import { type GlobalCapableVpCommandInput } from "#cli/global-vp.js";
@@ -29,6 +32,8 @@ export interface CommandMcpServerDefinition {
29
32
  args: readonly string[];
30
33
  /** Codex TOML env allow-list forwarded by the host MCP client. */
31
34
  codexEnvVars?: readonly string[];
35
+ /** Codex TOML static env map rendered as an inline table. */
36
+ codexEnv?: Readonly<Record<string, string>>;
32
37
  /** Claude `.mcp.json` env expansion map. */
33
38
  claudeEnv?: Readonly<Record<string, string>>;
34
39
  /** Extra Codex TOML fields beyond command/args/env_vars/enabled. */
@@ -39,9 +44,11 @@ export declare const PLAYWRIGHT_MCP_VERSION = "0.0.78";
39
44
  export declare const PLAYWRIGHT_MCP_PACKAGE = "@playwright/mcp@0.0.78";
40
45
  export declare function commandMcpHeader(serverId: string): string;
41
46
  export declare function commandMcpCodexBlock(definition: CommandMcpServerDefinition): string;
47
+ export declare function hasAmbiguousMcpServerDottedDefinition(raw: string, serverId: string): boolean;
48
+ export declare function hasManagedMcpServerTableConflict(raw: string, serverId: string): boolean;
49
+ export declare function upsertMcpServerBlock(raw: string, serverId: string, block: string): string;
42
50
  export declare function upsertCommandMcpServer(raw: string, definition: CommandMcpServerDefinition): string;
43
51
  export declare function commandMcpClaudeServer(definition: CommandMcpServerDefinition): ClaudeMcpServer;
44
- export declare const WEBPRESSO_MCP_SERVER_NAME = "webpresso";
45
52
  export declare const WEBPRESSO_MCP_HEADER = "[mcp_servers.webpresso]";
46
53
  export interface PinnedCodexMcpRuntime {
47
54
  options: MergeOptions;
@@ -136,36 +143,6 @@ export type EnsureClaudePlaywrightMcpResult = {
136
143
  path: string;
137
144
  };
138
145
  export declare function ensureClaudePlaywrightMcp(input: EnsureClaudePlaywrightMcpInput): EnsureClaudePlaywrightMcpResult;
139
- export interface WebpressoInstallProbe {
140
- /** Test seam — override the candidate roots. Default: probe in fixed order. */
141
- candidates?: readonly string[];
142
- /** Test seam — resolve the stable global `wp` shim available on PATH. */
143
- stableEntry?: () => string | null;
144
- /** Test seam — return value for `pnpm root -g`. Default: shell out. */
145
- pnpmGlobalRoot?: () => string | null;
146
- /** Test seam — return value for `npm root -g`. Default: shell out. */
147
- npmGlobalRoot?: () => string | null;
148
- }
149
- /**
150
- * Resolve the absolute path to webpresso's global `bin/wp` launcher on this machine. Probes
151
- * the locations consumers use to install webpresso, in order of stability:
152
- *
153
- * 1. the stable global `wp` shim available on PATH
154
- * 2. the currently executing `@webpresso/agent-kit` package
155
- * 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
156
- * (path-stable; updated by Claude Code's plugin manager)
157
- * 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
158
- * 5. pnpm global — `$(pnpm root -g)/@webpresso/agent-kit/`
159
- * 6. npm global — `$(npm root -g)/@webpresso/agent-kit/`
160
- *
161
- * Returns `null` when none of the candidates contain `bin/wp`. The caller
162
- * surfaces a clear error rather than writing a broken codex config.
163
- */
164
- export declare function findWebpressoMcpEntry(probe?: WebpressoInstallProbe): string | null;
165
- export declare function agentKitMcpLaunchCommand(entryPath: string): {
166
- command: string;
167
- args: string[];
168
- };
169
146
  export declare function agentKitMcpBlock(entryPath: string): string;
170
147
  export declare function upsertWebpressoMcpServer(raw: string, entryPath: string): string;
171
148
  export interface EnsureCodexWebpressoMcpInput {
@@ -185,6 +162,10 @@ export type EnsureCodexWebpressoMcpResult = {
185
162
  kind: "codex-webpresso-mcp-unchanged";
186
163
  path: string;
187
164
  entryPath: string;
165
+ } | {
166
+ kind: "codex-webpresso-mcp-ambiguous";
167
+ path: string;
168
+ entryPath: string;
188
169
  } | {
189
170
  kind: "codex-webpresso-mcp-skipped-dry-run";
190
171
  path: string;