@erclx/canon 5.37.0 → 5.39.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/SKILL.md +12 -9
- package/claude/skills/auto-ship/SKILL.md +43 -23
- package/claude/skills/backlog-triage/SKILL.md +62 -53
- package/claude/skills/backlog-triage/references/apply.md +69 -0
- package/claude/skills/build-in-slices/SKILL.md +8 -4
- package/claude/skills/canon-cli/SKILL.md +5 -1
- package/claude/skills/canon-feedback/SKILL.md +18 -8
- package/claude/skills/canon-feedback-triage/SKILL.md +10 -3
- package/claude/skills/canvas-board/SKILL.md +36 -17
- package/claude/skills/ci-workflow/SKILL.md +5 -4
- package/claude/skills/code-craft/SKILL.md +10 -6
- package/claude/skills/codebase-layout/SKILL.md +3 -5
- package/claude/skills/context-fold/REQUIREMENT.md +4 -4
- package/claude/skills/context-fold/SKILL.md +42 -23
- package/claude/skills/context-fold/references/context-refresh.md +4 -3
- package/claude/skills/context-fold/references/context.md +79 -64
- package/claude/skills/create-rule/SKILL.md +7 -3
- package/claude/skills/create-skill/SKILL.md +27 -7
- package/claude/skills/create-skill/references/skill-reference.md +41 -17
- package/claude/skills/decision-escalate/SKILL.md +8 -5
- package/claude/skills/deploy-app/SKILL.md +1 -1
- package/claude/skills/deprecation-migration/SKILL.md +12 -4
- package/claude/skills/design-taste/SKILL.md +17 -11
- package/claude/skills/docs-sync/REQUIREMENT.md +1 -0
- package/claude/skills/docs-sync/SKILL.md +17 -6
- package/claude/skills/docs-sync/references/docs.md +54 -21
- package/claude/skills/docs-sync/references/readme.md +32 -8
- package/claude/skills/document-health/SKILL.md +3 -4
- package/claude/skills/draft-and-pick/SKILL.md +73 -47
- package/claude/skills/draft-doc/SKILL.md +9 -4
- package/claude/skills/draft-doc/references/context.md +4 -4
- package/claude/skills/draft-doc/references/docs.md +1 -0
- package/claude/skills/draft-doc/references/wiki.md +3 -2
- package/claude/skills/draft-figure/SKILL.md +9 -7
- package/claude/skills/draft-identity/SKILL.md +24 -52
- package/claude/skills/draft-identity/references/card-route.md +46 -0
- package/claude/skills/draft-ready/SKILL.md +19 -7
- package/claude/skills/draft-screencast/SKILL.md +6 -112
- package/claude/skills/draft-screencast/references/beats-template.md +119 -0
- package/claude/skills/draft-slides/SKILL.md +7 -4
- package/claude/skills/git-branch/SKILL.md +3 -3
- package/claude/skills/git-commit/SKILL.md +5 -3
- package/claude/skills/git-followup/SKILL.md +16 -9
- package/claude/skills/git-issue/SKILL.md +6 -5
- package/claude/skills/git-issue/references/issue.md +11 -10
- package/claude/skills/git-pr/SKILL.md +56 -44
- package/claude/skills/git-ship/SKILL.md +43 -34
- package/claude/skills/git-ship/references/ci-watch.md +31 -0
- package/claude/skills/git-split/SKILL.md +28 -100
- package/claude/skills/git-split/references/independent.md +40 -0
- package/claude/skills/git-split/references/stacked.md +73 -0
- package/claude/skills/git-stage/SKILL.md +9 -7
- package/claude/skills/git-worktree/SKILL.md +27 -49
- package/claude/skills/git-worktree/references/cleanup.md +55 -0
- package/claude/skills/markdown-craft/SKILL.md +2 -2
- package/claude/skills/markdown-craft/references/markdown.md +82 -52
- package/claude/skills/plan-feature/SKILL.md +52 -46
- package/claude/skills/plan-feature/references/batches.md +46 -0
- package/claude/skills/plan-groundwork/SKILL.md +60 -74
- package/claude/skills/plan-groundwork/references/groundwork.md +53 -24
- package/claude/skills/plan-groundwork/references/output.md +48 -0
- package/claude/skills/plan-intake/SKILL.md +28 -21
- package/claude/skills/plan-intake-answer/SKILL.md +14 -13
- package/claude/skills/read-frames/SKILL.md +2 -0
- package/claude/skills/record-screencast/SKILL.md +31 -11
- package/claude/skills/review-address/SKILL.md +76 -158
- package/claude/skills/review-address/references/rebase-only.md +34 -0
- package/claude/skills/review-craft/SKILL.md +27 -11
- package/claude/skills/review-pr/SKILL.md +91 -40
- package/claude/skills/review-pr/references/post.md +1 -1
- package/claude/skills/review-ui/SKILL.md +62 -37
- package/claude/skills/review-ui/references/hosted-preview.md +30 -0
- package/claude/skills/role-orchestrator/SKILL.md +105 -74
- package/claude/skills/role-orchestrator/references/orchestrator-filing.md +26 -0
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +1 -1
- package/claude/skills/role-planner/SKILL.md +66 -64
- package/claude/skills/role-reviewer/SKILL.md +57 -46
- package/claude/skills/role-worker/SKILL.md +68 -63
- package/claude/skills/search-craft/SKILL.md +7 -5
- package/claude/skills/session-compact/SKILL.md +16 -11
- package/claude/skills/session-map/SKILL.md +31 -10
- package/claude/skills/session-relay/SKILL.md +32 -65
- package/claude/skills/session-resume/SKILL.md +18 -13
- package/claude/skills/session-worktree/SKILL.md +70 -42
- package/claude/skills/systematic-debugging/SKILL.md +6 -1
- package/claude/skills/target-check/SKILL.md +13 -6
- package/claude/skills/target-setup/SKILL.md +41 -30
- package/claude/skills/target-setup/references/verify.md +6 -5
- package/claude/skills/task-board/SKILL.md +68 -60
- package/claude/skills/task-board/references/create-report.md +36 -0
- package/claude/skills/task-board/references/tasks.md +3 -1
- package/claude/skills/task-complete/SKILL.md +20 -18
- package/claude/skills/teach-workspace/SKILL.md +61 -33
- package/claude/skills/test-craft/SKILL.md +2 -1
- package/claude/skills/test-first/SKILL.md +15 -9
- package/claude/skills/ui-checklist/SKILL.md +18 -16
- package/claude/skills/ux-audit/SKILL.md +9 -10
- package/claude/skills/ux-measure/SKILL.md +22 -18
- package/claude/skills/video-craft/SKILL.md +15 -7
- package/claude/skills/write-human/SKILL.md +9 -1
- package/claude/skills/youtube-transcripts/SKILL.md +2 -1
- package/docs/agents/context-audit-checks.md +19 -1
- package/docs/agents/context-audit.md +2 -2
- package/docs/agents/driver.md +1 -1
- package/docs/agents/hooks.md +21 -1
- package/docs/agents/index.md +10 -14
- package/docs/agents/indexes.md +25 -29
- package/docs/agents/install-and-sync.md +124 -235
- package/docs/agents/markdown-audit-density.md +39 -0
- package/docs/agents/markdown-audit-weight.md +9 -7
- package/docs/agents/markdown-audit.md +18 -14
- package/docs/agents/migrate.md +41 -16
- package/docs/agents/output-shape.md +60 -45
- package/docs/agents/overview.md +36 -12
- package/docs/agents/routing.md +1 -1
- package/docs/agents/rule-citations.md +1 -1
- package/docs/agents/skills-reach.md +1 -1
- package/docs/agents/targets.md +25 -77
- package/docs/target/migrations.md +1 -1
- package/docs/target/projects.md +3 -3
- package/docs/target/scenarios.md +1 -1
- package/docs/workflow/ai-workflow.md +2 -2
- package/docs/workflow/parallel-features.md +2 -2
- package/docs/workflow/skill-map.md +1 -1
- package/docs/workflow/visual-design-workflow.md +1 -1
- package/governance/detect.toml +6 -1
- package/package.json +6 -3
- package/scripts/core/install-check.sh +1 -1
- package/src/commands/claude.ts +1 -2
- package/src/commands/context.ts +106 -7
- package/src/commands/hooks.ts +63 -0
- package/src/commands/markdown.ts +169 -32
- package/src/commands/pr.ts +1 -1
- package/src/commands/records.ts +0 -1
- package/src/context/audit.ts +256 -5
- package/src/context/classify/prompts.ts +1 -1
- package/src/context/gate.ts +23 -7
- package/src/context/shape-gated.ts +28 -0
- package/src/design/document.ts +1 -1
- package/src/design/tokens.ts +1 -1
- package/src/docs/read.ts +15 -21
- package/src/gate/measures.ts +15 -190
- package/src/gate/stages.ts +21 -23
- package/src/hooks/reply-links.ts +110 -0
- package/src/markdown/density.ts +258 -0
- package/src/markdown/gate.ts +57 -18
- package/src/markdown/reference-shape.ts +103 -0
- package/src/markdown/scope.ts +174 -0
- package/src/markdown/structure.ts +10 -60
- package/src/sandbox/equivalence.ts +7 -9
- package/src/shipped/references.ts +1 -1
- package/src/teach/browser/head.ts +2 -2
- package/src/teach/browser/sidebar.ts +3 -3
- package/src/teach/browser/theme.ts +2 -2
- package/src/tooling/inject.ts +2 -2
- package/src/tooling/package.ts +15 -18
- package/src/tooling/verify-stack.ts +6 -3
- package/tooling/astro/configs/.oxfmtrc.json +8 -0
- package/tooling/astro/configs/.prettierrc +13 -0
- package/tooling/astro/manifest.toml +13 -0
- package/tooling/astro/reference.md +15 -5
- package/tooling/base/configs/.oxfmtrc.json +7 -0
- package/tooling/base/configs/scripts/verify.ts +1 -1
- package/tooling/base/manifest.toml +6 -6
- package/tooling/base/reference.md +12 -9
- package/tooling/base/seeds/.lintstagedrc +1 -3
- package/tooling/base/seeds/canon/context/ci.md +3 -3
- package/tooling/base/seeds/canon/context/development.md +2 -2
- package/tooling/claude/manifest.toml +5 -1
- package/tooling/claude/seeds/.claude/hooks/reply-links.sh +72 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +22 -1
- package/tooling/claude/seeds/.claude/settings.json +4 -0
- package/tooling/go/reference.md +2 -2
- package/tooling/nextjs/configs/.oxlintrc.json +223 -0
- package/tooling/nextjs/manifest.toml +2 -5
- package/tooling/nextjs/reference.md +4 -4
- package/tooling/php/manifest.toml +6 -1
- package/tooling/php/reference.md +2 -2
- package/tooling/python/manifest.toml +6 -1
- package/tooling/python/reference.md +4 -4
- package/tooling/vite-react/manifest.toml +1 -4
- package/tooling/vite-react/reference.md +3 -3
- package/tooling/web/configs/.oxlintrc.json +213 -0
- package/tooling/web/manifest.toml +9 -13
- package/tooling/web/reference.md +14 -14
- package/docs/agents/commands.md +0 -154
- package/docs/agents/docs.md +0 -27
- package/docs/agents/drift-surfaces.md +0 -201
- package/docs/agents/gov-detect.md +0 -47
- package/docs/agents/scripting.md +0 -142
- package/src/markdown/growth.ts +0 -43
- package/tooling/base/configs/.prettierrc +0 -12
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/nextjs/configs/eslint.config.js +0 -91
- package/tooling/web/configs/eslint.config.js +0 -82
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Claude Code sends a payload and closes stdin. A bare read with nothing feeding
|
|
4
|
+
# it blocks forever and holds the session open, so the read is bounded. `read`
|
|
5
|
+
# rather than `timeout cat`, which macOS does not ship.
|
|
6
|
+
IFS= read -r -d '' -t 2 input
|
|
7
|
+
[ -n "$input" ] || {
|
|
8
|
+
printf '%s reads a Claude Code hook payload on stdin and cannot be run by hand.\n' "${0##*/}" >&2
|
|
9
|
+
exit 1
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# A reply with no link is the ordinary turn, so it leaves before anything
|
|
13
|
+
# spawns. The payload holds the reply JSON-escaped, and `](` survives the
|
|
14
|
+
# escaping untouched, so a shell test on the raw payload is enough. This is the
|
|
15
|
+
# one quiet exit: every later failure to measure reports instead.
|
|
16
|
+
case "$input" in
|
|
17
|
+
*']('*) ;;
|
|
18
|
+
*) exit 0 ;;
|
|
19
|
+
esac
|
|
20
|
+
|
|
21
|
+
# A failure to measure exits 1 rather than 2. Exit 2 forces the session to
|
|
22
|
+
# continue, and a hook that cannot read `stop_hook_active` would then block
|
|
23
|
+
# every continuation too.
|
|
24
|
+
unread() {
|
|
25
|
+
printf 'Reply-links: the final reply was not checked. %s\n' "$1" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
command -v jq >/dev/null 2>&1 || unread 'Found no `jq` on PATH.'
|
|
30
|
+
|
|
31
|
+
event=$(printf '%s' "$input" | jq -r '.hook_event_name // empty' 2>/dev/null)
|
|
32
|
+
[ -n "$event" ] || unread 'The payload did not parse.'
|
|
33
|
+
[ "$event" = "Stop" ] || exit 0
|
|
34
|
+
|
|
35
|
+
# The forced continuation after a block fires this hook again with the field
|
|
36
|
+
# true. Passing it is what makes the block fire once, so the corrected links
|
|
37
|
+
# are not checked a second time.
|
|
38
|
+
stop_hook_active=$(printf '%s' "$input" | jq -r '.stop_hook_active // false')
|
|
39
|
+
[ "$stop_hook_active" = "true" ] && exit 0
|
|
40
|
+
|
|
41
|
+
reply=$(printf '%s' "$input" | jq -r '.last_assistant_message // empty')
|
|
42
|
+
case "$reply" in
|
|
43
|
+
*']('*) ;;
|
|
44
|
+
*) exit 0 ;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
# The verb resolves a relative link against the main worktree root, read from
|
|
48
|
+
# the directory the session stands in, so the payload's cwd is named rather than
|
|
49
|
+
# inherited from wherever the hook was spawned.
|
|
50
|
+
cwd=$(printf '%s' "$input" | jq -r '.cwd // empty')
|
|
51
|
+
[ -n "$cwd" ] && [ -d "$cwd" ] || unread 'The payload carried no working directory that exists.'
|
|
52
|
+
|
|
53
|
+
# A project has no checkout of the CLI, so this resolves the installed binary
|
|
54
|
+
# alone, and a machine without it says so rather than passing the reply.
|
|
55
|
+
if command -v canon >/dev/null 2>&1; then
|
|
56
|
+
record=$(cd "$cwd" && printf '%s' "$reply" | canon hooks reply-links --json 2>/dev/null)
|
|
57
|
+
else
|
|
58
|
+
unread 'Found no `canon` binary on PATH. Install one with `bun add -g @erclx/canon`.'
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# The record decides rather than the exit code. A binary predating the verb
|
|
62
|
+
# exits 1 on an unknown command, which is the code a finding also leaves, and
|
|
63
|
+
# it writes no record.
|
|
64
|
+
ok=$(printf '%s' "$record" | jq -r 'if .ok == true then "true" elif .ok == false then "false" else empty end' 2>/dev/null)
|
|
65
|
+
case "$ok" in
|
|
66
|
+
true) exit 0 ;;
|
|
67
|
+
false)
|
|
68
|
+
printf '%s\n' "$(printf '%s' "$record" | jq -r '.message')" >&2
|
|
69
|
+
exit 2
|
|
70
|
+
;;
|
|
71
|
+
*) unread 'The link check returned no record. An installed `canon` that predates `canon hooks reply-links` does this.' ;;
|
|
72
|
+
esac
|
|
@@ -77,13 +77,24 @@ headings=$(printf '%s' "$record" |
|
|
|
77
77
|
colons=$(printf '%s' "$record" |
|
|
78
78
|
jq -r --arg new "$new" '.entries[]?.colons[]? | (.lead // (.text[:.column] | sub("^.*\\s"; ""))) as $lead | select($new | contains($lead + ":")) | ":\(.line):\(.column + 1) \(.text)"' 2>/dev/null)
|
|
79
79
|
|
|
80
|
+
# Density findings are handed back whole, gating or not, since the verb only
|
|
81
|
+
# returns them for a path in its scope and a finding the push does not fail on
|
|
82
|
+
# yet is the one a rewrite has to clear before its folder is gated.
|
|
83
|
+
density=$(printf '%s' "$record" |
|
|
84
|
+
jq -r '.entries[]?.density[]? | ":\(.line) \(.kind) " + (if .limit == null then "opens with neither a paragraph nor a table" else "\(.value) past \(.limit)" end) + (if .gating then " gating" else "" end)' 2>/dev/null)
|
|
85
|
+
|
|
86
|
+
# A page marked `kind: reference` carries reference shape findings, handed back
|
|
87
|
+
# whole the same way, since a gated one fails the push like a density finding.
|
|
88
|
+
shape=$(printf '%s' "$record" |
|
|
89
|
+
jq -r '.entries[]?.referenceShape[]? | ":\(.line) \(.kind) \(.text)" + (if .gating then " gating" else "" end)' 2>/dev/null)
|
|
90
|
+
|
|
80
91
|
# A set the verb shipped empty measures nothing and would report a clean file.
|
|
81
92
|
# Reading the findings alone turns that narrowed check into a pass, so the field
|
|
82
93
|
# is read beside them.
|
|
83
94
|
empty=$(printf '%s' "$record" |
|
|
84
95
|
jq -r '[.bans.emptySets[]?] | join(", ")' 2>/dev/null)
|
|
85
96
|
|
|
86
|
-
[ -z "$hits" ] && [ -z "$headings" ] && [ -z "$colons" ] && [ -z "$unread" ] && [ -z "$empty" ] && exit 0
|
|
97
|
+
[ -z "$hits" ] && [ -z "$headings" ] && [ -z "$colons" ] && [ -z "$density" ] && [ -z "$shape" ] && [ -z "$unread" ] && [ -z "$empty" ] && exit 0
|
|
87
98
|
|
|
88
99
|
nl=$'\n'
|
|
89
100
|
msg=""
|
|
@@ -111,4 +122,14 @@ if [ -n "$colons" ]; then
|
|
|
111
122
|
msg="${msg:+$msg$nl}$found"
|
|
112
123
|
fi
|
|
113
124
|
|
|
125
|
+
if [ -n "$density" ]; then
|
|
126
|
+
found=$(printf 'Standards-audit: %s breaks the markdown density limits, being a 350-character paragraph, 2 paragraphs in a row, a 200-character bullet, 5 plain bullets in a row, no H4, and a paragraph or table opening every H3. Split each block at its seam rather than trimming words to pass. A finding marked gating fails the push.\n%s' "$file" "$density")
|
|
127
|
+
msg="${msg:+$msg$nl}$found"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [ -n "$shape" ]; then
|
|
131
|
+
found=$(printf 'Standards-audit: %s is marked kind: reference and breaks its shape, being an opening, then Output, Refusals, and See also, each at most once and in that order, no H3, and no flag table. Point at the command'"'"'s own --help for flags. A finding marked gating fails the push.\n%s' "$file" "$shape")
|
|
132
|
+
msg="${msg:+$msg$nl}$found"
|
|
133
|
+
fi
|
|
134
|
+
|
|
114
135
|
jq -nc --arg msg "$msg" '{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:$msg}}'
|
package/tooling/go/reference.md
CHANGED
|
@@ -10,11 +10,11 @@ The go stack covers Go modules linted and formatted by `golangci-lint` v2, type-
|
|
|
10
10
|
|
|
11
11
|
1. Scaffold with `go mod init <module-path>`. The module path is the project's own identity, so this stack never ships a `go.mod`.
|
|
12
12
|
2. Keep `./...` out of `node_modules`: `go mod edit -ignore=./node_modules`. At a root sync the base layer installs `node_modules/` inside the module, and a package there can ship a `.go` file that `go vet`, `go test`, and `golangci-lint` would otherwise walk. The directive needs Go 1.25 or later.
|
|
13
|
-
3. Seed `package.json` so the base layer's bun-side tools (husky,
|
|
13
|
+
3. Seed `package.json` so the base layer's bun-side tools (husky, oxfmt, commitlint) have a target to install into: `bun init -y`.
|
|
14
14
|
4. Install base tooling: `canon tooling sync base . --write`
|
|
15
15
|
5. Install go tooling: `canon tooling sync go . --write`
|
|
16
16
|
6. Install the linter: `go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest`. The manifest declares no `[dependencies.dev]`, because manifest injection runs `bun add -D`, which cannot install a Go tool. This step stays manual.
|
|
17
|
-
7. Run `bun run lint:fix` then `bun run check`.
|
|
17
|
+
7. Run `bun run lint:fix`, then `bun run format`, then `bun run check`.
|
|
18
18
|
|
|
19
19
|
The go stack also ships `smoke_test.go` at the module root as a copy-once seed. A module with no `.go` file fails `golangci-lint run`, `go vet`, and `go test` on an empty package list, so the seed is what lets `bun run check` pass on a fresh scaffold. It declares `package main`, so delete or rename it once the root package takes another name, or the build reports two packages in one folder.
|
|
20
20
|
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"plugins": ["typescript", "unicorn"],
|
|
4
|
+
"categories": {
|
|
5
|
+
"correctness": "off"
|
|
6
|
+
},
|
|
7
|
+
"env": {
|
|
8
|
+
"builtin": true
|
|
9
|
+
},
|
|
10
|
+
"ignorePatterns": [
|
|
11
|
+
".next",
|
|
12
|
+
"next-env.d.ts",
|
|
13
|
+
"dist",
|
|
14
|
+
"dist-ssr",
|
|
15
|
+
"coverage",
|
|
16
|
+
"release",
|
|
17
|
+
".claude",
|
|
18
|
+
".vscode",
|
|
19
|
+
".husky",
|
|
20
|
+
"test-results",
|
|
21
|
+
"playwright-report",
|
|
22
|
+
"blob-report",
|
|
23
|
+
"playwright/.cache"
|
|
24
|
+
],
|
|
25
|
+
"rules": {
|
|
26
|
+
"constructor-super": "error",
|
|
27
|
+
"for-direction": "error",
|
|
28
|
+
"getter-return": "error",
|
|
29
|
+
"no-async-promise-executor": "error",
|
|
30
|
+
"no-case-declarations": "error",
|
|
31
|
+
"no-class-assign": "error",
|
|
32
|
+
"no-compare-neg-zero": "error",
|
|
33
|
+
"no-cond-assign": "error",
|
|
34
|
+
"no-const-assign": "error",
|
|
35
|
+
"no-constant-binary-expression": "error",
|
|
36
|
+
"no-constant-condition": "error",
|
|
37
|
+
"no-control-regex": "error",
|
|
38
|
+
"no-debugger": "error",
|
|
39
|
+
"no-delete-var": "error",
|
|
40
|
+
"no-dupe-class-members": "error",
|
|
41
|
+
"no-dupe-else-if": "error",
|
|
42
|
+
"no-dupe-keys": "error",
|
|
43
|
+
"no-duplicate-case": "error",
|
|
44
|
+
"no-empty": "error",
|
|
45
|
+
"no-empty-character-class": "error",
|
|
46
|
+
"no-empty-pattern": "error",
|
|
47
|
+
"no-empty-static-block": "error",
|
|
48
|
+
"no-ex-assign": "error",
|
|
49
|
+
"no-extra-boolean-cast": "error",
|
|
50
|
+
"no-fallthrough": "error",
|
|
51
|
+
"no-func-assign": "error",
|
|
52
|
+
"no-global-assign": "error",
|
|
53
|
+
"no-import-assign": "error",
|
|
54
|
+
"no-invalid-regexp": "error",
|
|
55
|
+
"no-irregular-whitespace": "error",
|
|
56
|
+
"no-loss-of-precision": "error",
|
|
57
|
+
"no-misleading-character-class": "error",
|
|
58
|
+
"no-new-native-nonconstructor": "error",
|
|
59
|
+
"no-nonoctal-decimal-escape": "error",
|
|
60
|
+
"no-obj-calls": "error",
|
|
61
|
+
"no-prototype-builtins": "error",
|
|
62
|
+
"no-redeclare": "error",
|
|
63
|
+
"no-regex-spaces": "error",
|
|
64
|
+
"no-self-assign": "error",
|
|
65
|
+
"no-setter-return": "error",
|
|
66
|
+
"no-shadow-restricted-names": "error",
|
|
67
|
+
"no-sparse-arrays": "error",
|
|
68
|
+
"no-this-before-super": "error",
|
|
69
|
+
"no-unassigned-vars": "error",
|
|
70
|
+
"no-unreachable": "error",
|
|
71
|
+
"no-unsafe-finally": "error",
|
|
72
|
+
"no-unsafe-negation": "error",
|
|
73
|
+
"no-unsafe-optional-chaining": "error",
|
|
74
|
+
"no-unused-labels": "error",
|
|
75
|
+
"no-unused-private-class-members": "error",
|
|
76
|
+
"no-unused-vars": "error",
|
|
77
|
+
"no-useless-backreference": "error",
|
|
78
|
+
"no-useless-catch": "error",
|
|
79
|
+
"no-useless-escape": "error",
|
|
80
|
+
"no-with": "error",
|
|
81
|
+
"preserve-caught-error": "error",
|
|
82
|
+
"require-yield": "error",
|
|
83
|
+
"use-isnan": "error",
|
|
84
|
+
"valid-typeof": "error",
|
|
85
|
+
"no-array-constructor": "error",
|
|
86
|
+
"no-unused-expressions": "error",
|
|
87
|
+
"typescript/ban-ts-comment": "error",
|
|
88
|
+
"typescript/no-duplicate-enum-values": "error",
|
|
89
|
+
"typescript/no-empty-object-type": "error",
|
|
90
|
+
"typescript/no-explicit-any": "error",
|
|
91
|
+
"typescript/no-extra-non-null-assertion": "error",
|
|
92
|
+
"typescript/no-misused-new": "error",
|
|
93
|
+
"typescript/no-namespace": "error",
|
|
94
|
+
"typescript/no-non-null-asserted-optional-chain": "error",
|
|
95
|
+
"typescript/no-require-imports": "error",
|
|
96
|
+
"typescript/no-this-alias": "error",
|
|
97
|
+
"typescript/no-unnecessary-type-constraint": "error",
|
|
98
|
+
"typescript/no-unsafe-declaration-merging": "error",
|
|
99
|
+
"typescript/no-unsafe-function-type": "error",
|
|
100
|
+
"typescript/no-wrapper-object-types": "error",
|
|
101
|
+
"typescript/prefer-as-const": "error",
|
|
102
|
+
"typescript/prefer-namespace-keyword": "error",
|
|
103
|
+
"typescript/triple-slash-reference": "error"
|
|
104
|
+
},
|
|
105
|
+
"overrides": [
|
|
106
|
+
{
|
|
107
|
+
"files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
|
|
108
|
+
"rules": {
|
|
109
|
+
"constructor-super": "off",
|
|
110
|
+
"getter-return": "off",
|
|
111
|
+
"no-class-assign": "off",
|
|
112
|
+
"no-const-assign": "off",
|
|
113
|
+
"no-dupe-class-members": "off",
|
|
114
|
+
"no-dupe-keys": "off",
|
|
115
|
+
"no-func-assign": "off",
|
|
116
|
+
"no-import-assign": "off",
|
|
117
|
+
"no-new-native-nonconstructor": "off",
|
|
118
|
+
"no-obj-calls": "off",
|
|
119
|
+
"no-redeclare": "off",
|
|
120
|
+
"no-setter-return": "off",
|
|
121
|
+
"no-this-before-super": "off",
|
|
122
|
+
"no-unreachable": "off",
|
|
123
|
+
"no-unsafe-negation": "off",
|
|
124
|
+
"no-var": "error",
|
|
125
|
+
"no-with": "off",
|
|
126
|
+
"prefer-const": "error",
|
|
127
|
+
"prefer-rest-params": "error",
|
|
128
|
+
"prefer-spread": "error"
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"files": ["**/*.{ts,tsx,js,jsx}"],
|
|
133
|
+
"rules": {
|
|
134
|
+
"simple-import-sort/imports": "error",
|
|
135
|
+
"simple-import-sort/exports": "error",
|
|
136
|
+
"check-file/filename-naming-convention": [
|
|
137
|
+
"error",
|
|
138
|
+
{
|
|
139
|
+
"**/*.{ts,tsx}": "KEBAB_CASE"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"ignoreMiddleExtensions": true
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"check-file/folder-naming-convention": [
|
|
146
|
+
"error",
|
|
147
|
+
{
|
|
148
|
+
"src/**/!(__tests__)/": "KEBAB_CASE"
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"no-unused-vars": [
|
|
152
|
+
"error",
|
|
153
|
+
{
|
|
154
|
+
"varsIgnorePattern": "^_",
|
|
155
|
+
"argsIgnorePattern": "^_"
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"react/rules-of-hooks": "error",
|
|
159
|
+
"react/exhaustive-deps": "warn",
|
|
160
|
+
"react/static-components": "error",
|
|
161
|
+
"react/use-memo": "error",
|
|
162
|
+
"react/preserve-manual-memoization": "error",
|
|
163
|
+
"react/incompatible-library": "warn",
|
|
164
|
+
"react/immutability": "error",
|
|
165
|
+
"react/globals": "error",
|
|
166
|
+
"react/refs": "error",
|
|
167
|
+
"react/set-state-in-effect": "error",
|
|
168
|
+
"react/error-boundaries": "error",
|
|
169
|
+
"react/purity": "error",
|
|
170
|
+
"react/set-state-in-render": "error",
|
|
171
|
+
"react/unsupported-syntax": "warn",
|
|
172
|
+
"react/only-export-components": [
|
|
173
|
+
"warn",
|
|
174
|
+
{
|
|
175
|
+
"allowConstantExport": true
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
"jsPlugins": [
|
|
180
|
+
"eslint-plugin-simple-import-sort",
|
|
181
|
+
"eslint-plugin-check-file"
|
|
182
|
+
],
|
|
183
|
+
"plugins": ["react"],
|
|
184
|
+
"env": {
|
|
185
|
+
"browser": true
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"files": ["src/app/**/*.{ts,tsx}"],
|
|
190
|
+
"rules": {
|
|
191
|
+
"check-file/folder-naming-convention": "off",
|
|
192
|
+
"react/only-export-components": "off"
|
|
193
|
+
},
|
|
194
|
+
"jsPlugins": ["eslint-plugin-check-file"],
|
|
195
|
+
"plugins": ["react"]
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"files": ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
|
|
199
|
+
"rules": {
|
|
200
|
+
"vitest/expect-expect": "error",
|
|
201
|
+
"vitest/no-identical-title": "error",
|
|
202
|
+
"vitest/no-commented-out-tests": "error",
|
|
203
|
+
"vitest/valid-title": "error",
|
|
204
|
+
"vitest/valid-expect": "error",
|
|
205
|
+
"vitest/valid-describe-callback": "error",
|
|
206
|
+
"vitest/require-local-test-context-for-concurrent-snapshots": "error",
|
|
207
|
+
"vitest/no-import-node-test": "error",
|
|
208
|
+
"vitest/no-focused-tests": "error"
|
|
209
|
+
},
|
|
210
|
+
"plugins": ["vitest"]
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"files": [
|
|
214
|
+
"*.config.{js,mjs,cjs,ts}",
|
|
215
|
+
"vitest.config.ts",
|
|
216
|
+
"playwright.config.ts"
|
|
217
|
+
],
|
|
218
|
+
"env": {
|
|
219
|
+
"node": true
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
}
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
name = "nextjs"
|
|
3
3
|
extends = "web"
|
|
4
4
|
runtime = "bun"
|
|
5
|
-
scaffold = "bunx create-next-app@latest {{name}} --typescript --tailwind --
|
|
5
|
+
scaffold = "bunx create-next-app@latest {{name}} --typescript --tailwind --no-linter --app --src-dir --import-alias \"@/*\" --use-bun --skip-install --disable-git --no-agents-md --yes"
|
|
6
6
|
|
|
7
7
|
[dependencies.dev]
|
|
8
|
-
packages = [
|
|
9
|
-
"next",
|
|
10
|
-
"@tailwindcss/postcss",
|
|
11
|
-
]
|
|
8
|
+
packages = ["next", "@tailwindcss/postcss"]
|
|
12
9
|
|
|
13
10
|
[scripts]
|
|
14
11
|
"preview" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) && export WORKTREE_PORT_OFFSET && next start --port $((3000 + WORKTREE_PORT_OFFSET))"
|
|
@@ -4,22 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The nextjs stack covers Next.js + TypeScript projects using the App Router. It ships golden configs for `next.config.ts`, `vitest.config.ts` (plain `defineConfig`, no bundler merge), `playwright.config.ts` (build-then-preview), and an
|
|
7
|
+
The nextjs stack covers Next.js + TypeScript projects using the App Router. It ships golden configs for `next.config.ts`, `vitest.config.ts` (plain `defineConfig`, no bundler merge), `playwright.config.ts` (build-then-preview), and an `.oxlintrc.json` that replaces the web layer's with `.next` ignores and an App Router override. Shared web tooling (oxlint base, screenshot template, VS Code, CI, verify script) comes from the `web` layer.
|
|
8
8
|
|
|
9
9
|
## Scaffold checklist
|
|
10
10
|
|
|
11
|
-
1. Scaffold with `bunx create-next-app@latest <name> --typescript --tailwind --
|
|
11
|
+
1. Scaffold with `bunx create-next-app@latest <name> --typescript --tailwind --no-linter --app --src-dir --import-alias "@/*" --use-bun --skip-install --disable-git --no-agents-md --yes`. `--no-agents-md` skips the scaffold-time `AGENTS.md`/`CLAUDE.md` write, which otherwise duplicates the root `CLAUDE.md`. `--no-linter` skips the scaffold's `eslint.config.mjs` and `lint` script, and is accepted though `--help` lists only `--eslint` and `--biome`.
|
|
12
12
|
2. Install web tooling: `canon tooling sync web . --write`
|
|
13
13
|
3. Install nextjs configs: `canon tooling sync nextjs . --write`
|
|
14
14
|
4. Extend the `ci` and `development` context entries under `canon/context/` per the web reference's extend sections plus the nextjs rows below.
|
|
15
|
-
5. Run `bun run lint:fix` then `bun run check`.
|
|
15
|
+
5. Run `bun run lint:fix`, then `bun run format`, then `bun run check`.
|
|
16
16
|
|
|
17
17
|
## What ships as golden configs
|
|
18
18
|
|
|
19
19
|
- `next.config.ts`: `agentRules: false` stops Next from regenerating `AGENTS.md`/`CLAUDE.md` on every run, which would otherwise compete with the root `CLAUDE.md`. `turbopack.root: import.meta.dirname` pins the workspace root, silencing Next's multi-lockfile inference warning in any checkout carrying more than one lockfile above the project, a worktree included.
|
|
20
20
|
- `vitest.config.ts`: plain `defineConfig`, no `mergeConfig` or `getViteConfig` since Next has no Vite config to merge from. jsdom, globals, setup file, `passWithNoTests: true`, v8 coverage, `.next/**` in test excludes.
|
|
21
21
|
- `playwright.config.ts`: all browsers, `webServer` runs `bun run build && bun run preview` on port `3000` plus `WORKTREE_PORT_OFFSET`, `reuseExistingServer: false`. `DIST_PREBUILT` drops the `build` half, matching the astro stack's flag.
|
|
22
|
-
-
|
|
22
|
+
- `.oxlintrc.json`: replaces the web layer's whole file, since oxlint reads one config, with `.next` and `next-env.d.ts` added to `ignorePatterns`. `react/only-export-components` is `off` for `src/app/**`, since route and layout files export non-component values the rule would otherwise flag. `check-file/folder-naming-convention` is `off` for the same subtree, since App Router's bracket, paren, and at-sign folder syntax (dynamic segments, route groups, parallel slots) fails `KEBAB_CASE`.
|
|
23
23
|
|
|
24
24
|
## Port
|
|
25
25
|
|
|
@@ -12,7 +12,12 @@ scaffold = "mkdir {{name}} && cd {{name}} && composer init -n --name example/{{n
|
|
|
12
12
|
"test:run" = "vendor/bin/phpunit --testdox"
|
|
13
13
|
|
|
14
14
|
[gitignore]
|
|
15
|
-
"# PHP" = [
|
|
15
|
+
"# PHP" = [
|
|
16
|
+
"vendor/",
|
|
17
|
+
".php-cs-fixer.cache",
|
|
18
|
+
".phpunit.cache/",
|
|
19
|
+
".phpunit.result.cache",
|
|
20
|
+
]
|
|
16
21
|
|
|
17
22
|
[verify]
|
|
18
23
|
prepare = "bun init -y && composer require --dev friendsofphp/php-cs-fixer phpstan/phpstan phpunit/phpunit"
|
package/tooling/php/reference.md
CHANGED
|
@@ -9,11 +9,11 @@ The php stack covers Composer projects on PHP 8.3 or later, formatted by PHP CS
|
|
|
9
9
|
## Scaffold checklist
|
|
10
10
|
|
|
11
11
|
1. Scaffold with `composer init -n --name <vendor>/<name> --autoload src/`. The package name and namespace are the project's own identity, so this stack never ships a `composer.json`.
|
|
12
|
-
2. Seed `package.json` so the base layer's bun-side tools (husky,
|
|
12
|
+
2. Seed `package.json` so the base layer's bun-side tools (husky, oxfmt, commitlint) have a target to install into: `bun init -y`.
|
|
13
13
|
3. Install base tooling: `canon tooling sync base . --write`
|
|
14
14
|
4. Install php tooling: `canon tooling sync php . --write`
|
|
15
15
|
5. Install the dev tools: `composer require --dev friendsofphp/php-cs-fixer phpstan/phpstan phpunit/phpunit`. The manifest declares no `[dependencies.dev]`, because manifest injection runs `bun add -D`, which cannot install a Composer package. This step stays manual.
|
|
16
|
-
6. Run `bun run lint:fix` then `bun run check`.
|
|
16
|
+
6. Run `bun run lint:fix`, then `bun run format`, then `bun run check`.
|
|
17
17
|
|
|
18
18
|
Use PHP 8.3 or later, since PHPUnit 12 requires it.
|
|
19
19
|
|
|
@@ -13,7 +13,12 @@ scaffold = "uv init --package {{name}}"
|
|
|
13
13
|
"test:cov" = "uv run pytest --cov --cov-report=term-missing --cov-report=html"
|
|
14
14
|
|
|
15
15
|
[gitignore]
|
|
16
|
-
"# Python" = [
|
|
16
|
+
"# Python" = [
|
|
17
|
+
".pytest_cache/",
|
|
18
|
+
".mypy_cache/",
|
|
19
|
+
".ruff_cache/",
|
|
20
|
+
".coverage_cache/",
|
|
21
|
+
]
|
|
17
22
|
|
|
18
23
|
[verify]
|
|
19
24
|
prepare = "bun init -y && uv add --dev ruff mypy pytest pytest-cov && uv sync"
|
|
@@ -11,12 +11,12 @@ Configs ship as sidecar files (`ruff.toml`, `mypy.ini`, `pytest.ini`, `.coverage
|
|
|
11
11
|
## Scaffold checklist
|
|
12
12
|
|
|
13
13
|
1. Scaffold with `uv init --package <name>`. This creates `pyproject.toml` with a `uv_build` backend, `.python-version` pinned to 3.14, and `src/<name with underscores>/__init__.py` holding an annotated `def main() -> None:`, so source lands under `src/` where `mypy.ini`, `pytest.ini`, and `.coveragerc` look for it. `uv init` defaults `requires-python` to `>=3.14`, which matches the `.python-version` pin this stack ships.
|
|
14
|
-
2. Seed `package.json` so the base layer's bun-side tools (husky,
|
|
14
|
+
2. Seed `package.json` so the base layer's bun-side tools (husky, oxfmt, commitlint) have a target to install into: `bun init -y`. Without this the sync drops base configs but skips the dep install, since `resolve_missing_deps` short-circuits when `package.json` is absent.
|
|
15
15
|
3. Install base tooling: `canon tooling sync base . --write`
|
|
16
16
|
4. Install python tooling: `canon tooling sync python . --write`
|
|
17
17
|
5. Install Python tooling deps: `uv add --dev ruff mypy pytest pytest-cov`. v1 of this stack does not declare these in `[dependencies.dev]` because manifest injection hardcodes `bun add -D`, which can not install Python packages. Until the injector branches on `runtime`, this step is manual.
|
|
18
18
|
6. Sync the lockfile and create the venv: `uv sync`.
|
|
19
|
-
7. Run `bun run lint:fix` then `bun run check`.
|
|
19
|
+
7. Run `bun run lint:fix`, then `bun run format`, then `bun run check`.
|
|
20
20
|
|
|
21
21
|
The python stack also ships `tests/test_smoke.py` as a copy-once seed. `pytest` collects at least one test on first run, so `bun run test:run` exits 0 instead of the empty-collection exit code 5. Delete or replace the smoke test with real tests.
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ The python stack also ships `tests/test_smoke.py` as a copy-once seed. `pytest`
|
|
|
31
31
|
|
|
32
32
|
## Hybrid project shape
|
|
33
33
|
|
|
34
|
-
A python project synced with this stack ends up with both `package.json` from base and `pyproject.toml` from `uv init`. The base layer brings
|
|
34
|
+
A python project synced with this stack ends up with both `package.json` from base and `pyproject.toml` from `uv init`. The base layer brings oxfmt, commitlint, and husky for non-Python files. Both `node_modules/` and `.venv/` coexist at the project root. The hybrid shape gives Python projects access to the toolkit's cross-cutting tools without forking the base stack.
|
|
35
35
|
|
|
36
36
|
## Dependencies
|
|
37
37
|
|
|
@@ -39,7 +39,7 @@ The manifest declares no `[dependencies.dev]`. Manifest injection currently call
|
|
|
39
39
|
|
|
40
40
|
## Verify command
|
|
41
41
|
|
|
42
|
-
`canon tooling verify python` runs the manifest's `[verify] prepare` before Sync, which is checklist steps 2, 5, and 6: `bun init -y`, `uv add --dev ruff mypy pytest pytest-cov`, and `uv sync`. `uv init` writes no `package.json`, and a verify that reaches its end with none fails, so the prepare is what lets `bun run lint:fix` and `bun run check` run at all. Python's `verify.json` requires the `lint`, `typecheck`, and `test:run` scripts that delegate to `uv run`, so the run needs `uv` on the machine and a network for the installs. The end-to-end test and screenshot phases are gated on `package.json` script keys that python does not declare, so they skip.
|
|
42
|
+
`canon tooling verify python` runs the manifest's `[verify] prepare` before Sync, which is checklist steps 2, 5, and 6: `bun init -y`, `uv add --dev ruff mypy pytest pytest-cov`, and `uv sync`. `uv init` writes no `package.json`, and a verify that reaches its end with none fails, so the prepare is what lets `bun run lint:fix`, `bun run format`, and `bun run check` run at all. Python's `verify.json` requires the `lint`, `typecheck`, and `test:run` scripts that delegate to `uv run`, so the run needs `uv` on the machine and a network for the installs. The end-to-end test and screenshot phases are gated on `package.json` script keys that python does not declare, so they skip.
|
|
43
43
|
|
|
44
44
|
## Anti-patterns
|
|
45
45
|
|
|
@@ -5,10 +5,7 @@ runtime = "bun"
|
|
|
5
5
|
scaffold = "bun create vite@latest {{name}} --template react-ts"
|
|
6
6
|
|
|
7
7
|
[dependencies.dev]
|
|
8
|
-
packages = [
|
|
9
|
-
"vite",
|
|
10
|
-
"@vitejs/plugin-react",
|
|
11
|
-
]
|
|
8
|
+
packages = ["vite", "@vitejs/plugin-react"]
|
|
12
9
|
|
|
13
10
|
[scripts]
|
|
14
11
|
"dev" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) && export WORKTREE_PORT_OFFSET && vite"
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The vite-react stack covers Vite + React + TypeScript projects: web apps and Chrome extensions. It ships golden configs for `vite.config.ts`, `vitest.config.ts` (merging from vite config), `playwright.config.ts`, and a unified `tsconfig.json` with `@/` path alias. Shared web tooling (
|
|
7
|
+
The vite-react stack covers Vite + React + TypeScript projects: web apps and Chrome extensions. It ships golden configs for `vite.config.ts`, `vitest.config.ts` (merging from vite config), `playwright.config.ts`, and a unified `tsconfig.json` with `@/` path alias. Shared web tooling (oxlint, screenshot template, VS Code, CI, verify script) comes from the `web` layer.
|
|
8
8
|
|
|
9
9
|
## Scaffold checklist
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ The vite-react stack covers Vite + React + TypeScript projects: web apps and Chr
|
|
|
12
12
|
2. Install base and web tooling: `canon tooling sync web . --write`
|
|
13
13
|
3. Install vite-react deps and configs: `canon tooling sync vite-react . --write`
|
|
14
14
|
4. Extend the `ci` and `development` context entries under `canon/context/` per the web reference's extend sections plus the vite-react rows below.
|
|
15
|
-
5. Run `bun run lint:fix` then `bun run check`.
|
|
15
|
+
5. Run `bun run lint:fix`, then `bun run format`, then `bun run check`.
|
|
16
16
|
|
|
17
17
|
## What ships as golden configs
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ When scaffolding a Chrome extension, override the installed golden configs:
|
|
|
28
28
|
- `vite.config.ts`: use `crx({ manifest })` and `zip()` from `@crxjs/vite-plugin` instead of `react()` alone. Keep the derived `server.port` and `server.strictPort: true`, set `server.hmr.clientPort` to the same derived value, and add `chrome-extension://` to CORS origins. Drop `VITE_BASE_URL`.
|
|
29
29
|
- `vitest.config.ts`: use a standalone `defineConfig` (no `mergeConfig`). crxjs plugin breaks Vitest. Declare `@vitejs/plugin-react` and `@tailwindcss/vite` directly. Add `**/release/**` to excludes and `manifest.config.ts`, `**/*.d.ts` to coverage excludes.
|
|
30
30
|
- `playwright.config.ts`: chromium-only (Firefox and WebKit cannot run extensions). Bundled `chromium` channel. No `baseURL` or `webServer`. Tests load the built extension directly from `dist/`.
|
|
31
|
-
- `e2e/fixtures.ts`: extend Playwright base `test` with `context` (persistent context loading the extension from `dist/`) and `extensionId` (extracted from service worker URL). Rename `use` to `apply` to avoid
|
|
31
|
+
- `e2e/fixtures.ts`: extend Playwright base `test` with `context` (persistent context loading the extension from `dist/`) and `extensionId` (extracted from service worker URL). Rename `use` to `apply` to avoid oxlint's `react/rules-of-hooks`. `waitForEvent('serviceworker')` blocks until the MV3 service worker registers.
|
|
32
32
|
- `manifest.config.ts`: use `defineManifest` from `@crxjs/vite-plugin`. Read `name` and `version` from `package.json`. Entry points `src/popup/index.html`, `src/sidepanel/index.html`, `src/background/index.ts`, `src/content/main.tsx`. Permissions `sidePanel`, `contentSettings`, `storage`. Icon `public/logo.png` at size 48.
|
|
33
33
|
- `screenshot` script: `bun run build && bun e2e/screenshot.ts` (no preview server).
|
|
34
34
|
- Additional gitignore entries: `*.crx`, `*.pem`, `release/`.
|