@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +93 -66
- package/bin/_run.js +143 -1
- package/bin/runtime-manifest.json +40 -0
- package/catalog/AGENTS.md.tpl +7 -6
- package/catalog/agent/commands/plan-refine.md +3 -3
- package/catalog/agent/commands/pll.md +2 -0
- package/catalog/agent/guides/parallel-execution.md +2 -0
- package/catalog/agent/rules/extraction-parity.md +27 -1
- package/catalog/agent/rules/public-package-safety.md +24 -1
- package/catalog/agent/skills/plan-refine/SKILL.md +5 -4
- package/catalog/agent/skills/pll/SKILL.md +1 -0
- package/catalog/base-kit/.github/workflows/ci.webpresso.yml.tmpl +33 -0
- package/catalog/base-kit/commitlint.config.ts.tmpl +1 -3
- package/catalog/base-kit/e2e/fixtures/smoke.html.tmpl +13 -0
- package/catalog/base-kit/e2e/smoke.spec.ts.tmpl +13 -0
- package/catalog/base-kit/oxlint.config.ts.tmpl +26 -0
- package/catalog/base-kit/playwright.config.ts.tmpl +10 -0
- package/catalog/base-kit/src/quality-sample.test.ts.tmpl +19 -0
- package/catalog/base-kit/src/quality-sample.ts.tmpl +11 -0
- package/catalog/base-kit/stryker.config.ts.tmpl +14 -0
- package/catalog/base-kit/tsconfig.json.tmpl +9 -0
- package/catalog/base-kit/vitest.config.ts.tmpl +10 -0
- package/catalog/docs/templates/adr.md +1 -1
- package/catalog/docs/templates/blueprint.md +2 -0
- package/catalog/docs/templates/blueprint.yaml +16 -15
- package/catalog/docs/templates/guide.md +1 -1
- package/catalog/docs/templates/postmortem.md +1 -1
- package/catalog/docs/templates/research.md +1 -1
- package/catalog/docs/templates/runbook.md +1 -1
- package/catalog/docs/templates/system.md +12 -3
- package/catalog/docs/templates/tech-debt.md +1 -0
- package/commands/blueprint.md +10 -12
- package/dist/esm/audit/blueprint-db-consistency.d.ts +1 -1
- package/dist/esm/audit/blueprint-db-consistency.js +6 -8
- package/dist/esm/audit/blueprint-lifecycle-sql.js +10 -3
- package/dist/esm/audit/cloudflare-deploy-contract.d.ts +3 -0
- package/dist/esm/audit/cloudflare-deploy-contract.js +64 -0
- package/dist/esm/audit/no-legacy-cli-bin.d.ts +3 -0
- package/dist/esm/audit/no-legacy-cli-bin.js +100 -0
- package/dist/esm/audit/package-surface.js +14 -1
- package/dist/esm/audit/repo-guardrails.js +40 -13
- package/dist/esm/audit/resolve-audit-script.d.ts +24 -0
- package/dist/esm/audit/resolve-audit-script.js +27 -0
- package/dist/esm/audit/roadmap-links.js +23 -10
- package/dist/esm/blueprint/core/schema.d.ts +8 -8
- package/dist/esm/blueprint/core/schema.js +2 -2
- package/dist/esm/blueprint/db/enums.d.ts +1 -1
- package/dist/esm/blueprint/db/ingester.js +18 -10
- package/dist/esm/blueprint/index.d.ts +0 -1
- package/dist/esm/blueprint/index.js +0 -2
- package/dist/esm/blueprint/lifecycle/audit.js +9 -2
- package/dist/esm/blueprint/lifecycle/local.js +15 -4
- package/dist/esm/blueprint/local.d.ts +0 -3
- package/dist/esm/blueprint/local.js +0 -2
- package/dist/esm/blueprint/service/BlueprintCreationService.js +16 -8
- package/dist/esm/blueprint/service/BlueprintService.js +37 -19
- package/dist/esm/blueprint/service/scanner.js +73 -9
- package/dist/esm/blueprint/tracked-document/schema.d.ts +2 -2
- package/dist/esm/blueprint/utils/document-paths.d.ts +23 -0
- package/dist/esm/blueprint/utils/document-paths.js +91 -0
- package/dist/esm/blueprint/utils/package-assets.d.ts +11 -0
- package/dist/esm/blueprint/utils/package-assets.js +33 -4
- package/dist/esm/build/package-manifest.js +7 -0
- package/dist/esm/build/release-policy.d.ts +27 -0
- package/dist/esm/build/release-policy.js +29 -0
- package/dist/esm/build/runtime-targets.d.ts +13 -0
- package/dist/esm/build/runtime-targets.js +48 -0
- package/dist/esm/build/sync-catalog-doc-templates.d.ts +23 -0
- package/dist/esm/build/sync-catalog-doc-templates.js +93 -0
- package/dist/esm/cli/auto-update/detect-pm.d.ts +15 -0
- package/dist/esm/cli/auto-update/detect-pm.js +24 -9
- package/dist/esm/cli/auto-update/skip.js +9 -1
- package/dist/esm/cli/bundle/agent-command-inventory.d.ts +120 -0
- package/dist/esm/cli/bundle/agent-command-inventory.js +100 -0
- package/dist/esm/cli/bundle/index.d.ts +17 -0
- package/dist/esm/cli/bundle/index.js +15 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +49 -5
- package/dist/esm/cli/commands/audit-core.d.ts +1 -1
- package/dist/esm/cli/commands/audit.js +4 -7
- package/dist/esm/cli/commands/blueprint/router.js +16 -10
- package/dist/esm/cli/commands/blueprint/template-resolver.js +8 -4
- package/dist/esm/cli/commands/hook.d.ts +8 -0
- package/dist/esm/cli/commands/hook.js +47 -0
- package/dist/esm/cli/commands/init/host-visibility.js +4 -2
- package/dist/esm/cli/commands/init/index.js +80 -7
- package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +12 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +142 -7
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/codex-ownership.js +9 -1
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +130 -20
- package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.d.ts +65 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.js +64 -0
- package/dist/esm/cli/commands/package-manager.d.ts +15 -0
- package/dist/esm/cli/commands/package-manager.js +42 -0
- package/dist/esm/cli/commands/test.d.ts +1 -0
- package/dist/esm/cli/commands/test.js +2 -1
- package/dist/esm/cli/commands/typecheck.js +10 -19
- package/dist/esm/cli/package-scripts.d.ts +12 -0
- package/dist/esm/cli/package-scripts.js +59 -0
- package/dist/esm/cli/utils.js +3 -22
- package/dist/esm/cli/wp-extensions.d.ts +14 -0
- package/dist/esm/cli/wp-extensions.js +34 -0
- package/dist/esm/config/docs-lint/schemas/common.d.ts +1 -1
- package/dist/esm/config/docs-lint/schemas/implementation-plan.d.ts +2 -2
- package/dist/esm/config/docs-lint/schemas/parent-roadmap.d.ts +1 -1
- package/dist/esm/config/stryker/index.d.ts +85 -0
- package/dist/esm/config/stryker/index.js +31 -0
- package/dist/esm/e2e/command-builder.js +35 -7
- package/dist/esm/e2e/config.d.ts +56 -0
- package/dist/esm/e2e/config.js +114 -0
- package/dist/esm/e2e/execution.js +8 -0
- package/dist/esm/e2e/run-planner.js +2 -0
- package/dist/esm/e2e/types.d.ts +3 -0
- package/dist/esm/format/index.js +5 -1
- package/dist/esm/hooks/guard-switch/index.d.ts +1 -1
- package/dist/esm/hooks/guard-switch/index.js +22 -14
- package/dist/esm/hooks/post-tool/lint-after-edit.d.ts +1 -0
- package/dist/esm/hooks/post-tool/lint-after-edit.js +5 -2
- package/dist/esm/hooks/pretool-guard/validators/file-conventions.js +1 -1
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.d.ts +6 -0
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +27 -2
- package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +2 -1
- package/dist/esm/hooks/pretool-guard/validators/path-contract.js +59 -34
- package/dist/esm/hooks/pretool-guard/validators/plan-frontmatter.js +3 -3
- package/dist/esm/hooks/shared/routing-block.js +18 -4
- package/dist/esm/hooks/shared/validators/blueprint.js +3 -0
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +1 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +5 -2
- package/dist/esm/lint/index.js +3 -1
- package/dist/esm/mcp/auto-discover.d.ts +2 -0
- package/dist/esm/mcp/auto-discover.js +14 -6
- package/dist/esm/mcp/blueprint-server.js +379 -80
- package/dist/esm/mcp/cli.js +21 -0
- package/dist/esm/mcp/runners/test.js +15 -0
- package/dist/esm/mcp/server.d.ts +7 -0
- package/dist/esm/mcp/server.js +16 -27
- package/dist/esm/mcp/tools/_registry.d.ts +3 -0
- package/dist/esm/mcp/tools/_registry.js +21 -0
- package/dist/esm/mcp/tools/audit.d.ts +1 -0
- package/dist/esm/mcp/tools/audit.js +13 -8
- package/dist/esm/mcp/tools/typecheck.js +4 -2
- package/dist/esm/mutation/affected.d.ts +9 -0
- package/dist/esm/mutation/affected.js +36 -0
- package/dist/esm/package.json +8 -0
- package/dist/esm/runtime/package-version.d.ts +2 -0
- package/dist/esm/runtime/package-version.js +43 -0
- package/dist/esm/test/command-builder.d.ts +4 -0
- package/dist/esm/test/command-builder.js +28 -3
- package/dist/esm/test-helpers/hermetic-env.d.ts +25 -0
- package/dist/esm/test-helpers/hermetic-env.js +31 -0
- package/dist/esm/tool-runtime/index.d.ts +5 -0
- package/dist/esm/tool-runtime/index.js +24 -0
- package/dist/esm/tool-runtime/resolve-runner.d.ts +16 -0
- package/dist/esm/tool-runtime/resolve-runner.js +42 -0
- package/dist/esm/typecheck/index.js +4 -2
- package/dist/esm/wp-extension/index.d.ts +50 -0
- package/dist/esm/wp-extension/index.js +268 -0
- package/package.json +75 -46
- package/skills/plan-refine/SKILL.md +5 -4
- package/skills/pll/SKILL.md +1 -0
- package/dist/esm/blueprint/dag/cycle-detector.d.ts +0 -12
- package/dist/esm/blueprint/dag/cycle-detector.js +0 -46
- package/dist/esm/blueprint/dag/executor.d.ts +0 -140
- package/dist/esm/blueprint/dag/executor.js +0 -292
- package/dist/esm/blueprint/dag/index.d.ts +0 -20
- package/dist/esm/blueprint/dag/index.js +0 -17
- package/dist/esm/blueprint/dag/interfaces.d.ts +0 -56
- package/dist/esm/blueprint/dag/interfaces.js +0 -13
- package/dist/esm/blueprint/dag/local/independence.d.ts +0 -107
- package/dist/esm/blueprint/dag/local/independence.js +0 -231
- package/dist/esm/blueprint/dag/local/index.d.ts +0 -14
- package/dist/esm/blueprint/dag/local/index.js +0 -14
- package/dist/esm/blueprint/dag/local/package-graph.d.ts +0 -66
- package/dist/esm/blueprint/dag/local/package-graph.js +0 -148
- package/dist/esm/blueprint/dag/plan-parser.d.ts +0 -54
- package/dist/esm/blueprint/dag/plan-parser.js +0 -236
- package/dist/esm/blueprint/dag/task-graph-algorithms.d.ts +0 -13
- package/dist/esm/blueprint/dag/task-graph-algorithms.js +0 -236
- package/dist/esm/blueprint/dag/task-graph.d.ts +0 -171
- package/dist/esm/blueprint/dag/task-graph.js +0 -370
- package/dist/esm/blueprint/dag/types.d.ts +0 -17
- package/dist/esm/blueprint/dag/types.js +0 -2
- package/dist/esm/blueprint/graph/index.d.ts +0 -5
- package/dist/esm/blueprint/graph/index.js +0 -5
- package/dist/esm/blueprint/graph/mermaid-parser.d.ts +0 -3
- package/dist/esm/blueprint/graph/mermaid-parser.js +0 -93
- package/dist/esm/blueprint/graph/mermaid-serializer.d.ts +0 -3
- package/dist/esm/blueprint/graph/mermaid-serializer.js +0 -20
- package/dist/esm/blueprint/graph/schema.d.ts +0 -89
- package/dist/esm/blueprint/graph/schema.js +0 -104
- package/dist/esm/blueprint/graph/task-graph-adapter.d.ts +0 -6
- package/dist/esm/blueprint/graph/task-graph-adapter.js +0 -30
|
@@ -5,8 +5,9 @@ import { parseBlueprintForDb } from '#db/parser/blueprint-db-parser';
|
|
|
5
5
|
import { blueprintToSpecKit } from '#export/spec-kit/index';
|
|
6
6
|
import { getProjectRoot } from '#cli/utils';
|
|
7
7
|
import { resolveBlueprintRoot } from '#utils/blueprint-root';
|
|
8
|
+
import { getBlueprintDocumentPaths } from '#utils/document-paths.js';
|
|
8
9
|
import { applyBlueprintLifecycleToFile, BlueprintCreationService, BlueprintService, complexitySchema, relativeBlueprintSlug, parseBlueprint, planStatusSchema, runBlueprintAudit, resolveBlueprintFile, serializeBlueprint, validateAllTasksDone, } from '#local';
|
|
9
|
-
import {
|
|
10
|
+
import { resolvePackageAssetPreferred } from '#utils/package-assets';
|
|
10
11
|
import { describeBlueprintExecutionRuntime, buildBlueprintLaunchSpec, buildStoppedRuntimeEvidence, controlBlueprintExecution, initializeBlueprintExecutionProgressBridge, launchBlueprintExecution, persistBlueprintExecutionArtifacts, persistBlueprintExecutionMetadata, recordLaunchFailure, reconcileBlueprintRuntimeSnapshot, readBlueprintExecutionState, syncBlueprintExecutionProgress, writeBlueprintRuntimeSnapshot, } from './execution.js';
|
|
11
12
|
import { advanceTask as advanceTaskMutation, finalizeBlueprint as finalizeBlueprintMutation, promoteBlueprint as promoteBlueprintMutation, } from './mutations.js';
|
|
12
13
|
import { BlueprintAuditFailedError, executeBlueprintSubcommand } from './router-dispatch.js';
|
|
@@ -40,7 +41,10 @@ function assertBlueprintCanMoveToStatus(blueprint, nextStatus) {
|
|
|
40
41
|
* when the lookup fails in unrelated contexts (e.g. `wp --help`).
|
|
41
42
|
*/
|
|
42
43
|
function resolveRepoBlueprintTemplatePath() {
|
|
43
|
-
return
|
|
44
|
+
return resolvePackageAssetPreferred([
|
|
45
|
+
'docs/templates/blueprint.md',
|
|
46
|
+
'catalog/docs/templates/blueprint.md',
|
|
47
|
+
]);
|
|
44
48
|
}
|
|
45
49
|
function todayIsoDate() {
|
|
46
50
|
return new Date().toISOString().split('T')[0] ?? new Date().toISOString();
|
|
@@ -306,10 +310,12 @@ export async function moveBlueprint(slug, status, options = {}) {
|
|
|
306
310
|
const projectRoot = resolveProjectRoot(options.projectRoot);
|
|
307
311
|
const nextStatus = normalizeBlueprintStatus(status);
|
|
308
312
|
const location = await resolveBlueprintLocation(slug, projectRoot);
|
|
313
|
+
const isFlatFile = path.basename(location.path) !== '_overview.md';
|
|
309
314
|
const sourceDir = path.dirname(location.path);
|
|
310
|
-
const
|
|
311
|
-
const
|
|
312
|
-
|
|
315
|
+
const targetPaths = getBlueprintDocumentPaths(resolveBlueprintRoot(projectRoot), nextStatus, relativeBlueprintSlug(location.slug));
|
|
316
|
+
const targetDir = targetPaths.directory;
|
|
317
|
+
const targetPath = isFlatFile ? targetPaths.flat : targetPaths.folder;
|
|
318
|
+
if (location.path === targetPath && location.blueprint.status === nextStatus) {
|
|
313
319
|
return {
|
|
314
320
|
fromPath: location.path,
|
|
315
321
|
fromStatus: location.blueprint.status,
|
|
@@ -325,18 +331,18 @@ export async function moveBlueprint(slug, status, options = {}) {
|
|
|
325
331
|
throw new Error('Blueprint move is recovery-only. Use wp blueprint start/task/finalize for normal lifecycle changes, or pass --force-recovery.');
|
|
326
332
|
}
|
|
327
333
|
assertBlueprintCanMoveToStatus(location.blueprint, nextStatus);
|
|
328
|
-
if (
|
|
329
|
-
await mkdir(path.dirname(
|
|
330
|
-
await rename(sourceDir, targetDir);
|
|
334
|
+
if (location.path !== targetPath) {
|
|
335
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
336
|
+
await rename(isFlatFile ? location.path : sourceDir, isFlatFile ? targetPath : targetDir);
|
|
331
337
|
}
|
|
332
338
|
const updated = await writeBlueprintWithStatus(targetPath, location.blueprint, nextStatus);
|
|
333
339
|
return {
|
|
334
340
|
fromPath: location.path,
|
|
335
341
|
fromStatus: location.blueprint.status,
|
|
336
|
-
message:
|
|
342
|
+
message: location.path === targetPath
|
|
337
343
|
? `Updated blueprint ${location.slug} to ${nextStatus}.`
|
|
338
344
|
: `Moved blueprint ${location.slug} to ${nextStatus}.`,
|
|
339
|
-
moved:
|
|
345
|
+
moved: location.path !== targetPath,
|
|
340
346
|
slug: location.slug,
|
|
341
347
|
toPath: targetPath,
|
|
342
348
|
toStatus: nextStatus,
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { readdirSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { resolvePackageAssetPreferred } from '#utils/package-assets.js';
|
|
4
4
|
/**
|
|
5
|
-
* Default templates directory: docs/templates/
|
|
6
|
-
*
|
|
5
|
+
* Default templates directory: docs/templates/ in a source checkout, falling
|
|
6
|
+
* back to the shipped catalog/docs/templates/ in the published package (same
|
|
7
|
+
* strategy as resolveRepoBlueprintTemplatePath in router.ts).
|
|
7
8
|
*/
|
|
8
9
|
function defaultTemplatesDir() {
|
|
9
|
-
return path.dirname(
|
|
10
|
+
return path.dirname(resolvePackageAssetPreferred([
|
|
11
|
+
'docs/templates/blueprint.md',
|
|
12
|
+
'catalog/docs/templates/blueprint.md',
|
|
13
|
+
]));
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* List available templates from `templatesDir` (defaults to docs/templates/).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CAC } from 'cac';
|
|
2
|
+
declare const HOOK_NAMES: readonly ["pretool-guard", "post-tool", "stop-qa", "guard-switch", "sessionstart-routing"];
|
|
3
|
+
export type HookName = (typeof HOOK_NAMES)[number];
|
|
4
|
+
export declare function isHookName(value: string): value is HookName;
|
|
5
|
+
export declare function runHookCommand(name: string): Promise<void>;
|
|
6
|
+
export declare function registerHookCommand(cli: CAC): void;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const HOOK_NAMES = [
|
|
2
|
+
'pretool-guard',
|
|
3
|
+
'post-tool',
|
|
4
|
+
'stop-qa',
|
|
5
|
+
'guard-switch',
|
|
6
|
+
'sessionstart-routing',
|
|
7
|
+
];
|
|
8
|
+
const HOOK_HANDLERS = {
|
|
9
|
+
'pretool-guard': async () => {
|
|
10
|
+
const { main } = await import('#hooks/pretool-guard/index');
|
|
11
|
+
await main();
|
|
12
|
+
},
|
|
13
|
+
'post-tool': async () => {
|
|
14
|
+
const { main } = await import('#hooks/post-tool/lint-after-edit');
|
|
15
|
+
await main();
|
|
16
|
+
},
|
|
17
|
+
'stop-qa': async () => {
|
|
18
|
+
const { main } = await import('#hooks/stop/qa-changed-files');
|
|
19
|
+
await main();
|
|
20
|
+
},
|
|
21
|
+
'guard-switch': async () => {
|
|
22
|
+
const { main } = await import('#hooks/guard-switch/index');
|
|
23
|
+
await main();
|
|
24
|
+
},
|
|
25
|
+
'sessionstart-routing': async () => {
|
|
26
|
+
const { main } = await import('#hooks/sessionstart/index');
|
|
27
|
+
await main();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export function isHookName(value) {
|
|
31
|
+
return value in HOOK_HANDLERS;
|
|
32
|
+
}
|
|
33
|
+
export async function runHookCommand(name) {
|
|
34
|
+
if (!isHookName(name)) {
|
|
35
|
+
throw new Error(`Unknown hook "${name}". Expected one of: ${HOOK_NAMES.join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
await HOOK_HANDLERS[name]();
|
|
38
|
+
}
|
|
39
|
+
export function registerHookCommand(cli) {
|
|
40
|
+
cli
|
|
41
|
+
.command('hook <name>', 'Run an internal plugin hook entrypoint')
|
|
42
|
+
.action(async (name) => {
|
|
43
|
+
await runHookCommand(name);
|
|
44
|
+
return 0;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -5,6 +5,8 @@ export const AGENT_HOSTS = ['codex', 'claude', 'opencode'];
|
|
|
5
5
|
export const REQUIRED_CORE_CAPABILITIES = ['verify', 'plan-refine'];
|
|
6
6
|
export const VISIBILITY_STATUSES = ['visible-now', 'visible-after-restart', 'not-visible'];
|
|
7
7
|
export function parseAgentHosts(value) {
|
|
8
|
+
if (value?.trim() === 'none')
|
|
9
|
+
return [];
|
|
8
10
|
if (!value || value.trim().length === 0 || value.trim() === 'all')
|
|
9
11
|
return [...AGENT_HOSTS];
|
|
10
12
|
const out = [];
|
|
@@ -19,7 +21,7 @@ export function parseAgentHosts(value) {
|
|
|
19
21
|
unknown.push(token);
|
|
20
22
|
}
|
|
21
23
|
if (unknown.length > 0) {
|
|
22
|
-
throw new Error(`Unknown host(s): ${unknown.join(', ')}. Expected one of: ${AGENT_HOSTS.join(', ')}, all.`);
|
|
24
|
+
throw new Error(`Unknown host(s): ${unknown.join(', ')}. Expected one of: ${AGENT_HOSTS.join(', ')}, all, none.`);
|
|
23
25
|
}
|
|
24
26
|
return [...new Set(out)];
|
|
25
27
|
}
|
|
@@ -54,7 +56,7 @@ export function hostSkillRoots(repoRoot, host, homeDir = homedir()) {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
export function auditHostSkillVisibility(input) {
|
|
57
|
-
const selectedHosts = input.hosts
|
|
59
|
+
const selectedHosts = input.hosts ? [...input.hosts] : [...AGENT_HOSTS];
|
|
58
60
|
const requiredCapabilities = input.requiredCapabilities && input.requiredCapabilities.length > 0
|
|
59
61
|
? [...input.requiredCapabilities]
|
|
60
62
|
: [...REQUIRED_CORE_CAPABILITIES];
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* config keys, and generated surfaces it owns while leaving consumer-owned
|
|
7
7
|
* divergent files untouched unless `--overwrite` is passed.
|
|
8
8
|
*/
|
|
9
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
10
|
import { basename, dirname, join, relative } from 'node:path';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
12
|
import { isTelemetryEnabled, reportTthw } from '#telemetry/setup-tthw';
|
|
@@ -26,10 +26,11 @@ import { GENERATED_PATHS_BLOCK, patchGitignore } from './gitignore-patcher.js';
|
|
|
26
26
|
import { scaffoldAgentsMd } from './scaffold-agents-md.js';
|
|
27
27
|
import { scaffoldBlueprints } from './scaffold-blueprints.js';
|
|
28
28
|
import { scaffoldDocs } from './scaffold-docs.js';
|
|
29
|
-
import { scaffoldBaseKit } from './scaffold-base-kit.js';
|
|
29
|
+
import { BASE_KIT_QUALITY_TARGETS, collectRuntimeContractGuidance, scaffoldBaseKit, } from './scaffold-base-kit.js';
|
|
30
30
|
import { scaffoldMonorepoNav } from './scaffold-monorepo-nav.js';
|
|
31
31
|
import { REQUIRED_CORE_CAPABILITIES, auditHostSkillVisibility, parseAgentHosts, serializeHostVisibility, summarizeHostVisibility, } from './host-visibility.js';
|
|
32
32
|
import { scaffoldAgentHooks, trustCodexWebpressoHooksForRepo, trustCodexPresetHooksForUser, } from './scaffolders/agent-hooks/index.js';
|
|
33
|
+
import { ensureAgentKitGlobal } from './scaffolders/agent-kit-global/index.js';
|
|
33
34
|
import { scaffoldAuditHooks } from './scaffolders/audit-hooks/index.js';
|
|
34
35
|
import { ensureClaudeCodeUserPlugin } from './scaffolders/claude-plugin/index.js';
|
|
35
36
|
import { scaffoldClaudeRules } from './scaffolders/claude-rules/index.js';
|
|
@@ -103,6 +104,31 @@ function inferBlueprintsDirOverride(repoRoot, existingConfig) {
|
|
|
103
104
|
}
|
|
104
105
|
return relativePath;
|
|
105
106
|
}
|
|
107
|
+
function readPackageJsonSafe(repoRoot) {
|
|
108
|
+
const packageJsonPath = join(repoRoot, 'package.json');
|
|
109
|
+
if (!existsSync(packageJsonPath)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
return JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function printRuntimeContractGuidance(packageJson) {
|
|
120
|
+
const guidance = collectRuntimeContractGuidance(packageJson);
|
|
121
|
+
console.log('\nRuntime-owned tooling contract:');
|
|
122
|
+
console.log(' wp now owns execution for test, e2e, lint, format, and typecheck.');
|
|
123
|
+
console.log(' Keep local dependencies that your tests, configs, or tsconfig types import directly.');
|
|
124
|
+
if (guidance.keepLocalAuthoringDeps.length > 0) {
|
|
125
|
+
console.log(` Keep local authoring deps when imported directly: ${guidance.keepLocalAuthoringDeps.join(', ')}`);
|
|
126
|
+
}
|
|
127
|
+
if (guidance.reviewForRemovalDeps.length > 0) {
|
|
128
|
+
console.log(` Review execution-only deps for removal if they only powered local binaries: ${guidance.reviewForRemovalDeps.join(', ')}`);
|
|
129
|
+
}
|
|
130
|
+
console.log(' Do not blanket-remove devDependencies just because wp can execute the tool.');
|
|
131
|
+
}
|
|
106
132
|
export async function runInit(flags) {
|
|
107
133
|
const startMs = Date.now();
|
|
108
134
|
const cwd = flags.cwd ?? process.cwd();
|
|
@@ -470,6 +496,37 @@ export async function runInit(flags) {
|
|
|
470
496
|
console.log(` codex webpresso mcp: ⚠ no install root found (checked ${webpressoMcpResult.checked.length} paths). Install webpresso globally (\`bun add -g webpresso\`) or via the Claude plugin to wire up codex MCP.`);
|
|
471
497
|
break;
|
|
472
498
|
}
|
|
499
|
+
// Self-update the ONE globally-distributed agent-kit binary (PATH `wp`,
|
|
500
|
+
// plugin MCP, hooks all resolve to it), mirroring omx/omc/codex/claude.
|
|
501
|
+
// Non-fatal: a failed refresh never fails consumer setup, and it skips
|
|
502
|
+
// cleanly on a source/git clone, on `WP_SKIP_AUTO_INSTALL=1`, and in CI.
|
|
503
|
+
if (isCiEnvironment) {
|
|
504
|
+
console.log(' agent-kit global: - skipped (CI environment)');
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
const agentKitGlobalResult = ensureAgentKitGlobal({ options });
|
|
508
|
+
switch (agentKitGlobalResult.kind) {
|
|
509
|
+
case 'agent-kit-global-updated':
|
|
510
|
+
console.log(' agent-kit global: ✓ refreshed via vp install -g');
|
|
511
|
+
break;
|
|
512
|
+
case 'agent-kit-global-skipped-dry-run':
|
|
513
|
+
console.log(' agent-kit global: skipped (--dry-run)');
|
|
514
|
+
break;
|
|
515
|
+
case 'agent-kit-global-skipped-opt-out':
|
|
516
|
+
console.log(' agent-kit global: skipped (WP_SKIP_AUTO_INSTALL=1)');
|
|
517
|
+
break;
|
|
518
|
+
case 'agent-kit-global-skipped-source-clone':
|
|
519
|
+
console.log(` agent-kit global: - skipped (running from source clone ${agentKitGlobalResult.repoRoot})`);
|
|
520
|
+
break;
|
|
521
|
+
case 'agent-kit-global-skipped-no-vp':
|
|
522
|
+
console.warn(` agent-kit global: ⚠ ${agentKitGlobalResult.hint}`);
|
|
523
|
+
break;
|
|
524
|
+
case 'agent-kit-global-failed':
|
|
525
|
+
console.warn(` agent-kit global: ⚠ \`${agentKitGlobalResult.command.join(' ')}\` exited with ${agentKitGlobalResult.exitCode}; ` +
|
|
526
|
+
'the existing global binary is unchanged. Re-run `wp setup` once the registry is reachable.');
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
473
530
|
const claudePluginResult = ensureClaudeCodeUserPlugin({
|
|
474
531
|
options,
|
|
475
532
|
packageRoot,
|
|
@@ -612,6 +669,14 @@ export async function runInit(flags) {
|
|
|
612
669
|
console.log(` drifted: ${summary.drifted}`);
|
|
613
670
|
if (options.dryRun)
|
|
614
671
|
console.log(` would-change: ${summary['skipped-dry']}`);
|
|
672
|
+
if (tier3Selection.includes('base-kit')) {
|
|
673
|
+
const qualityTargets = new Set(BASE_KIT_QUALITY_TARGETS);
|
|
674
|
+
const qualityResults = baseKitResults.filter((result) => qualityTargets.has(relative(consumer.repoRoot, result.targetPath).replaceAll('\\', '/')));
|
|
675
|
+
const qualityCreated = qualityResults.filter((result) => result.action === 'created').length;
|
|
676
|
+
const qualityPreserved = qualityResults.filter((result) => result.action === 'identical').length;
|
|
677
|
+
const qualityDryRun = qualityResults.filter((result) => result.action === 'skipped-dry').length;
|
|
678
|
+
console.log(` repo quality scaffold: ${options.dryRun ? `${qualityDryRun} would be created` : `${qualityCreated} created, ${qualityPreserved} preserved`}`);
|
|
679
|
+
}
|
|
615
680
|
if (summary.drifted > 0) {
|
|
616
681
|
console.log('\n Note: some consumer-owned files exist with different content and were left unchanged.\n' +
|
|
617
682
|
' Review the drift or re-run with `--overwrite` to force eligible managed files.');
|
|
@@ -629,8 +694,13 @@ export async function runInit(flags) {
|
|
|
629
694
|
};
|
|
630
695
|
writeConfig(consumer.repoRoot, config);
|
|
631
696
|
console.log('\nHost skill visibility:');
|
|
632
|
-
|
|
633
|
-
console.log(
|
|
697
|
+
if (visibilityAudit.selectedHosts.length === 0) {
|
|
698
|
+
console.log(' hosts: - skipped (--host none)');
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
for (const line of summarizeHostVisibility(consumer.repoRoot, visibilityAudit)) {
|
|
702
|
+
console.log(line);
|
|
703
|
+
}
|
|
634
704
|
}
|
|
635
705
|
const missing = visibilityAudit.results.filter((result) => result.status === 'not-visible');
|
|
636
706
|
if (missing.length > 0) {
|
|
@@ -659,7 +729,10 @@ export async function runInit(flags) {
|
|
|
659
729
|
}
|
|
660
730
|
}
|
|
661
731
|
}
|
|
662
|
-
|
|
732
|
+
printRuntimeContractGuidance(options.dryRun
|
|
733
|
+
? consumer.packageJson
|
|
734
|
+
: (readPackageJsonSafe(consumer.repoRoot) ?? consumer.packageJson));
|
|
735
|
+
console.log('\nwp init: setup phases finished.');
|
|
663
736
|
if (omxFailure === 'not-found')
|
|
664
737
|
return EXIT_SETUP_FAIL;
|
|
665
738
|
if (omxFailure === 'spawn-failed')
|
|
@@ -698,7 +771,7 @@ export async function runInit(flags) {
|
|
|
698
771
|
if (!options.dryRun) {
|
|
699
772
|
console.log([
|
|
700
773
|
'',
|
|
701
|
-
'✅ Setup complete.',
|
|
774
|
+
'✅ Setup complete for the verified phases above.',
|
|
702
775
|
'',
|
|
703
776
|
' Next: wp blueprint new "your first task"',
|
|
704
777
|
' wp gain # token savings after your first session',
|
|
@@ -730,7 +803,7 @@ export function registerInitCommand(cli, commandName = 'init') {
|
|
|
730
803
|
.command(commandName, description)
|
|
731
804
|
.option('--with <skills>', withHelp)
|
|
732
805
|
.option('--without <skills>', withoutHelp)
|
|
733
|
-
.option('--host <hosts>', 'Comma-separated host targets: codex, claude, opencode, all')
|
|
806
|
+
.option('--host <hosts>', 'Comma-separated host targets: codex, claude, opencode, all, none')
|
|
734
807
|
.option('--all', 'Install every skill (Tier-1 + Tier-2 + all Tier-3)')
|
|
735
808
|
.option('--overwrite', 'Force full-file replacement for eligible managed files (default: reconcile owned content and preserve divergent consumer files)')
|
|
736
809
|
.option('--dry-run', 'Show what would change without writing anything')
|
|
@@ -5,5 +5,17 @@ export interface ScaffoldBaseKitInput {
|
|
|
5
5
|
options: MergeOptions;
|
|
6
6
|
globalInstall?: boolean;
|
|
7
7
|
}
|
|
8
|
+
export interface RuntimeContractGuidance {
|
|
9
|
+
keepLocalAuthoringDeps: string[];
|
|
10
|
+
reviewForRemovalDeps: string[];
|
|
11
|
+
}
|
|
12
|
+
interface PackageJsonLike {
|
|
13
|
+
dependencies?: Record<string, string>;
|
|
14
|
+
devDependencies?: Record<string, string>;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare function collectRuntimeContractGuidance(packageJson: PackageJsonLike | null | undefined): RuntimeContractGuidance;
|
|
18
|
+
export declare const BASE_KIT_QUALITY_TARGETS: string[];
|
|
8
19
|
export declare function scaffoldBaseKit(input: ScaffoldBaseKitInput): MergeResult[];
|
|
20
|
+
export {};
|
|
9
21
|
//# sourceMappingURL=scaffold-base-kit.d.ts.map
|
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { writeFileMerged } from './merge.js';
|
|
4
|
+
const AUTHORING_TIME_DEPENDENCIES = [
|
|
5
|
+
'vitest',
|
|
6
|
+
'@playwright/test',
|
|
7
|
+
'@testing-library/jest-dom',
|
|
8
|
+
'typescript',
|
|
9
|
+
];
|
|
10
|
+
const EXECUTION_ONLY_REVIEW_DEPENDENCIES = [
|
|
11
|
+
'oxlint',
|
|
12
|
+
'oxfmt',
|
|
13
|
+
'prettier',
|
|
14
|
+
'markdownlint-cli2',
|
|
15
|
+
'stryker',
|
|
16
|
+
];
|
|
17
|
+
export function collectRuntimeContractGuidance(packageJson) {
|
|
18
|
+
const deps = {
|
|
19
|
+
...readDependencyBucket(packageJson?.['dependencies']),
|
|
20
|
+
...readDependencyBucket(packageJson?.['devDependencies']),
|
|
21
|
+
};
|
|
22
|
+
const installed = new Set(Object.keys(deps));
|
|
23
|
+
return {
|
|
24
|
+
keepLocalAuthoringDeps: AUTHORING_TIME_DEPENDENCIES.filter((name) => installed.has(name)),
|
|
25
|
+
reviewForRemovalDeps: EXECUTION_ONLY_REVIEW_DEPENDENCIES.filter((name) => installed.has(name)),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
4
28
|
/** Template files relative to `catalog/base-kit/`, and their target paths relative to repoRoot. */
|
|
5
29
|
const TEMPLATE_MAP = [
|
|
6
30
|
['.editorconfig.tmpl', '.editorconfig'],
|
|
@@ -18,6 +42,19 @@ const TEMPLATE_MAP = [
|
|
|
18
42
|
['test/.gitkeep.tmpl', 'test/.gitkeep'],
|
|
19
43
|
['e2e/.gitkeep.tmpl', 'e2e/.gitkeep'],
|
|
20
44
|
];
|
|
45
|
+
/** Consumer-owned quality scaffold: create for fresh repos, never clobber. */
|
|
46
|
+
const QUALITY_BOOTSTRAP_ONLY_MAP = [
|
|
47
|
+
['tsconfig.json.tmpl', 'tsconfig.json'],
|
|
48
|
+
['vitest.config.ts.tmpl', 'vitest.config.ts'],
|
|
49
|
+
['oxlint.config.ts.tmpl', 'oxlint.config.ts'],
|
|
50
|
+
['stryker.config.ts.tmpl', 'stryker.config.ts'],
|
|
51
|
+
['playwright.config.ts.tmpl', 'playwright.config.ts'],
|
|
52
|
+
['src/quality-sample.ts.tmpl', 'src/quality-sample.ts'],
|
|
53
|
+
['src/quality-sample.test.ts.tmpl', 'src/quality-sample.test.ts'],
|
|
54
|
+
['e2e/fixtures/smoke.html.tmpl', 'e2e/fixtures/smoke.html'],
|
|
55
|
+
['e2e/smoke.spec.ts.tmpl', 'e2e/smoke.spec.ts'],
|
|
56
|
+
];
|
|
57
|
+
export const BASE_KIT_QUALITY_TARGETS = QUALITY_BOOTSTRAP_ONLY_MAP.map(([, targetRel]) => targetRel);
|
|
21
58
|
/**
|
|
22
59
|
* Bootstrap-only templates: the scaffolder writes them when absent (so a
|
|
23
60
|
* fresh repo gets sane defaults) but NEVER overwrites them once they exist
|
|
@@ -75,35 +112,85 @@ function mergePackageJson(repoRoot, options, globalInstall = false) {
|
|
|
75
112
|
const hasVerifySecrets = typeof scripts['verify:secrets'] === 'string';
|
|
76
113
|
const hasSecretQuarantineAudit = typeof scripts['audit:secret-provider-quarantine'] === 'string';
|
|
77
114
|
const hasPrepareScript = typeof scripts['prepare'] === 'string';
|
|
78
|
-
const
|
|
115
|
+
const hasLintScript = typeof scripts['lint'] === 'string';
|
|
116
|
+
const hasTypecheckScript = typeof scripts['typecheck'] === 'string';
|
|
117
|
+
const hasTestScript = typeof scripts['test'] === 'string' && !isNpmInitPlaceholderTestScript(scripts['test']);
|
|
118
|
+
const hasMutationScript = typeof scripts['mutation'] === 'string';
|
|
119
|
+
const hasTestMutationScript = typeof scripts['test:mutation'] === 'string';
|
|
120
|
+
const hasE2eScript = typeof scripts['e2e'] === 'string';
|
|
121
|
+
const hasQaScript = typeof scripts['qa'] === 'string';
|
|
122
|
+
const verifyPathsScript = 'wp audit absolute-path-policy --root .';
|
|
79
123
|
const verifySecretsScript = 'bun scripts/check-no-dev-vars.ts';
|
|
80
124
|
const secretQuarantineAuditScript = 'bun scripts/audit-secret-provider-quarantine.ts';
|
|
125
|
+
const lintScript = 'wp lint src e2e *.config.ts';
|
|
126
|
+
const typecheckScript = 'wp typecheck';
|
|
127
|
+
const testScript = 'wp test --file vitest.config.ts';
|
|
128
|
+
const mutationScript = 'wp test --mutation';
|
|
129
|
+
const testMutationScript = 'stryker run stryker.config.ts';
|
|
130
|
+
const e2eScript = 'wp e2e --config playwright.config.ts';
|
|
131
|
+
const qaScript = [
|
|
132
|
+
'wp lint src e2e *.config.ts',
|
|
133
|
+
'wp typecheck',
|
|
134
|
+
'wp test --file vitest.config.ts',
|
|
135
|
+
'wp test --mutation',
|
|
136
|
+
'wp e2e --config playwright.config.ts',
|
|
137
|
+
].join(' && ');
|
|
81
138
|
const devDeps = (pkg['devDependencies'] ?? {});
|
|
82
|
-
const hasAgentKitDevDep = typeof devDeps['webpresso'] === 'string';
|
|
83
|
-
const
|
|
139
|
+
const hasAgentKitDevDep = typeof devDeps['@webpresso/agent-kit'] === 'string';
|
|
140
|
+
const hasLegacyAgentKitDevDep = typeof devDeps['webpresso'] === 'string';
|
|
141
|
+
const shouldSkipSelfInstall = packageName === '@webpresso/agent-kit' || packageName === 'webpresso';
|
|
84
142
|
const shouldManageAgentKitAsGlobal = globalInstall && !shouldSkipSelfInstall;
|
|
143
|
+
const requiredAuthoringDeps = {
|
|
144
|
+
'@playwright/test': 'latest',
|
|
145
|
+
'@stryker-mutator/core': 'latest',
|
|
146
|
+
'@stryker-mutator/vitest-runner': 'latest',
|
|
147
|
+
'@types/node': 'latest',
|
|
148
|
+
typescript: 'latest',
|
|
149
|
+
vitest: 'latest',
|
|
150
|
+
};
|
|
85
151
|
if (alreadyHasEngines &&
|
|
86
152
|
alreadyHasPm &&
|
|
87
|
-
(shouldSkipSelfInstall ||
|
|
153
|
+
(shouldSkipSelfInstall ||
|
|
154
|
+
shouldManageAgentKitAsGlobal ||
|
|
155
|
+
hasAgentKitDevDep ||
|
|
156
|
+
hasLegacyAgentKitDevDep) &&
|
|
157
|
+
Object.keys(requiredAuthoringDeps).every((name) => typeof devDeps[name] === 'string') &&
|
|
88
158
|
(shouldSkipSelfInstall || hasSetupAgent) &&
|
|
89
159
|
(shouldSkipSelfInstall || hasVerifyPaths) &&
|
|
90
160
|
(shouldSkipSelfInstall || hasVerifySecrets) &&
|
|
91
161
|
(shouldSkipSelfInstall || hasSecretQuarantineAudit) &&
|
|
92
|
-
(shouldSkipSelfInstall || hasPrepareScript)
|
|
162
|
+
(shouldSkipSelfInstall || hasPrepareScript) &&
|
|
163
|
+
hasLintScript &&
|
|
164
|
+
hasTypecheckScript &&
|
|
165
|
+
hasTestScript &&
|
|
166
|
+
hasMutationScript &&
|
|
167
|
+
hasTestMutationScript &&
|
|
168
|
+
hasE2eScript &&
|
|
169
|
+
hasQaScript) {
|
|
93
170
|
return { targetPath: pkgPath, action: 'identical' };
|
|
94
171
|
}
|
|
95
172
|
pkg['engines'] = { ...existing, node: engines.node };
|
|
96
173
|
if (!alreadyHasPm)
|
|
97
174
|
pkg['packageManager'] = packageManager;
|
|
175
|
+
if (typeof pkg['type'] !== 'string')
|
|
176
|
+
pkg['type'] = 'module';
|
|
98
177
|
// Ensure husky is in devDependencies so `vp exec husky init` works
|
|
99
178
|
if (!devDeps['husky']) {
|
|
100
179
|
devDeps['husky'] = '^9.0.0';
|
|
101
180
|
}
|
|
102
|
-
if (!shouldSkipSelfInstall &&
|
|
181
|
+
if (!shouldSkipSelfInstall &&
|
|
182
|
+
!shouldManageAgentKitAsGlobal &&
|
|
183
|
+
!hasAgentKitDevDep &&
|
|
184
|
+
!hasLegacyAgentKitDevDep) {
|
|
103
185
|
// Keep consumers on the currently published dist-tag rather than a
|
|
104
186
|
// repo-internal path. Do not wire this through `prepare`: `wp` is not
|
|
105
187
|
// reliably on PATH during `vp install`, so `setup:agent` stays opt-in.
|
|
106
|
-
devDeps['webpresso'] = 'latest';
|
|
188
|
+
devDeps['@webpresso/agent-kit'] = 'latest';
|
|
189
|
+
}
|
|
190
|
+
for (const [name, version] of Object.entries(requiredAuthoringDeps)) {
|
|
191
|
+
if (!devDeps[name]) {
|
|
192
|
+
devDeps[name] = version;
|
|
193
|
+
}
|
|
107
194
|
}
|
|
108
195
|
pkg['devDependencies'] = devDeps;
|
|
109
196
|
if (!shouldSkipSelfInstall && !hasSetupAgent) {
|
|
@@ -121,6 +208,27 @@ function mergePackageJson(repoRoot, options, globalInstall = false) {
|
|
|
121
208
|
if (!shouldSkipSelfInstall && !hasPrepareScript) {
|
|
122
209
|
scripts['prepare'] = 'husky';
|
|
123
210
|
}
|
|
211
|
+
if (!hasLintScript) {
|
|
212
|
+
scripts['lint'] = lintScript;
|
|
213
|
+
}
|
|
214
|
+
if (!hasTypecheckScript) {
|
|
215
|
+
scripts['typecheck'] = typecheckScript;
|
|
216
|
+
}
|
|
217
|
+
if (!hasTestScript) {
|
|
218
|
+
scripts['test'] = testScript;
|
|
219
|
+
}
|
|
220
|
+
if (!hasMutationScript) {
|
|
221
|
+
scripts['mutation'] = mutationScript;
|
|
222
|
+
}
|
|
223
|
+
if (!hasTestMutationScript) {
|
|
224
|
+
scripts['test:mutation'] = testMutationScript;
|
|
225
|
+
}
|
|
226
|
+
if (!hasE2eScript) {
|
|
227
|
+
scripts['e2e'] = e2eScript;
|
|
228
|
+
}
|
|
229
|
+
if (!hasQaScript) {
|
|
230
|
+
scripts['qa'] = qaScript;
|
|
231
|
+
}
|
|
124
232
|
if (Object.keys(scripts).length > 0) {
|
|
125
233
|
pkg['scripts'] = scripts;
|
|
126
234
|
}
|
|
@@ -161,6 +269,24 @@ export function scaffoldBaseKit(input) {
|
|
|
161
269
|
writeFileSync(targetPath, content);
|
|
162
270
|
results.push({ targetPath, action: 'created' });
|
|
163
271
|
}
|
|
272
|
+
for (const [tmplRel, targetRel] of QUALITY_BOOTSTRAP_ONLY_MAP) {
|
|
273
|
+
const tmplPath = join(baseKitDir, tmplRel);
|
|
274
|
+
if (!existsSync(tmplPath))
|
|
275
|
+
continue;
|
|
276
|
+
const targetPath = join(repoRoot, targetRel);
|
|
277
|
+
if (existsSync(targetPath)) {
|
|
278
|
+
results.push({ targetPath, action: 'identical' });
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const content = readFileSync(tmplPath, 'utf8');
|
|
282
|
+
if (options.dryRun) {
|
|
283
|
+
results.push({ targetPath, action: 'skipped-dry' });
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
287
|
+
writeFileSync(targetPath, content);
|
|
288
|
+
results.push({ targetPath, action: 'created' });
|
|
289
|
+
}
|
|
164
290
|
// Make husky hook files executable
|
|
165
291
|
if (!options.dryRun) {
|
|
166
292
|
for (const [tmplRel, targetRel] of TEMPLATE_MAP) {
|
|
@@ -180,4 +306,13 @@ export function scaffoldBaseKit(input) {
|
|
|
180
306
|
results.push(mergePackageJson(repoRoot, options, globalInstall));
|
|
181
307
|
return results;
|
|
182
308
|
}
|
|
309
|
+
function readDependencyBucket(value) {
|
|
310
|
+
if (!value || typeof value !== 'object') {
|
|
311
|
+
return {};
|
|
312
|
+
}
|
|
313
|
+
return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[0] === 'string' && typeof entry[1] === 'string'));
|
|
314
|
+
}
|
|
315
|
+
function isNpmInitPlaceholderTestScript(value) {
|
|
316
|
+
return /^echo ['"]?Error: no test specified['"]? && exit 1$/u.test(value.trim());
|
|
317
|
+
}
|
|
183
318
|
//# sourceMappingURL=scaffold-base-kit.js.map
|
|
@@ -10,6 +10,8 @@ export const KNOWN_WEBPRESSO_CODEX_BINS = [
|
|
|
10
10
|
const KNOWN_WEBPRESSO_CODEX_BIN_SET = new Set(KNOWN_WEBPRESSO_CODEX_BINS);
|
|
11
11
|
const NODE_MODULES_BIN_PATTERN = /^(?:\.\/|\/.*\/)?node_modules\/\.bin\/([\w-]+)$/u;
|
|
12
12
|
const GUARDED_NODE_MODULES_BIN_PATTERN = /^\[ -x (["']?)((?:\.\/|\/.*\/)?node_modules\/\.bin\/([\w-]+))\1 \] && \1\2\1 \|\| (?:true|printf .+)$/u;
|
|
13
|
+
const MANAGED_LAUNCHER_PATTERN = /^(?:["']?)((?:\.\/|\/.*\/)?\.codex\/managed-hooks\/((?:wp|ak)-[\w-]+)\.sh)(?:["']?)$/u;
|
|
14
|
+
const GUARDED_MANAGED_LAUNCHER_PATTERN = /^\[ -x (["']?)((?:\.\/|\/.*\/)?\.codex\/managed-hooks\/((?:wp|ak)-[\w-]+)\.sh)\1 \] && \1\2\1 \|\| (?:true|printf .+)$/u;
|
|
13
15
|
export function isWebpressoOwnedCodexHook(metadata, expectedSourcePaths) {
|
|
14
16
|
if (!isObject(metadata))
|
|
15
17
|
return false;
|
|
@@ -46,8 +48,14 @@ function extractDirectNodeModulesBin(command) {
|
|
|
46
48
|
const match = NODE_MODULES_BIN_PATTERN.exec(normalizedCommand);
|
|
47
49
|
if (match?.[1])
|
|
48
50
|
return match[1];
|
|
51
|
+
const managedLauncherMatch = MANAGED_LAUNCHER_PATTERN.exec(normalizedCommand);
|
|
52
|
+
if (managedLauncherMatch?.[2])
|
|
53
|
+
return managedLauncherMatch[2];
|
|
49
54
|
const guardedMatch = GUARDED_NODE_MODULES_BIN_PATTERN.exec(command.trim());
|
|
50
|
-
|
|
55
|
+
if (guardedMatch?.[3])
|
|
56
|
+
return guardedMatch[3];
|
|
57
|
+
const guardedManagedLauncherMatch = GUARDED_MANAGED_LAUNCHER_PATTERN.exec(command.trim());
|
|
58
|
+
return guardedManagedLauncherMatch?.[3] ?? null;
|
|
51
59
|
}
|
|
52
60
|
function stripSingleShellQuotePair(value) {
|
|
53
61
|
if (value.length < 2)
|