@webpresso/agent-kit 0.21.4 → 0.23.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 (194) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +93 -66
  4. package/bin/_run.js +143 -1
  5. package/bin/runtime-manifest.json +40 -0
  6. package/catalog/AGENTS.md.tpl +7 -6
  7. package/catalog/agent/commands/plan-refine.md +3 -3
  8. package/catalog/agent/commands/pll.md +2 -0
  9. package/catalog/agent/guides/parallel-execution.md +2 -0
  10. package/catalog/agent/rules/extraction-parity.md +27 -1
  11. package/catalog/agent/rules/public-package-safety.md +24 -1
  12. package/catalog/agent/skills/plan-refine/SKILL.md +5 -4
  13. package/catalog/agent/skills/pll/SKILL.md +1 -0
  14. package/catalog/base-kit/.github/workflows/ci.webpresso.yml.tmpl +33 -0
  15. package/catalog/base-kit/commitlint.config.ts.tmpl +1 -3
  16. package/catalog/base-kit/e2e/fixtures/smoke.html.tmpl +13 -0
  17. package/catalog/base-kit/e2e/smoke.spec.ts.tmpl +13 -0
  18. package/catalog/base-kit/oxlint.config.ts.tmpl +26 -0
  19. package/catalog/base-kit/playwright.config.ts.tmpl +10 -0
  20. package/catalog/base-kit/src/quality-sample.test.ts.tmpl +19 -0
  21. package/catalog/base-kit/src/quality-sample.ts.tmpl +11 -0
  22. package/catalog/base-kit/stryker.config.ts.tmpl +14 -0
  23. package/catalog/base-kit/tsconfig.json.tmpl +9 -0
  24. package/catalog/base-kit/vitest.config.ts.tmpl +10 -0
  25. package/catalog/docs/templates/adr.md +1 -1
  26. package/catalog/docs/templates/blueprint.md +2 -0
  27. package/catalog/docs/templates/blueprint.yaml +16 -15
  28. package/catalog/docs/templates/guide.md +1 -1
  29. package/catalog/docs/templates/postmortem.md +1 -1
  30. package/catalog/docs/templates/research.md +1 -1
  31. package/catalog/docs/templates/runbook.md +1 -1
  32. package/catalog/docs/templates/system.md +12 -3
  33. package/catalog/docs/templates/tech-debt.md +1 -0
  34. package/commands/blueprint.md +10 -12
  35. package/dist/esm/audit/blueprint-db-consistency.d.ts +1 -1
  36. package/dist/esm/audit/blueprint-db-consistency.js +6 -8
  37. package/dist/esm/audit/blueprint-lifecycle-sql.js +10 -3
  38. package/dist/esm/audit/cloudflare-deploy-contract.d.ts +3 -0
  39. package/dist/esm/audit/cloudflare-deploy-contract.js +64 -0
  40. package/dist/esm/audit/no-legacy-cli-bin.d.ts +3 -0
  41. package/dist/esm/audit/no-legacy-cli-bin.js +100 -0
  42. package/dist/esm/audit/package-surface.js +14 -1
  43. package/dist/esm/audit/repo-guardrails.js +40 -13
  44. package/dist/esm/audit/resolve-audit-script.d.ts +24 -0
  45. package/dist/esm/audit/resolve-audit-script.js +27 -0
  46. package/dist/esm/audit/roadmap-links.js +23 -10
  47. package/dist/esm/blueprint/core/schema.d.ts +8 -8
  48. package/dist/esm/blueprint/core/schema.js +2 -2
  49. package/dist/esm/blueprint/db/enums.d.ts +1 -1
  50. package/dist/esm/blueprint/db/ingester.js +18 -10
  51. package/dist/esm/blueprint/index.d.ts +0 -1
  52. package/dist/esm/blueprint/index.js +0 -2
  53. package/dist/esm/blueprint/lifecycle/audit.js +9 -2
  54. package/dist/esm/blueprint/lifecycle/local.js +15 -4
  55. package/dist/esm/blueprint/local.d.ts +0 -3
  56. package/dist/esm/blueprint/local.js +0 -2
  57. package/dist/esm/blueprint/service/BlueprintCreationService.js +16 -8
  58. package/dist/esm/blueprint/service/BlueprintService.js +37 -19
  59. package/dist/esm/blueprint/service/scanner.js +73 -9
  60. package/dist/esm/blueprint/tracked-document/schema.d.ts +2 -2
  61. package/dist/esm/blueprint/utils/document-paths.d.ts +23 -0
  62. package/dist/esm/blueprint/utils/document-paths.js +91 -0
  63. package/dist/esm/blueprint/utils/package-assets.d.ts +11 -0
  64. package/dist/esm/blueprint/utils/package-assets.js +33 -4
  65. package/dist/esm/build/package-manifest.js +7 -0
  66. package/dist/esm/build/release-policy.d.ts +27 -0
  67. package/dist/esm/build/release-policy.js +29 -0
  68. package/dist/esm/build/runtime-targets.d.ts +13 -0
  69. package/dist/esm/build/runtime-targets.js +48 -0
  70. package/dist/esm/build/sync-catalog-doc-templates.d.ts +23 -0
  71. package/dist/esm/build/sync-catalog-doc-templates.js +93 -0
  72. package/dist/esm/cli/auto-update/detect-pm.d.ts +15 -0
  73. package/dist/esm/cli/auto-update/detect-pm.js +24 -9
  74. package/dist/esm/cli/auto-update/skip.js +9 -1
  75. package/dist/esm/cli/bundle/agent-command-inventory.d.ts +120 -0
  76. package/dist/esm/cli/bundle/agent-command-inventory.js +100 -0
  77. package/dist/esm/cli/bundle/index.d.ts +17 -0
  78. package/dist/esm/cli/bundle/index.js +15 -0
  79. package/dist/esm/cli/cli.d.ts +1 -1
  80. package/dist/esm/cli/cli.js +49 -5
  81. package/dist/esm/cli/commands/audit-core.d.ts +1 -1
  82. package/dist/esm/cli/commands/audit.js +4 -7
  83. package/dist/esm/cli/commands/blueprint/router.js +16 -10
  84. package/dist/esm/cli/commands/blueprint/template-resolver.js +8 -4
  85. package/dist/esm/cli/commands/hook.d.ts +8 -0
  86. package/dist/esm/cli/commands/hook.js +47 -0
  87. package/dist/esm/cli/commands/init/host-visibility.js +4 -2
  88. package/dist/esm/cli/commands/init/index.js +80 -7
  89. package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +12 -0
  90. package/dist/esm/cli/commands/init/scaffold-base-kit.js +142 -7
  91. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/codex-ownership.js +9 -1
  92. package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +130 -20
  93. package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.d.ts +65 -0
  94. package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.js +64 -0
  95. package/dist/esm/cli/commands/package-manager.d.ts +15 -0
  96. package/dist/esm/cli/commands/package-manager.js +42 -0
  97. package/dist/esm/cli/commands/test.d.ts +1 -0
  98. package/dist/esm/cli/commands/test.js +2 -1
  99. package/dist/esm/cli/commands/typecheck.js +10 -19
  100. package/dist/esm/cli/package-scripts.d.ts +12 -0
  101. package/dist/esm/cli/package-scripts.js +59 -0
  102. package/dist/esm/cli/utils.js +3 -22
  103. package/dist/esm/cli/wp-extensions.d.ts +14 -0
  104. package/dist/esm/cli/wp-extensions.js +34 -0
  105. package/dist/esm/config/docs-lint/schemas/common.d.ts +1 -1
  106. package/dist/esm/config/docs-lint/schemas/implementation-plan.d.ts +2 -2
  107. package/dist/esm/config/docs-lint/schemas/parent-roadmap.d.ts +1 -1
  108. package/dist/esm/config/stryker/index.d.ts +85 -0
  109. package/dist/esm/config/stryker/index.js +31 -0
  110. package/dist/esm/e2e/command-builder.js +35 -7
  111. package/dist/esm/e2e/config.d.ts +56 -0
  112. package/dist/esm/e2e/config.js +114 -0
  113. package/dist/esm/e2e/execution.js +8 -0
  114. package/dist/esm/e2e/run-planner.js +2 -0
  115. package/dist/esm/e2e/types.d.ts +3 -0
  116. package/dist/esm/format/index.js +5 -1
  117. package/dist/esm/hooks/guard-switch/index.d.ts +1 -1
  118. package/dist/esm/hooks/guard-switch/index.js +22 -14
  119. package/dist/esm/hooks/post-tool/lint-after-edit.d.ts +1 -0
  120. package/dist/esm/hooks/post-tool/lint-after-edit.js +5 -2
  121. package/dist/esm/hooks/pretool-guard/validators/file-conventions.js +1 -1
  122. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.d.ts +6 -0
  123. package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +27 -2
  124. package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +2 -1
  125. package/dist/esm/hooks/pretool-guard/validators/path-contract.js +59 -34
  126. package/dist/esm/hooks/pretool-guard/validators/plan-frontmatter.js +3 -3
  127. package/dist/esm/hooks/shared/routing-block.js +18 -4
  128. package/dist/esm/hooks/shared/validators/blueprint.js +3 -0
  129. package/dist/esm/hooks/stop/qa-changed-files.d.ts +1 -0
  130. package/dist/esm/hooks/stop/qa-changed-files.js +5 -2
  131. package/dist/esm/lint/index.js +3 -1
  132. package/dist/esm/mcp/auto-discover.d.ts +2 -0
  133. package/dist/esm/mcp/auto-discover.js +14 -6
  134. package/dist/esm/mcp/blueprint-server.js +379 -80
  135. package/dist/esm/mcp/cli.js +21 -0
  136. package/dist/esm/mcp/runners/test.js +15 -0
  137. package/dist/esm/mcp/server.d.ts +7 -0
  138. package/dist/esm/mcp/server.js +16 -27
  139. package/dist/esm/mcp/tools/_registry.d.ts +3 -0
  140. package/dist/esm/mcp/tools/_registry.js +21 -0
  141. package/dist/esm/mcp/tools/audit.d.ts +1 -0
  142. package/dist/esm/mcp/tools/audit.js +13 -8
  143. package/dist/esm/mcp/tools/typecheck.js +4 -2
  144. package/dist/esm/mutation/affected.d.ts +9 -0
  145. package/dist/esm/mutation/affected.js +36 -0
  146. package/dist/esm/package.json +8 -0
  147. package/dist/esm/runtime/package-version.d.ts +2 -0
  148. package/dist/esm/runtime/package-version.js +43 -0
  149. package/dist/esm/test/command-builder.d.ts +4 -0
  150. package/dist/esm/test/command-builder.js +28 -3
  151. package/dist/esm/test-helpers/hermetic-env.d.ts +25 -0
  152. package/dist/esm/test-helpers/hermetic-env.js +31 -0
  153. package/dist/esm/tool-runtime/index.d.ts +5 -0
  154. package/dist/esm/tool-runtime/index.js +24 -0
  155. package/dist/esm/tool-runtime/resolve-runner.d.ts +16 -0
  156. package/dist/esm/tool-runtime/resolve-runner.js +42 -0
  157. package/dist/esm/typecheck/index.js +4 -2
  158. package/dist/esm/wp-extension/index.d.ts +50 -0
  159. package/dist/esm/wp-extension/index.js +268 -0
  160. package/package.json +75 -46
  161. package/skills/plan-refine/SKILL.md +5 -4
  162. package/skills/pll/SKILL.md +1 -0
  163. package/dist/esm/blueprint/dag/cycle-detector.d.ts +0 -12
  164. package/dist/esm/blueprint/dag/cycle-detector.js +0 -46
  165. package/dist/esm/blueprint/dag/executor.d.ts +0 -140
  166. package/dist/esm/blueprint/dag/executor.js +0 -292
  167. package/dist/esm/blueprint/dag/index.d.ts +0 -20
  168. package/dist/esm/blueprint/dag/index.js +0 -17
  169. package/dist/esm/blueprint/dag/interfaces.d.ts +0 -56
  170. package/dist/esm/blueprint/dag/interfaces.js +0 -13
  171. package/dist/esm/blueprint/dag/local/independence.d.ts +0 -107
  172. package/dist/esm/blueprint/dag/local/independence.js +0 -231
  173. package/dist/esm/blueprint/dag/local/index.d.ts +0 -14
  174. package/dist/esm/blueprint/dag/local/index.js +0 -14
  175. package/dist/esm/blueprint/dag/local/package-graph.d.ts +0 -66
  176. package/dist/esm/blueprint/dag/local/package-graph.js +0 -148
  177. package/dist/esm/blueprint/dag/plan-parser.d.ts +0 -54
  178. package/dist/esm/blueprint/dag/plan-parser.js +0 -236
  179. package/dist/esm/blueprint/dag/task-graph-algorithms.d.ts +0 -13
  180. package/dist/esm/blueprint/dag/task-graph-algorithms.js +0 -236
  181. package/dist/esm/blueprint/dag/task-graph.d.ts +0 -171
  182. package/dist/esm/blueprint/dag/task-graph.js +0 -370
  183. package/dist/esm/blueprint/dag/types.d.ts +0 -17
  184. package/dist/esm/blueprint/dag/types.js +0 -2
  185. package/dist/esm/blueprint/graph/index.d.ts +0 -5
  186. package/dist/esm/blueprint/graph/index.js +0 -5
  187. package/dist/esm/blueprint/graph/mermaid-parser.d.ts +0 -3
  188. package/dist/esm/blueprint/graph/mermaid-parser.js +0 -93
  189. package/dist/esm/blueprint/graph/mermaid-serializer.d.ts +0 -3
  190. package/dist/esm/blueprint/graph/mermaid-serializer.js +0 -20
  191. package/dist/esm/blueprint/graph/schema.d.ts +0 -89
  192. package/dist/esm/blueprint/graph/schema.js +0 -104
  193. package/dist/esm/blueprint/graph/task-graph-adapter.d.ts +0 -6
  194. package/dist/esm/blueprint/graph/task-graph-adapter.js +0 -30
