@erclx/canon 5.33.0 → 5.35.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 +3 -5
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/REQUIREMENT.md +2 -3
- package/claude/skills/api-design/SKILL.md +2 -3
- package/claude/skills/api-design/references/adopted.md +1 -1
- package/claude/skills/auto-ship/references/draft-mark.md +1 -1
- package/claude/skills/canon-cli/SKILL.md +10 -11
- package/claude/skills/canon-feedback/REQUIREMENT.md +1 -0
- package/claude/skills/canon-feedback/SKILL.md +10 -28
- package/claude/skills/canon-feedback/references/template.md +53 -0
- package/claude/skills/canvas-board/SKILL.md +4 -1
- package/claude/skills/canvas-board/references/canvas.md +26 -3
- package/claude/skills/code-craft/REQUIREMENT.md +1 -1
- package/claude/skills/code-craft/SKILL.md +0 -1
- package/claude/skills/create-rule/SKILL.md +1 -1
- package/claude/skills/create-rule/references/rule.md +3 -1
- package/claude/skills/create-skill/SKILL.md +2 -1
- package/claude/skills/create-skill/references/skill-paths.md +12 -15
- package/{standards/standard.md → claude/skills/create-skill/references/skill-reference.md} +50 -45
- package/claude/skills/create-skill/references/skill.md +10 -4
- package/claude/skills/draft-and-pick/SKILL.md +1 -1
- package/claude/skills/git-commit/references/versioning.md +13 -13
- package/claude/skills/git-issue/references/issue.md +4 -1
- package/claude/skills/git-pr/SKILL.md +1 -1
- package/claude/skills/git-pr/references/publish.md +1 -1
- package/claude/skills/review-address/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/SKILL.md +2 -2
- package/claude/skills/review-craft/references/ui.md +1 -1
- package/claude/skills/review-pr/SKILL.md +3 -3
- package/claude/skills/review-pr/references/post.md +1 -1
- package/claude/skills/review-ui/REQUIREMENT.md +1 -1
- package/claude/skills/review-ui/SKILL.md +8 -6
- package/claude/skills/review-ui/references/driving.md +8 -8
- package/claude/skills/review-ui/references/post.md +52 -16
- package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
- package/claude/skills/role-orchestrator/SKILL.md +11 -12
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +3 -1
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +11 -8
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +10 -4
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +11 -2
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +11 -12
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +12 -15
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +6 -4
- package/claude/skills/role-orchestrator/scripts/poll.ts +50 -1
- package/claude/skills/role-reviewer/REQUIREMENT.md +17 -7
- package/claude/skills/role-reviewer/SKILL.md +17 -10
- package/claude/skills/role-worker/REQUIREMENT.md +1 -1
- package/claude/skills/role-worker/SKILL.md +6 -6
- package/claude/skills/session-compact/references/handoff-note.md +1 -1
- package/claude/skills/target-setup/SKILL.md +12 -6
- package/claude/skills/target-setup/references/detect.md +22 -5
- package/claude/skills/test-craft/REQUIREMENT.md +2 -3
- package/claude/skills/test-craft/SKILL.md +15 -3
- package/docs/agents/audits.md +1 -1
- package/docs/agents/canvas.md +5 -1
- package/docs/agents/commands.md +3 -5
- package/docs/agents/counts.md +5 -6
- package/docs/agents/drift-surfaces.md +15 -19
- package/docs/agents/gov-detect.md +47 -0
- package/docs/agents/index.md +6 -4
- package/docs/agents/install-and-sync.md +11 -31
- package/docs/agents/markdown-audit.md +10 -12
- package/docs/agents/migrate.md +1 -1
- package/docs/agents/pr-evidence-layout.md +70 -0
- package/docs/agents/pr-evidence.md +8 -9
- package/docs/agents/pr-frames.md +7 -2
- package/docs/agents/pr-lift.md +132 -0
- package/docs/agents/records-stale.md +1 -1
- package/docs/agents/records-validate.md +11 -23
- package/docs/agents/records.md +1 -1
- package/docs/agents/routing.md +1 -1
- package/docs/agents/rule-citations.md +11 -14
- package/docs/agents/scripting.md +4 -21
- package/docs/agents/state-scoped-risk.md +1 -1
- package/docs/agents/tasks-validate.md +1 -1
- package/docs/agents/teach.md +1 -1
- package/docs/target/index.md +1 -0
- package/docs/target/migrations.md +4 -0
- package/docs/target/projects.md +11 -11
- package/docs/target/scenarios.md +5 -6
- package/docs/target/standards-moved.md +32 -0
- package/docs/target/sync.md +5 -5
- package/docs/workflow/operating-model.md +16 -18
- package/docs/workflow/skill-map.md +1 -1
- package/governance/detect.toml +197 -0
- package/governance/renames.toml +0 -1
- package/governance/rules/code/000-code.md +1 -13
- package/governance/rules/code/010-testing.md +2 -30
- package/governance/rules/ui/400-ui.md +1 -1
- package/governance/rules/ui/480-canvas.md +13 -0
- package/governance/stacks/base.toml +15 -8
- package/governance/stacks/go.toml +2 -0
- package/governance/stacks/node.toml +1 -1
- package/governance/stacks/php.toml +2 -0
- package/governance/stacks/python.toml +1 -1
- package/package.json +1 -4
- package/scripts/core/install-check.sh +2 -3
- package/scripts/core/regen-hero.ts +0 -6
- package/scripts/lib/ui.sh +0 -9
- package/src/audits/catalog.ts +0 -9
- package/src/canvas/arrange.ts +66 -0
- package/src/canvas/capture.ts +20 -6
- package/src/canvas/content.ts +39 -0
- package/src/canvas/fit.ts +238 -0
- package/src/canvas/tokens.ts +28 -10
- package/src/capture/frame-values.ts +2 -32
- package/src/claude/routing.ts +1 -1
- package/src/claude/skills-reach.ts +4 -6
- package/src/cli/help.ts +3 -4
- package/src/cli.ts +0 -2
- package/src/commands/canvas.ts +179 -1
- package/src/commands/gov.ts +149 -10
- package/src/commands/init.ts +1 -1
- package/src/commands/labels.ts +4 -44
- package/src/commands/migrate.ts +1 -1
- package/src/commands/pr.ts +376 -1
- package/src/commands/records.ts +4 -20
- package/src/commands/tooling.ts +2 -4
- package/src/counts/catalogs.ts +0 -6
- package/src/feedback/body.ts +26 -5
- package/src/gate/boundaries.ts +2 -2
- package/src/gate/measures.ts +64 -72
- package/src/gate/sequencer.ts +51 -2
- package/src/gate/stages.ts +3 -22
- package/src/gov/citations.ts +11 -43
- package/src/gov/detect.ts +301 -0
- package/src/gov/list.ts +23 -2
- package/src/gov/stacks.ts +9 -0
- package/src/markdown/bans.ts +1 -1
- package/src/migrate/scratch-evidence.ts +2 -2
- package/src/pr/evidence.ts +218 -45
- package/src/pr/frames.ts +23 -3
- package/src/pr/lift.ts +418 -0
- package/src/pr/rest.ts +3 -0
- package/src/pr/review-scope.ts +76 -0
- package/src/records/validate.ts +6 -194
- package/src/sandbox/equivalence.ts +14 -7
- package/src/sandbox/provision.ts +0 -5
- package/src/secrets/shipped.ts +1 -2
- package/src/serve/static.ts +1 -2
- package/src/shipped/references.ts +29 -80
- package/src/sync/check.ts +18 -14
- package/src/tooling/inject.ts +6 -37
- package/src/tooling/read.ts +2 -3
- package/src/tooling/scan.ts +4 -17
- package/src/tooling/subfolder.ts +2 -66
- package/tooling/base/configs/scripts/verify.json +1 -1
- package/tooling/base/configs/scripts/verify.ts +1 -12
- package/tooling/base/manifest.toml +1 -2
- package/tooling/base/reference.md +10 -16
- package/tooling/base/seeds/.github/workflows/verify.yml +0 -3
- package/tooling/base/seeds/.lintstagedrc +1 -2
- package/tooling/base/seeds/canon/context/ci.md +0 -1
- package/tooling/base/seeds/canon/context/development.md +1 -1
- package/tooling/claude/reference.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +13 -1
- package/tooling/go/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +2 -2
- package/tooling/web/configs/.github/workflows/verify.yml +0 -3
- package/tooling/web/manifest.toml +0 -1
- package/tooling/web/reference.md +2 -4
- package/docs/agents/standards-audit.md +0 -40
- package/governance/rules/tooling/765-spelling.md +0 -19
- package/governance/stacks/astro.toml +0 -2
- package/governance/stacks/nextjs.toml +0 -2
- package/governance/stacks/node-server.toml +0 -2
- package/governance/stacks/python-fastapi.toml +0 -2
- package/governance/stacks/react.toml +0 -2
- package/src/commands/standards.ts +0 -278
- package/src/labels/spelling.ts +0 -120
- package/src/standards/audit.ts +0 -146
- package/src/standards/list.ts +0 -33
- package/src/standards/read.ts +0 -177
- package/src/standards/scope.ts +0 -56
- package/standards/index.md +0 -10
- package/tooling/base/configs/.vscode/extensions.json +0 -9
- package/tooling/base/configs/.vscode/settings.json +0 -3
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +0 -25
- package/tooling/base/seeds/cspell.json +0 -20
- package/tooling/go/seeds/.cspell/tech-stack.txt +0 -16
- package/tooling/nextjs/seeds/.cspell/tech-stack.txt +0 -3
- package/tooling/php/seeds/.cspell/tech-stack.txt +0 -5
- package/tooling/python/seeds/.cspell/tech-stack.txt +0 -18
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +0 -1
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +0 -2
- package/tooling/web/configs/.vscode/extensions.json +0 -13
- package/tooling/web/configs/.vscode/settings.json +0 -10
- package/tooling/web/seeds/.cspell/tech-stack.txt +0 -21
package/src/tooling/scan.ts
CHANGED
|
@@ -16,13 +16,7 @@ import {
|
|
|
16
16
|
readPackage,
|
|
17
17
|
type ScriptState,
|
|
18
18
|
} from '@/tooling/package'
|
|
19
|
-
import {
|
|
20
|
-
hasSpellConfig,
|
|
21
|
-
isSubfolderTarget,
|
|
22
|
-
isWithheldInSubfolder,
|
|
23
|
-
SUBFOLDER_SPELL_CONFIG,
|
|
24
|
-
subfolderSpellConfig,
|
|
25
|
-
} from '@/tooling/subfolder'
|
|
19
|
+
import { isSubfolderTarget, isWithheldInSubfolder } from '@/tooling/subfolder'
|
|
26
20
|
|
|
27
21
|
export interface ConfigState {
|
|
28
22
|
readonly rel: string
|
|
@@ -73,9 +67,9 @@ function isIdentical(a: string, b: string): boolean {
|
|
|
73
67
|
* so the path is reported once.
|
|
74
68
|
*
|
|
75
69
|
* A target below its git toplevel is scanned as a subfolder: a config or seed
|
|
76
|
-
* GitHub reads only at the root moves to `withheld` and counts as no change
|
|
77
|
-
*
|
|
78
|
-
*
|
|
70
|
+
* GitHub reads only at the root moves to `withheld` and counts as no change.
|
|
71
|
+
* The scope is read here so every caller of `scan` agrees without passing a
|
|
72
|
+
* flag.
|
|
79
73
|
*/
|
|
80
74
|
export function scan(chain: readonly Manifest[], target: string): ScanResult {
|
|
81
75
|
const isSubfolder = isSubfolderTarget(target)
|
|
@@ -132,13 +126,6 @@ export function scan(chain: readonly Manifest[], target: string): ScanResult {
|
|
|
132
126
|
}
|
|
133
127
|
}
|
|
134
128
|
|
|
135
|
-
if (isSubfolder && subfolderSpellConfig(chain) !== undefined) {
|
|
136
|
-
seeds.push({
|
|
137
|
-
rel: SUBFOLDER_SPELL_CONFIG,
|
|
138
|
-
state: hasSpellConfig(target) ? 'present' : 'missing',
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
129
|
const packagePath = join(target, 'package.json')
|
|
143
130
|
const pkg = readPackage(packagePath)
|
|
144
131
|
const scripts = pkg ? collectScripts(chain, pkg) : []
|
package/src/tooling/subfolder.ts
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { realpathSync } from 'node:fs'
|
|
2
|
+
import { relative } from 'node:path'
|
|
3
3
|
import { gitEnv } from '@/git/env'
|
|
4
|
-
import { isWholeStack, type Manifest, seedFiles } from '@/tooling/manifest'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The path the generated subfolder spell config is written to. Written
|
|
8
|
-
* copy-once, since a project that already configured cspell here owns it.
|
|
9
|
-
*/
|
|
10
|
-
export const SUBFOLDER_SPELL_CONFIG = 'cspell.json'
|
|
11
4
|
|
|
12
5
|
const WITHHELD_PREFIX = '.github/'
|
|
13
6
|
|
|
14
|
-
const SPELL_CONFIG_NAMES = ['cspell.json', '.cspell.json']
|
|
15
|
-
|
|
16
7
|
/**
|
|
17
8
|
* Whether the target sits below the root of the git repository holding it. A
|
|
18
9
|
* target outside any repository, or one git cannot read, counts as a root, so
|
|
@@ -57,58 +48,3 @@ export function subfolderPath(target: string): string | undefined {
|
|
|
57
48
|
export function isWithheldInSubfolder(rel: string): boolean {
|
|
58
49
|
return rel.startsWith(WITHHELD_PREFIX)
|
|
59
50
|
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Whether the target already carries a cspell config of its own, in any of
|
|
63
|
-
* the file names cspell searches for.
|
|
64
|
-
*/
|
|
65
|
-
export function hasSpellConfig(target: string): boolean {
|
|
66
|
-
if (SPELL_CONFIG_NAMES.some((name) => existsSync(join(target, name)))) {
|
|
67
|
-
return true
|
|
68
|
-
}
|
|
69
|
-
if (!existsSync(target)) return false
|
|
70
|
-
return readdirSync(target).some((name) => name.startsWith('cspell.config.'))
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Builds the nested cspell config that registers a subfolder's seeded word
|
|
75
|
-
* lists. A root `cspell '**'` merges it with the root config for files under
|
|
76
|
-
* the subfolder. Each dictionary takes a `local-` name, since reusing a root
|
|
77
|
-
* dictionary's name shadows it inside the subfolder and a root word then fails
|
|
78
|
-
* there.
|
|
79
|
-
*
|
|
80
|
-
* Returns nothing when the chain carries `base`, whose own seed already writes
|
|
81
|
-
* a config, or when no stack seeds a word list.
|
|
82
|
-
*/
|
|
83
|
-
export function subfolderSpellConfig(
|
|
84
|
-
chain: readonly Manifest[],
|
|
85
|
-
): string | undefined {
|
|
86
|
-
if (
|
|
87
|
-
chain.some((manifest) => manifest.name === 'base' && isWholeStack(manifest))
|
|
88
|
-
) {
|
|
89
|
-
return undefined
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const lists = new Set<string>()
|
|
93
|
-
for (const manifest of chain) {
|
|
94
|
-
for (const rel of seedFiles(manifest)) {
|
|
95
|
-
if (rel.startsWith('.cspell/') && rel.endsWith('.txt')) lists.add(rel)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (lists.size === 0) return undefined
|
|
99
|
-
|
|
100
|
-
const definitions = [...lists].sort().map((path) => ({
|
|
101
|
-
name: `local-${basename(path, '.txt')}`,
|
|
102
|
-
path,
|
|
103
|
-
addWords: true,
|
|
104
|
-
}))
|
|
105
|
-
|
|
106
|
-
const config = {
|
|
107
|
-
version: '0.2',
|
|
108
|
-
dictionaryDefinitions: definitions,
|
|
109
|
-
dictionaries: definitions.map((definition) => definition.name),
|
|
110
|
-
ignorePaths: ['.cspell/**'],
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return `${JSON.stringify(config, null, 2)}\n`
|
|
114
|
-
}
|
|
@@ -54,12 +54,6 @@ const PHASES: readonly Phase[] = [
|
|
|
54
54
|
failed: 'Format check failed',
|
|
55
55
|
passed: 'Format check passed',
|
|
56
56
|
},
|
|
57
|
-
{
|
|
58
|
-
script: 'check:spell',
|
|
59
|
-
title: 'Spelling',
|
|
60
|
-
failed: 'Spell check failed',
|
|
61
|
-
passed: 'Spell check passed',
|
|
62
|
-
},
|
|
63
57
|
{
|
|
64
58
|
script: 'check:shell',
|
|
65
59
|
title: 'Shell',
|
|
@@ -83,12 +77,7 @@ const PHASES: readonly Phase[] = [
|
|
|
83
77
|
// A subfolder synced with --skip base declares none of these, since the
|
|
84
78
|
// repository root owns them, so a list that does not require one runs it only
|
|
85
79
|
// where the folder declares it.
|
|
86
|
-
const BASE_PHASES = new Set([
|
|
87
|
-
'format',
|
|
88
|
-
'check:format',
|
|
89
|
-
'check:spell',
|
|
90
|
-
'check:shell',
|
|
91
|
-
])
|
|
80
|
+
const BASE_PHASES = new Set(['format', 'check:format', 'check:shell'])
|
|
92
81
|
|
|
93
82
|
const PHASE_LIST = 'scripts/verify.json'
|
|
94
83
|
const CARD_EXCLUSION = 'scripts/check-card-exclusion.sh'
|
|
@@ -11,14 +11,12 @@ per_root = ["scripts/verify.sh", "scripts/verify.ts", "scripts/verify.json"]
|
|
|
11
11
|
[dependencies.dev]
|
|
12
12
|
packages = [
|
|
13
13
|
"prettier",
|
|
14
|
-
"cspell",
|
|
15
14
|
"husky",
|
|
16
15
|
"@commitlint/cli",
|
|
17
16
|
"@commitlint/config-conventional",
|
|
18
17
|
]
|
|
19
18
|
|
|
20
19
|
[scripts]
|
|
21
|
-
"check:spell" = "cspell '**' '.*/**' '.*' --no-progress --color --show-context"
|
|
22
20
|
"check:format" = "prettier --check --log-level warn --ignore-path .gitignore --ignore-path .prettierignore . && find scripts -name '*.sh' -exec shfmt --diff --indent 2 {} +"
|
|
23
21
|
"check:shell" = "find scripts -name '*.sh' -exec shellcheck --severity=warning {} +"
|
|
24
22
|
"format" = "prettier --write --log-level warn --ignore-path .gitignore --ignore-path .prettierignore . && find scripts -name '*.sh' -exec shfmt --write --indent 2 {} +"
|
|
@@ -29,3 +27,4 @@ packages = [
|
|
|
29
27
|
"# System" = [".DS_Store"]
|
|
30
28
|
"# Dependencies" = ["node_modules/"]
|
|
31
29
|
"# Secrets" = [".env", ".env.*", "*.local", "!.env.example"]
|
|
30
|
+
"# VSCode" = [".vscode/"]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
The base layer covers every project the toolkit scaffolds, whatever language sits on top. It ships formatting,
|
|
5
|
+
The base layer covers every project the toolkit scaffolds, whatever language sits on top. It ships formatting, shell linting, conventional commits, git hooks, CI, and one maintenance script. Every other stack extends it, so a decision made here is one every stack inherits.
|
|
6
6
|
|
|
7
7
|
A repository with several language roots layers this stack once at the root and skips it per subtree, since git honors only one `core.hooksPath` and a re-dropped husky silently breaks. `canon docs scenarios` carries the recipe.
|
|
8
8
|
|
|
@@ -15,17 +15,14 @@ Golden config files live in `tooling/base/configs/` and are copied into the targ
|
|
|
15
15
|
- `.editorconfig`: `root = true`, with an `[*.sh]` block setting `indent_style = space` and `indent_size = 2`.
|
|
16
16
|
- `commitlint.config.js`: ESM default export extending `@commitlint/config-conventional`. Rules are `header-max-length: 72`, `scope-case: lower-case`, `subject-full-stop: never`, `subject-case` disabled, and a local `no-claude-co-author` rule refusing a `Co-authored-by` trailer that names Claude or Anthropic.
|
|
17
17
|
- `.husky/`: `pre-commit`, `commit-msg`, `pre-push`, `post-merge`, `post-rewrite`.
|
|
18
|
-
- `.vscode/extensions.json` and `.vscode/settings.json`: editor wiring for Prettier, cspell, shfmt, and shellcheck.
|
|
19
18
|
- `scripts/verify.sh`: the maintenance entry point behind `check`, a wrapper that hands off to `scripts/verify.ts`.
|
|
20
|
-
- `scripts/verify.ts`: the one verify runner every stack shares. It runs typecheck, lint, format, format check,
|
|
21
|
-
- `scripts/verify.json`: the phases a stack requires, plus any tools and preconditions it probes first. The nearest stack's copy wins. A required phase whose script `package.json` lacks fails the run. A base phase the list leaves out runs only where the folder declares its script. Base requires its
|
|
19
|
+
- `scripts/verify.ts`: the one verify runner every stack shares. It runs typecheck, lint, format, format check, shell, unit tests, build, markdown bans, then card exclusion, always in that order, and skips any phase the folder's `scripts/verify.json` leaves out. Node modules only, since a target's own lint and typecheck read it.
|
|
20
|
+
- `scripts/verify.json`: the phases a stack requires, plus any tools and preconditions it probes first. The nearest stack's copy wins. A required phase whose script `package.json` lacks fails the run. A base phase the list leaves out runs only where the folder declares its script. Base requires its three phases, so a base-only target still fails on a missing one. These three files are base's `[sync] per_root` set, which a `--skip base` subfolder still receives.
|
|
22
21
|
|
|
23
22
|
## What ships as user-owned seeds
|
|
24
23
|
|
|
25
24
|
Seeds live in `tooling/base/seeds/`. Sync drops each once on first install and never overwrites it, so a project extends them freely.
|
|
26
25
|
|
|
27
|
-
- `cspell.json`: `version: "0.2"`, `language: "en"`, `useGitignore: true`, `gitignoreRoot: ["."]`, dictionary definitions for `project-terms` and `tech-stack` with `addWords: true` on both, and `ignorePaths: [".cspell/**", ".git/**"]` to skip dictionary self-checks and git object files.
|
|
28
|
-
- `.cspell/project-terms.txt` and `.cspell/tech-stack.txt`: one word per line, sorted alphabetically.
|
|
29
26
|
- `.lintstagedrc`: the glob map below.
|
|
30
27
|
- `.prettierignore`: created empty. Projects add their own entries.
|
|
31
28
|
- `.github/workflows/verify.yml`: runs on pull requests targeting `main` and on `workflow_dispatch`. A project with more than one language root adds its own jobs here.
|
|
@@ -36,15 +33,14 @@ Seeds live in `tooling/base/seeds/`. Sync drops each once on first install and n
|
|
|
36
33
|
|
|
37
34
|
- Runtime: `bun` as package manager and script runner, `bunx` over `npx` for a one-off executable.
|
|
38
35
|
- Formatting: Prettier for what it parses, shfmt for shell. Two formatters because Prettier has no shell parser.
|
|
39
|
-
- Spelling: cspell over the whole tree, with project vocabulary split into a project-terms dictionary and a tech-stack one.
|
|
40
36
|
- Shell: shfmt formats and shellcheck lints at warning severity. Both take their files from `find scripts -name '*.sh'`, since `scripts/` can mix shell with TypeScript and shellcheck has no directory mode. A shell script with a shebang and no `.sh` extension is covered by neither, so give it the extension.
|
|
41
37
|
- Commits: commitlint against conventional commits, wired through the husky `commit-msg` hook. Format is `<type>(<scope>): <subject>` in imperative mood with no trailing period.
|
|
42
|
-
- Dev dependencies: `prettier`, `
|
|
38
|
+
- Dev dependencies: `prettier`, `husky`, `@commitlint/cli`, `@commitlint/config-conventional`. Install via `bun add -D`.
|
|
43
39
|
|
|
44
40
|
## File layout
|
|
45
41
|
|
|
46
42
|
- All shell scripts live in `scripts/`. Do not place a `.sh` file outside it.
|
|
47
|
-
-
|
|
43
|
+
- Hooks live in `.husky/`, seeded context docs in `canon/context/`.
|
|
48
44
|
- The `canon/context/` location matches the three-tier context model: project-wide invariants in `CLAUDE.md` and `canon/REQUIREMENTS.md`, path-scoped rules in `.claude/rules/`, and on-demand domain narrative in `canon/context/`. Indexes stay opt-in.
|
|
49
45
|
|
|
50
46
|
## Hooks
|
|
@@ -59,13 +55,13 @@ Seeds live in `tooling/base/seeds/`. Sync drops each once on first install and n
|
|
|
59
55
|
|
|
60
56
|
Seeded baseline globs:
|
|
61
57
|
|
|
62
|
-
- `**/*.{json,md,mdc}` runs `prettier --write --ignore-path .gitignore --ignore-path .prettierignore`
|
|
58
|
+
- `**/*.{json,md,mdc}` runs `prettier --write --ignore-path .gitignore --ignore-path .prettierignore`
|
|
63
59
|
- `**/*.md` runs `canon indexes regen`
|
|
64
60
|
- `**/*.sh` runs `shfmt --write --indent 2` then `shellcheck --severity=warning`
|
|
65
61
|
|
|
66
62
|
## CI
|
|
67
63
|
|
|
68
|
-
- Steps: checkout, setup Bun at latest, `bun install --frozen-lockfile`, install `shfmt` and `shellcheck` via apt, then `check:format
|
|
64
|
+
- Steps: checkout, setup Bun at latest, `bun install --frozen-lockfile`, install `shfmt` and `shellcheck` via apt, then `check:format` and `check:shell`.
|
|
69
65
|
- CI asserts and never writes. Format must be clean before push.
|
|
70
66
|
|
|
71
67
|
## Gitignore
|
|
@@ -73,13 +69,12 @@ Seeded baseline globs:
|
|
|
73
69
|
- `# System`: `.DS_Store`
|
|
74
70
|
- `# Dependencies`: `node_modules/`
|
|
75
71
|
- `# Secrets`: `.env`, `.env.*`, `*.local`, `!.env.example`
|
|
72
|
+
- `# VSCode`: `.vscode/`
|
|
76
73
|
|
|
77
74
|
## Anti-patterns
|
|
78
75
|
|
|
79
76
|
Sticky negative knowledge. Do not relearn.
|
|
80
77
|
|
|
81
|
-
- Do NOT drop `gitignoreRoot: ["."]` from `cspell.json`. Without it, cspell run from inside a linked worktree under `.claude/worktrees/` walks up into the parent repo's `.gitignore`, resolves every worktree file as living under the ignored worktree path, and checks zero files. New words then pass locally and fail in CI.
|
|
82
|
-
- Do NOT rely on the default `**` glob for spelling. It skips dot-prefixed folders, leaving `.claude/`, `.github/`, and `.husky/` unchecked. Pass `'**' '.*/**' '.*'` explicitly.
|
|
83
78
|
- Do NOT invoke prettier without both `--ignore-path .gitignore --ignore-path .prettierignore`. Passing one drops the other, since the flag replaces the default rather than adding to it.
|
|
84
79
|
- Do NOT omit `--log-level warn` from a prettier invocation. The default prints a line per unchanged file.
|
|
85
80
|
- Do NOT put logic in a husky hook and expect its shebang to hold. Husky runs hooks as `sh -e`, so a hook carrying logic is POSIX sh under errexit whatever the first line says.
|
|
@@ -92,11 +87,10 @@ Sticky negative knowledge. Do not relearn.
|
|
|
92
87
|
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
93
88
|
| `bun run check` | Repairs a checkout via `scripts/verify.ts`. Honors `VERIFY_NESTED=true` to suppress timeline boundaries when another script calls it. |
|
|
94
89
|
| `bun run check:format` | Asserts prettier and shfmt formatting without writing |
|
|
95
|
-
| `bun run check:spell` | Runs cspell across every file, with context on failures |
|
|
96
90
|
| `bun run check:shell` | Runs shellcheck at warning severity |
|
|
97
91
|
| `bun run format` | Writes prettier and shfmt formatting in place |
|
|
98
92
|
| `bun run prepare` | Initializes husky hooks, run automatically on `bun install` |
|
|
99
93
|
|
|
100
|
-
`bun run check` repairs a checkout rather than gating one. It runs `format` first to auto-fix drifted code, then asserts only what the formatters could not fix. The pull request workflow calls `check:format
|
|
94
|
+
`bun run check` repairs a checkout rather than gating one. It runs `format` first to auto-fix drifted code, then asserts only what the formatters could not fix. The pull request workflow calls `check:format` and `check:shell` directly, and those two are the gate.
|
|
101
95
|
|
|
102
|
-
`scripts/verify.ts`'s `Markdown bans` stage is the exception: it gates rather than repairs. It runs `canon markdown audit` over every tracked markdown file except `CHANGELOG.md`, since a generated changelog carries commit subjects nobody wrote against the ban set, and exits `2` on a finding or `3` on a shipped-empty ban set, failing `bun run check` and the `pre-push` hook that calls it. A refusal to measure exits `1` and is logged as a skip rather than a failure, as does a corpus with no file left to check once `CHANGELOG.md` is set aside. The stage needs `canon` on PATH. `canon docs projects` names the install command. Without it, the stage is skipped and logged, and coverage falls back to the
|
|
96
|
+
`scripts/verify.ts`'s `Markdown bans` stage is the exception: it gates rather than repairs. It runs `canon markdown audit` over every tracked markdown file except `CHANGELOG.md`, since a generated changelog carries commit subjects nobody wrote against the ban set, and exits `2` on a finding or `3` on a shipped-empty ban set, failing `bun run check` and the `pre-push` hook that calls it. A refusal to measure exits `1` and is logged as a skip rather than a failure, as does a corpus with no file left to check once `CHANGELOG.md` is set aside. The stage needs `canon` on PATH. `canon docs projects` names the install command. Without it, the stage is skipped and logged, and coverage falls back to the two checks above.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"**/*.{json,md,mdc}": [
|
|
3
|
-
"prettier --write --ignore-path .gitignore --ignore-path .prettierignore"
|
|
4
|
-
"cspell --no-must-find-files"
|
|
3
|
+
"prettier --write --ignore-path .gitignore --ignore-path .prettierignore"
|
|
5
4
|
],
|
|
6
5
|
"**/*.md": ["canon indexes regen"],
|
|
7
6
|
"**/*.sh": ["shfmt --write --indent 2", "shellcheck --severity=warning"]
|
|
@@ -25,7 +25,6 @@ Defined in `.github/workflows/verify.yml`. All jobs must pass before merge.
|
|
|
25
25
|
| Check | Command | What it asserts |
|
|
26
26
|
| ------ | ---------------------- | ---------------------------------- |
|
|
27
27
|
| Format | `bun run check:format` | prettier and shfmt are clean |
|
|
28
|
-
| Spell | `bun run check:spell` | cspell passes against dictionaries |
|
|
29
28
|
| Shell | `bun run check:shell` | shellcheck passes at warning level |
|
|
30
29
|
|
|
31
30
|
## Running CI locally
|
|
@@ -32,6 +32,6 @@ All `.sh` files live under `scripts/`. Do not place shell scripts outside `scrip
|
|
|
32
32
|
|
|
33
33
|
## Husky hooks
|
|
34
34
|
|
|
35
|
-
- `pre-commit` runs `lint-staged` (prettier,
|
|
35
|
+
- `pre-commit` runs `lint-staged` (prettier, shfmt, shellcheck on staged files).
|
|
36
36
|
- `commit-msg` runs `commitlint` against the conventional commit format.
|
|
37
37
|
- `pre-push` runs `bun run check`. When a markdown-bans audit tool is on PATH, it also gates on banned characters across every tracked markdown file except `CHANGELOG.md`. After pushing, run `git status`. If files changed, commit the diff as `style(<scope>):` and push again.
|
|
@@ -42,7 +42,7 @@ A project installed before the board became a folder still holds `.claude/TASKS.
|
|
|
42
42
|
|
|
43
43
|
Convert by hand, once per project:
|
|
44
44
|
|
|
45
|
-
1. Split each `###` block into `.canon/tasks/vXX.Y-<slug>.md`, adding the `title` and `description` frontmatter the tasks
|
|
45
|
+
1. Split each `###` block into `.canon/tasks/vXX.Y-<slug>.md`, adding the `title` and `description` frontmatter the tasks reference in the `task-board` skill requires. Compare each new file against the block it came from rather than checking that every block landed somewhere.
|
|
46
46
|
2. Run `canon indexes regen --no-stage --root . .canon/tasks/<any-task>.md` to build the catalog.
|
|
47
47
|
3. Delete `.claude/TASKS.md`, and swap its `.gitignore` entry for `.canon/tasks/`.
|
|
48
48
|
|
|
@@ -50,7 +50,19 @@ END {
|
|
|
50
50
|
while (i <= n && substr(s, i, 1) != "\n") i++
|
|
51
51
|
continue
|
|
52
52
|
}
|
|
53
|
-
if (c == "
|
|
53
|
+
if (c == "(" && substr(s, i, 2) == "((") {
|
|
54
|
+
d = 0
|
|
55
|
+
while (i <= n) {
|
|
56
|
+
a = substr(s, i, 1)
|
|
57
|
+
if (a == "(") d++
|
|
58
|
+
else if (a == ")") { d--; if (d == 0) { seg = seg a; i++; break } }
|
|
59
|
+
seg = seg a; i++
|
|
60
|
+
}
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
if (c == "<" && substr(s, i, 3) == "<<<") { seg = seg "<<<"; i += 3; continue }
|
|
64
|
+
if (c == "<" && substr(s, i, 2) == "<<" && seg ~ /^[ \t]*let[ \t]/) { seg = seg "<<"; i += 2; continue }
|
|
65
|
+
if (c == "<" && substr(s, i, 2) == "<<") {
|
|
54
66
|
j = i + 2; dash = 0
|
|
55
67
|
if (substr(s, j, 1) == "-") { dash = 1; j++ }
|
|
56
68
|
while (substr(s, j, 1) ~ /[ \t]/) j++
|
package/tooling/go/reference.md
CHANGED
|
@@ -10,7 +10,7 @@ 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, prettier,
|
|
13
|
+
3. Seed `package.json` so the base layer's bun-side tools (husky, prettier, 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.
|
package/tooling/php/reference.md
CHANGED
|
@@ -9,7 +9,7 @@ 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, prettier,
|
|
12
|
+
2. Seed `package.json` so the base layer's bun-side tools (husky, prettier, 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.
|
|
@@ -11,7 +11,7 @@ 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, prettier,
|
|
14
|
+
2. Seed `package.json` so the base layer's bun-side tools (husky, prettier, 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.
|
|
@@ -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 prettier,
|
|
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 prettier, 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
|
|
package/tooling/web/reference.md
CHANGED
|
@@ -17,7 +17,6 @@ Golden config files live in `tooling/web/configs/` and are copied into the targe
|
|
|
17
17
|
- `scripts/lib/preview-server.sh`: sourced, never executed. Builds, serves on `PREVIEW_PORT`, blocks until the port answers, and traps the whole process group on exit, including the detached grandchild `lsof` finds. Both capture scripts source it so the startup lives once.
|
|
18
18
|
- `scripts/readme-screenshot.sh`: captures one case under `SCREENSHOT_FILTER` and copies its light and dark frames to `assets/evidence/readme/`. `README_FILTER` ships empty with `header/1280` as its example, and the script exits 1 until a project fills it, since a shipped default would capture the wrong part of the page in every project but one. Its copy reads from `screenshots/<hostname>/`, which is where the harness writes.
|
|
19
19
|
- `.github/workflows/readme-screenshot.yml`: refreshes that frame on a pull request and commits it back to the branch. The path list ships as `REPLACE_WITH_PROJECT_PATHS`, and the job's first step after checkout exits 1 while it stays, since a job that never fires leaves no run and no diff to notice. The workflow's own path is in the list so the installing pull request reaches that step. When a commit-back is right and when a report is, `governance/rules/tooling/700-ci-workflow.md` states the test.
|
|
20
|
-
- `.vscode/extensions.json` and `.vscode/settings.json`: editor wiring for ESLint, Tailwind, Playwright, Vitest.
|
|
21
20
|
- `.github/workflows/verify.yml`: `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests` jobs.
|
|
22
21
|
- `scripts/verify.json`: the phases base's verify runner requires here, being typecheck, lint, unit tests, and build. `## Verify script` covers the order and the card exclusion stage.
|
|
23
22
|
- `scripts/worktree-port.sh`: prints a base port plus this working directory's offset. Called with no argument it prints the offset alone. It refuses a folder left under the worktrees directory after its worktree was removed, rather than printing a port for it.
|
|
@@ -78,9 +77,8 @@ Sticky negative knowledge. Do not relearn.
|
|
|
78
77
|
|
|
79
78
|
## lint-staged (extend)
|
|
80
79
|
|
|
81
|
-
- Add `**/*.{js,jsx,ts,tsx}` glob running `eslint --fix --max-warnings 0`, `prettier --write
|
|
80
|
+
- Add `**/*.{js,jsx,ts,tsx}` glob running `eslint --fix --max-warnings 0`, and `prettier --write`.
|
|
82
81
|
- Extend the prettier glob to include `css`: `**/*.{json,css,md,mdc}`.
|
|
83
|
-
- Each file type runs cspell once via its own glob. No standalone cspell glob.
|
|
84
82
|
|
|
85
83
|
## CI docs (extend)
|
|
86
84
|
|
|
@@ -128,6 +126,6 @@ The sweep under `screenshots/` is ignored again, and only a flagged case's `evid
|
|
|
128
126
|
|
|
129
127
|
## Verify script
|
|
130
128
|
|
|
131
|
-
The web layer's `scripts/verify.json` requires `typecheck`, `lint`, `test:run`, and `build`, and base's `scripts/verify.ts` runs them in its fixed order: typecheck, lint, format,
|
|
129
|
+
The web layer's `scripts/verify.json` requires `typecheck`, `lint`, `test:run`, and `build`, and base's `scripts/verify.ts` runs them in its fixed order: typecheck, lint, format, shell, unit tests, build, markdown bans, then the card exclusion check where one is installed. 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.
|
|
132
130
|
|
|
133
131
|
The card stage runs `scripts/check-card-exclusion.sh` whenever that file is installed, which keeps the social card route's build exclusion on the default path rather than behind a flag. It tests for the script rather than the stack, so a project with no card route runs one less stage with no override, and 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.
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Standard success criteria
|
|
3
|
-
description: Reading the corpus against the success-criterion gate, the two headings it accepts, why the check scopes to arrival rather than the whole corpus, and the exit codes it sets
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Standard success criteria
|
|
7
|
-
|
|
8
|
-
`canon standards audit` reads the corpus at `standards/` and reports which files state a success criterion against which do not, per `standards/standard.md`. It fails only on a standard new to the current branch, never on one already short the section.
|
|
9
|
-
|
|
10
|
-
Two headings count, at any casing. `## Success criterion` is the wording that standard states the rule under, and `## What a working <document type> looks like` is the wording its template prescribes for the section itself. Most of the corpus writes the templated form, so accepting the rule's wording alone would refuse a conforming standard.
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
canon standards audit
|
|
14
|
-
canon standards audit --json
|
|
15
|
-
canon standards audit --arrivals-only
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
| Option | Behavior |
|
|
19
|
-
| ----------------- | ------------------------------------------------------------ |
|
|
20
|
-
| `[path]` | Project root, defaulting to the current directory |
|
|
21
|
-
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
22
|
-
| `--arrivals-only` | Run the gating check alone, printing nothing on a clean pass |
|
|
23
|
-
|
|
24
|
-
## Why arrival rather than the corpus
|
|
25
|
-
|
|
26
|
-
`standards/standard.md` states that a criterion is added to an existing standard when that standard is next exercised, not in a sweep: a criterion written with no failure to point at is the taste-based edit the rule exists to prevent. Gating the whole corpus would fail every push until every standard already short the section was closed at once, which is the sweep that rule forbids. The check reads the whole corpus and fails only on a file present in the working tree and absent at the branch's merge base, treating a rename into the corpus the same as a standard authored fresh.
|
|
27
|
-
|
|
28
|
-
## Exit codes and refusals
|
|
29
|
-
|
|
30
|
-
| Code | Meaning |
|
|
31
|
-
| ---- | ---------------------------------------------------------------------- |
|
|
32
|
-
| `0` | every arriving standard carries the section |
|
|
33
|
-
| `1` | refused, with `reason` naming the cause |
|
|
34
|
-
| `2` | a standard new to this branch states no criterion under either heading |
|
|
35
|
-
|
|
36
|
-
A project authoring no standards refuses with `no-corpus`, the ordinary state of most targets, the same absence `canon claude skills audit` reads as its own `no-corpus`.
|
|
37
|
-
|
|
38
|
-
## What it does not measure
|
|
39
|
-
|
|
40
|
-
Presence of the heading is the whole check. The section's content, the questions it must answer or the task it must let a reader complete, is a judgment `canon standards audit` cannot read, so a standard carrying an empty or token section still passes.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Route .cspell/ dictionary additions to the right seeded file and keep each sorted
|
|
3
|
-
paths:
|
|
4
|
-
- '.cspell/**'
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Spelling standards
|
|
8
|
-
|
|
9
|
-
## Dictionary routing
|
|
10
|
-
|
|
11
|
-
- Rewrite a typo rather than adding it. Add only a real term.
|
|
12
|
-
- Add a term from a tool, library, or platform the project depends on to `.cspell/tech-stack.txt`, whether it is the dependency's own name or vocabulary from its config, API, or spec.
|
|
13
|
-
- Add jargon, an acronym, a handle, or another project-specific term to `.cspell/project-terms.txt`.
|
|
14
|
-
- Leave a dictionary declared `addWords: false` alone. It mirrors a closed set maintained elsewhere in the project rather than approved vocabulary, so route a word there through whatever maintains that set instead of editing the dictionary file.
|
|
15
|
-
- Add a third dictionary only when cspell still flags a term neither file covers. Declare its path in `cspell.json` with `addWords: true` before adding words to it.
|
|
16
|
-
|
|
17
|
-
## File shape
|
|
18
|
-
|
|
19
|
-
- Keep every dictionary file sorted alphabetically.
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
extends = "node"
|
|
2
|
-
rules = ["210-astro", "300-testing-ts", "305-e2e-reliability", "306-test-scope", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture", "450-link-behavior", "460-design-taste", "465-interface-casing","470-motion"]
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
extends = "node"
|
|
2
|
-
rules = ["200-react", "250-tailwind", "300-testing-ts", "305-e2e-reliability", "306-test-scope", "310-zod", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture", "450-link-behavior", "460-design-taste", "465-interface-casing","470-motion"]
|