@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
@@ -8,42 +8,25 @@
8
8
  */
9
9
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
10
  import { CallToolRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, RootsListChangedNotificationSchema, } from '@modelcontextprotocol/sdk/types.js';
11
- import { existsSync, readFileSync } from 'node:fs';
12
11
  import { dirname, join } from 'node:path';
13
12
  import { fileURLToPath } from 'node:url';
14
- import { discoverTools, } from './auto-discover.js';
13
+ import { discoverTools, registerToolDescriptors, } from './auto-discover.js';
15
14
  import { registerBlueprintServer } from './blueprint-server.js';
15
+ import { COMPILED_TOOL_REGISTRY } from './tools/_registry.js';
16
+ import { readOwnedPackageVersion } from '#runtime/package-version.js';
16
17
  const SERVER_NAME = 'webpresso';
17
- // Walk upward from this module's location until we find package.json. Works
18
- // for both src/mcp/server.ts (dev) and dist/esm/mcp/server.js (built) without
19
- // hardcoding asymmetric `../../..` counts.
20
- const MAX_UPWARD_LEVELS = 8;
21
- function readPackageVersion() {
22
- let dir = dirname(fileURLToPath(import.meta.url));
23
- for (let i = 0; i < MAX_UPWARD_LEVELS; i++) {
24
- const candidate = join(dir, 'package.json');
25
- if (existsSync(candidate)) {
26
- const pkg = JSON.parse(readFileSync(candidate, 'utf-8'));
27
- // Some build outputs emit a marker `package.json` (e.g. `{ "type": "module" }`)
28
- // without a version. Skip those and keep walking so we land on the real
29
- // package root, instead of throwing the moment we see any package.json.
30
- if (typeof pkg.version === 'string' && pkg.version.length > 0)
31
- return pkg.version;
32
- }
33
- const parent = dirname(dir);
34
- if (parent === dir)
35
- break;
36
- dir = parent;
37
- }
38
- throw new Error('Cannot locate a versioned package.json relative to webpresso MCP server module');
39
- }
40
- const SERVER_VERSION = readPackageVersion();
18
+ const SERVER_VERSION = readOwnedPackageVersion(import.meta.url);
41
19
  function defaultToolsDir() {
42
20
  // import.meta.url resolves to either src/mcp/server.ts (dev/test via vitest)
43
21
  // or dist/esm/mcp/server.js (built). The tools directory is colocated.
44
22
  const here = dirname(fileURLToPath(import.meta.url));
45
23
  return join(here, 'tools');
46
24
  }