@@ -15,8 +15,8 @@ export declare const implementationPlanFrontmatter: z.ZodObject<{
15
15
  completed: "completed";
16
16
  draft: "draft";
17
17
  planned: "planned";
18
- "in-progress": "in-progress";
19
18
  parked: "parked";
19
+ "in-progress": "in-progress";
20
20
  archived: "archived";
21
21
  current: "current";
22
22
  complete: "complete";
@@ -40,8 +40,8 @@ export declare const implementationPlanFrontmatter: z.ZodObject<{
40
40
  completed: "completed";
41
41
  draft: "draft";
42
42
  planned: "planned";
43
- "in-progress": "in-progress";
44
43
  parked: "parked";
44
+ "in-progress": "in-progress";
45
45
  archived: "archived";
46
46
  current: "current";
47
47
  complete: "complete";
@@ -14,8 +14,8 @@ export declare const parentRoadmapFrontmatter: z.ZodObject<{
14
14
  completed: "completed";
15
15
  draft: "draft";
16
16
  planned: "planned";
17
- "in-progress": "in-progress";
18
17
  parked: "parked";
18
+ "in-progress": "in-progress";
19
19
  archived: "archived";
20
20
  current: "current";
21
21
  complete: "complete";
@@ -40,5 +40,90 @@ export declare const baseConfig: {
40
40
  incremental: boolean;
41
41
  incrementalFile: string;
42
42
  };
43
+ /**
44
+ * Extends baseConfig with TypeScript checker defaults.
45
+ * Use this in any TypeScript package instead of baseConfig directly.
46
+ *
47
+ * @example
48
+ * import { typescriptBaseConfig } from '@webpresso/agent-kit/stryker'
49
+ *
50
+ * export default { ...typescriptBaseConfig }
51
+ * // or, for packages with a CF-pool vitest config:
52
+ * export default { ...typescriptBaseConfig, vitest: { configFile: 'vitest.stryker.config.ts' } }
53
+ */
54
+ export declare const typescriptBaseConfig: {
55
+ checkers: string[];
56
+ tsconfigFile: string;
57
+ packageManager: string;
58
+ testRunner: string;
59
+ plugins: string[];
60
+ ignorePatterns: string[];
61
+ mutate: string[];
62
+ concurrency: number;
63
+ timeoutMS: number;
64
+ dryRunTimeoutMinutes: number;
65
+ ignoreStatic: boolean;
66
+ thresholds: {
67
+ high: number;
68
+ low: number;
69
+ break: number;
70
+ };
71
+ mutator: {
72
+ excludedMutations: string[];
73
+ };
74
+ reporters: string[];
75
+ htmlReporter: {
76
+ fileName: string;
77
+ };
78
+ jsonReporter: {
79
+ fileName: string;
80
+ };
81
+ incremental: boolean;
82
+ incrementalFile: string;
83
+ };
84
+ /**
85
+ * Extends typescriptBaseConfig for Cloudflare Workers packages whose vitest config
86
+ * uses @cloudflare/vitest-pool-workers (incompatible with Stryker's pool injection).
87
+ * Points to a per-package vitest.stryker.config.ts that uses the standard forks pool
88
+ * and excludes any tests that require CF runtime globals (cloudflare:test).
89
+ *
90
+ * @example
91
+ * import { typescriptWorkersBaseConfig } from '@webpresso/agent-kit/stryker'
92
+ *
93
+ * export default { ...typescriptWorkersBaseConfig }
94
+ */
95
+ export declare const typescriptWorkersBaseConfig: {
96
+ vitest: {
97
+ configFile: string;
98
+ };
99
+ checkers: string[];
100
+ tsconfigFile: string;
101
+ packageManager: string;
102
+ testRunner: string;
103
+ plugins: string[];
104
+ ignorePatterns: string[];
105
+ mutate: string[];
106
+ concurrency: number;
107
+ timeoutMS: number;
108
+ dryRunTimeoutMinutes: number;
109
+ ignoreStatic: boolean;
110
+ thresholds: {
111
+ high: number;
112
+ low: number;
113
+ break: number;
114
+ };
115
+ mutator: {
116
+ excludedMutations: string[];
117
+ };
118
+ reporters: string[];
119
+ htmlReporter: {
120
+ fileName: string;
121
+ };
122
+ jsonReporter: {
123
+ fileName: string;
124
+ };
125
+ incremental: boolean;
126
+ incrementalFile: string;
127
+ };
43
128
  export default baseConfig;
44
129
  //# sourceMappingURL=index.d.ts.map
@@ -75,5 +75,36 @@ export const baseConfig = {
75
75
  incremental: true,
76
76
  incrementalFile: 'reports/stryker-incremental.json',
77
77
  };
78
+ /**
79
+ * Extends baseConfig with TypeScript checker defaults.
80
+ * Use this in any TypeScript package instead of baseConfig directly.
81
+ *
82
+ * @example
83
+ * import { typescriptBaseConfig } from '@webpresso/agent-kit/stryker'
84
+ *
85
+ * export default { ...typescriptBaseConfig }
86
+ * // or, for packages with a CF-pool vitest config:
87
+ * export default { ...typescriptBaseConfig, vitest: { configFile: 'vitest.stryker.config.ts' } }
88
+ */
89
+ export const typescriptBaseConfig = {
90
+ ...baseConfig,
91
+ checkers: ['typescript'],
92
+ tsconfigFile: 'tsconfig.json',
93
+ };
94
+ /**
95
+ * Extends typescriptBaseConfig for Cloudflare Workers packages whose vitest config
96
+ * uses @cloudflare/vitest-pool-workers (incompatible with Stryker's pool injection).
97
+ * Points to a per-package vitest.stryker.config.ts that uses the standard forks pool
98
+ * and excludes any tests that require CF runtime globals (cloudflare:test).
99
+ *
100
+ * @example
101
+ * import { typescriptWorkersBaseConfig } from '@webpresso/agent-kit/stryker'
102
+ *
103
+ * export default { ...typescriptWorkersBaseConfig }
104
+ */
105
+ export const typescriptWorkersBaseConfig = {
106
+ ...typescriptBaseConfig,
107
+ vitest: { configFile: 'vitest.stryker.config.ts' },
108
+ };
78
109
  export default baseConfig;
79
110
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,4 @@
1
+ import { getManagedRunner } from '#tool-runtime';
1
2
  import path from 'node:path';
2
3
  export function buildE2eCommand(options) {
3
4
  switch (options.step.runner) {
@@ -15,10 +16,13 @@ function buildPlaywrightCommand(options) {
15
16
  throw new Error(`Step ${step.logName} uses runner "playwright" but does not define configPath.`);
16
17
  }
17
18
  const { baseDir, configArg, files } = resolveRunnerPaths(step.configPath, options.files ?? []);
18
- const args = [...buildPnpmExecPrefix(baseDir), 'playwright', 'test', '--config', configArg];
19
+ const resolution = withBaseDir(getManagedRunner('playwright', {
20
+ outputPolicy: resolveOutputPolicy(options.outputPolicy, options.filterOutput),
21
+ }), baseDir);
22
+ const args = [...resolution.args, 'test', '--config', configArg];
19
23
  appendPlaywrightFlags(args, options);
20
24
  args.push(...(step.fixedArgs ?? []), ...files, ...(options.passthrough ?? []));
21
- return { command: 'pnpm', args };
25
+ return { command: resolution.command, args };
22
26
  }
23
27
  function buildVitestE2eCommand(options) {
24
28
  const { step } = options;
@@ -26,12 +30,15 @@ function buildVitestE2eCommand(options) {
26
30
  throw new Error(`Step ${step.logName} uses runner "vitest" but does not define configPath.`);
27
31
  }
28
32
  const { baseDir, configArg, files } = resolveRunnerPaths(step.configPath, options.files ?? []);
29
- const args = [...buildPnpmExecPrefix(baseDir), 'vitest', 'run', '--config', configArg];
33
+ const resolution = withBaseDir(getManagedRunner('vitest', {
34
+ outputPolicy: resolveOutputPolicy(options.outputPolicy, options.filterOutput),
35
+ }), baseDir);
36
+ const args = [...resolution.args, 'run', '--config', configArg];
30
37
  if (options.workers !== undefined) {
31
38
  args.push('--poolOptions.threads.maxThreads', String(options.workers));
32
39
  }
33
40
  args.push(...(step.fixedArgs ?? []), ...files, ...(options.passthrough ?? []));
34
- return { command: 'pnpm', args };
41
+ return { command: resolution.command, args };
35
42
  }
36
43
  function buildCustomCommand(options) {
37
44
  const { step } = options;
@@ -69,9 +76,6 @@ function appendPlaywrightFlags(args, options) {
69
76
  args.push('--test-list', options.testList);
70
77
  }
71
78
  }
72
- function buildPnpmExecPrefix(baseDir) {
73
- return baseDir === '.' ? ['exec'] : ['--dir', baseDir, 'exec'];
74
- }
75
79
  function resolveRunnerPaths(configPath, files) {
76
80
  const normalizedConfigPath = configPath.replace(/\\/gu, '/');
77
81
  const baseDir = path.posix.dirname(normalizedConfigPath);
@@ -95,4 +99,28 @@ function resolveRunnerPaths(configPath, files) {
95
99
  }),
96
100
  };
97
101
  }
102
+ function withBaseDir(resolution, baseDir) {
103
+ if (baseDir === '.') {
104
+ return { command: resolution.command, args: [...resolution.args] };
105
+ }
106
+ if (resolution.command === 'vp') {
107
+ return {
108
+ command: resolution.command,
109
+ args: ['--dir', baseDir, ...resolution.args],
110
+ };
111
+ }
112
+ const [wrappedCommand, ...wrappedArgs] = resolution.args;
113
+ if (resolution.command === 'rtk' && wrappedCommand === 'vp') {
114
+ return {
115
+ command: resolution.command,
116
+ args: ['vp', '--dir', baseDir, ...wrappedArgs],
117
+ };
118
+ }
119
+ return { command: resolution.command, args: [...resolution.args] };
120
+ }
121
+ function resolveOutputPolicy(outputPolicy, filterOutput) {
122
+ if (outputPolicy)
123
+ return outputPolicy;
124
+ return filterOutput === false ? 'structured' : 'rtk-filtered';
125
+ }
98
126
  //# sourceMappingURL=command-builder.js.map
@@ -6,6 +6,62 @@ declare const webpressoConfigSchema: z.ZodObject<{
6
6
  hostAdapterModule: z.ZodString;
7
7
  hostAdapterExport: z.ZodOptional<z.ZodString>;
8
8
  }, z.core.$strict>>;
9
+ deploy: z.ZodOptional<z.ZodObject<{
10
+ cloudflare: z.ZodOptional<z.ZodObject<{
11
+ lanes: z.ZodObject<{
12
+ dev: z.ZodObject<{
13
+ wranglerEnvName: z.ZodString;
14
+ }, z.core.$strict>;
15
+ preview_main: z.ZodObject<{
16
+ wranglerEnvName: z.ZodString;
17
+ }, z.core.$strict>;
18
+ preview_pr: z.ZodObject<{
19
+ wranglerEnvNamePattern: z.ZodString;
20
+ }, z.core.$strict>;
21
+ prd: z.ZodObject<{
22
+ wranglerEnvName: z.ZodString & z.ZodType<"production", string, z.core.$ZodTypeInternals<"production", string>>;
23
+ deployedWorkerNameMode: z.ZodLiteral<"top_level_name">;
24
+ }, z.core.$strict>;
25
+ }, z.core.$strict>;
26
+ production: z.ZodObject<{
27
+ metadataPath: z.ZodLiteral<"infra/release-metadata.production.json">;
28
+ }, z.core.$strict>;
29
+ targets: z.ZodArray<z.ZodObject<{
30
+ id: z.ZodString;
31
+ type: z.ZodEnum<{
32
+ single_worker: "single_worker";
33
+ worker_plus_assets: "worker_plus_assets";
34
+ monorepo_multi_target: "monorepo_multi_target";
35
+ }>;
36
+ topLevelWorkerName: z.ZodString;
37
+ previewTransport: z.ZodEnum<{
38
+ custom_domain_env: "custom_domain_env";
39
+ workers_dev_env: "workers_dev_env";
40
+ }>;
41
+ routeSpec: z.ZodOptional<z.ZodObject<{
42
+ pattern: z.ZodString;
43
+ }, z.core.$strict>>;
44
+ durableObjectBindings: z.ZodOptional<z.ZodArray<z.ZodObject<{
45
+ name: z.ZodString;
46
+ className: z.ZodString;
47
+ scriptName: z.ZodOptional<z.ZodString>;
48
+ }, z.core.$strict>>>;
49
+ vars: z.ZodRecord<z.ZodString, z.ZodUnknown>;
50
+ requiredSecrets: z.ZodArray<z.ZodString>;
51
+ storageMode: z.ZodEnum<{
52
+ isolated: "isolated";
53
+ shared_via_script_name: "shared_via_script_name";
54
+ }>;
55
+ destroyMode: z.ZodLiteral<"wrangler_delete_env">;
56
+ repoCleanupHook: z.ZodOptional<z.ZodString>;
57
+ blastRadiusDoc: z.ZodOptional<z.ZodString>;
58
+ productionStrategyDefault: z.ZodEnum<{
59
+ direct: "direct";
60
+ gradual: "gradual";
61
+ }>;
62
+ }, z.core.$strict>>;
63
+ }, z.core.$strict>>;
64
+ }, z.core.$strict>>;
9
65
  }, z.core.$strict>;
10
66
  export type WebpressoConfig = z.infer<typeof webpressoConfigSchema>;
11
67
  export type WebpressoE2eConfig = NonNullable<WebpressoConfig['e2e']>;
@@ -1,15 +1,129 @@
1
1
  import { z } from 'zod';
2
2
  export const WEBPRESSO_CONFIG_FILE_NAME = 'webpresso.config.ts';
3
3
  export const WEBPRESSO_CONFIG_EXPORT_NAME = 'webpressoConfig';
4
+ const wranglerEnvNameSchema = z
5
+ .string()
6
+ .min(1, 'wranglerEnvName must not be empty.')
7
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'wranglerEnvName must be dash-safe lowercase letters, numbers, and hyphens only.');
4
8
  const e2eWebpressoConfigSchema = z
