@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
|
@@ -64,3 +64,36 @@ jobs:
|
|
|
64
64
|
WP="$(pwd)/node_modules/.bin/wp"
|
|
65
65
|
[ -x "$WP" ] || WP=wp
|
|
66
66
|
"$WP" audit guardrails
|
|
67
|
+
|
|
68
|
+
deploy-contract:
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v5
|
|
72
|
+
- uses: pnpm/action-setup@v6
|
|
73
|
+
- uses: actions/setup-node@v5
|
|
74
|
+
with:
|
|
75
|
+
node-version: '24.16.0'
|
|
76
|
+
cache: pnpm
|
|
77
|
+
- uses: oven-sh/setup-bun@v2
|
|
78
|
+
with:
|
|
79
|
+
bun-version: latest
|
|
80
|
+
- run: pnpm install --frozen-lockfile
|
|
81
|
+
- name: Verify deploy-contract gate when production release metadata is present
|
|
82
|
+
run: |
|
|
83
|
+
set -euo pipefail
|
|
84
|
+
|
|
85
|
+
METADATA_PATH='infra/release-metadata.production.json'
|
|
86
|
+
|
|
87
|
+
if [ ! -f "$METADATA_PATH" ]; then
|
|
88
|
+
echo "No production release metadata present at $METADATA_PATH; skipping deploy-contract gate."
|
|
89
|
+
exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
if ! node -e "const pkg=require('./package.json'); process.exit(pkg.scripts && pkg.scripts['verify:deploy-contract'] ? 0 : 1)"; then
|
|
93
|
+
echo "::error::Detected $METADATA_PATH but no verify:deploy-contract script."
|
|
94
|
+
echo "::error::Repos adopting the shared deploy contract must keep agent-kit provider-neutral and supply a repo-owned deploy verifier."
|
|
95
|
+
echo "::error::That verifier owns provider-specific env-name derivation, Preview-URL prohibitions for DO previews, and must fail closed for migration-bearing Durable Object releases."
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
pnpm run verify:deploy-contract
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
const smokePagePath = join(process.cwd(), 'e2e', 'fixtures', 'smoke.html')
|
|
6
|
+
|
|
7
|
+
test('checks the file-based smoke page', async () => {
|
|
8
|
+
const html = await readFile(smokePagePath, 'utf8')
|
|
9
|
+
|
|
10
|
+
expect(html).toContain('Agent Kit quality scaffold')
|
|
11
|
+
expect(html).toContain('data-testid="status"')
|
|
12
|
+
expect(html).toContain('ready')
|
|
13
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { config } from '@webpresso/agent-kit/oxlint'
|
|
2
|
+
|
|
3
|
+
const oxlintConfig: Record<string, unknown> = {
|
|
4
|
+
...config,
|
|
5
|
+
env: {
|
|
6
|
+
builtin: true,
|
|
7
|
+
node: true,
|
|
8
|
+
},
|
|
9
|
+
ignorePatterns: [
|
|
10
|
+
'dist',
|
|
11
|
+
'node_modules',
|
|
12
|
+
'reports',
|
|
13
|
+
'.stryker-tmp',
|
|
14
|
+
'.agent',
|
|
15
|
+
'.agents',
|
|
16
|
+
'.claude',
|
|
17
|
+
'.codex',
|
|
18
|
+
'.cursor',
|
|
19
|
+
'.gemini',
|
|
20
|
+
'.opencode',
|
|
21
|
+
'.omx',
|
|
22
|
+
'.windsurf',
|
|
23
|
+
],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default oxlintConfig
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { add, clamp } from './quality-sample.js'
|
|
4
|
+
|
|
5
|
+
describe('quality sample', () => {
|
|
6
|
+
it('adds two numbers', () => {
|
|
7
|
+
expect(add(2, 3)).toBe(5)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('clamps values below, inside, and above the range', () => {
|
|
11
|
+
expect(clamp(-1, 0, 10)).toBe(0)
|
|
12
|
+
expect(clamp(5, 0, 10)).toBe(5)
|
|
13
|
+
expect(clamp(11, 0, 10)).toBe(10)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('rejects an invalid range', () => {
|
|
17
|
+
expect(() => clamp(1, 10, 0)).toThrow(RangeError)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function add(left: number, right: number): number {
|
|
2
|
+
return left + right
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function clamp(value: number, min: number, max: number): number {
|
|
6
|
+
if (min > max) {
|
|
7
|
+
throw new RangeError('min must be less than or equal to max')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return Math.min(Math.max(value, min), max)
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { typescriptBaseConfig } from '@webpresso/agent-kit/stryker'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
...typescriptBaseConfig,
|
|
5
|
+
thresholds: {
|
|
6
|
+
high: 0,
|
|
7
|
+
low: 0,
|
|
8
|
+
break: 0,
|
|
9
|
+
},
|
|
10
|
+
vitest: {
|
|
11
|
+
configFile: 'vitest.config.ts',
|
|
12
|
+
},
|
|
13
|
+
mutate: ['src/**/*.ts', '!src/**/*.test.ts', '!src/**/*.d.ts'],
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./node_modules/@webpresso/agent-kit/tsconfig/base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"types": ["node", "vitest/globals"],
|
|
5
|
+
"noEmit": true
|
|
6
|
+
},
|
|
7
|
+
"include": ["src/**/*.ts", "test/**/*.ts", "e2e/**/*.ts", "*.config.ts"],
|
|
8
|
+
"exclude": ["node_modules", "dist", "reports", ".stryker-tmp"]
|
|
9
|
+
}
|
|
@@ -6,6 +6,7 @@ created: '2026-04-22'
|
|
|
6
6
|
last_updated: '2026-04-22'
|
|
7
7
|
progress: '0% (drafted)'
|
|
8
8
|
depends_on: []
|
|
9
|
+
cross_repo_depends_on: []
|
|
9
10
|
tags: []
|
|
10
11
|
---
|
|
11
12
|
|
|
@@ -20,6 +21,7 @@ tags: []
|
|
|
20
21
|
- Draft slug: `{{slug}}`
|
|
21
22
|
- Output path: `{{output_path}}`
|
|
22
23
|
- Generated command: `wp blueprint new "{{description}}" --complexity {{complexity}}`
|
|
24
|
+
- Default shape: flat file (`blueprints/<status>/<slug>.md`)
|
|
23
25
|
- Validation scope: parser compliance before write
|
|
24
26
|
|
|
25
27
|
## Architecture Overview
|
|
@@ -4,6 +4,7 @@ description: Blueprint template for features/initiatives
|
|
|
4
4
|
notes:
|
|
5
5
|
- 'This file describes the current preferred blueprint structure, not an immutable final schema.'
|
|
6
6
|
- 'Repo-wide validity is determined by the live blueprint parser/audit rules, not by requiring every optional section below.'
|
|
7
|
+
- 'Default creation shape: blueprints/<status>/<slug>.md. Folder-based blueprints remain valid at blueprints/<status>/<slug>/_overview.md when sibling docs are needed.'
|
|
7
8
|
|
|
8
9
|
frontmatter:
|
|
9
10
|
required:
|
|
@@ -12,7 +13,7 @@ frontmatter:
|
|
|
12
13
|
description: Must be exactly "blueprint"
|
|
13
14
|
status:
|
|
14
15
|
enum: [draft, planned, parked, in-progress, completed, archived]
|
|
15
|
-
description: Current plan status (must match
|
|
16
|
+
description: Current plan status (must match lifecycle placement)
|
|
16
17
|
complexity:
|
|
17
18
|
enum: [XS, S, M, L, XL]
|
|
18
19
|
description: Estimated complexity
|
|
@@ -21,12 +22,15 @@ frontmatter:
|
|
|
21
22
|
format: YYYY-MM-DD
|
|
22
23
|
description: Last modification date
|
|
23
24
|
optional:
|
|
24
|
-
|
|
25
|
+
parent_roadmap:
|
|
25
26
|
type: string
|
|
26
|
-
description:
|
|
27
|
+
description: Local parent-roadmap slug/path in the same repo
|
|
27
28
|
depends_on:
|
|
28
29
|
type: array
|
|
29
|
-
description:
|
|
30
|
+
description: Local blueprint dependencies in the same repo
|
|
31
|
+
cross_repo_depends_on:
|
|
32
|
+
type: array
|
|
33
|
+
description: Cross-repo blueprint dependencies expressed as { repo, slug, require_status? }
|
|
30
34
|
|
|
31
35
|
sections:
|
|
32
36
|
required: []
|
|
@@ -78,21 +82,18 @@ sections:
|
|
|
78
82
|
|
|
79
83
|
location:
|
|
80
84
|
patterns:
|
|
81
|
-
- 'blueprints
|
|
85
|
+
- 'blueprints/*/*.md'
|
|
82
86
|
- 'blueprints/*/*/_overview.md'
|
|
83
|
-
- 'blueprints
|
|
84
|
-
- 'blueprints/
|
|
85
|
-
- 'blueprints/
|
|
86
|
-
- 'blueprints/
|
|
87
|
-
- 'blueprints/
|
|
88
|
-
- 'blueprints/draft/*/_overview.md'
|
|
89
|
-
exclude:
|
|
90
|
-
- 'blueprints/draft/*.md' # Standalone draft trackers such as deferred backlog
|
|
87
|
+
- 'blueprints/completed/*.md'
|
|
88
|
+
- 'blueprints/planned/*.md'
|
|
89
|
+
- 'blueprints/parked/*.md'
|
|
90
|
+
- 'blueprints/in-progress/*.md'
|
|
91
|
+
- 'blueprints/draft/*.md'
|
|
91
92
|
|
|
92
93
|
naming:
|
|
93
|
-
pattern: '_overview.md'
|
|
94
|
+
pattern: '<slug>.md or _overview.md'
|
|
94
95
|
case: exact
|
|
95
|
-
notes: 'Use
|
|
96
|
+
notes: 'Use <slug>.md by default. Use folder + _overview.md when the blueprint needs sibling markdown docs.'
|
|
96
97
|
|
|
97
98
|
task_format:
|
|
98
99
|
heading:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: system
|
|
3
|
-
last_updated: "
|
|
3
|
+
last_updated: "2026-05-27"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# {{System Name}}
|
|
@@ -11,8 +11,17 @@ last_updated: "YYYY-MM-DD"
|
|
|
11
11
|
|
|
12
12
|
## Architecture
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
|
|
14
|
+
```mermaid
|
|
15
|
+
flowchart LR
|
|
16
|
+
A[Main component] --> B[Dependency or downstream system]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Infrastructure / deployment
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
flowchart LR
|
|
23
|
+
CI[Deploy entry point] --> RUNTIME[Runtime surface]
|
|
24
|
+
INFRA[Durable infrastructure owner] --> STATE[(Stateful resource)]
|
|
16
25
|
```
|
|
17
26
|
|
|
18
27
|
## Key invariants
|
package/commands/blueprint.md
CHANGED
|
@@ -8,21 +8,19 @@ Use the focused blueprint MCP tools.
|
|
|
8
8
|
- `wp_blueprint_get` — fetch one blueprint with freshness metadata
|
|
9
9
|
- `wp_blueprint_context` — assemble bounded task context
|
|
10
10
|
- `wp_blueprint_create` — create a draft blueprint; requires `project_id` and accepts optional `request_id` and `head_at_ingest` for retry-safe, stale-write-safe creation
|
|
11
|
+
- `wp_blueprint_put` — whole-document structured authoring; writes the canonical blueprint markdown from typed input and returns revision metadata
|
|
12
|
+
- `wp_blueprint_transition` — optimistic-concurrency lifecycle transition; requires `expected_version` and returns updated revision metadata
|
|
11
13
|
- `wp_blueprint_task_next` — return the next ready task; accepts optional `project_id` when the current cwd is a multi-repo workspace container
|
|
12
14
|
- `wp_blueprint_task_advance` — change task status (non-`done`); requires `project_id` and accepts optional `request_id` and `head_at_ingest` for retry-safe mutation
|
|
13
15
|
- `wp_blueprint_task_verify` — mark a task `done` with evidence; accepts optional `request_id` and `head_at_ingest` for retry-safe verification
|
|
14
16
|
- `wp_blueprint_promote` / `wp_blueprint_finalize` — accept optional `project_id` for nested-workspace disambiguation
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Guidance:
|
|
17
19
|
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- Reusing the same `request_id` with the same payload is idempotent.
|
|
26
|
-
- Reusing the same `request_id` with a different payload is rejected.
|
|
27
|
-
- If `head_at_ingest` is stale, the mutation is rejected and points the caller
|
|
28
|
-
back to a canonical `wp_*` refresh path.
|
|
20
|
+
- Prefer `project_id` from `wp_blueprint_projects` when multiple repos are visible.
|
|
21
|
+
- Use `request_id` for retry-safe mutations and reuse it only with the same payload.
|
|
22
|
+
- Carry `head_at_ingest` from read/context tools into stale-write-sensitive mutations.
|
|
23
|
+
- Author documents through `wp_blueprint_put`, then lifecycle with `wp_blueprint_transition`.
|
|
24
|
+
- Deferred `wp_blueprint_patch` semantic ops (`add_task`, `update_task`, `set_summary`, `replace_decision`) are future layers; patch is **not** part of the v1 canonical surface.
|
|
25
|
+
- MCP Apps editor support is a follow-on enhancement over `wp_blueprint_put` / `wp_blueprint_transition`.
|
|
26
|
+
- Hosts without MCP Apps support keep using the structured tools above.
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Checks (when enabled):
|
|
9
9
|
* 1. Every `blueprints` row's `file_path` actually exists on disk.
|
|
10
|
-
* 2. Every blueprint
|
|
10
|
+
* 2. Every canonical blueprint markdown file on disk has a corresponding DB row.
|
|
11
11
|
* 3. `content_hash` in DB matches the current SHA-256 of the file content.
|
|
12
12
|
*/
|
|
13
13
|
import type { RepoAuditResult } from './repo-guardrails.js';
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Checks (when enabled):
|
|
9
9
|
* 1. Every `blueprints` row's `file_path` actually exists on disk.
|
|
10
|
-
* 2. Every blueprint
|
|
10
|
+
* 2. Every canonical blueprint markdown file on disk has a corresponding DB row.
|
|
11
11
|
* 3. `content_hash` in DB matches the current SHA-256 of the file content.
|
|
12
12
|
*/
|
|
13
13
|
import { createHash } from 'node:crypto';
|
|
14
14
|
import { existsSync, readFileSync } from 'node:fs';
|
|
15
15
|
import path from 'node:path';
|
|
16
|
-
import {
|
|
16
|
+
import { scanBlueprintDirectory } from '#service/scanner.js';
|
|
17
17
|
const DB_PATH = path.join('.agent', '.blueprints.db');
|
|
18
18
|
const _DISABLED_RESULT = {
|
|
19
19
|
ok: true,
|
|
@@ -76,12 +76,10 @@ export async function auditBlueprintDbConsistency(cwd) {
|
|
|
76
76
|
// 2: files on disk → verify each has a DB row
|
|
77
77
|
// -----------------------------------------------------------------------
|
|
78
78
|
const dbPaths = new Set(rows.map((r) => r.file_path));
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
ignore: ['node_modules/**'],
|
|
84
|
-
});
|
|
79
|
+
const overviewFiles = scanBlueprintDirectory({
|
|
80
|
+
baseDir: path.join(cwd, 'blueprints'),
|
|
81
|
+
includeSpecialFolders: true,
|
|
82
|
+
}).map((entry) => path.relative(cwd, entry.path).replace(/\\/g, '/'));
|
|
85
83
|
checked += overviewFiles.length;
|
|
86
84
|
for (const rel of overviewFiles) {
|
|
87
85
|
const normalised = rel.replace(/\\/g, '/');
|
|
@@ -45,6 +45,16 @@ export async function auditBlueprintLifecycleSql(cwd) {
|
|
|
45
45
|
const violations = [];
|
|
46
46
|
let checked = 0;
|
|
47
47
|
try {
|
|
48
|
+
const allBlueprints = db
|
|
49
|
+
.prepare('SELECT slug, status, file_path, progress_pct FROM blueprints')
|
|
50
|
+
.all();
|
|
51
|
+
if (allBlueprints.length === 0) {
|
|
52
|
+
const { auditBlueprintLifecycle } = await import('./repo-guardrails.js');
|
|
53
|
+
const markdownAudit = auditBlueprintLifecycle(cwd);
|
|
54
|
+
if (markdownAudit.checked > 0) {
|
|
55
|
+
return markdownAudit;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
48
58
|
// -----------------------------------------------------------------------
|
|
49
59
|
// 1. in-progress blueprints with 0 tasks
|
|
50
60
|
// -----------------------------------------------------------------------
|
|
@@ -68,9 +78,6 @@ export async function auditBlueprintLifecycleSql(cwd) {
|
|
|
68
78
|
// Derive the directory segment from the file_path and compare to status.
|
|
69
79
|
// Blueprint file_path convention: blueprints/<status>/<slug>/_overview.md
|
|
70
80
|
// -----------------------------------------------------------------------
|
|
71
|
-
const allBlueprints = db
|
|
72
|
-
.prepare('SELECT slug, status, file_path, progress_pct FROM blueprints')
|
|
73
|
-
.all();
|
|
74
81
|
checked += allBlueprints.length;
|
|
75
82
|
for (const row of allBlueprints) {
|
|
76
83
|
// Derive directory status from the path: second segment after 'blueprints/'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadWebpressoConfigSafe } from '#e2e/load-host-adapter';
|
|
4
|
+
function violation(file, message) {
|
|
5
|
+
return { file, message };
|
|
6
|
+
}
|
|
7
|
+
export async function auditCloudflareDeployContract(root) {
|
|
8
|
+
let loaded;
|
|
9
|
+
try {
|
|
10
|
+
loaded = await loadWebpressoConfigSafe({ cwd: root });
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
title: 'Cloudflare deploy contract',
|
|
17
|
+
checked: 1,
|
|
18
|
+
violations: [violation(path.join(root, 'webpresso.config.ts'), message)],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const configPath = loaded?.configPath ?? path.join(root, 'webpresso.config.ts');
|
|
22
|
+
const cloudflare = loaded?.config.deploy?.cloudflare;
|
|
23
|
+
if (!cloudflare) {
|
|
24
|
+
return {
|
|
25
|
+
ok: true,
|
|
26
|
+
title: 'Cloudflare deploy contract',
|
|
27
|
+
checked: 0,
|
|
28
|
+
violations: [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const violations = [];
|
|
32
|
+
const metadataPath = path.join(root, cloudflare.production.metadataPath);
|
|
33
|
+
if (!existsSync(metadataPath)) {
|
|
34
|
+
violations.push(violation(configPath, `shared deploy contract requires ${cloudflare.production.metadataPath} to exist`));
|
|
35
|
+
}
|
|
36
|
+
for (const target of cloudflare.targets) {
|
|
37
|
+
const isDurableObjectTarget = (target.durableObjectBindings?.length ?? 0) > 0;
|
|
38
|
+
if (target.previewTransport === 'custom_domain_env' && !target.routeSpec) {
|
|
39
|
+
violations.push(violation(configPath, `target ${target.id} uses custom_domain_env but does not declare routeSpec`));
|
|
40
|
+
}
|
|
41
|
+
if (target.durableObjectBindings && target.durableObjectBindings.length === 0) {
|
|
42
|
+
violations.push(violation(configPath, `target ${target.id} declares durableObjectBindings but provides no env-specific bindings`));
|
|
43
|
+
}
|
|
44
|
+
if (isDurableObjectTarget && target.previewTransport !== 'custom_domain_env') {
|
|
45
|
+
violations.push(violation(configPath, `target ${target.id} is a Durable Object consumer and must use previewTransport "custom_domain_env"`));
|
|
46
|
+
}
|
|
47
|
+
if (isDurableObjectTarget && Object.keys(target.vars).length === 0) {
|
|
48
|
+
violations.push(violation(configPath, `target ${target.id} is a Durable Object consumer and must declare at least one env-specific var`));
|
|
49
|
+
}
|
|
50
|
+
if (isDurableObjectTarget && target.requiredSecrets.length === 0) {
|
|
51
|
+
violations.push(violation(configPath, `target ${target.id} is a Durable Object consumer and must declare at least one required secret name`));
|
|
52
|
+
}
|
|
53
|
+
if (target.storageMode === 'shared_via_script_name' && !target.blastRadiusDoc) {
|
|
54
|
+
violations.push(violation(configPath, `target ${target.id} uses shared_via_script_name without blastRadiusDoc`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
ok: violations.length === 0,
|
|
59
|
+
title: 'Cloudflare deploy contract',
|
|
60
|
+
checked: 1 + cloudflare.targets.length,
|
|
61
|
+
violations,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=cloudflare-deploy-contract.js.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, relative, resolve } from 'node:path';
|
|
3
|
+
// `wp` remains the canonical public CLI in AGENTS.md. This audit only guards
|
|
4
|
+
// retired compatibility aliases from leaking into active user-facing surfaces.
|
|
5
|
+
const LEGACY_COMMAND_PATTERN = /\b(?:ak|cli2|wk)\s+[a-z][\w:-]*(?:\s+[a-z][\w:-]*)*/giu;
|
|
6
|
+
const INTERNAL_HELPER_PATTERN = /\bwp-(?:pretool-guard|post-tool|stop-qa|guard-switch|sessionstart-routing|check-dev-link)\b/u;
|
|
7
|
+
const REPLACEMENT_PATTERN = /\bwebpresso agent [a-z][\w:-]*(?: [a-z][\w:-]*)*/iu;
|
|
8
|
+
const MIGRATION_MARKER_PATTERN = /\b(?:current-state|migration-only|replacement|future)\b/iu;
|
|
9
|
+
// Scan current user-facing/documentation inputs only. Source tests and completed/parked
|
|
10
|
+
// blueprints intentionally preserve historical command names as regression fixtures
|
|
11
|
+
// and audit evidence; blocking them would make this guardrail non-adoptable.
|
|
12
|
+
const SCAN_DIRS = [
|
|
13
|
+
'catalog',
|
|
14
|
+
'commands',
|
|
15
|
+
'scripts',
|
|
16
|
+
'test-fixtures',
|
|
17
|
+
'blueprints/planned',
|
|
18
|
+
'blueprints/in-progress',
|
|
19
|
+
];
|
|
20
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.agent', '.omx', '.codex']);
|
|
21
|
+
const TEXT_EXTENSIONS = new Set([
|
|
22
|
+
'.md',
|
|
23
|
+
'.mdx',
|
|
24
|
+
'.txt',
|
|
25
|
+
'.json',
|
|
26
|
+
'.yaml',
|
|
27
|
+
'.yml',
|
|
28
|
+
'.ts',
|
|
29
|
+
'.tsx',
|
|
30
|
+
'.js',
|
|
31
|
+
'.jsx',
|
|
32
|
+
'.sh',
|
|
33
|
+
]);
|
|
34
|
+
export function auditNoLegacyCliBin(rootDirectory = process.cwd()) {
|
|
35
|
+
const root = resolve(rootDirectory);
|
|
36
|
+
const violations = [];
|
|
37
|
+
let checked = 0;
|
|
38
|
+
for (const dir of SCAN_DIRS) {
|
|
39
|
+
const absoluteDir = join(root, dir);
|
|
40
|
+
if (!existsSync(absoluteDir))
|
|
41
|
+
continue;
|
|
42
|
+
for (const absolutePath of walkTextFiles(absoluteDir)) {
|
|
43
|
+
checked += 1;
|
|
44
|
+
const relativePath = relative(root, absolutePath);
|
|
45
|
+
const content = readFileSync(absolutePath, 'utf8');
|
|
46
|
+
const lines = content.split('\n');
|
|
47
|
+
for (const [index, line] of lines.entries()) {
|
|
48
|
+
const matches = line.matchAll(LEGACY_COMMAND_PATTERN);
|
|
49
|
+
for (const match of matches) {
|
|
50
|
+
const snippet = match[0]?.trim();
|
|
51
|
+
if (!snippet)
|
|
52
|
+
continue;
|
|
53
|
+
if (isAllowedLegacyLine(line))
|
|
54
|
+
continue;
|
|
55
|
+
violations.push({
|
|
56
|
+
file: relativePath,
|
|
57
|
+
message: `Line ${index + 1} exposes legacy command ${JSON.stringify(snippet)} without current-state/migration context and an exact \`webpresso agent ...\` replacement.`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
ok: violations.length === 0,
|
|
65
|
+
title: 'No retired CLI aliases in active docs/scripts',
|
|
66
|
+
checked,
|
|
67
|
+
violations,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function walkTextFiles(directory) {
|
|
71
|
+
const entries = readdirSync(directory, { withFileTypes: true });
|
|
72
|
+
const files = [];
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
if (SKIP_DIRS.has(entry.name))
|
|
75
|
+
continue;
|
|
76
|
+
const absolutePath = join(directory, entry.name);
|
|
77
|
+
if (entry.isDirectory()) {
|
|
78
|
+
files.push(...walkTextFiles(absolutePath));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (!entry.isFile())
|
|
82
|
+
continue;
|
|
83
|
+
const extension = entry.name.includes('.') ? `.${entry.name.split('.').pop()}` : '';
|
|
84
|
+
if (TEXT_EXTENSIONS.has(extension))
|
|
85
|
+
files.push(absolutePath);
|
|
86
|
+
}
|
|
87
|
+
return files;
|
|
88
|
+
}
|
|
89
|
+
function isAllowedLegacyLine(line) {
|
|
90
|
+
LEGACY_COMMAND_PATTERN.lastIndex = 0;
|
|
91
|
+
if (!LEGACY_COMMAND_PATTERN.test(line))
|
|
92
|
+
return true;
|
|
93
|
+
LEGACY_COMMAND_PATTERN.lastIndex = 0;
|
|
94
|
+
if (INTERNAL_HELPER_PATTERN.test(line))
|
|
95
|
+
return true;
|
|
96
|
+
if (!MIGRATION_MARKER_PATTERN.test(line))
|
|
97
|
+
return false;
|
|
98
|
+
return REPLACEMENT_PATTERN.test(line);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=no-legacy-cli-bin.js.map
|