25
+ function resolveDefaultToolLoadMode() {
26
+ return process.env.WP_MCP_TOOL_MODE === 'registry' || process.env.WP_COMPILED_RUNTIME === '1'
27
+ ? 'registry'
28
+ : 'filesystem';
29
+ }
47
30
  export async function createServer(options = {}) {
48
31
  const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
49
32
  capabilities: {
@@ -60,7 +43,13 @@ export async function createServer(options = {}) {
60
43
  tools.set(name, { name, description, inputSchema, outputSchema, handler, annotations });
61
44
  },
62
45
  };
63
- await discoverTools(registrar, options.toolsDir ?? defaultToolsDir());
46
+ const toolLoadMode = options.toolLoadMode ?? resolveDefaultToolLoadMode();
47
+ if (toolLoadMode === 'registry') {
48
+ registerToolDescriptors(registrar, COMPILED_TOOL_REGISTRY);
49
+ }
50
+ else {
51
+ await discoverTools(registrar, options.toolsDir ?? defaultToolsDir());
52
+ }
64
53
  // Task 2.1: register the blueprint structured-store tools AFTER auto-discover
65
54
  // so any tool-name collision surfaces here as a thrown error rather than
66
55
  // silent shadowing. Roots are looked up lazily via `server.listRoots()`; the
@@ -0,0 +1,3 @@
1
+ import type { ToolDescriptor } from '#mcp/auto-discover';
2
+ export declare const COMPILED_TOOL_REGISTRY: readonly ToolDescriptor[];
3
+ //# sourceMappingURL=_registry.d.ts.map
@@ -0,0 +1,21 @@
1
+ import audit from './audit.js';
2
+ import ciAct from './ci-act.js';
3
+ import e2e from './e2e.js';
4
+ import format from './format.js';
5
+ import lint from './lint.js';
6
+ import qa from './qa.js';
7
+ import test from './test.js';
8
+ import typecheck from './typecheck.js';
9
+ import workerTail from './worker-tail.js';
10
+ export const COMPILED_TOOL_REGISTRY = [
11
+ audit,
12
+ ciAct,
13
+ e2e,
14
+ format,
15
+ lint,
16
+ qa,
17
+ test,
18
+ typecheck,
19
+ workerTail,
20
+ ];
21
+ //# sourceMappingURL=_registry.js.map
@@ -32,6 +32,7 @@ declare const inputSchema: z.ZodObject<{
32
32
  "catalog-drift": "catalog-drift";
33
33
  "package-surface": "package-surface";
34
34
  "architecture-drift": "architecture-drift";
35
+ "cloudflare-deploy-contract": "cloudflare-deploy-contract";
35
36
  "absolute-path-policy": "absolute-path-policy";
36
37
  "ai-contracts": "ai-contracts";
37
38
  }>;
@@ -15,9 +15,8 @@
15
15
  * — the handler never throws out, so the MCP server stays responsive.
16
16
  */
17
17
  import { spawn } from 'node:child_process';
18
- import { existsSync } from 'node:fs';
19
18
  import { z } from 'zod';
20
- import { resolvePackageAsset } from '#utils/package-assets';
19
+ import { resolveAuditScriptPath } from '#audit/resolve-audit-script';
21
20
  import { applyOutputTransform } from '#output-transforms/index';
22
21
  import { createSummaryOutputSchema, createSummaryResult } from './_shared/result.js';
23
22
  const KINDS = [
@@ -29,6 +28,7 @@ const KINDS = [
29
28
  'docs-frontmatter',
30
29
  'blueprint-lifecycle',
31
30
  'architecture-drift',
31
+ 'cloudflare-deploy-contract',
32
32
  'absolute-path-policy',
33
33
  'roadmap-links',
34
34
  'bundle-budget',
@@ -62,12 +62,7 @@ const outputSchema = createSummaryOutputSchema({
62
62
  kind: z.enum(KINDS),
63
63
  });
64
64
  function resolveAuditScript(name) {
65
- // Source layout: `src/mcp/tools/audit.ts` → `../../audit/<name>`.
66
- const fromSource = new URL(`../../audit/${name}`, import.meta.url);
67
- if (existsSync(fromSource)) {
68
- return fromSource.pathname;
69
- }
70
- return resolvePackageAsset(`src/audit/${name}`);
65
+ return resolveAuditScriptPath(name, { moduleUrl: import.meta.url });
71
66
  }
72
67
  async function runScript(script) {
73
68
  return new Promise((resolve) => {
@@ -161,6 +156,16 @@ async function dispatch(input) {
161
156
  details: auditResult,
162
157
  };
163
158
  }
159
+ case 'cloudflare-deploy-contract': {
160
+ const { auditCloudflareDeployContract } = await import('#audit/cloudflare-deploy-contract');
161
+ const auditResult = await auditCloudflareDeployContract(input.cwd ?? input.directory ?? process.cwd());
162
+ return {
163
+ passed: auditResult.ok,
164
+ summary: summarizeRepoAudit(kind, auditResult),
165
+ kind,
166
+ details: auditResult,
167
+ };
168
+ }
164
169
  case 'absolute-path-policy': {
165
170
  const { auditAbsolutePathPolicy } = await import('#audit/absolute-path-policy');
166
171
  const auditResult = auditAbsolutePathPolicy(input.cwd ?? input.directory ?? process.cwd());
@@ -14,6 +14,7 @@ import { join } from 'node:path';
14
14
  import { globSync } from 'glob';
15
15
  import { z } from 'zod';
16
16
  import { applyOutputTransform } from '#output-transforms/index';
17
+ import { getManagedRunner } from '#tool-runtime';
17
18
  import { resolveProjectRoot } from './_shared/project-root.js';
18
19
  import { createSummaryOutputSchema, createSummaryResult } from './_shared/result.js';
19
20
  import { isRunFailure, runCommand } from './_shared/run-command.js';
@@ -143,11 +144,12 @@ const tool = {
143
144
  // current resolution treats each entry as a relative path either way.
144
145
  const workspaceGlobs = targets ? readWorkspaceGlobs(cwd) : null;
145
146
  const runs = [];
147
+ const resolution = getManagedRunner('tsc', { outputPolicy: 'structured' });
146
148
  if (targets) {
147
149
  for (const pkg of targets) {
148
150
  const resolvedTarget = resolveTypecheckTarget(cwd, pkg, workspaceGlobs);
149
151
  const tsconfig = join(resolvedTarget, 'tsconfig.json');
150
- const outcome = await runCommand('tsc', ['--noEmit', '-p', tsconfig], runOptions);
152
+ const outcome = await runCommand(resolution.command, [...resolution.args, '--noEmit', '-p', tsconfig], runOptions);
151
153
  if (isRunFailure(outcome)) {
152
154
  throw outcome.error;
153
155
  }
@@ -155,7 +157,7 @@ const tool = {
155
157
  }
156
158
  }
157
159
  else {
158
- const outcome = await runCommand('tsc', ['--noEmit'], runOptions);
160
+ const outcome = await runCommand(resolution.command, [...resolution.args, '--noEmit'], runOptions);
159
161
  if (isRunFailure(outcome)) {
160
162
  throw outcome.error;
161
163
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Run Stryker only on packages changed vs. the base branch.
3
+ * Returns 0 on success, 1 if any package fails its break threshold.
4
+ *
5
+ * Reads GITHUB_BASE_REF (set by GitHub Actions on pull_request events) to
6
+ * determine the base branch; falls back to "main".
7
+ */
8
+ export declare function runAffectedMutation(): 0 | 1;
9
+ //# sourceMappingURL=affected.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { execSync } from 'node:child_process';
2
+ /**
3
+ * Run Stryker only on packages changed vs. the base branch.
4
+ * Returns 0 on success, 1 if any package fails its break threshold.
5
+ *
6
+ * Reads GITHUB_BASE_REF (set by GitHub Actions on pull_request events) to
7
+ * determine the base branch; falls back to "main".
8
+ */
9
+ export function runAffectedMutation() {
10
+ const base = process.env.GITHUB_BASE_REF ?? 'main';
11
+ const changed = execSync(`git diff --name-only origin/${base}...HEAD`)
12
+ .toString()
13
+ .trim()
14
+ .split('\n')
15
+ .filter(Boolean);
16
+ const affectedPkgs = new Set();
17
+ for (const file of changed) {
18
+ const match = file.match(/^(apps\/[^/]+|packages\/[^/]+)\//);
19
+ if (match)
20
+ affectedPkgs.add(match[1]);
21
+ }
22
+ if (affectedPkgs.size === 0) {
23
+ console.log('No affected packages — skipping mutation.');
24
+ return 0;
25
+ }
26
+ for (const pkg of affectedPkgs) {
27
+ try {
28
+ execSync(`pnpm --filter ./${pkg} mutation --if-present`, { stdio: 'inherit' });
29
+ }
30
+ catch {
31
+ return 1;
32
+ }
33
+ }
34
+ return 0;
35
+ }
36
+ //# sourceMappingURL=affected.js.map
@@ -48,6 +48,14 @@
48
48
  "#mcp/*": "./mcp/*.js",
49
49
  "#content/*.js": "./content/*.js",
50
50
  "#content/*": "./content/*.js",
51
+ "#tool-runtime": "./tool-runtime/index.js",
52
+ "#tool-runtime/*.js": "./tool-runtime/*.js",
53
+ "#tool-runtime/*": "./tool-runtime/*.js",
54
+ "#wp-extension": "./wp-extension/index.js",
55
+ "#wp-extension/*.js": "./wp-extension/*.js",
56
+ "#wp-extension/*": "./wp-extension/*.js",
57
+ "#runtime/*.js": "./runtime/*.js",
58
+ "#runtime/*": "./runtime/*.js",
51
59
  "#output-transforms/*.js": "./output-transforms/*.js",
52
60
  "#output-transforms/*": "./output-transforms/*.js",
53
61
  "#lint/*.js": "./lint/*.js",
@@ -0,0 +1,2 @@
1
+ export declare function readOwnedPackageVersion(moduleUrl: string): string;
2
+ //# sourceMappingURL=package-version.d.ts.map
@@ -0,0 +1,43 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const ACCEPTED_PACKAGE_PREFIXES = ['@webpresso/agent-kit', 'webpresso'];
5
+ const MAX_UPWARD_LEVELS = 8;
6
+ function matchesOwnedPackageName(name) {
7
+ return (typeof name === 'string' &&
8
+ ACCEPTED_PACKAGE_PREFIXES.some((prefix) => name === prefix || name.startsWith(`${prefix}-`)));
9
+ }
10
+ function readVersionFromDir(startDir) {
11
+ let dir = path.resolve(startDir);
12
+ for (let i = 0; i < MAX_UPWARD_LEVELS; i++) {
13
+ const candidate = path.join(dir, 'package.json');
14
+ if (existsSync(candidate)) {
15
+ try {
16
+ const parsed = JSON.parse(readFileSync(candidate, 'utf8'));
17
+ if (matchesOwnedPackageName(parsed.name) && typeof parsed.version === 'string') {
18
+ return parsed.version;
19
+ }
20
+ }
21
+ catch {
22
+ // keep walking
23
+ }
24
+ }
25
+ const parent = path.dirname(dir);
26
+ if (parent === dir)
27
+ break;
28
+ dir = parent;
29
+ }
30
+ return null;
31
+ }
32
+ export function readOwnedPackageVersion(moduleUrl) {
33
+ const fromModule = readVersionFromDir(path.dirname(fileURLToPath(moduleUrl)));
34
+ if (fromModule)
35
+ return fromModule;
36
+ if (process.execPath) {
37
+ const fromExec = readVersionFromDir(path.dirname(process.execPath));
38
+ if (fromExec)
39
+ return fromExec;
40
+ }
41
+ return '0.0.0';
42
+ }
43
+ //# sourceMappingURL=package-version.js.map
@@ -1,4 +1,5 @@
1
1
  import type { ResolvedTestTarget } from './target-resolver.js';
2
+ import { type ManagedRunnerOutputPolicy } from '#tool-runtime';
2
3
  export interface CommandConfig {
3
4
  command: string;
4
5
  args: string[];
@@ -6,6 +7,7 @@ export interface CommandConfig {
6
7
  }
7
8
  export type VpRunLogMode = 'interleaved' | 'labeled' | 'grouped';
8
9
  export interface TestCommandOptions {
10
+ cwd?: string;
9
11
  watch?: boolean;
10
12
  coverage?: boolean;
11
13
  testNamePattern?: string;
@@ -17,6 +19,8 @@ export interface TestCommandOptions {
17
19
  concurrencyLimit?: number;
18
20
  log?: VpRunLogMode;
19
21
  passthrough?: readonly string[];
22
+ filterOutput?: boolean;
23
+ outputPolicy?: ManagedRunnerOutputPolicy;
20
24
  }
21
25
  export declare function buildTestCommand(target: ResolvedTestTarget, options?: TestCommandOptions): CommandConfig;
22
26
  export declare function buildVpTestCommand(filters: readonly string[], options?: TestCommandOptions): CommandConfig;
@@ -1,4 +1,9 @@
1
+ import { getManagedRunner } from '#tool-runtime';
2
+ import { getPackageScript, isRecursiveWpScript, packageUsesVitest } from '#cli/package-scripts.js';
1
3
  export function buildTestCommand(target, options = {}) {
4
+ if (target.type === 'all' && shouldBypassRecursiveWpTest(options.cwd ?? process.cwd())) {
5
+ return buildVitestCommand([], options);
6
+ }
2
7
  if (target.type === 'file') {
3
8
  return buildVitestCommand(target.values, options);
4
9
  }
@@ -7,7 +12,7 @@ export function buildTestCommand(target, options = {}) {
7
12
  export function buildVpTestCommand(filters, options = {}) {
8
13
  const task = getVpTestTask(options);
9
14
  const resolvedFilters = filters.map((filter) => formatVpRunFilter(filter, task));
10
- const explicitTargets = resolvedFilters.every(isExplicitVpTaskTarget);
15
+ const explicitTargets = resolvedFilters.length > 0 && resolvedFilters.every(isExplicitVpTaskTarget);
11
16
  const args = ['run', ...resolvedFilters];
12
17
  appendVpRunOptions(args, options);
13
18
  if (!explicitTargets) {
@@ -17,8 +22,14 @@ export function buildVpTestCommand(filters, options = {}) {
17
22
  if (passthrough.length > 0) {
18
23
  args.push('--', ...passthrough);
19
24
  }
25
+ const resolution = getManagedRunner('vp', {
26
+ outputPolicy: resolveOutputPolicy(options.outputPolicy, options.filterOutput),
27
+ });
20
28
  const env = buildVpRunEnv(options);
21
- return env ? { command: 'vp', args, env } : { command: 'vp', args };
29
+ const mergedArgs = [...resolution.args, ...args];
30
+ return env
31
+ ? { command: resolution.command, args: mergedArgs, env }
32
+ : { command: resolution.command, args: mergedArgs };
22
33
  }
23
34
  export function buildVitestCommand(files, options = {}) {
24
35
  const args = [options.watch ? '--watch' : 'run'];
@@ -40,7 +51,10 @@ export function buildVitestCommand(files, options = {}) {
40
51
  args.push('--config', configFile);
41
52
  }
42
53
  args.push(...buildVitestPassthrough(options), ...testFiles);
43
- return { command: 'vitest', args };
54
+ const resolution = getManagedRunner('vitest', {
55
+ outputPolicy: resolveOutputPolicy(options.outputPolicy, options.filterOutput),
56
+ });
57
+ return { command: resolution.command, args: [...resolution.args, ...args] };
44
58
  }
45
59
  export function getVpTestTask(options) {
46
60
  if (options.mutation)
@@ -95,4 +109,15 @@ function buildVitestPassthrough(options) {
95
109
  function isVitestConfigFile(file) {
96
110
  return /^vitest(?:\.[\w-]+)?\.config\.(?:ts|mts|cts|js|mjs|cjs)$/u.test(file);
97
111
  }
112
+ function resolveOutputPolicy(outputPolicy, filterOutput) {
113
+ if (outputPolicy)
114
+ return outputPolicy;
115
+ return filterOutput === false ? 'structured' : 'rtk-filtered';
116
+ }
117
+ function shouldBypassRecursiveWpTest(cwd) {
118
+ const testScript = getPackageScript(cwd, 'test');
119
+ if (!testScript || !isRecursiveWpScript(testScript, 'test'))
120
+ return false;
121
+ return packageUsesVitest(cwd);
122
+ }
98
123
  //# sourceMappingURL=command-builder.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Hermetic environment baseline for the whole test suite.
3
+ *
4
+ * agent-kit's suite is routinely run *inside* an agent session (Claude Code,
5
+ * Codex), and those sessions export ambient variables that the production code
6
+ * legitimately honors at runtime:
7
+ *
8
+ * - `CLAUDE_PROJECT_DIR` — `resolveProjectRoot` (src/mcp/tools/_shared/project-root.ts)
9
+ * ranks this above the discovered cwd, so a leaked value makes blueprint-server
10
+ * tests target the real repo + its shared SQLite DB instead of their temp dir,
11
+ * producing wrong-data assertions and lock-contention timeouts.
12
+ * - `WP_SKIP_UPDATE_CHECK` — suppresses the managed-CLI refresh spawn that the
13
+ * init scaffolder tests assert fires; a leaked value (exported by the shell or
14
+ * left behind by a sibling test file under the shared forks worker) drops the
15
+ * expected spawn and fails spawn-count assertions.
16
+ *
17
+ * The fix is isolation, not changing the runtime precedence: reset these before
18
+ * every test so the suite is deterministic regardless of the launching
19
+ * environment. Tests that exercise these variables set them explicitly in their
20
+ * own body (which runs after this hook), so behavior coverage is unaffected.
21
+ */
22
+ export declare const LEAKY_ENV_KEYS: readonly ["CLAUDE_PROJECT_DIR", "WP_SKIP_UPDATE_CHECK"];
23
+ /** Delete every agent-session-leaked env var so each test starts hermetic. */
24
+ export declare function resetLeakyEnv(): void;
25
+ //# sourceMappingURL=hermetic-env.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { beforeEach } from 'vitest';
2
+ /**
3
+ * Hermetic environment baseline for the whole test suite.
4
+ *
5
+ * agent-kit's suite is routinely run *inside* an agent session (Claude Code,
6
+ * Codex), and those sessions export ambient variables that the production code
7
+ * legitimately honors at runtime:
8
+ *
9
+ * - `CLAUDE_PROJECT_DIR` — `resolveProjectRoot` (src/mcp/tools/_shared/project-root.ts)
10
+ * ranks this above the discovered cwd, so a leaked value makes blueprint-server
11
+ * tests target the real repo + its shared SQLite DB instead of their temp dir,
12
+ * producing wrong-data assertions and lock-contention timeouts.
13
+ * - `WP_SKIP_UPDATE_CHECK` — suppresses the managed-CLI refresh spawn that the
14
+ * init scaffolder tests assert fires; a leaked value (exported by the shell or
15
+ * left behind by a sibling test file under the shared forks worker) drops the
16
+ * expected spawn and fails spawn-count assertions.
17
+ *
18
+ * The fix is isolation, not changing the runtime precedence: reset these before
19
+ * every test so the suite is deterministic regardless of the launching
20
+ * environment. Tests that exercise these variables set them explicitly in their
21
+ * own body (which runs after this hook), so behavior coverage is unaffected.
22
+ */
23
+ export const LEAKY_ENV_KEYS = ['CLAUDE_PROJECT_DIR', 'WP_SKIP_UPDATE_CHECK'];
24
+ /** Delete every agent-session-leaked env var so each test starts hermetic. */
25
+ export function resetLeakyEnv() {
26
+ for (const key of LEAKY_ENV_KEYS) {
27
+ delete process.env[key];
28
+ }
29
+ }
30
+ beforeEach(resetLeakyEnv);
31
+ //# sourceMappingURL=hermetic-env.js.map
@@ -0,0 +1,5 @@
1
+ import { type ManagedRunnerResolution, type ResolveRunnerOptions, type ManagedRunnerOutputPolicy } from './resolve-runner.js';
2
+ export declare function getManagedRunner(tool: string, options?: ResolveRunnerOptions): ManagedRunnerResolution;
3
+ export declare function clearManagedRunnerCache(): void;
4
+ export type { ManagedRunnerOutputPolicy, ManagedRunnerResolution, ResolveRunnerOptions };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { resolveRunner, } from './resolve-runner.js';
2
+ const runtimeCache = new Map();
3
+ function cacheKey(tool, options) {
4
+ const outputPolicy = options.outputPolicy ?? (options.filterOutput === false ? 'structured' : 'rtk-filtered');
5
+ return JSON.stringify({
6
+ tool,
7
+ outputPolicy,
8
+ fallbackCommand: options.fallbackCommand ?? null,
9
+ fallbackArgs: options.fallbackArgs ?? [],
10
+ });
11
+ }
12
+ export function getManagedRunner(tool, options = {}) {
13
+ const key = cacheKey(tool, options);
14
+ const cached = runtimeCache.get(key);
15
+ if (cached)
16
+ return cached;
17
+ const resolved = resolveRunner(tool, options);
18
+ runtimeCache.set(key, resolved);
19
+ return resolved;
20
+ }
21
+ export function clearManagedRunnerCache() {
22
+ runtimeCache.clear();
23
+ }
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,16 @@
1
+ export interface ManagedRunnerResolution {
2
+ readonly tool: string;
3
+ readonly command: string;
4
+ readonly args: readonly string[];
5
+ readonly source: 'managed' | 'fallback';
6
+ }
7
+ export type ManagedRunnerOutputPolicy = 'rtk-filtered' | 'structured';
8
+ export interface ResolveRunnerOptions {
9
+ readonly fallbackCommand?: string;
10
+ readonly fallbackArgs?: readonly string[];
11
+ /** @deprecated Use {@link outputPolicy} for explicit output routing. */
12
+ readonly filterOutput?: boolean;
13
+ readonly outputPolicy?: ManagedRunnerOutputPolicy;
14
+ }
15
+ export declare function resolveRunner(tool: string, options?: ResolveRunnerOptions): ManagedRunnerResolution;
16
+ //# sourceMappingURL=resolve-runner.d.ts.map
@@ -0,0 +1,42 @@
1
+ const MANAGED_TOOL_PREFIX = {
2
+ oxfmt: { command: 'vp', args: ['exec', 'oxfmt'] },
3
+ playwright: { command: 'vp', args: ['exec', 'playwright'] },
4
+ tsc: { command: 'vp', args: ['exec', 'tsc'] },
5
+ vitest: { command: 'vp', args: ['exec', 'vitest'] },
6
+ vp: { command: 'vp', args: [] },
7
+ };
8
+ function withOptionalRtk(resolution, outputPolicy) {
9
+ if (outputPolicy !== 'rtk-filtered')
10
+ return resolution;
11
+ return {
12
+ ...resolution,
13
+ command: 'rtk',
14
+ args: [resolution.command, ...resolution.args],
15
+ };
16
+ }
17
+ export function resolveRunner(tool, options = {}) {
18
+ const normalized = tool.trim();
19
+ if (!normalized) {
20
+ throw new Error('tool runtime resolution requires a non-empty tool name');
21
+ }
22
+ const outputPolicy = options.outputPolicy ?? (options.filterOutput === false ? 'structured' : 'rtk-filtered');
23
+ const managed = MANAGED_TOOL_PREFIX[normalized];
24
+ if (managed) {
25
+ return withOptionalRtk({
26
+ tool: normalized,
27
+ command: managed.command,
28
+ args: [...managed.args],
29
+ source: 'managed',
30
+ }, outputPolicy);
31
+ }
32
+ if (options.fallbackCommand) {
33
+ return withOptionalRtk({
34
+ tool: normalized,
35
+ command: options.fallbackCommand,
36
+ args: [...(options.fallbackArgs ?? [])],
37
+ source: 'fallback',
38
+ }, outputPolicy);
39
+ }
40
+ throw new Error(`No managed runtime runner is defined for tool "${normalized}"`);
41
+ }
42
+ //# sourceMappingURL=resolve-runner.js.map
@@ -12,6 +12,7 @@ import { join } from 'node:path';
12
12
  import { globSync } from 'glob';
13
13
  import { isRunFailure, runCommand } from '#mcp/tools/_shared/run-command';
14
14
  import { resolveProjectRoot } from '#mcp/tools/_shared/project-root';
15
+ import { getManagedRunner } from '#tool-runtime';
15
16
  const DEFAULT_TYPECHECK_TIMEOUT_MS = 10 * 60 * 1_000;
16
17
  // Matches both standard tsc formats:
17
18
  // src/foo.ts(5,12): error TS2304: Cannot find name 'bar'.
@@ -99,11 +100,12 @@ export async function runTypecheck(options = {}) {
99
100
  const targets = options.packages && options.packages.length > 0 ? options.packages : null;
100
101
  const workspaceGlobs = targets ? readWorkspaceGlobs(cwd) : null;
101
102
  const runs = [];
103
+ const resolution = getManagedRunner('tsc', { outputPolicy: 'structured' });
102
104
  if (targets) {
103
105
  for (const pkg of targets) {
104
106
  const resolvedTarget = resolveTypecheckTarget(cwd, pkg, workspaceGlobs);
105
107
  const tsconfig = join(resolvedTarget, 'tsconfig.json');
106
- const outcome = await runCommand('tsc', ['--noEmit', '-p', tsconfig], runOptions);
108
+ const outcome = await runCommand(resolution.command, [...resolution.args, '--noEmit', '-p', tsconfig], runOptions);
107
109
  if (isRunFailure(outcome)) {
108
110
  throw outcome.error;
109
111
  }
@@ -111,7 +113,7 @@ export async function runTypecheck(options = {}) {
111
113
  }
112
114
  }
113
115
  else {
114
- const outcome = await runCommand('tsc', ['--noEmit'], runOptions);
116
+ const outcome = await runCommand(resolution.command, [...resolution.args, '--noEmit'], runOptions);
115
117
  if (isRunFailure(outcome)) {
116
118
  throw outcome.error;
117
119
  }
@@ -0,0 +1,50 @@
1
+ import type { CAC } from 'cac';
2
+ export interface WpExtensionContext {
3
+ readonly cwd: string;
4
+ readonly env: NodeJS.ProcessEnv;
5
+ }
6
+ export interface WpExtensionCommandV1 {
7
+ readonly name: string;
8
+ readonly description: string;
9
+ readonly register: (cli: CAC) => void;
10
+ }
11
+ export interface WpExtensionAliasV1 {
12
+ readonly name: string;
13
+ readonly commandName: string;
14
+ }
15
+ export interface WpExtensionV1 {
16
+ readonly apiVersion: '1';
17
+ readonly name: string;
18
+ readonly version: string;
19
+ readonly hostRange: string;
20
+ readonly detect: (context: WpExtensionContext) => boolean | Promise<boolean>;
21
+ readonly commands: readonly WpExtensionCommandV1[];
22
+ readonly aliases?: readonly WpExtensionAliasV1[];
23
+ }
24
+ export interface LoadedWpExtension {
25
+ readonly packageName: string;
26
+ readonly specifier: string;
27
+ readonly extension?: WpExtensionV1;
28
+ readonly compatible: boolean;
29
+ readonly detected: boolean;
30
+ readonly warnings: readonly string[];
31
+ }
32
+ export interface WpExtensionAliasResolution {
33
+ readonly aliases: ReadonlyMap<string, WpExtensionAliasV1>;
34
+ readonly warnings: readonly string[];
35
+ readonly acceptedCommandNames: readonly string[];
36
+ }
37
+ export interface LoadWpExtensionsOptions {
38
+ readonly cwd?: string;
39
+ readonly env?: NodeJS.ProcessEnv;
40
+ readonly hostVersion: string;
41
+ readonly importModule?: (specifier: string) => Promise<{
42
+ default?: unknown;
43
+ }>;
44
+ readonly resolveFrom?: (fromFile: string, specifier: string) => string;
45
+ readonly readJsonFile?: (path: string) => unknown;
46
+ }
47
+ export declare function loadWpExtensions(options: LoadWpExtensionsOptions): Promise<readonly LoadedWpExtension[]>;
48
+ export declare function resolveAcceptedExtensionAliases(extensions: readonly LoadedWpExtension[], baseCommands: Iterable<string>, acceptedCommandNames: Iterable<string>): WpExtensionAliasResolution;
49
+ export declare function isWpExtensionV1(value: unknown): value is WpExtensionV1;
50
+ //# sourceMappingURL=index.d.ts.map