@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
@@ -9,9 +9,10 @@
9
9
  *
10
10
  * Runs by default on every `wp setup`.
11
11
  */
12
- import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
12
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
13
13
  import { homedir } from 'node:os';
14
- import { join, resolve } from 'node:path';
14
+ import { dirname, join, resolve } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
15
16
  import { patchJsonFile } from '#cli/commands/init/merge';
16
17
  import { CodexAppServerClient } from '#codex/app-server/client.js';
17
18
  import { normalizeGlobalCodexHooksFile, resolveBinaryOnPath, } from '#cli/commands/init/scaffolders/agent-hooks/codex-global-normalize';
@@ -28,16 +29,32 @@ import { buildSkillTag, extractSkillHooks, isTaggedSkillHook, } from './skill-ho
28
29
  // bypass when the guard binary is missing/non-executable.
29
30
  const PRETOOL_GUARD_BIN = 'wp-pretool-guard';
30
31
  const PRETOOL_GUARD_MISSING_DENY = `printf '%s\\n' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"wp-pretool-guard is unavailable. Run vp install or wp setup."}}'`;
32
+ const CLAUDE_MANAGED_HOOK_SUBDIR = '.claude/hooks/managed';
33
+ const CODEX_MANAGED_HOOK_SUBDIR = '.codex/managed-hooks';
34
+ function claudeManagedHookLauncherPath(name) {
35
+ return `$CLAUDE_PROJECT_DIR/${CLAUDE_MANAGED_HOOK_SUBDIR}/${name}.sh`;
36
+ }
37
+ function codexManagedHookLauncherPath(repoRoot, name) {
38
+ return resolve(repoRoot, CODEX_MANAGED_HOOK_SUBDIR, `${name}.sh`);
39
+ }
40
+ function quoteShell(value) {
41
+ return `'${value.replaceAll("'", "'\\''")}'`;
42
+ }
43
+ function quoteHookCommandPath(value) {
44
+ if (value.startsWith('$CLAUDE_PROJECT_DIR/'))
45
+ return `"${value}"`;
46
+ return quoteShell(value);
47
+ }
31
48
  function buildGuardedHookCommand(binPath, name) {
49
+ const quotedBinPath = quoteHookCommandPath(binPath);
32
50
  if (name === PRETOOL_GUARD_BIN) {
33
- return `[ -x "${binPath}" ] && "${binPath}" || ${PRETOOL_GUARD_MISSING_DENY}`;
51
+ return `[ -x ${quotedBinPath} ] && ${quotedBinPath} || ${PRETOOL_GUARD_MISSING_DENY}`;
34
52
  }
35
- return `[ -x "${binPath}" ] && "${binPath}" || true`;
53
+ return `[ -x ${quotedBinPath} ] && ${quotedBinPath} || true`;
36
54
  }
37
- const CC_BIN = (name) => buildGuardedHookCommand(`$CLAUDE_PROJECT_DIR/node_modules/.bin/${name}`, name);
55
+ const CC_BIN = (name) => buildGuardedHookCommand(claudeManagedHookLauncherPath(name), name);
38
56
  const CODEX_BIN = (repoRoot) => (name) => {
39
- const binPath = resolve(repoRoot, 'node_modules', '.bin', name);
40
- return buildGuardedHookCommand(binPath, name);
57
+ return buildGuardedHookCommand(codexManagedHookLauncherPath(repoRoot, name), name);
41
58
  };
42
59
  // Canonical hook event names recognised by both Claude Code and Codex CLI.
43
60
  // Used by `hoistTopLevelEvents` to identify legacy flat-form keys to migrate.