5
9
  .object({
6
10
  hostAdapterModule: z.string().min(1, 'e2e.hostAdapterModule must not be empty.'),
7
11
  hostAdapterExport: z.string().min(1, 'e2e.hostAdapterExport must not be empty.').optional(),
8
12
  })
9
13
  .strict();
14
+ const cloudflareDeployLaneSchema = z
15
+ .object({
16
+ wranglerEnvName: wranglerEnvNameSchema,
17
+ })
18
+ .strict();
19
+ const previewPrCloudflareDeployLaneSchema = z
20
+ .object({
21
+ wranglerEnvNamePattern: z
22
+ .string()
23
+ .min(1, 'wranglerEnvNamePattern must not be empty.')
24
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*-<n>$/, 'wranglerEnvNamePattern must be dash-safe and end with -<n>.'),
25
+ })
26
+ .strict();
27
+ const productionCloudflareDeployLaneSchema = cloudflareDeployLaneSchema.extend({
28
+ wranglerEnvName: wranglerEnvNameSchema.refine((value) => value === 'production', {
29
+ message: 'deploy.cloudflare.lanes.prd.wranglerEnvName must be "production".',
30
+ }),
31
+ deployedWorkerNameMode: z.literal('top_level_name'),
32
+ });
33
+ const cloudflareRouteSpecSchema = z
34
+ .object({
35
+ pattern: z.string().min(1, 'routeSpec.pattern must not be empty.'),
36
+ })
37
+ .strict();
38
+ const cloudflareDurableObjectBindingSchema = z
39
+ .object({
40
+ name: z.string().min(1, 'durableObjectBindings[].name must not be empty.'),
41
+ className: z.string().min(1, 'durableObjectBindings[].className must not be empty.'),
42
+ scriptName: z.string().min(1, 'durableObjectBindings[].scriptName must not be empty.').optional(),
43
+ })
44
+ .strict();
45
+ const cloudflareTargetSchema = z
46
+ .object({
47
+ id: z.string().min(1, 'deploy.cloudflare.targets[].id must not be empty.'),
48
+ type: z.enum(['single_worker', 'worker_plus_assets', 'monorepo_multi_target']),
49
+ topLevelWorkerName: z.string().min(1, 'topLevelWorkerName must not be empty.'),
50
+ previewTransport: z.enum(['custom_domain_env', 'workers_dev_env']),
51
+ routeSpec: cloudflareRouteSpecSchema.optional(),
52
+ durableObjectBindings: z.array(cloudflareDurableObjectBindingSchema).optional(),
53
+ vars: z.record(z.string(), z.unknown()),
54
+ requiredSecrets: z.array(z.string().min(1, 'requiredSecrets[] must not be empty.')),
55
+ storageMode: z.enum(['isolated', 'shared_via_script_name']),
56
+ destroyMode: z.literal('wrangler_delete_env'),
57
+ repoCleanupHook: z.string().min(1, 'repoCleanupHook must not be empty.').optional(),
58
+ blastRadiusDoc: z.string().min(1, 'blastRadiusDoc must not be empty.').optional(),
59
+ productionStrategyDefault: z.enum(['direct', 'gradual']),
60
+ })
61
+ .strict()
62
+ .superRefine((target, ctx) => {
63
+ const isDurableObjectTarget = (target.durableObjectBindings?.length ?? 0) > 0;
64
+ if (target.previewTransport === 'custom_domain_env' && !target.routeSpec) {
65
+ ctx.addIssue({
66
+ code: z.ZodIssueCode.custom,
67
+ path: ['routeSpec'],
68
+ message: 'routeSpec is required when previewTransport is "custom_domain_env".',
69
+ });
70
+ }
71
+ if (isDurableObjectTarget && target.previewTransport !== 'custom_domain_env') {
72
+ ctx.addIssue({
73
+ code: z.ZodIssueCode.custom,
74
+ path: ['previewTransport'],
75
+ message: 'Durable Object targets must use previewTransport "custom_domain_env" unless a future explicit exception contract is introduced.',
76
+ });
77
+ }
78
+ if (isDurableObjectTarget && Object.keys(target.vars).length === 0) {
79
+ ctx.addIssue({
80
+ code: z.ZodIssueCode.custom,
81
+ path: ['vars'],
82
+ message: 'Durable Object targets must declare at least one env-specific var.',
83
+ });
84
+ }
85
+ if (isDurableObjectTarget && target.requiredSecrets.length === 0) {
86
+ ctx.addIssue({
87
+ code: z.ZodIssueCode.custom,
88
+ path: ['requiredSecrets'],
89
+ message: 'Durable Object targets must declare at least one required secret name.',
90
+ });
91
+ }
92
+ if (target.storageMode === 'shared_via_script_name' && !target.blastRadiusDoc) {
93
+ ctx.addIssue({
94
+ code: z.ZodIssueCode.custom,
95
+ path: ['blastRadiusDoc'],
96
+ message: 'blastRadiusDoc is required when storageMode is "shared_via_script_name".',
97
+ });
98
+ }
99
+ });
100
+ const cloudflareDeployConfigSchema = z
101
+ .object({
102
+ lanes: z
103
+ .object({
104
+ dev: cloudflareDeployLaneSchema,
105
+ preview_main: cloudflareDeployLaneSchema,
106
+ preview_pr: previewPrCloudflareDeployLaneSchema,
107
+ prd: productionCloudflareDeployLaneSchema,
108
+ })
109
+ .strict(),
110
+ production: z
111
+ .object({
112
+ metadataPath: z.literal('infra/release-metadata.production.json'),
113
+ })
114
+ .strict(),
115
+ targets: z.array(cloudflareTargetSchema),
116
+ })
117
+ .strict();
118
+ const deployWebpressoConfigSchema = z
119
+ .object({
120
+ cloudflare: cloudflareDeployConfigSchema.optional(),
121
+ })
122
+ .strict();
10
123
  const webpressoConfigSchema = z
