@erclx/canon 4.50.0 → 4.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/docs-draft/REQUIREMENT.md +35 -0
- package/claude/skills/docs-draft/SKILL.md +59 -0
- package/docs/workflow/ai-workflow.md +1 -0
- package/package.json +8 -2
- package/src/claude/cases/authoring.ts +5 -0
- package/tooling/web/manifest.toml +1 -0
- package/tooling/web/reference.md +1 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docs-draft
|
|
3
|
+
description: Why a brand-new docs/*.md page needs a placement decision and a confirm step, not the rewrite path docs-sync already owns
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Docs draft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session drafting documentation for a surface that has no page yet either invents structure from memory or reaches for `docs-sync`, which has nothing to diff a nonexistent page against and reports the topic as unrelated to any change. Either way the page ships with no read of `standards/docs.md` and no catalog placement decided against the folder's actual shelves.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Read `standards/docs.md` before drafting, since the frontmatter contract and the four reader questions are what make the page arguable against a sibling
|
|
15
|
+
- Decide placement from the existing catalog rather than guessing a folder, reusing a `category` value verbatim when one fits and defaulting to the `docs/` root when none does
|
|
16
|
+
- Confirm the resolved path and the full content with the user before writing, since placement is a judgment call with no diff to preview it against
|
|
17
|
+
- Run `canon indexes regen` on the containing folder after writing, so the folder's `index.md` picks up the new page immediately rather than drifting until the next unrelated regen
|
|
18
|
+
|
|
19
|
+
## Must not
|
|
20
|
+
|
|
21
|
+
- Rewrite an existing page. A topic already covered by a page refuses toward `docs-sync`.
|
|
22
|
+
- Hand-edit an `index.md`. It regenerates from sibling frontmatter, and a hand edit is overwritten on the next regen.
|
|
23
|
+
- Build a hand-drawn diagram-and-capture authoring loop. `standards/docs.md`'s Mermaid-fence permission is the only path to a diagram this skill takes.
|
|
24
|
+
|
|
25
|
+
## Guards
|
|
26
|
+
|
|
27
|
+
- No topic given: stop and ask what surface the page should cover.
|
|
28
|
+
- The derived slug already resolves through `canon docs <slug>`: stop and point at `docs-sync` instead. This catches an exact-name collision only.
|
|
29
|
+
- A page in the catalog already covers the topic under a different name: stop the same way, checked against the titles and descriptions Placement already reads.
|
|
30
|
+
|
|
31
|
+
## Out of scope
|
|
32
|
+
|
|
33
|
+
- Rewriting or syncing an existing `docs/*.md` section against a diff since main: `docs-sync`
|
|
34
|
+
- The `.claude/` planning surface: `claude-docs`
|
|
35
|
+
- Drafting a standard, a snippet, or a governance rule: `create-standard`, `create-snippet`, `create-rule`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docs-draft
|
|
3
|
+
description: Drafts a brand-new `docs/*.md` page against `standards/docs.md`, decides its placement in the existing catalog, confirms with the user, then writes. Use when asked to "add a docs page for X", "write a new doc for X", "document X under docs/", or "create a docs page for X" where no existing page covers the topic. Do NOT use to rewrite or sync an existing `docs/*.md` section against a diff, which is `docs-sync`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Docs draft
|
|
7
|
+
|
|
8
|
+
Drafts one brand-new `docs/*.md` page end to end: read the standard, decide where the page belongs in the existing catalog, confirm the draft with the user, then write.
|
|
9
|
+
|
|
10
|
+
Read these files in parallel:
|
|
11
|
+
|
|
12
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/docs.md`: the reader a page serves, its frontmatter, structure, and what it links out to rather than restates
|
|
13
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: banned words, punctuation, and formatting for all generated text
|
|
14
|
+
- The `write-human` skill: voice, rhythm, and sentence construction for all generated text
|
|
15
|
+
|
|
16
|
+
## Guards
|
|
17
|
+
|
|
18
|
+
- If no topic is given, stop: `❌ No topic given. Name the surface this page should cover.`
|
|
19
|
+
- Derive a kebab-case slug from the topic and run `canon docs <slug>`. A resolved page means the topic is already covered under that exact name. Stop: `❌ <slug> already resolves to an existing page. Run canon:docs-sync instead.` This is a name match rather than a topic match. Placement below checks the wider case.
|
|
20
|
+
|
|
21
|
+
## Placement
|
|
22
|
+
|
|
23
|
+
- Read `docs/index.md` and its sub-catalogs for the closest existing `category`. <!-- canon-allow-reference: illustrates the target project's own docs/ tree, not a citation of this repository's own corpus -->
|
|
24
|
+
- Check every page title and description this read surfaces against the topic. The Guards check above only catches an exact-slug collision, and a page already covering the same subject under a different slug still resolves here at no extra cost, since this read already runs. Stop the same way on a match: `❌ <path> already covers this topic under a different name. Run canon:docs-sync instead.`
|
|
25
|
+
- Reuse a matching `category` value verbatim. A near-miss spelling opens a second shelf holding one page, per the docs standard.
|
|
26
|
+
- Default to the `docs/` root with no `category` when nothing fits. A subfolder earns itself only once a shelf of pages already sits there, per the standard's splitting rule.
|
|
27
|
+
|
|
28
|
+
## Draft
|
|
29
|
+
|
|
30
|
+
- Draft `title`, `description`, and `category` (where one applies), then the page body, against `${CLAUDE_SKILL_DIR}/../../standards/docs.md`.
|
|
31
|
+
- Write for a reader with no source open. The standard's four questions are the test: what the surface is, what to run or write, what it refuses, and where to go for the adjacent surface.
|
|
32
|
+
|
|
33
|
+
## Confirm
|
|
34
|
+
|
|
35
|
+
- Show the resolved path and the full drafted content before writing.
|
|
36
|
+
- Confirm both with the user. This skill waits for that answer rather than treating the tool permission dialog as the gate, since placement here is a judgment call with no diff to preview it against.
|
|
37
|
+
|
|
38
|
+
## Write
|
|
39
|
+
|
|
40
|
+
- Write the file at the confirmed path, creating the folder when it is absent.
|
|
41
|
+
- Run `canon markdown audit <path>`.
|
|
42
|
+
- Run `canon indexes regen <folder>` on the containing folder, so its `index.md` picks up the new page.
|
|
43
|
+
|
|
44
|
+
## Response format
|
|
45
|
+
|
|
46
|
+
### Preview
|
|
47
|
+
|
|
48
|
+
**Topic:** `<topic>`
|
|
49
|
+
**Placement:** `<path>` (category: `<category-or-root>`)
|
|
50
|
+
|
|
51
|
+
```markdown
|
|
52
|
+
<drafted frontmatter and body>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### After confirmation
|
|
56
|
+
|
|
57
|
+
```plaintext
|
|
58
|
+
✅ Drafted: <path>
|
|
59
|
+
```
|
|
@@ -290,6 +290,7 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
290
290
|
| `canon:create-skill` | For a new `SKILL.md` |
|
|
291
291
|
| `canon:create-snippet` | For a reusable prompt |
|
|
292
292
|
| `canon:create-standard` | For a new authoring convention |
|
|
293
|
+
| `canon:docs-draft` | For a brand-new `docs/*.md` page, drafted against `standards/docs.md` |
|
|
293
294
|
| `canon:bash-script` | For an interactive, human-facing shell tool |
|
|
294
295
|
| `canon:bash-cli-script` | For a non-interactive automation, CI, or pipeline script |
|
|
295
296
|
| `canon:ci-workflow` | For a GitHub Actions workflow file |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erclx/canon",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.52.0",
|
|
5
5
|
"description": "Infrastructure and quality tooling for developer workflows",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -40,7 +40,12 @@
|
|
|
40
40
|
"snapshot": "./scripts/core/snapshot.sh",
|
|
41
41
|
"bootstrap": "./scripts/core/bootstrap.sh",
|
|
42
42
|
"canon:sandbox": "canon sandbox",
|
|
43
|
-
"canon:sandbox:reset": "canon sandbox reset"
|
|
43
|
+
"canon:sandbox:reset": "canon sandbox reset",
|
|
44
|
+
"web:tokens": "canon design css --no-components > web/src/styles/tokens.css.new && (echo '/* Generated by `canon design css --no-components`. Regenerate with `bun run web:tokens`. Do not hand-edit. */'; cat web/src/styles/tokens.css.new) > web/src/styles/tokens.css && rm web/src/styles/tokens.css.new",
|
|
45
|
+
"web:dev": "cd web && astro dev",
|
|
46
|
+
"web:build": "bun run web:tokens && cd web && astro check && astro build",
|
|
47
|
+
"web:preview": "cd web && astro preview",
|
|
48
|
+
"web:e2e": "cd web && playwright test"
|
|
44
49
|
},
|
|
45
50
|
"dependencies": {
|
|
46
51
|
"commander": "^13.1.0",
|
|
@@ -61,6 +66,7 @@
|
|
|
61
66
|
"cspell": "^8.17.1",
|
|
62
67
|
"husky": "^9.1.7",
|
|
63
68
|
"prettier": "^3.8.1",
|
|
69
|
+
"prettier-plugin-astro": "^0.14.1",
|
|
64
70
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
65
71
|
"typescript": "^5.9.3",
|
|
66
72
|
"vitest": "^4.1.5"
|
|
@@ -37,6 +37,11 @@ export const AUTHORING_CASES: readonly SkillCase[] = [
|
|
|
37
37
|
"The docs folder and README are stale against what's on main, refresh them.",
|
|
38
38
|
expect: 'docs-sync',
|
|
39
39
|
},
|
|
40
|
+
{
|
|
41
|
+
prompt:
|
|
42
|
+
'Write a brand-new docs page for the capture command, nothing under docs/ covers it yet.',
|
|
43
|
+
expect: 'docs-draft',
|
|
44
|
+
},
|
|
40
45
|
{
|
|
41
46
|
prompt: 'Say what that dense answer actually means in plain terms.',
|
|
42
47
|
expect: 'restate-plainly',
|
|
@@ -49,6 +49,7 @@ packages = [
|
|
|
49
49
|
"check:full" = "./scripts/verify.sh && bun run test:e2e"
|
|
50
50
|
|
|
51
51
|
[scripts.override]
|
|
52
|
+
"lint" = "eslint . --max-warnings 0"
|
|
52
53
|
"screenshot" = "PREVIEW_PORT=$(bash scripts/worktree-port.sh 4173) && export PREVIEW_PORT && bash scripts/screenshot.sh"
|
|
53
54
|
|
|
54
55
|
[gitignore]
|
package/tooling/web/reference.md
CHANGED
|
@@ -53,6 +53,7 @@ Sticky negative knowledge. Do not relearn.
|
|
|
53
53
|
|
|
54
54
|
- Do NOT use `tsc -b` in a Vite project. Composite mode emits `.js` next to `.ts` and ESLint lints the emitted files. Use `tsc --noEmit`.
|
|
55
55
|
- Do NOT accept `eslint@^10` alongside `typescript-eslint@^8`. Chain breaks with `TypeError: Class extends value undefined` from `LegacyESLint`. Pin `eslint@^9` until `typescript-eslint@^9` with ESLint 10 support ships.
|
|
56
|
+
- Do NOT trust `vite-react`'s scaffolded `lint` script. It ships its own `"lint": "oxlint"` under a bare `.oxlintrc.json`, which runs a different rule set from the stack's ESLint config and never gates on it. `[scripts.override]` forces the stack's own eslint invocation back over it.
|
|
56
57
|
- Do NOT rely on bare-folder exclude globs like `exclude: ["e2e"]`. Use `"e2e/**/*"`.
|
|
57
58
|
- Do NOT ship Vitest with no-tests-fail. Fresh scaffolds have zero tests. Use `passWithNoTests: true` or equivalent until the project has at least one test.
|
|
58
59
|
- Do NOT put Playwright `trace` at the top level of `defineConfig`. It lives under `use`.
|