@@ -77,6 +94,8 @@ const DIRECT_NODE_MODULES_BIN_PATTERN = /^(?:\.\/|\/.*\/)?node_modules\/\.bin\/(
77
94
  const GUARDED_NODE_MODULES_BIN_PATTERN = /^\[ -x (["']?)((?:\.\/|\/.*\/)?node_modules\/\.bin\/([\w-]+))\1 \] && \1\2\1 \|\| (?:true|printf .+)$/u;
78
95
  const DIRECT_CLAUDE_NODE_MODULES_BIN_PATTERN = /^["']?\$CLAUDE_PROJECT_DIR\/node_modules\/\.bin\/([\w-]+)["']?$/u;
79
96
  const GUARDED_CLAUDE_NODE_MODULES_BIN_PATTERN = /^\[ -x (["']?)\$CLAUDE_PROJECT_DIR\/node_modules\/\.bin\/([\w-]+)\1 \] && \1\$CLAUDE_PROJECT_DIR\/node_modules\/\.bin\/\2\1 \|\| (?:true|printf .+)$/u;
97
+ const DIRECT_MANAGED_HOOK_LAUNCHER_PATTERN = /^(?:["']?)((?:\$CLAUDE_PROJECT_DIR\/\.claude\/hooks\/managed|(?:\.\/|\/.*\/)?\.claude\/hooks\/managed|(?:\.\/|\/.*\/)?\.codex\/managed-hooks)\/((?:wp|ak)-[\w-]+)\.sh)(?:["']?)$/u;
98
+ const GUARDED_MANAGED_HOOK_LAUNCHER_PATTERN = /^\[ -x (["']?)((?:\$CLAUDE_PROJECT_DIR\/\.claude\/hooks\/managed|(?:\.\/|\/.*\/)?\.claude\/hooks\/managed|(?:\.\/|\/.*\/)?\.codex\/managed-hooks)\/((?:wp|ak)-[\w-]+)\.sh)\1 \] && \1\2\1 \|\| (?:true|printf .+)$/u;
80
99
  // Capture the basename of any path that ends in a known script extension.
81
100
  // Handles trailing chars (quote, space, end-of-string).
82
101
  const SCRIPT_BASENAME_PATTERN = new RegExp(String.raw `([\w-]+\.(?:${SCRIPT_EXTENSIONS.join('|')}))(?=$|["'\s])`, 'u');
@@ -110,9 +129,15 @@ function extractAgentKitCodexBinName(command) {
110
129
  const directBinMatch = DIRECT_NODE_MODULES_BIN_PATTERN.exec(normalizedCommand);
111
130
  if (directBinMatch !== null)
112
131
  return directBinMatch[1] ?? null;
132
+ const directManagedLauncherMatch = DIRECT_MANAGED_HOOK_LAUNCHER_PATTERN.exec(normalizedCommand);
133
+ if (directManagedLauncherMatch !== null)
134
+ return directManagedLauncherMatch[2] ?? null;
113
135
  const guardedBinMatch = GUARDED_NODE_MODULES_BIN_PATTERN.exec(command.trim());
114
136
  if (guardedBinMatch !== null)
115
137
  return guardedBinMatch[3] ?? null;
138
+ const guardedManagedLauncherMatch = GUARDED_MANAGED_HOOK_LAUNCHER_PATTERN.exec(command.trim());
139
+ if (guardedManagedLauncherMatch !== null)
140
+ return guardedManagedLauncherMatch[3] ?? null;
116
141
  return null;
117
142
  }
118
143
  function extractClaudeBinName(command) {
@@ -120,9 +145,15 @@ function extractClaudeBinName(command) {
120
145
  const directBinMatch = DIRECT_CLAUDE_NODE_MODULES_BIN_PATTERN.exec(normalizedCommand);
121
146
  if (directBinMatch !== null)
122
147
  return directBinMatch[1] ?? null;
148
+ const directManagedLauncherMatch = DIRECT_MANAGED_HOOK_LAUNCHER_PATTERN.exec(normalizedCommand);
149
+ if (directManagedLauncherMatch !== null)
150
+ return directManagedLauncherMatch[2] ?? null;
123
151
  const guardedBinMatch = GUARDED_CLAUDE_NODE_MODULES_BIN_PATTERN.exec(command.trim());
124
152
  if (guardedBinMatch !== null)
125
153
  return guardedBinMatch[2] ?? null;
154
+ const guardedManagedLauncherMatch = GUARDED_MANAGED_HOOK_LAUNCHER_PATTERN.exec(command.trim());
155
+ if (guardedManagedLauncherMatch !== null)
156
+ return guardedManagedLauncherMatch[3] ?? null;
126
157
  return null;
127
158
  }
128
159
  function stripSingleShellQuotePair(value) {
@@ -305,20 +336,33 @@ function normalizeCodexAgentKitCommands(hooks, repoRoot) {
305
336
  }
306
337
  return normalized;
307
338
  }
308
- function pruneLegacyClaudeAgentKitCommands(hooks) {
339
+ function normalizeClaudeAgentKitCommands(hooks) {
309
340
  const normalized = {};
310
341
  for (const [event, groups] of Object.entries(hooks)) {
311
- const keptGroups = groups
312
- .map((group) => {
313
- const keptHooks = group.hooks.filter((hook) => {
314
- const classification = classifyWebpressoHookBin(extractClaudeBinName(hook.command));
315
- return classification === null || classification.kind !== 'legacy';
316
- });
317
- return keptHooks.length > 0 ? { ...group, hooks: keptHooks } : null;
318
- })
319
- .filter((group) => group !== null);
320
- if (keptGroups.length > 0)
321
- normalized[event] = keptGroups;
342
+ const normalizedGroups = groups.reduce((dedupedGroups, group) => {
343
+ const nextGroup = {
344
+ ...group,
345
+ hooks: group.hooks.flatMap((hook) => {
346
+ const command = hook.command;
347
+ if (typeof command !== 'string')
348
+ return hook;
349
+ const classification = classifyWebpressoHookBin(extractClaudeBinName(command));
350
+ if (classification === null)
351
+ return hook;
352
+ if (classification.kind === 'legacy')
353
+ return [];
354
+ return {
355
+ ...hook,
356
+ command: CC_BIN(classification.binName),
357
+ };
358
+ }),
359
+ };
360
+ if (nextGroup.hooks.length === 0)
361
+ return dedupedGroups;
362
+ return ensureGroup(dedupedGroups, nextGroup);
363
+ }, []);
364
+ if (normalizedGroups.length > 0)
365
+ normalized[event] = normalizedGroups;
322
366
  }
323
367
  return normalized;
324
368
  }
@@ -380,7 +424,7 @@ function patchClaudeUserSettings(existing) {
380
424
  return next;
381
425
  }
382
426
  function patchClaudeSettings(existing, skillHooks) {
383
- const existingHooks = pruneLegacyClaudeAgentKitCommands((existing.hooks ?? {}));
427
+ const existingHooks = normalizeClaudeAgentKitCommands((existing.hooks ?? {}));
384
428
  const withSkills = mergeSkillHooks(existingHooks, skillHooks);
385
429
  const webpresso = buildWebpressoHookGroups({
386
430
  resolveBin: CC_BIN,
@@ -560,8 +604,74 @@ function ensureGstackHooks(repoRoot, options = {}) {
560
604
  chmodSync(sessionPath, 0o755);
561
605
  }
562
606
  }
607
+ function resolveProjectHookBinPath(repoRoot, binName) {
608
+ return resolve(repoRoot, 'node_modules', '@webpresso', 'agent-kit', 'bin', `${binName}.js`);
609
+ }
610
+ function resolvePackageHookBin(binName) {
611
+ return join(resolvePackageRoot(), 'bin', `${binName}.js`);
612
+ }
613
+ function resolvePackageRoot() {
614
+ let dir = dirname(fileURLToPath(import.meta.url));
615
+ for (let depth = 0; depth < 10; depth++) {
616
+ if (existsSync(join(dir, 'package.json')) && existsSync(join(dir, 'bin', 'wp.js'))) {
617
+ return dir;
618
+ }
619
+ const parent = dirname(dir);
620
+ if (parent === dir)
621
+ break;
622
+ dir = parent;
623
+ }
624
+ throw new Error('wp setup: could not locate @webpresso/agent-kit package root for hook launchers.');
625
+ }
626
+ function renderManagedWebpressoHookLauncher(repoRoot, binName) {
627
+ const nodeBinary = quoteShell(process.execPath);
628
+ const projectBinPath = quoteShell(resolveProjectHookBinPath(repoRoot, binName));
629
+ const fallbackBinPath = quoteShell(resolvePackageHookBin(binName));
630
+ const missingFallback = binName === PRETOOL_GUARD_BIN ? PRETOOL_GUARD_MISSING_DENY : 'exit 0';
631
+ return `#!/bin/sh
632
+ NODE_BINARY=${nodeBinary}
633
+ PROJECT_BIN_PATH=${projectBinPath}
634
+ FALLBACK_BIN_PATH=${fallbackBinPath}
635
+
636
+ if [ ! -x "$NODE_BINARY" ]; then
637
+ ${missingFallback}
638
+ exit 0
639
+ fi
640
+
641
+ if [ -f "$PROJECT_BIN_PATH" ]; then
642
+ exec "$NODE_BINARY" "$PROJECT_BIN_PATH" "$@"
643
+ fi
644
+
645
+ if [ -f "$FALLBACK_BIN_PATH" ]; then
646
+ exec "$NODE_BINARY" "$FALLBACK_BIN_PATH" "$@"
647
+ fi
648
+
649
+ ${missingFallback}
650
+ exit 0
651
+ `;
652
+ }
653
+ function ensureManagedWebpressoHookLaunchers(repoRoot, options = {}) {
654
+ if (options.dryRun)
655
+ return;
656
+ const launcherTargets = [
657
+ join(repoRoot, CLAUDE_MANAGED_HOOK_SUBDIR),
658
+ join(repoRoot, CODEX_MANAGED_HOOK_SUBDIR),
659
+ ];
660
+ for (const directory of launcherTargets) {
661
+ mkdirSync(directory, { recursive: true });
662
+ for (const binName of WEBPRESSO_HOOK_BIN_NAMES) {
663
+ const launcherPath = join(directory, `${binName}.sh`);
664
+ const content = renderManagedWebpressoHookLauncher(repoRoot, binName);
665
+ if (!existsSync(launcherPath) || readFileSync(launcherPath, 'utf8') !== content) {
666
+ writeFileSync(launcherPath, content, 'utf8');
667
+ }
668
+ chmodSync(launcherPath, 0o755);
669
+ }
670
+ }
671
+ }
563
672
  export async function scaffoldAgentHooks(input) {
564
673
  ensureGstackHooks(input.repoRoot, input.options);
674
+ ensureManagedWebpressoHookLaunchers(input.repoRoot, input.options);
565
675
  const skillHooks = extractSkillHooks(join(input.repoRoot, '.agent', 'skills'));
566
676
  const result = {
567
677
  claude: patchJsonFile(join(input.repoRoot, '.claude', 'settings.json'), (existing) => patchClaudeSettings(existing, skillHooks), input.options),
@@ -0,0 +1,65 @@
1
+ /**
2
+ * `agent-kit-global` self-update scaffolder.
3
+ *
4
+ * Keeps the ONE globally-distributed `@webpresso/agent-kit` binary fresh on
5
+ * every `wp setup`, mirroring how omx / omc / codex / claude self-update their
6
+ * own global installs. The PATH `wp`, the Claude plugin MCP, and the agent
7
+ * hooks all resolve to this single global binary, so refreshing it here means
8
+ * the next invocation everywhere runs the latest published release.
9
+ *
10
+ * Uses the exact same command the auto-update installer infers
11
+ * (`buildVpGlobalInstallCommand` — single source of truth), so there is no
12
+ * second place that can drift on the install incantation.
13
+ *
14
+ * Skipped (no-op, non-fatal) when:
15
+ * - `--dry-run` (no writes anywhere),
16
+ * - `WP_SKIP_AUTO_INSTALL=1` (the documented opt-out, surfaced in the update
17
+ * banner),
18
+ * - the running binary resolves into a webpresso source/git clone — a global
19
+ * install would clobber the developer's working clone with a published
20
+ * tarball (`detectGitInstall`),
21
+ * - `vp` is not on PATH (nothing to install with).
22
+ *
23
+ * A failed refresh is reported but NEVER fails consumer setup: keeping the
24
+ * global tool current is ancillary to scaffolding the consumer repo (same
25
+ * warn-only contract as the codex-cli scaffolder).
26
+ */
27
+ import { spawnSync } from 'node:child_process';
28
+ import type { MergeOptions } from '#cli/commands/init/merge';
29
+ import { type SpinnerFactory } from '#cli/commands/init/scaffolders/spinner';
30
+ export interface EnsureAgentKitGlobalInput {
31
+ options: MergeOptions;
32
+ /** DI seam for child_process.spawnSync. */
33
+ spawn?: typeof spawnSync;
34
+ /** DI seam for environment-backed opt-out. */
35
+ env?: NodeJS.ProcessEnv;
36
+ /** The running binary path (defaults to process.argv[1]). Used for source-clone detection. */
37
+ argv1?: string;
38
+ /** DI seam for source/git-clone detection. */
39
+ detectGit?: (argv1: string) => string | null;
40
+ /** DI seam for spinner. Defaults to noop when !process.stdout.isTTY. */
41
+ spinnerFactory?: SpinnerFactory;
42
+ }
43
+ export type EnsureAgentKitGlobalResult = {
44
+ kind: 'agent-kit-global-updated';
45
+ command: readonly string[];
46
+ } | {
47
+ kind: 'agent-kit-global-skipped-dry-run';
48
+ } | {
49
+ kind: 'agent-kit-global-skipped-opt-out';
50
+ } | {
51
+ kind: 'agent-kit-global-skipped-source-clone';
52
+ repoRoot: string;
53
+ } | {
54
+ kind: 'agent-kit-global-skipped-no-vp';
55
+ hint: string;
56
+ } | {
57
+ kind: 'agent-kit-global-failed';
58
+ exitCode: number;
59
+ command: readonly string[];
60
+ };
61
+ /**
62
+ * Refresh the single global `@webpresso/agent-kit` install via `vp install -g`.
63
+ */
64
+ export declare function ensureAgentKitGlobal(input: EnsureAgentKitGlobalInput): EnsureAgentKitGlobalResult;
65
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,64 @@
1
+ /**
2
+ * `agent-kit-global` self-update scaffolder.
3
+ *
4
+ * Keeps the ONE globally-distributed `@webpresso/agent-kit` binary fresh on
5
+ * every `wp setup`, mirroring how omx / omc / codex / claude self-update their
6
+ * own global installs. The PATH `wp`, the Claude plugin MCP, and the agent
7
+ * hooks all resolve to this single global binary, so refreshing it here means
8
+ * the next invocation everywhere runs the latest published release.
9
+ *
10
+ * Uses the exact same command the auto-update installer infers
11
+ * (`buildVpGlobalInstallCommand` — single source of truth), so there is no
12
+ * second place that can drift on the install incantation.
13
+ *
14
+ * Skipped (no-op, non-fatal) when:
15
+ * - `--dry-run` (no writes anywhere),
16
+ * - `WP_SKIP_AUTO_INSTALL=1` (the documented opt-out, surfaced in the update
17
+ * banner),
18
+ * - the running binary resolves into a webpresso source/git clone — a global
19
+ * install would clobber the developer's working clone with a published
20
+ * tarball (`detectGitInstall`),
21
+ * - `vp` is not on PATH (nothing to install with).
22
+ *
23
+ * A failed refresh is reported but NEVER fails consumer setup: keeping the
24
+ * global tool current is ancillary to scaffolding the consumer repo (same
25
+ * warn-only contract as the codex-cli scaffolder).
26
+ */
27
+ import { spawnSync } from 'node:child_process';
28
+ import { makeNoopSpinnerFactory } from '#cli/commands/init/scaffolders/spinner';
29
+ import { buildVpGlobalInstallCommand, detectGitInstall, PUBLIC_PACKAGE_NAME, } from '#cli/auto-update/detect-pm.js';
30
+ const NO_VP_HINT = 'vp (vite-plus) is not on PATH; cannot refresh the global ' +
31
+ `${PUBLIC_PACKAGE_NAME}. Install vite-plus, then re-run \`wp setup\`.`;
32
+ /**
33
+ * Refresh the single global `@webpresso/agent-kit` install via `vp install -g`.
34
+ */
35
+ export function ensureAgentKitGlobal(input) {
36
+ if (input.options.dryRun)
37
+ return { kind: 'agent-kit-global-skipped-dry-run' };
38
+ const env = input.env ?? process.env;
39
+ if (env.WP_SKIP_AUTO_INSTALL === '1') {
40
+ return { kind: 'agent-kit-global-skipped-opt-out' };
41
+ }
42
+ const argv1 = input.argv1 ?? process.argv[1] ?? '';
43
+ const detectGit = input.detectGit ?? detectGitInstall;
44
+ const sourceCloneRoot = argv1.length > 0 ? detectGit(argv1) : null;
45
+ if (sourceCloneRoot !== null) {
46
+ return { kind: 'agent-kit-global-skipped-source-clone', repoRoot: sourceCloneRoot };
47
+ }
48
+ const spawn = input.spawn ?? spawnSync;
49
+ const spinner = (input.spinnerFactory ?? makeNoopSpinnerFactory())('agent-kit-global');
50
+ const probe = spawn('vp', ['--version'], { encoding: 'utf8' });
51
+ if (probe.error || (probe.status !== null && probe.status !== 0)) {
52
+ return { kind: 'agent-kit-global-skipped-no-vp', hint: NO_VP_HINT };
53
+ }
54
+ const command = buildVpGlobalInstallCommand();
55
+ spinner.start();
56
+ const install = spawn(command[0], command.slice(1), { stdio: 'inherit' });
57
+ if (install.status !== 0) {
58
+ spinner.fail('agent-kit global refresh failed');
59
+ return { kind: 'agent-kit-global-failed', exitCode: install.status ?? -1, command };
60
+ }
61
+ spinner.succeed('agent-kit global up to date');
62
+ return { kind: 'agent-kit-global-updated', command };
63
+ }
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,15 @@
1
+ import type { CAC } from 'cac';
2
+ import type { SpawnSyncReturns } from 'node:child_process';
3
+ export declare const PACKAGE_MANAGER_VERBS: readonly ["install", "add", "remove", "update", "exec", "run"];
4
+ export type PackageManagerVerb = (typeof PACKAGE_MANAGER_VERBS)[number];
5
+ export interface PackageManagerCommandConfig {
6
+ readonly command: string;
7
+ readonly args: readonly string[];
8
+ }
9
+ export interface PackageManagerCommandDeps {
10
+ readonly run?: (command: string, args: readonly string[]) => SpawnSyncReturns<string>;
11
+ }
12
+ export declare function registerPackageManagerCommand(cli: CAC, verb: PackageManagerVerb): void;
13
+ export declare function buildPackageManagerCommand(verb: PackageManagerVerb, argv?: readonly string[]): PackageManagerCommandConfig;
14
+ export declare function runPackageManagerCommand(verb: PackageManagerVerb, deps?: PackageManagerCommandDeps): number;
15
+ //# sourceMappingURL=package-manager.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { getManagedRunner } from '#tool-runtime';
3
+ export const PACKAGE_MANAGER_VERBS = ['install', 'add', 'remove', 'update', 'exec', 'run'];
4
+ const HELP_BY_VERB = {
5
+ install: 'Install dependencies through the managed vp facade.',
6
+ add: 'Add dependencies through the managed vp facade.',
7
+ remove: 'Remove dependencies through the managed vp facade.',
8
+ update: 'Update dependencies through the managed vp facade.',
9
+ exec: 'Run a binary through the managed vp facade.',
10
+ run: 'Run a package script through the managed vp facade.',
11
+ };
12
+ export function registerPackageManagerCommand(cli, verb) {
13
+ cli
14
+ .command(`${verb} [...args]`, HELP_BY_VERB[verb])
15
+ .allowUnknownOptions()
16
+ .action(() => runPackageManagerCommand(verb));
17
+ }
18
+ export function buildPackageManagerCommand(verb, argv = process.argv) {
19
+ const resolution = getManagedRunner('vp', { outputPolicy: 'structured' });
20
+ return {
21
+ command: resolution.command,
22
+ args: [...resolution.args, verb, ...extractVerbArgs(verb, argv)],
23
+ };
24
+ }
25
+ export function runPackageManagerCommand(verb, deps = {}) {
26
+ const command = buildPackageManagerCommand(verb);
27
+ const result = (deps.run ?? defaultRun)(command.command, command.args);
28
+ return typeof result.status === 'number' ? result.status : 1;
29
+ }
30
+ function extractVerbArgs(verb, argv) {
31
+ const verbIndex = argv.findIndex((arg, index) => index >= 2 && arg === verb);
32
+ return verbIndex === -1 ? [] : argv.slice(verbIndex + 1);
33
+ }
34
+ function defaultRun(command, args) {
35
+ return spawnSync(command, [...args], {
36
+ encoding: 'utf8',
37
+ env: process.env,
38
+ stdio: 'inherit',
39
+ windowsHide: true,
40
+ });
41
+ }
42
+ //# sourceMappingURL=package-manager.js.map
@@ -2,6 +2,7 @@ import type { CommandConfig, TestCommandOptions } from '#test';
2
2
  import type { CAC } from 'cac';
3
3
  export declare const TEST_COMMAND_HELP: string;
4
4
  export interface AkTestCommandInput extends TestCommandOptions {
5
+ cwd?: string;
5
6
  package?: readonly string[] | string;
6
7
  file?: readonly string[] | string;
7
8
  targets?: readonly string[] | string;
@@ -14,7 +14,7 @@ export function createAkTestCommandConfig(input) {
14
14
  file: toArray(input.file),
15
15
  positional: toArray(input.targets),
16
16
  });
17
- return buildTestCommand(target, input);
17
+ return buildTestCommand(target, { ...input, cwd: input.cwd });
18
18
  }
19
19
  export function registerTestCommand(cli) {
20
20
  cli
@@ -35,6 +35,7 @@ export function registerTestCommand(cli) {
35
35
  .action((targets, flags) => {
36
36
  const rawArgv = process.argv.slice(2);
37
37
  const command = createAkTestCommandConfig({
38
+ cwd: process.cwd(),
38
39
  package: flags.package,
39
40
  file: flags.file,
40
41
  targets: targets ?? [],
@@ -1,6 +1,6 @@
1
+ import { getManagedRunner } from '#tool-runtime';
2
+ import { getPackageScript, isRecursiveWpScript } from '#cli/package-scripts.js';
1
3
  import { spawnSync } from 'node:child_process';
2
- import { existsSync, readFileSync } from 'node:fs';
3
- import { join } from 'node:path';
4
4
  export const TYPECHECK_COMMAND_HELP = [
5
5
  'Typecheck the current workspace through the portable wp surface.',
6
6
  '',
@@ -16,15 +16,18 @@ export function registerTypecheckCommand(cli) {
16
16
  }
17
17
  export function buildTypecheckCommand(options = {}) {
18
18
  const cwd = options.cwd ?? process.cwd();
19
- if (hasCheckTypesScript(cwd)) {
19
+ const checkTypesScript = getPackageScript(cwd, 'check-types');
20
+ if (checkTypesScript && !isRecursiveWpScript(checkTypesScript, 'typecheck')) {
21
+ const resolution = getManagedRunner('vp', { outputPolicy: 'structured' });
20
22
  return {
21
- command: 'vp',
22
- args: ['run', 'check-types'],
23
+ command: resolution.command,
24
+ args: [...resolution.args, 'run', 'check-types'],
23
25
  };
24
26
  }
27
+ const resolution = getManagedRunner('tsc', { outputPolicy: 'structured' });
25
28
  return {
26
- command: 'tsc',
27
- args: ['--noEmit', ...(options.pretty ? [] : ['--pretty', 'false'])],
29
+ command: resolution.command,
30
+ args: [...resolution.args, '--noEmit', ...(options.pretty ? [] : ['--pretty', 'false'])],
28
31
  };
29
32
  }
30
33
  export function runTypecheckCommand(options = {}, deps = {}) {
@@ -42,16 +45,4 @@ function defaultRun(command, args) {
42
45
  windowsHide: true,
43
46
  });
44
47
  }
45
- function hasCheckTypesScript(cwd) {
46
- const packageJsonPath = join(cwd, 'package.json');
47
- if (!existsSync(packageJsonPath))
48
- return false;
49
- try {
50
- const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
51
- return typeof parsed.scripts?.['check-types'] === 'string';
52
- }
53
- catch {
54
- return false;
55
- }
56
- }
57
48
  //# sourceMappingURL=typecheck.js.map
@@ -0,0 +1,12 @@
1
+ export interface PackageJsonLike {
2
+ readonly scripts?: Record<string, unknown>;
3
+ readonly dependencies?: Record<string, unknown>;
4
+ readonly devDependencies?: Record<string, unknown>;
5
+ readonly optionalDependencies?: Record<string, unknown>;
6
+ }
7
+ export declare function readPackageJson(cwd: string): PackageJsonLike | undefined;
8
+ export declare function getPackageScript(cwd: string, name: string): string | undefined;
9
+ export declare function packageHasDependency(cwd: string, dependencyName: string): boolean;
10
+ export declare function packageUsesVitest(cwd: string): boolean;
11
+ export declare function isRecursiveWpScript(script: string, verb: string): boolean;
12
+ //# sourceMappingURL=package-scripts.d.ts.map
@@ -0,0 +1,59 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ export function readPackageJson(cwd) {
4
+ const packageJsonPath = join(cwd, 'package.json');
5
+ if (!existsSync(packageJsonPath))
6
+ return;
7
+ try {
8
+ const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
9
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
10
+ return;
11
+ return parsed;
12
+ }
13
+ catch {
14
+ return;
15
+ }
16
+ }
17
+ export function getPackageScript(cwd, name) {
18
+ const parsed = readPackageJson(cwd);
19
+ const candidate = parsed?.scripts?.[name];
20
+ return typeof candidate === 'string' ? candidate : undefined;
21
+ }
22
+ export function packageHasDependency(cwd, dependencyName) {
23
+ const parsed = readPackageJson(cwd);
24
+ if (!parsed)
25
+ return false;
26
+ return ['dependencies', 'devDependencies', 'optionalDependencies'].some((section) => {
27
+ const dependencies = parsed[section];
28
+ return Boolean(dependencies &&
29
+ typeof dependencies === 'object' &&
30
+ !Array.isArray(dependencies) &&
31
+ dependencyName in dependencies);
32
+ });
33
+ }
34
+ export function packageUsesVitest(cwd) {
35
+ return packageHasDependency(cwd, 'vitest');
36
+ }
37
+ export function isRecursiveWpScript(script, verb) {
38
+ const normalized = stripLeadingEnvAssignments(script.trim());
39
+ if (!normalized)
40
+ return false;
41
+ const patterns = [
42
+ new RegExp(`^(?:vp\\s+exec\\s+)?wp\\s+${escapeRegExp(verb)}(?:\\s|$)`),
43
+ new RegExp(`^(?:bunx?|npx)\\s+(?:--yes\\s+)?(?:@webpresso/agent-kit\\s+)?wp\\s+${escapeRegExp(verb)}(?:\\s|$)`),
44
+ ];
45
+ return patterns.some((pattern) => pattern.test(normalized));
46
+ }
47
+ function stripLeadingEnvAssignments(input) {
48
+ let remaining = input.replace(/^env\s+/u, '');
49
+ while (true) {
50
+ const next = remaining.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S+)\s+)/u, '');
51
+ if (next === remaining)
52
+ return remaining.trim();
53
+ remaining = next;
54
+ }
55
+ }
56
+ function escapeRegExp(value) {
57
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
58
+ }
59
+ //# sourceMappingURL=package-scripts.js.map
@@ -5,8 +5,9 @@
5
5
  * unknown-command formatting) and webpresso/packages/cli/cli-utils
6
6
  * (getProjectRoot) so this package has no @webpresso/* runtime dependencies.
7
7
  */
8
- import { existsSync, readFileSync } from 'node:fs';
9
8
  import path from 'node:path';
9
+ import { existsSync } from 'node:fs';
10
+ import { readOwnedPackageVersion } from '#runtime/package-version.js';
10
11
  // ---------------------------------------------------------------------------
11
12
  // Project root resolution
12
13
  // ---------------------------------------------------------------------------
@@ -131,26 +132,6 @@ export function formatUnknownCommandError(input, commands, binName = 'wp') {
131
132
  * having to know how many `..` segments to append.
132
133
  */
133
134
  export function readPackageVersion(metaUrl) {
134
- const url = new URL(metaUrl);
135
- let dir = path.dirname(url.pathname);
136
- for (let i = 0; i < 6; i++) {
137
- const candidate = path.join(dir, 'package.json');
138
- if (existsSync(candidate)) {
139
- try {
140
- const parsed = JSON.parse(readFileSync(candidate, 'utf-8'));
141
- if (parsed.name === 'webpresso') {
142
- return parsed.version ?? '0.0.0';
143
- }
144
- }
145
- catch {
146
- // keep walking
147
- }
148
- }
149
- const parent = path.dirname(dir);
150
- if (parent === dir)
151
- break;
152
- dir = parent;
153
- }
154
- return '0.0.0';
135
+ return readOwnedPackageVersion(metaUrl);
155
136
  }
156
137
  //# sourceMappingURL=utils.js.map
@@ -0,0 +1,14 @@
1
+ import type { CAC } from 'cac';
2
+ import { type LoadWpExtensionsOptions, type WpExtensionAliasV1 } from '#wp-extension';
3
+ export interface RegisterWpExtensionsOptions extends LoadWpExtensionsOptions {
4
+ readonly cli: CAC;
5
+ readonly baseCommands: readonly string[];
6
+ }
7
+ export interface RegisteredWpExtensions {
8
+ readonly aliasMap: ReadonlyMap<string, WpExtensionAliasV1>;
9
+ readonly warnings: readonly string[];
10
+ readonly commandNames: readonly string[];
11
+ }
12
+ export declare function registerWpExtensions(options: RegisterWpExtensionsOptions): Promise<RegisteredWpExtensions>;
13
+ export declare function resolveWpCommandAlias(command: string | undefined, aliasMap: ReadonlyMap<string, WpExtensionAliasV1>): string | undefined;
14
+ //# sourceMappingURL=wp-extensions.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { loadWpExtensions, resolveAcceptedExtensionAliases, } from '#wp-extension';
2
+ export async function registerWpExtensions(options) {
3
+ const loaded = await loadWpExtensions(options);
4
+ const warnings = loaded.flatMap((entry) => entry.warnings);
5
+ const commandNames = [];
6
+ const blockedCommandNames = new Set(options.baseCommands);
7
+ const registeredCommandNames = new Set();
8
+ for (const extension of loaded) {
9
+ if (!extension.extension || !extension.compatible || !extension.detected)
10
+ continue;
11
+ for (const command of extension.extension.commands) {
12
+ if (blockedCommandNames.has(command.name)) {
13
+ warnings.push(`${extension.packageName}: skipped command "${command.name}" because it collides with an existing command`);
14
+ continue;
15
+ }
16
+ command.register(options.cli);
17
+ commandNames.push(command.name);
18
+ blockedCommandNames.add(command.name);
19
+ registeredCommandNames.add(command.name);
20
+ }
21
+ }
22
+ const aliasResolution = resolveAcceptedExtensionAliases(loaded, options.baseCommands, registeredCommandNames);
23
+ return {
24
+ aliasMap: aliasResolution.aliases,
25
+ warnings: [...warnings, ...aliasResolution.warnings],
26
+ commandNames,
27
+ };
28
+ }
29
+ export function resolveWpCommandAlias(command, aliasMap) {
30
+ if (!command)
31
+ return command;
32
+ return aliasMap.get(command)?.commandName ?? command;
33
+ }
34
+ //# sourceMappingURL=wp-extensions.js.map
@@ -46,8 +46,8 @@ export declare const implementationStatus: z.ZodEnum<{
46
46
  completed: "completed";
47
47
  draft: "draft";
48
48
  planned: "planned";
49
- "in-progress": "in-progress";
50
49
  parked: "parked";
50
+ "in-progress": "in-progress";
51
51
  archived: "archived";
52
52
  current: "current";
53
53
  complete: "complete";