11
124
  .object({
12
125
  e2e: e2eWebpressoConfigSchema.optional(),
126
+ deploy: deployWebpressoConfigSchema.optional(),
13
127
  })
14
128
  .strict();
15
129
  export class WebpressoConfigValidationError extends Error {
@@ -18,6 +18,8 @@ export async function createE2eExecutionPlan(input, cwd = process.cwd()) {
18
18
  workers: input.workers,
19
19
  testList: input.testList,
20
20
  passthrough: input.passthrough,
21
+ outputPolicy: input.outputPolicy,
22
+ filterOutput: input.filterOutput,
21
23
  });
22
24
  }
23
25
  const hostAdapter = await loadConfiguredHostAdapter(cwd);
@@ -35,6 +37,8 @@ export async function createE2eExecutionPlan(input, cwd = process.cwd()) {
35
37
  workers: input.workers,
36
38
  testList: input.testList,
37
39
  passthrough: input.passthrough,
40
+ outputPolicy: input.outputPolicy,
41
+ filterOutput: input.filterOutput,
38
42
  });
39
43
  }
40
44
  if (hostAdapter.adapter.buildExecutionPlan) {
@@ -49,6 +53,8 @@ export async function createE2eExecutionPlan(input, cwd = process.cwd()) {
49
53
  workers: input.workers,
50
54
  testList: input.testList,
51
55
  passthrough: input.passthrough,
56
+ outputPolicy: input.outputPolicy,
57
+ filterOutput: input.filterOutput,
52
58
  });
