@erclx/canon 5.44.0 → 5.46.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/README.md +1 -1
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/REQUIREMENT.md +15 -31
- package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
- package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
- package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
- package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
- package/claude/skills/canon-cli/SKILL.md +0 -1
- package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
- package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
- package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
- package/claude/skills/code-craft/REQUIREMENT.md +14 -28
- package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
- package/claude/skills/context-fold/REQUIREMENT.md +15 -39
- package/claude/skills/context-fold/references/context.md +3 -3
- package/claude/skills/create-rule/REQUIREMENT.md +10 -24
- package/claude/skills/create-rule/SKILL.md +3 -0
- package/claude/skills/create-skill/REQUIREMENT.md +10 -21
- package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
- package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
- package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
- package/claude/skills/design-identity/REQUIREMENT.md +14 -20
- package/claude/skills/design-taste/REQUIREMENT.md +16 -57
- package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
- package/claude/skills/document-health/REQUIREMENT.md +15 -29
- package/claude/skills/document-health/SKILL.md +2 -2
- package/claude/skills/document-repair/REQUIREMENT.md +32 -0
- package/claude/skills/document-repair/SKILL.md +76 -0
- package/claude/skills/document-repair/references/batches.md +44 -0
- package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
- package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
- package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
- package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
- package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
- package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
- package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
- package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
- package/claude/skills/git-branch/REQUIREMENT.md +12 -26
- package/claude/skills/git-commit/REQUIREMENT.md +11 -15
- package/claude/skills/git-followup/REQUIREMENT.md +11 -22
- package/claude/skills/git-issue/REQUIREMENT.md +9 -15
- package/claude/skills/git-pr/REQUIREMENT.md +13 -32
- package/claude/skills/git-pr/SKILL.md +10 -2
- package/claude/skills/git-pr/references/closing-issues.md +47 -0
- package/claude/skills/git-pr/references/pr.md +4 -0
- package/claude/skills/git-ship/REQUIREMENT.md +13 -26
- package/claude/skills/git-split/REQUIREMENT.md +10 -17
- package/claude/skills/git-stage/REQUIREMENT.md +12 -18
- package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
- package/claude/skills/make-deck/REQUIREMENT.md +13 -21
- package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
- package/claude/skills/pick-by-eye/REQUIREMENT.md +17 -67
- package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
- package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
- package/claude/skills/plan-groundwork/SKILL.md +5 -2
- package/claude/skills/plan-groundwork/references/output.md +47 -1
- package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
- package/claude/skills/plan-intake/references/intake.md +2 -2
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
- package/claude/skills/plan-intake-answer/SKILL.md +7 -1
- package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
- package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
- package/claude/skills/read-frames/REQUIREMENT.md +3 -8
- package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
- package/claude/skills/review-address/REQUIREMENT.md +14 -38
- package/claude/skills/review-craft/REQUIREMENT.md +14 -32
- package/claude/skills/review-pr/REQUIREMENT.md +15 -34
- package/claude/skills/review-ui/REQUIREMENT.md +14 -39
- package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
- package/claude/skills/role-planner/REQUIREMENT.md +15 -73
- package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
- package/claude/skills/role-reviewer/SKILL.md +5 -1
- package/claude/skills/role-worker/REQUIREMENT.md +13 -41
- package/claude/skills/role-worker/SKILL.md +2 -0
- package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
- package/claude/skills/search-craft/REQUIREMENT.md +12 -36
- package/claude/skills/search-craft/SKILL.md +1 -1
- package/claude/skills/search-craft/references/adopted.md +2 -2
- package/claude/skills/session-compact/REQUIREMENT.md +13 -23
- package/claude/skills/session-map/REQUIREMENT.md +13 -29
- package/claude/skills/session-relay/REQUIREMENT.md +14 -58
- package/claude/skills/session-relay/SKILL.md +6 -0
- package/claude/skills/session-resume/REQUIREMENT.md +13 -27
- package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
- package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
- package/claude/skills/target-check/REQUIREMENT.md +16 -23
- package/claude/skills/target-setup/REQUIREMENT.md +11 -34
- package/claude/skills/target-setup/SKILL.md +2 -2
- package/claude/skills/target-setup/references/detect.md +0 -1
- package/claude/skills/target-setup/references/verify.md +2 -2
- package/claude/skills/task-board/REQUIREMENT.md +13 -22
- package/claude/skills/task-board/SKILL.md +7 -0
- package/claude/skills/task-board/references/tasks.md +1 -1
- package/claude/skills/task-complete/REQUIREMENT.md +11 -24
- package/claude/skills/task-complete/references/archive.md +1 -0
- package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
- package/claude/skills/teach-workspace/references/promotion.md +5 -5
- package/claude/skills/test-craft/REQUIREMENT.md +15 -46
- package/claude/skills/test-first/REQUIREMENT.md +14 -20
- package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
- package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
- package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
- package/claude/skills/video-craft/REQUIREMENT.md +14 -27
- package/claude/skills/write-doc/REQUIREMENT.md +14 -24
- package/claude/skills/write-human/REQUIREMENT.md +15 -27
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
- package/docs/agents/context-audit.md +19 -12
- package/docs/agents/install-and-sync.md +2 -2
- package/docs/agents/markdown-audit.md +15 -10
- package/docs/agents/output-shape.md +1 -2
- package/docs/target/migrations.md +18 -0
- package/docs/target/projects.md +3 -2
- package/docs/target/scenarios.md +4 -1
- package/docs/workflow/skill-map-on-request.md +1 -1
- package/docs/workflow/skill-map.md +6 -5
- package/governance/detect.toml +4 -0
- package/governance/ledger/lang/go.md +61 -0
- package/governance/ledger/lang/php.md +50 -0
- package/governance/ledger/lang/python.md +68 -0
- package/governance/ledger/lang/typescript.md +64 -0
- package/governance/ledger/lib/database.md +65 -0
- package/governance/ledger/lib/e2e-reliability.md +57 -0
- package/governance/ledger/lib/pydantic.md +61 -0
- package/governance/ledger/lib/security-server.md +62 -0
- package/governance/ledger/lib/security-web.md +51 -0
- package/governance/ledger/lib/tanstack-query.md +57 -0
- package/governance/ledger/lib/test-scope.md +43 -0
- package/governance/ledger/lib/testing-go.md +57 -0
- package/governance/ledger/lib/testing-php.md +51 -0
- package/governance/ledger/lib/testing-py.md +67 -0
- package/governance/ledger/lib/testing-ts.md +63 -0
- package/governance/ledger/lib/zod.md +47 -0
- package/governance/ledger/tooling/ci-workflow.md +33 -0
- package/governance/ledger/tooling/code-comments.md +48 -0
- package/governance/ledger/tooling/config-comments.md +27 -0
- package/governance/ledger/tooling/dependencies.md +38 -0
- package/governance/ledger/ui/a11y.md +55 -0
- package/governance/ledger/ui/copy.md +49 -0
- package/governance/ledger/ui/design-reference.md +42 -0
- package/governance/ledger/ui/design-taste.md +19 -0
- package/governance/ledger/ui/forms.md +71 -0
- package/governance/ledger/ui/interface-casing.md +47 -0
- package/governance/ledger/ui/keyboard.md +68 -0
- package/governance/ledger/ui/link-behavior.md +29 -0
- package/governance/ledger/ui/motion.md +33 -0
- package/governance/ledger/ui/surface-capture.md +69 -0
- package/governance/ledger/ui/ux-completeness.md +79 -0
- package/governance/renames.toml +0 -2
- package/governance/rules/claude/output.md +5 -1
- package/governance/rules/code/routing.md +5 -1
- package/governance/rules/lang/go.md +7 -16
- package/governance/rules/lang/php.md +3 -3
- package/governance/rules/lang/python.md +9 -18
- package/governance/rules/lang/typescript.md +9 -19
- package/governance/rules/lib/database.md +5 -5
- package/governance/rules/lib/e2e-reliability.md +4 -6
- package/governance/rules/lib/pydantic.md +14 -16
- package/governance/rules/lib/security-server.md +4 -4
- package/governance/rules/lib/security-web.md +6 -10
- package/governance/rules/lib/tanstack-query.md +10 -12
- package/governance/rules/lib/test-scope.md +4 -4
- package/governance/rules/lib/testing-go.md +1 -2
- package/governance/rules/lib/testing-php.md +4 -5
- package/governance/rules/lib/testing-py.md +11 -19
- package/governance/rules/lib/testing-ts.md +7 -16
- package/governance/rules/lib/zod.md +6 -8
- package/governance/rules/tooling/code-comments.md +2 -4
- package/governance/rules/tooling/config-comments.md +1 -4
- package/governance/rules/tooling/dependencies.md +1 -1
- package/governance/rules/ui/a11y.md +16 -45
- package/governance/rules/ui/copy.md +6 -9
- package/governance/rules/ui/forms.md +13 -19
- package/governance/rules/ui/interface-casing.md +5 -7
- package/governance/rules/ui/keyboard.md +38 -0
- package/governance/rules/ui/link-behavior.md +3 -3
- package/governance/rules/ui/motion.md +3 -3
- package/governance/rules/ui/surface-capture.md +15 -27
- package/governance/rules/ui/ux-completeness.md +16 -39
- package/governance/stacks/base.toml +0 -1
- package/package.json +1 -1
- package/scripts/core/install-check.sh +1 -1
- package/src/claude/cases/workflow.ts +12 -0
- package/src/cli/help.ts +0 -1
- package/src/cli.ts +0 -2
- package/src/commands/context.ts +57 -3
- package/src/commands/gov.ts +4 -0
- package/src/commands/init.ts +2 -2
- package/src/commands/labels.ts +83 -3
- package/src/commands/markdown.ts +188 -21
- package/src/commands/sessions.ts +36 -3
- package/src/commands/tasks.ts +180 -0
- package/src/commands/tooling.ts +18 -5
- package/src/commands/worktrees.ts +2 -0
- package/src/context/coverage.ts +210 -0
- package/src/context/gate.ts +12 -3
- package/src/design/components.ts +1 -1
- package/src/gate/stages.ts +1 -1
- package/src/gov/audit.ts +22 -2
- package/src/init/plan.ts +1 -8
- package/src/init/steps.ts +44 -7
- package/src/intake/items.ts +14 -0
- package/src/inventory/subjects.ts +1 -1
- package/src/labels/closing.ts +46 -0
- package/src/markdown/gated.ts +250 -0
- package/src/markdown/scope.ts +119 -2
- package/src/migrate/rename.ts +6 -0
- package/src/migrate/scratch-evidence.ts +12 -4
- package/src/records/backup.ts +3 -3
- package/src/records/validate.ts +3 -3
- package/src/roots/record.ts +17 -8
- package/src/sessions/claim.ts +7 -0
- package/src/sessions/live.ts +53 -6
- package/src/sessions/registry.ts +11 -0
- package/src/sessions/resolve.ts +32 -5
- package/src/tasks/closes.ts +136 -0
- package/src/tasks/record.ts +1 -1
- package/src/tooling/inject.ts +26 -7
- package/src/tooling/package.ts +32 -0
- package/src/tooling/read.ts +46 -3
- package/src/tooling/scan.ts +8 -2
- package/src/worktrees/reclaim.ts +16 -1
- package/tooling/astro/reference.md +64 -93
- package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
- package/tooling/base/configs/scripts/verify.ts +2 -2
- package/tooling/base/reference.md +1 -9
- package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
- package/tooling/base/seeds/canon/context/development/index.md +11 -0
- package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
- package/tooling/base/seeds/canon/context/index.md +1 -2
- package/tooling/claude/manifest.toml +1 -5
- package/tooling/claude/reference.md +36 -59
- package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
- package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
- package/tooling/claude/seeds/CLAUDE.md +2 -2
- package/tooling/nextjs/reference.md +0 -6
- package/tooling/php/reference.md +0 -4
- package/tooling/web/configs/.github/workflows/verify.yml +28 -0
- package/tooling/web/configs/.oxlintrc.json +7 -0
- package/tooling/web/configs/e2e/capture-types.ts +35 -0
- package/tooling/web/configs/e2e/screenshot.ts +23 -72
- package/tooling/web/manifest.toml +1 -1
- package/tooling/web/reference.md +77 -124
- package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
- package/governance/rules/canon/task-scope.md +0 -12
- package/src/commands/wiki.ts +0 -100
- package/src/wiki/init.ts +0 -85
|
@@ -18,12 +18,9 @@ esac
|
|
|
18
18
|
file_path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
|
|
19
19
|
[ -n "$file_path" ] || exit 0
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
# one, since inside a dotted root the dot hides nothing already hidden. A guard
|
|
23
|
-
# fixed at the old spelling warns on every correct scratch write in a project
|
|
24
|
-
# the move has reached.
|
|
21
|
+
# The scratch folder is `.canon/tmp/`, so a write there is the correct one.
|
|
25
22
|
case "$file_path" in
|
|
26
|
-
*/.
|
|
23
|
+
*/.canon/tmp/*) exit 0 ;;
|
|
27
24
|
esac
|
|
28
25
|
|
|
29
26
|
# A background session's temp folder is the harness's own, told to the session
|
|
@@ -55,11 +52,7 @@ esac
|
|
|
55
52
|
session=$(printf '%s' "$input" | jq -r '.session_id // "none"')
|
|
56
53
|
key=$(printf '%s' "$session" | tr -c 'A-Za-z0-9' '_')
|
|
57
54
|
project="${CLAUDE_PROJECT_DIR:-.}"
|
|
58
|
-
|
|
59
|
-
marker_dir="$project/.canon/tmp/hooks/scratch-guard"
|
|
60
|
-
else
|
|
61
|
-
marker_dir="$project/.claude/.tmp/hooks/scratch-guard"
|
|
62
|
-
fi
|
|
55
|
+
marker_dir="$project/.canon/tmp/hooks/scratch-guard"
|
|
63
56
|
marker="$marker_dir/$key"
|
|
64
57
|
[ -f "$marker" ] && exit 0
|
|
65
58
|
mkdir -p "$marker_dir"
|
|
@@ -18,14 +18,9 @@ session=$(printf '%s' "$input" | jq -r '.session_id // empty')
|
|
|
18
18
|
[ -n "$session" ] || exit 0
|
|
19
19
|
|
|
20
20
|
key=$(printf '%s' "$session" | tr -c 'A-Za-z0-9' '_')
|
|
21
|
-
# The marker is scratch, so it
|
|
22
|
-
# root the project carries rather than creating a second one beside it.
|
|
21
|
+
# The marker is scratch, so it lives under `.canon/tmp/`.
|
|
23
22
|
project="${CLAUDE_PROJECT_DIR:-.}"
|
|
24
|
-
|
|
25
|
-
marker_dir="$project/.canon/tmp/hooks/search-reminder"
|
|
26
|
-
else
|
|
27
|
-
marker_dir="$project/.claude/.tmp/hooks/search-reminder"
|
|
28
|
-
fi
|
|
23
|
+
marker_dir="$project/.canon/tmp/hooks/search-reminder"
|
|
29
24
|
marker="$marker_dir/$key"
|
|
30
25
|
[ -f "$marker" ] && exit 0
|
|
31
26
|
mkdir -p "$marker_dir"
|
|
@@ -18,11 +18,9 @@ case "$file" in
|
|
|
18
18
|
*) exit 0 ;;
|
|
19
19
|
esac
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
# audits a project's own session records the moment the move reaches it, which
|
|
23
|
-
# reports findings against prose nobody publishes.
|
|
21
|
+
# Session record folders are skipped, since they hold prose nobody publishes.
|
|
24
22
|
case "$file" in
|
|
25
|
-
*.claude
|
|
23
|
+
*.claude/review/* | *.claude/plans/*) exit 0 ;;
|
|
26
24
|
*.canon/tmp/* | *.canon/review/* | *.canon/plans/*) exit 0 ;;
|
|
27
25
|
esac
|
|
28
26
|
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Context
|
|
6
6
|
|
|
7
|
-
- Before non-trivial work in a domain read `canon/context
|
|
7
|
+
- Before non-trivial work in a domain, read its entry under `canon/context/`. Find it from the index anchor below.
|
|
8
8
|
|
|
9
9
|
@canon/REQUIREMENTS.md
|
|
10
10
|
@canon/context/index.md
|
|
11
11
|
|
|
12
12
|
## Commands
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- Run `bun run check` to verify and `bun run format` to fix before committing. The pre-push hook runs `check`, which writes nothing.
|
|
15
15
|
|
|
16
16
|
## Key paths
|
|
17
17
|
|
|
@@ -64,12 +64,6 @@ Next has no config-file port hook, unlike `server.port` in `astro.config.mjs` or
|
|
|
64
64
|
|
|
65
65
|
`create-next-app`'s default `tsconfig.json` needs no changes beyond project-specific path aliases, so a golden copy would ship nothing the scaffold does not already write.
|
|
66
66
|
|
|
67
|
-
## Gitignore (extend)
|
|
68
|
-
|
|
69
|
-
These `[gitignore]` groups mirror the manifest.
|
|
70
|
-
|
|
71
|
-
- `"# Next" = [".next/"]`
|
|
72
|
-
|
|
73
67
|
## Development docs (extend)
|
|
74
68
|
|
|
75
69
|
Append these rows to the `## Scripts` table.
|
package/tooling/php/reference.md
CHANGED
|
@@ -59,10 +59,6 @@ The manifest prepares a scaffold that lacks a `package.json`.
|
|
|
59
59
|
- The manifest's `[verify] prepare` runs checklist steps 2 and 5 for `canon tooling verify php`, being `bun init -y` and the `composer require --dev` line.
|
|
60
60
|
- The scaffold writes no `package.json`, and a verify that reaches its end with none fails.
|
|
61
61
|
|
|
62
|
-
## Gitignore
|
|
63
|
-
|
|
64
|
-
- `# PHP`: `vendor/`, `.php-cs-fixer.cache`, `.phpunit.cache/`, `.phpunit.result.cache`
|
|
65
|
-
|
|
66
62
|
## CI
|
|
67
63
|
|
|
68
64
|
- Install PHP with `shivammathur/setup-php` and `tools: composer`.
|
|
@@ -62,9 +62,37 @@ jobs:
|
|
|
62
62
|
- name: Install Dependencies
|
|
63
63
|
run: bun install --frozen-lockfile
|
|
64
64
|
|
|
65
|
+
- name: Detect Browser Tests
|
|
66
|
+
id: browser
|
|
67
|
+
run: |
|
|
68
|
+
if jq -e '.scripts["test:browser"]' package.json >/dev/null; then
|
|
69
|
+
echo "enabled=true" >> "$GITHUB_OUTPUT"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
- name: Install Playwright System Dependencies
|
|
73
|
+
if: steps.browser.outputs.enabled == 'true'
|
|
74
|
+
timeout-minutes: 10
|
|
75
|
+
run: bunx playwright install-deps chromium
|
|
76
|
+
|
|
77
|
+
- name: Cache Playwright Browsers
|
|
78
|
+
id: playwright-cache
|
|
79
|
+
if: steps.browser.outputs.enabled == 'true'
|
|
80
|
+
uses: actions/cache@v6
|
|
81
|
+
with:
|
|
82
|
+
path: ~/.cache/ms-playwright
|
|
83
|
+
key: playwright-chromium-${{ runner.os }}-${{ hashFiles('**/package.json') }}
|
|
84
|
+
|
|
85
|
+
- name: Install Playwright Chromium
|
|
86
|
+
if: steps.browser.outputs.enabled == 'true' && steps.playwright-cache.outputs.cache-hit != 'true'
|
|
87
|
+
run: bunx playwright install chromium
|
|
88
|
+
|
|
65
89
|
- name: Run Tests
|
|
66
90
|
run: bun run test:coverage
|
|
67
91
|
|
|
92
|
+
- name: Run Browser Tests
|
|
93
|
+
if: steps.browser.outputs.enabled == 'true'
|
|
94
|
+
run: bun run test:browser
|
|
95
|
+
|
|
68
96
|
build-verify:
|
|
69
97
|
name: 🏗️ Build
|
|
70
98
|
runs-on: ubuntu-latest
|
|
@@ -183,6 +183,13 @@
|
|
|
183
183
|
"browser": true
|
|
184
184
|
}
|
|
185
185
|
},
|
|
186
|
+
{
|
|
187
|
+
"files": ["**/components/ui/**"],
|
|
188
|
+
"plugins": ["react"],
|
|
189
|
+
"rules": {
|
|
190
|
+
"react/only-export-components": "off"
|
|
191
|
+
}
|
|
192
|
+
},
|
|
186
193
|
{
|
|
187
194
|
"files": ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
|
|
188
195
|
"rules": {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Page } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
/** One addressable part of a route, captured beside the whole-page frame. */
|
|
4
|
+
export interface CaptureSection {
|
|
5
|
+
name: string
|
|
6
|
+
selector: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Viewport {
|
|
10
|
+
readonly name: string
|
|
11
|
+
readonly width: number
|
|
12
|
+
readonly height: number
|
|
13
|
+
/** Whether a case flagged `evidence: true` also writes its frames at this width. */
|
|
14
|
+
readonly evidence: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CaptureCase {
|
|
18
|
+
section: string
|
|
19
|
+
theme: string
|
|
20
|
+
route: string
|
|
21
|
+
/** Names of viewports this case skips, for a route that reflows rather than breaks at that width. */
|
|
22
|
+
excludeViewports?: readonly string[]
|
|
23
|
+
evidence?: boolean
|
|
24
|
+
/** Selectors painted over in every frame the case writes, for a value that moves between runs with no code change. */
|
|
25
|
+
mask?: readonly string[]
|
|
26
|
+
sections?: CaptureSection[]
|
|
27
|
+
setup?: (page: Page) => Promise<void>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** What the harness loads from the project's `e2e/capture/cases.ts`. */
|
|
31
|
+
export interface CaptureModule {
|
|
32
|
+
CASES: CaptureCase[]
|
|
33
|
+
/** Where a case flagged `evidence: true` writes its frames, relative to the working directory. */
|
|
34
|
+
EVIDENCE_ROOT: string
|
|
35
|
+
}
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import type { Locator, Page } from '@playwright/test'
|
|
2
2
|
import { chromium } from '@playwright/test'
|
|
3
|
+
import { existsSync } from 'fs'
|
|
3
4
|
import { mkdir } from 'fs/promises'
|
|
4
5
|
import path from 'path'
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
interface Viewport {
|
|
13
|
-
readonly name: string
|
|
14
|
-
readonly width: number
|
|
15
|
-
readonly height: number
|
|
16
|
-
/** Whether a case flagged `evidence: true` also writes its frames at this width. */
|
|
17
|
-
readonly evidence: boolean
|
|
18
|
-
}
|
|
6
|
+
import { pathToFileURL } from 'url'
|
|
7
|
+
import type {
|
|
8
|
+
CaptureCase,
|
|
9
|
+
CaptureModule,
|
|
10
|
+
CaptureSection,
|
|
11
|
+
Viewport,
|
|
12
|
+
} from './capture-types'
|
|
19
13
|
|
|
20
14
|
/**
|
|
21
15
|
* The breakpoint buckets every case is crossed with, named by width. 320 is
|
|
@@ -30,61 +24,18 @@ const VIEWPORTS: readonly Viewport[] = [
|
|
|
30
24
|
{ name: '1536', width: 1536, height: 800, evidence: false },
|
|
31
25
|
]
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
section: string
|
|
35
|
-
theme: string
|
|
36
|
-
route: string
|
|
37
|
-
/** Names of viewports this case skips, for a route that reflows rather than breaks at that width. */
|
|
38
|
-
excludeViewports?: readonly string[]
|
|
39
|
-
evidence?: boolean
|
|
40
|
-
/** Selectors painted over in every frame the case writes, for a value that moves between runs with no code change. */
|
|
41
|
-
mask?: readonly string[]
|
|
42
|
-
sections?: CaptureSection[]
|
|
43
|
-
setup?: (page: Page) => Promise<void>
|
|
44
|
-
}
|
|
27
|
+
const CASES_FILE = path.resolve('e2e/capture/cases.ts')
|
|
45
28
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{ name: 'top', selector: '#top' },
|
|
53
|
-
{ name: 'proof', selector: '#proof' },
|
|
54
|
-
{ name: 'ask', selector: '#ask' },
|
|
55
|
-
{ name: 'rules', selector: '#rules' },
|
|
56
|
-
{ name: 'skills', selector: '#skills' },
|
|
57
|
-
{ name: 'plan', selector: '#plan' },
|
|
58
|
-
{ name: 'dispatch', selector: '#dispatch' },
|
|
59
|
-
{ name: 'workers', selector: '#workers' },
|
|
60
|
-
{ name: 'gate', selector: '#gate' },
|
|
61
|
-
{ name: 'evidence', selector: '#evidence' },
|
|
62
|
-
{ name: 'loop', selector: '#loop' },
|
|
63
|
-
{ name: 'merge', selector: '#merge' },
|
|
64
|
-
{ name: 'provenance', selector: '#provenance' },
|
|
65
|
-
{ name: 'start', selector: '#start' },
|
|
66
|
-
{ name: 'field', selector: '#field' },
|
|
67
|
-
{ name: 'close', selector: '#close' },
|
|
68
|
-
]
|
|
29
|
+
if (!existsSync(CASES_FILE)) {
|
|
30
|
+
console.error(
|
|
31
|
+
'e2e/capture/cases.ts is missing. Run canon tooling sync to seed it.',
|
|
32
|
+
)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
69
35
|
|
|
70
|
-
const CASES
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
theme: 'default',
|
|
74
|
-
route: '/',
|
|
75
|
-
evidence: true,
|
|
76
|
-
mask: ['.version'],
|
|
77
|
-
sections: HOME_SECTIONS,
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
section: 'home',
|
|
81
|
-
theme: 'dark',
|
|
82
|
-
route: '/',
|
|
83
|
-
mask: ['.version'],
|
|
84
|
-
sections: HOME_SECTIONS,
|
|
85
|
-
setup: (page) => page.emulateMedia({ colorScheme: 'dark' }),
|
|
86
|
-
},
|
|
87
|
-
]
|
|
36
|
+
const { CASES, EVIDENCE_ROOT } = (await import(
|
|
37
|
+
pathToFileURL(CASES_FILE).href
|
|
38
|
+
)) as CaptureModule
|
|
88
39
|
|
|
89
40
|
/** One case at one viewport, which is the unit a filter selects and a context is built for. */
|
|
90
41
|
interface CaptureRun {
|
|
@@ -170,9 +121,9 @@ async function settle(
|
|
|
170
121
|
const element = page.locator(section.selector)
|
|
171
122
|
// Read the count before scrolling, since a selector matching nothing
|
|
172
123
|
// otherwise costs the default timeout once per section. A miss is
|
|
173
|
-
// reported and skipped rather than raised, because `CASES`
|
|
174
|
-
// a
|
|
175
|
-
//
|
|
124
|
+
// reported and skipped rather than raised, because the seeded `CASES` name
|
|
125
|
+
// sections a fresh target's page may not have, and it would otherwise
|
|
126
|
+
// capture nothing at all. The project owning the
|
|
176
127
|
// selectors is the one that tests them, which is what the section spec
|
|
177
128
|
// beside its own page does.
|
|
178
129
|
if ((await element.count()) === 0) {
|
|
@@ -240,7 +191,7 @@ async function markFloatingChrome(page: Page) {
|
|
|
240
191
|
/**
|
|
241
192
|
* Turns a case's mask selectors into the locators every frame paints over. A
|
|
242
193
|
* selector matching nothing is reported and kept out rather than raised, for
|
|
243
|
-
* the same
|
|
194
|
+
* the same reason `settle` gives for a missing section.
|
|
244
195
|
*/
|
|
245
196
|
async function resolveMask(
|
|
246
197
|
page: Page,
|
|
@@ -318,7 +269,7 @@ for (const { captureCase, viewport, label } of RUNS) {
|
|
|
318
269
|
const mask = await resolveMask(page, label, captureCase.mask ?? [])
|
|
319
270
|
|
|
320
271
|
const sweepDir = path.join(OUT_DIR, captureCase.section)
|
|
321
|
-
const evidenceDir = path.join(
|
|
272
|
+
const evidenceDir = path.join(EVIDENCE_ROOT, captureCase.section)
|
|
322
273
|
const file = `${viewport.name}--${captureCase.theme}.png`
|
|
323
274
|
const writesEvidence = captureCase.evidence && viewport.evidence
|
|
324
275
|
|
package/tooling/web/reference.md
CHANGED
|
@@ -4,139 +4,118 @@
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The web layer covers the tooling shared across Vite + React, Astro, and
|
|
7
|
+
The web layer covers the tooling shared across Vite + React, Astro, and Next.js. It sets lint, unit and end-to-end tests, Tailwind, screenshots, ports, and CI, and each framework stack adds its own wiring on top.
|
|
8
8
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
Golden configs live in `tooling/web/configs/`. `canon tooling sync web . --write` copies them into the target and replaces whatever sits at those paths. They are the source of truth, so this reference covers rationale and the configs show the setup.
|
|
9
|
+
## oxlint
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- Run the recommended, React, and test-scoped vitest rules, with `check-file` and `simple-import-sort` as JS plugins
|
|
12
|
+
- Pin oxlint exactly, since its JS plugin host is alpha and a minor release could break `check-file` or `simple-import-sort`
|
|
13
|
+
- Keep import sorting on `simple-import-sort`, because oxfmt's built-in sort orders differently and would rewrite every import block
|
|
14
|
+
- Expect sync to force-replace `lint` and `lint:fix`, so a target stops running ESLint. Astro keeps ESLint, which its own reference covers.
|
|
15
|
+
- Delete a leftover `eslint.config.js` or `eslint.config.mjs` and `bun remove` the ESLint packages by hand after that sync, since sync deletes nothing a stack stopped shipping
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
## Vitest
|
|
16
18
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
+
- Use jsdom, globals on, and `src/test/setup.ts`, which imports `@testing-library/jest-dom/vitest` and runs `cleanup` after each test
|
|
20
|
+
- Test components with `@testing-library/react` and `@testing-library/user-event`
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
## Playwright
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
- Keep end-to-end specs in `e2e/`, running Chromium alone for a Chrome extension and every browser for a web app
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
- `VIEWPORTS` holds 320, 768, 1280, and 1536. Width 320 is the base a page has to hold without wrapping or clipping.
|
|
26
|
-
- `excludeViewports` skips a width, for a route whose long-form prose reflows at 320 instead of breaking.
|
|
27
|
-
- `evidence: true` also writes `evidence/<section>/<width>--<theme>.png` at 320 and 1280 alone, keeping the tracked set at twice the sections rather than four times.
|
|
26
|
+
## Tailwind
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
- Use v4 through `@tailwindcss/vite`, never the v3 integration
|
|
29
|
+
- Add shadcn through the sequence under `## Adding shadcn`, since a bare `init` overwrites `src/styles/global.css` and waits on prompts
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
## Adding shadcn
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
1. Copy `src/styles/global.css` aside, since init overwrites it.
|
|
34
|
+
2. Confirm `global.css` starts with `@import 'tailwindcss';`, which init reads to find Tailwind v4, and that the `@/*` alias sits in both `tsconfig.json` and `vite.config.ts`.
|
|
35
|
+
3. Take a preset name from `bunx shadcn@latest init --help`, since `-p` names a preset and not a primary color, and the default drifts between releases.
|
|
36
|
+
4. Run `bunx shadcn@latest init -t vite -b radix -p <preset> -y </dev/null` with a timeout. The stdin redirect stops a non-TTY session from hanging on a prompt.
|
|
37
|
+
5. Expect `components.json`, `src/lib/utils.ts`, and `src/components/ui/button.tsx`. Init installs the `cn` package for the helper and merges its theme into `global.css`, so reapply any copied styles.
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
## TypeScript and layout
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
- Keep app code in `src/`, Playwright in `e2e/`, shell in `scripts/`, and the Vitest globals in `src/test/setup.ts`
|
|
42
|
+
- Map the `@` alias to `./src` in both tsconfig and the framework's build config
|
|
43
|
+
- Keep the tsconfig at the root with `noEmit: true` in a Vite stack. Astro keeps the scaffold default from `@astrojs/check`.
|
|
44
|
+
- Typecheck with `tsc --noEmit`, never `tsc -b`, since composite mode emits `.js` next to `.ts` and the linter lints it
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
- Fonts, images, and same-origin frames are waited out on a bounded condition. A second `networkidle` does not re-arm for a load a scroll started.
|
|
44
|
-
- A section frame drops floating chrome (`position: sticky` or `fixed`), which would otherwise ride the scroll into the frame. The whole-page frame is shot first and keeps its chrome.
|
|
46
|
+
## Screenshot cases
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
- Edit the `CASES` in the seeded `e2e/capture/cases.ts`, one entry per output file naming a section, a theme, and a route, since sync overwrites the `e2e/screenshot.ts` harness
|
|
49
|
+
- Move cases from `e2e/screenshot.ts` to `e2e/capture/cases.ts` before a sync, and set `EVIDENCE_ROOT = 'evidence'` to keep an existing baseline
|
|
50
|
+
- Expect each case crossed with `VIEWPORTS`, written to `screenshots/<hostname>/<section>/<width>--<theme>.png`, so local and deployed runs stay apart
|
|
51
|
+
- `VIEWPORTS` holds 320, 768, 1280, and 1536. Width 320 is the base a page has to hold without wrapping or clipping.
|
|
52
|
+
- Set `excludeViewports` to skip a width, for a route whose long-form prose reflows at 320 instead of breaking
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
## Screenshot sections and masks
|
|
49
55
|
|
|
50
|
-
- `
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
56
|
+
- Set `evidence: true` to also write `<EVIDENCE_ROOT>/<section>/<width>--<theme>.png` at 320 and 1280 alone. `EVIDENCE_ROOT` defaults to `e2e/evidence`.
|
|
57
|
+
- Name `sections` on a case, one `{ name, selector }` per addressable part of the route, each written as its own frame beside the whole-page one
|
|
58
|
+
- Expect a section frame at `screenshots/<hostname>/<section>/<name>/<width>--<theme>.png`, plus the same path under `EVIDENCE_ROOT` where flagged
|
|
59
|
+
- Expect a selector matching nothing to be reported and skipped, since a seeded list may name sections the page lacks, and test that they resolve in the project owning the selectors
|
|
60
|
+
- List under `mask` the selectors painted over in every frame, for a value that moves with no code change, so a double capture compares the rest
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
## Screenshot settling
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
- Expect `reducedMotion: 'reduce'`, and each named section scrolled into view so an `IntersectionObserver` fires and `loading="lazy"` frames load before the page returns to the top
|
|
65
|
+
- Expect fonts, images, and same-origin frames waited out on a bounded condition, since a second `networkidle` does not re-arm for a load a scroll started
|
|
66
|
+
- Expect a section frame to drop floating chrome (`position: sticky` or `fixed`), while the whole-page frame is shot first and keeps its chrome
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
- `scripts/readme-screenshot.sh` captures one case under `SCREENSHOT_FILTER` into `assets/evidence/readme/`. `README_FILTER` ships empty, so it exits 1 until a project fills it.
|
|
61
|
-
- `.github/workflows/readme-screenshot.yml` ships its path list as `REPLACE_WITH_PROJECT_PATHS`, and its first step exits 1 while that stays.
|
|
62
|
-
- `.github/workflows/verify.yml` runs `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests`.
|
|
68
|
+
## Screenshot run flags
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
- `SCREENSHOT_FILTER` keeps cases whose `<section>/<width>--<theme>` label contains a comma-separated term, and exits 1 listing the labels on no match
|
|
71
|
+
- `--check-console-clean` exits 1 with the list if any `console` error fired, turning the capture into a smoke check
|
|
72
|
+
- `--require-base-url` exits 1 before launching a browser when `SCREENSHOT_BASE_URL` is unset, so a deployment script cannot capture `localhost`
|
|
73
|
+
- With a base URL, every flagged case is skipped so a production smoke run writes nothing to the committed path, and zero cases run exits 1
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
## Screenshot evidence
|
|
67
76
|
|
|
68
|
-
- `
|
|
69
|
-
-
|
|
70
|
-
- `
|
|
71
|
-
- `tsconfig.json` differs in its `extends` target. Astro uses `astro/tsconfigs/strict` and Vite projects use scaffold defaults.
|
|
77
|
+
- Expect the sweep under `screenshots/` to be ignored and only a flagged case's `EVIDENCE_ROOT` output tracked, so a target's first capture is the baseline it commits
|
|
78
|
+
- Size a case's `sections` list against the frames each later change regenerates, since a case naming sections commits a folder per section
|
|
79
|
+
- Run the capture after a surface changes, component files included, per `governance/rules/ui/surface-capture.md`, unless the production build strips the component out
|
|
72
80
|
|
|
73
|
-
##
|
|
81
|
+
## Screenshot scripts and workflows
|
|
74
82
|
|
|
75
|
-
- `
|
|
76
|
-
-
|
|
77
|
-
-
|
|
83
|
+
- `scripts/screenshot.sh` sources `scripts/lib/preview-server.sh`, builds, serves on `PREVIEW_PORT`, waits for the port, and traps the whole process group on exit
|
|
84
|
+
- `scripts/readme-screenshot.sh` captures one case under `SCREENSHOT_FILTER` into `assets/evidence/readme/`, and exits 1 until a project fills `README_FILTER`
|
|
85
|
+
- `.github/workflows/readme-screenshot.yml` ships its path list as `REPLACE_WITH_PROJECT_PATHS`, and its first step exits 1 while that stays
|
|
86
|
+
- `.github/workflows/verify.yml` runs `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests`. `unit-tests` installs Chromium and runs `test:browser` only when the project defines that script.
|
|
87
|
+
- Read `governance/rules/tooling/ci-workflow.md` for when a workflow's commit-back is right and when a report is
|
|
78
88
|
|
|
79
89
|
## Ports
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
### Deriving the port
|
|
84
|
-
|
|
85
|
-
The helper owns the offset, and a config only adds it.
|
|
86
|
-
|
|
87
|
-
- Derive every served port from `scripts/worktree-port.sh`. Never write a port literal into a script string.
|
|
91
|
+
- Derive every served port from `scripts/worktree-port.sh`, never a port literal in a script string, since two worktrees of one repository otherwise attach to one server
|
|
88
92
|
- Read `WORKTREE_PORT_OFFSET` in a config and add it to the stack's default port. Unset yields the default, so a plain clone keeps its port.
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
### Calling the helper
|
|
94
|
-
|
|
95
|
-
Call it as `VAR=$(bash scripts/worktree-port.sh) && export VAR && <server>`, never as `VAR=$(bash scripts/worktree-port.sh) <server>`. An assignment prefix discards the exit status of its own substitution. The shorter form starts the server with `VAR` empty, which every config reads as offset zero.
|
|
96
|
-
|
|
97
|
-
### Refusal in a removed worktree
|
|
98
|
-
|
|
99
|
-
Expect a non-zero exit and no port from a folder left under `.claude/worktrees/` once its worktree is gone. Git reports the parent repository from inside one, so every base served would land on the main checkout's port.
|
|
100
|
-
|
|
101
|
-
- A folder whose own `.git` was deleted refuses only under that directory, since location alone separates it from an ordinary subdirectory.
|
|
102
|
-
- A folder whose `.git` names a pruned administrative directory refuses wherever it sits.
|
|
103
|
-
- Set `WORKTREE_PORT_OFFSET` by hand to serve from such a folder anyway. It is the one override and is checked before any directory test.
|
|
104
|
-
|
|
105
|
-
## Anti-patterns
|
|
106
|
-
|
|
107
|
-
Negative knowledge that costs a failed run to relearn.
|
|
108
|
-
|
|
109
|
-
| Do NOT | Why and what to do |
|
|
110
|
-
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
111
|
-
| Use `exclude: ["e2e"]` | Bare-folder globs miss. Use `"e2e/**/*"`. |
|
|
112
|
-
| Put Playwright `trace` at the top of the config | It lives under `use`. |
|
|
113
|
-
| Ship Vitest failing on no tests | Fresh scaffolds have none. Use `passWithNoTests: true` until one exists. |
|
|
114
|
-
| Skip `skipLibCheck: true` in Vite + React | `@testing-library/jest-dom` and Vite's `module-runner` conflict otherwise. |
|
|
115
|
-
| Use `tsc -b` in a Vite project | Composite mode emits `.js` next to `.ts` and the linter lints it. Use `tsc --noEmit`. |
|
|
116
|
-
| Trust `vite-react`'s scaffolded `lint` script | Its bare `oxlint` exits 0 on warnings. `[scripts.override]` forces `--max-warnings 0` over it. |
|
|
117
|
-
| Run `bunx shadcn@latest init` over `global.css` | It silently overwrites `src/styles/global.css`. Back up first, and pass `-t -b -p -y` to skip prompts. |
|
|
93
|
+
- Expect an offset from a band of 50 hashed from the worktree folder name, and set `WORKTREE_PORT_OFFSET` by hand to break a tie between two worktrees
|
|
94
|
+
- Set `strictPort` on every dev and preview server, and Playwright `reuseExistingServer: false`, since a walked or reused server passes against the wrong code
|
|
95
|
+
- Call the helper as `VAR=$(bash scripts/worktree-port.sh) && export VAR && <server>`, since an assignment prefix discards the substitution's exit and starts the server at offset zero
|
|
118
96
|
|
|
119
|
-
##
|
|
97
|
+
## Ports in a removed worktree
|
|
120
98
|
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
99
|
+
- Expect a non-zero exit and no port from a folder left under `.claude/worktrees/` once its worktree is gone, since git reports the parent repository from inside one
|
|
100
|
+
- Expect a folder whose own `.git` was deleted to refuse only under that directory, since location alone separates it from an ordinary subdirectory
|
|
101
|
+
- Expect a folder whose `.git` names a pruned administrative directory to refuse wherever it sits
|
|
102
|
+
- Set `WORKTREE_PORT_OFFSET` by hand to serve from such a folder anyway, since it is the one override and is checked before any directory test
|
|
125
103
|
|
|
126
|
-
##
|
|
104
|
+
## lint-staged (extend)
|
|
127
105
|
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
- Keep import sorting on `simple-import-sort`, because oxfmt's built-in sort orders differently and would rewrite every import block.
|
|
106
|
+
- Add `**/*.{js,jsx,ts,tsx}` running `oxlint --fix --max-warnings 0` and `oxfmt --no-error-on-unmatched-pattern`
|
|
107
|
+
- Extend the oxfmt glob to include `css`, giving `**/*.{json,css,md}`
|
|
131
108
|
|
|
132
|
-
##
|
|
109
|
+
## Verify script
|
|
133
110
|
|
|
134
|
-
-
|
|
135
|
-
-
|
|
111
|
+
- Expect `scripts/verify.json` to require `typecheck`, `lint`, `test:run`, and `build`, which base's `scripts/verify.ts` runs in its fixed order
|
|
112
|
+
- That order is typecheck, lint, format, shell where the `shell` stack declares it, unit tests, build, markdown bans, then the card exclusion check
|
|
113
|
+
- Expect the card stage to run `scripts/check-card-exclusion.sh` whenever that file is installed, so a project with no card route runs one less stage with no override
|
|
136
114
|
|
|
137
115
|
## CI docs (extend)
|
|
138
116
|
|
|
139
|
-
Extend `canon/context/development/ci.md`
|
|
117
|
+
- Extend the `## Checks` table in `canon/context/development/ci.md` with the web jobs <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
|
118
|
+
- Document under `## Running CI locally` that `bun run check:full` runs verify plus `test:e2e`
|
|
140
119
|
|
|
141
120
|
| Check | Command | What it asserts |
|
|
142
121
|
| --------- | ----------------------- | ------------------------------------------- |
|
|
@@ -146,11 +125,10 @@ Extend `canon/context/development/ci.md` so the `## Checks` table reflects the w
|
|
|
146
125
|
| Build | `bun run build` | Production build succeeds |
|
|
147
126
|
| E2E | `bun run test:e2e` | Playwright passes against the built preview |
|
|
148
127
|
|
|
149
|
-
Under `## Running CI locally`, document that `bun run check:full` runs verify plus `test:e2e`.
|
|
150
|
-
|
|
151
128
|
## Development docs (extend)
|
|
152
129
|
|
|
153
|
-
Extend the `development` context entry under `canon/context/`
|
|
130
|
+
- Extend the `## Scripts` table in the `development` context entry under `canon/context/` with every web script
|
|
131
|
+
- Expect each framework stack to add its `dev`, `build`, `preview`, and `typecheck` rows
|
|
154
132
|
|
|
155
133
|
| Command | Purpose |
|
|
156
134
|
| --------------------------- | --------------------------------------- |
|
|
@@ -164,28 +142,3 @@ Extend the `development` context entry under `canon/context/` so the `## Scripts
|
|
|
164
142
|
| `bun run screenshot` | Build, preview, capture screenshots. |
|
|
165
143
|
| `bun run readme-screenshot` | Capture the README frame. |
|
|
166
144
|
| `bun run smoke:prod` | Capture against a required base URL. |
|
|
167
|
-
|
|
168
|
-
### Screenshot contract
|
|
169
|
-
|
|
170
|
-
`canon tooling verify <stack>` is the only automated caller of `bun run screenshot`. It runs the script for any stack whose `package.json` declares it and asserts that PNG files land under `screenshots/`.
|
|
171
|
-
|
|
172
|
-
- The count is a recursive find with no depth limit, so the seed's section folders satisfy it. Do not flatten the layout to protect that check.
|
|
173
|
-
- `governance/rules/ui/surface-capture.md` asks a session to run the capture after a surface changes, component files included, with an exemption for a component the production build strips out.
|
|
174
|
-
- The sweep under `screenshots/` is ignored and only a flagged case's `evidence/` output tracks, so a target's first capture is the baseline it commits.
|
|
175
|
-
- A case naming sections commits a folder per section, so size the list against the frames each later change regenerates.
|
|
176
|
-
|
|
177
|
-
## Gitignore (extend)
|
|
178
|
-
|
|
179
|
-
These `[gitignore]` groups mirror the manifest.
|
|
180
|
-
|
|
181
|
-
- `"# Playwright" = ["test-results/", "playwright-report/", "blob-report/", "playwright/.cache/"]`
|
|
182
|
-
- `"# Screenshots" = ["screenshots/"]`
|
|
183
|
-
|
|
184
|
-
## Verify script
|
|
185
|
-
|
|
186
|
-
The web layer's `scripts/verify.json` requires `typecheck`, `lint`, `test:run`, and `build`. Base's `scripts/verify.ts` runs them in its fixed order, being typecheck, lint, format, shell where the `shell` stack declares it, unit tests, build, markdown bans, then the card exclusion check where installed.
|
|
187
|
-
|
|
188
|
-
- Astro, vite-react, and nextjs inherit the list, since the nearest stack's copy wins. An adapter whose phases differ ships its own `verify.json` rather than a script.
|
|
189
|
-
- The card stage runs `scripts/check-card-exclusion.sh` whenever that file is installed, keeping the social card route's build exclusion on the default path rather than behind a flag.
|
|
190
|
-
- It tests for the script rather than the stack, so a project with no card route runs one less stage with no override.
|
|
191
|
-
- The stack shipping a card route owns what the check reads, being the build the stage before it produced. The astro reference carries the route itself.
|