53
59
  }
54
60
  return planE2eRun({
@@ -60,6 +66,8 @@ export async function createE2eExecutionPlan(input, cwd = process.cwd()) {
60
66
  workers: input.workers,
61
67
  testList: input.testList,
62
68
  passthrough: input.passthrough,
69
+ outputPolicy: input.outputPolicy,
70
+ filterOutput: input.filterOutput,
63
71
  });
64
72
  }
65
73
  export function plannedGroupsToCommandConfigs(groups) {
@@ -76,6 +76,8 @@ function planE2eRunsFromSuites(options) {
76
76
  workers: options.request.workers,
77
77
  testList: options.request.testList,
78
78
  passthrough: options.request.passthrough,
79
+ outputPolicy: options.request.outputPolicy,
80
+ filterOutput: options.request.filterOutput,
79
81
  });
80
82
  runs.push({
81
83
  suiteId: suite.id,
@@ -1,3 +1,4 @@
1
+ import type { ManagedRunnerOutputPolicy } from '#tool-runtime';
1
2
  export type E2eRunnerKind = 'playwright' | 'vitest' | 'command';
2
3
  export interface CommandConfig {
3
4
  command: string;
@@ -48,6 +49,8 @@ export interface E2eCommandRequest {
48
49
  workers?: number | string;
49
50
  testList?: string;
50
51
  passthrough?: readonly string[];
52
+ filterOutput?: boolean;
53
+ outputPolicy?: ManagedRunnerOutputPolicy;
51
54
  }
52
55
  export interface E2eExecutionRequest extends E2eCommandRequest {
53
56
  suite?: string;
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { isMissingBinary, isRunFailure, runCommand } from '#mcp/tools/_shared/run-command';
10
10
  import { resolveProjectRoot } from '#mcp/tools/_shared/project-root';
11
+ import { getManagedRunner } from '#tool-runtime';
11
12
  const DEFAULT_FORMAT_TIMEOUT_MS = 5 * 60 * 1_000;
12
13
  /**
13
14
  * Run formatter and return a structured result. Throws a clear error when
@@ -33,7 +34,10 @@ export async function runFormat(options = {}) {
33
34
  args.push('--ignore-path', '.gitignore');
34
35
  if (options.files && options.files.length > 0)
35
36
  args.push(...options.files);
36
- const outcome = await runCommand('oxfmt', args, runOptions);
37
+ const resolution = getManagedRunner('oxfmt', {
38
+ outputPolicy: 'structured',
39
+ });
40
+ const outcome = await runCommand(resolution.command, [...resolution.args, ...args], runOptions);
37
41
  if (isRunFailure(outcome)) {
38
42
  if (isMissingBinary(outcome)) {
39
43
  throw new Error("oxfmt binary not found on PATH. Install it as a devDependency: 'vp install -D oxfmt'");
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env bun
2
- export {};
2
+ export declare function main(): Promise<void>;
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1,18 +1,26 @@
1
1
  #!/usr/bin/env bun
2
2
  import { runHook } from '#hooks/shared/hook-bootstrap';
3
+ import { realpathSync } from 'node:fs';
4
+ import { fileURLToPath } from 'node:url';
3
5
  import { setGuardEnabled } from './state.js';
4
- runHook((input) => {
5
- const normalized = (input.prompt ?? '').toLowerCase().trim();
6
- if (normalized === 'guard off') {
7
- setGuardEnabled(false);
8
- console.error('🛡️ Guard disabled — pretool validators will be skipped');
9
- process.exit(2);
10
- }
11
- if (normalized === 'guard on') {
12
- setGuardEnabled(true);
13
- console.error('🛡️ Guard enabled — pretool validators active');
14
- process.exit(2);
15
- }
16
- return null;
17
- }, () => '{}');
6
+ export async function main() {
7
+ runHook((input) => {
8
+ const normalized = (input.prompt ?? '').toLowerCase().trim();
9
+ if (normalized === 'guard off') {
10
+ setGuardEnabled(false);
11
+ console.error('🛡️ Guard disabled — pretool validators will be skipped');
12
+ process.exit(2);
13
+ }
14
+ if (normalized === 'guard on') {
15
+ setGuardEnabled(true);
16
+ console.error('🛡️ Guard enabled — pretool validators active');
17
+ process.exit(2);
18
+ }
19
+ return null;
20
+ }, () => '{}');
21
+ }
22
+ if (process.argv[1] &&
23
+ realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1])) {
24
+ void main();
25
+ }
18
26
  //# sourceMappingURL=index.js.map
@@ -14,4 +14,5 @@ export declare function shouldLintFile(input: ToolInput): boolean;
14
14
  */
15
15
  export declare function lintFile(filePath: string, _projectDir: string): boolean;
16
16
  export declare function processPostToolUse(input: ToolInput, projectDir: string): boolean;
17
+ export declare function main(): Promise<void>;
17
18
  //# sourceMappingURL=lint-after-edit.d.ts.map
@@ -46,12 +46,15 @@ export function processPostToolUse(input, projectDir) {
46
46
  const filePath = input.tool_input.file_path;
47
47
  return lintFile(filePath, projectDir);
48
48
  }
49
- if (process.argv[1] &&
50
- realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1])) {
49
+ export async function main() {
51
50
  runHook((input) => {
52
51
  const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
53
52
  processPostToolUse(input, projectDir);
54
53
  return null;
55
54
  }, () => '{}');
56
55
  }
56
+ if (process.argv[1] &&
57
+ realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1])) {
58
+ void main();
59
+ }
57
60
  //# sourceMappingURL=lint-after-edit.js.map
@@ -46,7 +46,7 @@ export function validateFileConventions(input) {
46
46
  if (nonCanonicalPlanningViolation) {
47
47
  return { validator: 'file-conventions', passed: false, message: nonCanonicalPlanningViolation };
48
48
  }
49
- const blueprintPathViolation = getBlueprintPathViolation(normalized);
49
+ const blueprintPathViolation = getBlueprintPathViolation(normalized, undefined, input.cwd);
50
50
  if (blueprintPathViolation) {
51
51
  return { validator: 'file-conventions', passed: false, message: blueprintPathViolation };
52
52
  }
@@ -29,6 +29,11 @@ interface BlockedScriptSpec {
29
29
  category: CommandCategory;
30
30
  suggestion: string;
31
31
  }
32
+ interface BlockedRawNodeModulesToolSpec {
33
+ modulePath: string;
34
+ category: CommandCategory;
35
+ suggestion: string;
36
+ }
32
37
  interface RedirectOptions {
33
38
  mcpReady?: boolean;
34
39
  mcp?: MCPRedirectConfig;
@@ -39,6 +44,7 @@ export declare const AUDIT_MODE_ENV = "FORBIDDEN_COMMANDS_AUDIT";
39
44
  export declare const DOCS_REF = "AGENTS.md \"Forbidden Commands (CRITICAL)\" section";
40
45
  export declare const BLOCKED_TOOLS: BlockedToolSpec[];
41
46
  export declare const BLOCKED_SCRIPTS: BlockedScriptSpec[];
47
+ export declare const BLOCKED_RAW_NODE_MODULE_TOOLS: BlockedRawNodeModulesToolSpec[];
42
48
  export declare function generateRules(): CommandRule[];
43
49
  export declare const COMMAND_RULES: CommandRule[];
44
50
  export declare const SUGGESTION_MODIFIERS: SuggestionModifier[];
@@ -19,8 +19,18 @@ const TYPECHECK_HINT = 'wp_typecheck MCP tool with package/file scope';
19
19
  const E2E_HINT = 'wp_e2e MCP tool';
20
20
  const ENV_HINT = 'Use the repo-approved environment wrapper for secret-bearing commands';
21
21
  const TASK_TARGET_HINT = 'Use the repo-approved vp facade or MCP tool instead of raw execution';
22
- const EXEC_RUNNERS = ['vp exec'];
23
- const DIRECT_RUNNERS = ['vp'];
22
+ const EXEC_RUNNERS = [
23
+ 'vp exec',
24
+ 'pnpm exec',
25
+ 'npm exec',
26
+ 'npm exec --',
27
+ 'npx',
28
+ 'pnpx',
29
+ 'yarn exec',
30
+ 'yarn dlx',
31
+ 'bunx',
32
+ ];
33
+ const DIRECT_RUNNERS = ['vp', 'pnpm', 'yarn', 'yarnpkg'];
24
34
  const SCRIPT_RUNNERS = ['vp run', 'vp', 'pnpm', 'pnpm run', 'just'];
25
35
  export const BLOCKED_TOOLS = [
26
36
  {
@@ -59,6 +69,11 @@ export const BLOCKED_SCRIPTS = [
59
69
  { script: 'e2e', category: 'e2e', suggestion: E2E_HINT },
60
70
  { script: 'qa', category: 'unknown', suggestion: QA_HINT },
61
71
  ];
72
+ export const BLOCKED_RAW_NODE_MODULE_TOOLS = [
73
+ { modulePath: 'vitest/vitest.mjs', category: 'test', suggestion: TEST_HINT },
74
+ { modulePath: 'typescript/bin/tsc', category: 'typecheck', suggestion: TYPECHECK_HINT },
75
+ { modulePath: 'oxlint/bin/oxlint', category: 'lint', suggestion: LINT_HINT },
76
+ ];
62
77
  function escapeRegex(s) {
63
78
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
64
79
  }
@@ -66,6 +81,9 @@ function buildToolPattern(prefix, tool) {
66
81
  const escaped = prefix ? `${escapeRegex(prefix)} ${escapeRegex(tool)}` : escapeRegex(tool);
67
82
  return new RegExp(`^${escaped}(\\s|$)`);
68
83
  }
84
+ function buildRawNodeModulesToolPattern(modulePath) {
85
+ return new RegExp(`^node\\s+(?:\\.\\/)?node_modules\\/${escapeRegex(modulePath)}(?:\\s|$)`);
86
+ }
69
87
  export function generateRules() {
70
88
  const rules = [];
71
89
  for (const spec of BLOCKED_TOOLS) {
@@ -104,6 +122,13 @@ export function generateRules() {
104
122
  });
105
123
  }
106
124
  }
125
+ for (const spec of BLOCKED_RAW_NODE_MODULE_TOOLS) {
126
+ rules.push({
127
+ pattern: buildRawNodeModulesToolPattern(spec.modulePath),
128
+ category: spec.category,
129
+ suggestion: spec.suggestion,
130
+ });
131
+ }
107
132
  rules.push({
108
133
  pattern: /^vp exec markdownlint-cli2\b/,
109
134
  category: 'unknown',