@erclx/canon 5.32.0 → 5.33.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/auto-ship/SKILL.md +1 -1
- package/claude/skills/auto-ship/references/worktree-name.md +1 -1
- package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
- package/claude/skills/backlog-triage/SKILL.md +1 -1
- package/claude/skills/canon-cli/REQUIREMENT.md +16 -13
- package/claude/skills/canon-cli/SKILL.md +75 -32
- package/claude/skills/canon-feedback/SKILL.md +1 -1
- package/claude/skills/{canvas → canvas-board}/REQUIREMENT.md +2 -2
- package/claude/skills/{canvas → canvas-board}/SKILL.md +2 -2
- package/{standards → claude/skills/canvas-board/references}/design.md +11 -2
- package/claude/skills/context-fold/REQUIREMENT.md +25 -33
- package/claude/skills/context-fold/SKILL.md +25 -70
- package/claude/skills/context-fold/references/classify.md +3 -3
- package/claude/skills/context-fold/references/completion-report.md +4 -4
- package/claude/skills/context-fold/references/context-refresh.md +5 -5
- package/{standards → claude/skills/context-fold/references}/context.md +16 -5
- package/claude/skills/context-fold/references/unusable-baseline.md +3 -5
- package/claude/skills/create-rule/SKILL.md +2 -2
- package/{standards → claude/skills/create-rule/references}/rule.md +12 -5
- package/claude/skills/create-skill/SKILL.md +2 -2
- package/{standards → claude/skills/create-skill/references}/skill.md +17 -14
- package/claude/skills/design-taste/REQUIREMENT.md +3 -3
- package/claude/skills/design-taste/SKILL.md +1 -1
- package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
- package/claude/skills/docs-sync/SKILL.md +3 -3
- package/{standards → claude/skills/docs-sync/references}/docs.md +11 -0
- package/{standards → claude/skills/docs-sync/references}/readme.md +9 -2
- package/claude/skills/draft-and-pick/SKILL.md +5 -5
- package/claude/skills/draft-doc/SKILL.md +6 -6
- package/claude/skills/draft-figure/REQUIREMENT.md +2 -2
- package/claude/skills/draft-figure/SKILL.md +2 -2
- package/claude/skills/draft-figure/references/hand-drawn.md +1 -1
- package/claude/skills/draft-figure/references/mermaid-path.md +1 -1
- package/claude/skills/draft-identity/REQUIREMENT.md +2 -2
- package/claude/skills/draft-identity/SKILL.md +2 -2
- package/claude/skills/draft-ready/SKILL.md +1 -1
- package/claude/skills/git-branch/SKILL.md +1 -1
- package/{standards → claude/skills/git-branch/references}/branch.md +1 -1
- package/claude/skills/git-commit/SKILL.md +2 -2
- package/claude/skills/git-followup/REQUIREMENT.md +1 -1
- package/claude/skills/git-followup/SKILL.md +1 -1
- package/claude/skills/git-issue/SKILL.md +1 -1
- package/claude/skills/git-pr/SKILL.md +13 -13
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +38 -14
- package/claude/skills/git-pr/references/labels.md +5 -1
- package/{standards → claude/skills/git-pr/references}/pr.md +19 -9
- package/{standards → claude/skills/git-pr/references}/publish.md +4 -2
- package/claude/skills/git-pr/references/task-number.md +1 -1
- package/claude/skills/git-ship/SKILL.md +15 -14
- package/claude/skills/git-split/SKILL.md +3 -3
- package/claude/skills/git-stage/SKILL.md +1 -1
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/SKILL.md +1 -1
- package/claude/skills/review-address/references/post-review-findings.md +1 -1
- package/claude/skills/review-pr/REQUIREMENT.md +1 -1
- package/claude/skills/review-pr/SKILL.md +3 -3
- package/claude/skills/review-pr/references/body-variants.md +2 -2
- package/claude/skills/review-pr/references/key-changes.md +3 -3
- package/claude/skills/review-pr/references/post.md +4 -2
- package/claude/skills/review-ui/REQUIREMENT.md +1 -1
- package/claude/skills/review-ui/SKILL.md +1 -1
- package/claude/skills/review-ui/references/post.md +1 -1
- package/claude/skills/role-orchestrator/REQUIREMENT.md +3 -0
- package/claude/skills/role-orchestrator/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +8 -5
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +23 -1
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-resume.md +3 -0
- package/claude/skills/role-planner/REQUIREMENT.md +2 -1
- package/claude/skills/role-planner/SKILL.md +13 -2
- package/claude/skills/role-reviewer/SKILL.md +1 -1
- package/claude/skills/role-worker/REQUIREMENT.md +1 -0
- package/claude/skills/role-worker/SKILL.md +9 -1
- package/claude/skills/session-map/SKILL.md +1 -1
- package/claude/skills/session-resume/REQUIREMENT.md +2 -2
- package/claude/skills/session-worktree/SKILL.md +5 -5
- package/claude/skills/target-setup/references/detect.md +1 -1
- package/claude/skills/task-board/REQUIREMENT.md +7 -12
- package/claude/skills/task-board/SKILL.md +5 -17
- package/claude/skills/task-board/references/tasks.md +2 -2
- package/claude/skills/task-complete/REQUIREMENT.md +47 -0
- package/claude/skills/task-complete/SKILL.md +86 -0
- package/claude/skills/{task-board → task-complete}/references/archive.md +4 -4
- package/claude/skills/{context-fold → task-complete}/references/receipt-sweep.md +5 -5
- package/claude/skills/task-complete/references/unusable-baseline.md +19 -0
- package/claude/skills/teach-workspace/REQUIREMENT.md +6 -2
- package/claude/skills/teach-workspace/SKILL.md +8 -4
- package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
- package/claude/skills/{context-fold/references/promoted-pages.md → teach-workspace/references/promotion-fold.md} +3 -3
- package/claude/skills/teach-workspace/references/promotion.md +3 -3
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/ux-audit/SKILL.md +1 -1
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/docs/agents/canvas.md +1 -1
- package/docs/agents/commands.md +3 -2
- package/docs/agents/context-audit-checks.md +4 -4
- package/docs/agents/index.md +3 -3
- package/docs/agents/indexes.md +1 -1
- package/docs/agents/install-and-sync.md +6 -11
- package/docs/agents/key-changes.md +5 -5
- package/docs/agents/label-coverage.md +11 -0
- package/docs/agents/migrate.md +1 -1
- package/docs/agents/records-push.md +2 -2
- package/docs/agents/records-stale.md +12 -47
- package/docs/agents/records-validate.md +3 -7
- package/docs/agents/records.md +5 -27
- package/docs/agents/rule-citations.md +1 -1
- package/docs/agents/sandbox.md +4 -4
- package/docs/agents/skills-audit.md +1 -1
- package/docs/agents/tasks-plans.md +2 -2
- package/docs/agents/tasks.md +2 -2
- package/docs/target/migrations.md +10 -2
- package/docs/target/projects.md +1 -1
- package/docs/target/sync.md +1 -1
- package/docs/workflow/operating-model.md +2 -2
- package/docs/workflow/parallel-features.md +7 -7
- package/docs/workflow/skill-map-on-request.md +9 -9
- package/docs/workflow/skill-map.md +12 -11
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/governance/renames.toml +0 -11
- package/governance/rules/canon/context.md +13 -0
- package/governance/rules/claude/skill.md +17 -0
- package/governance/stacks/base.toml +2 -4
- package/package.json +4 -4
- package/scripts/core/install-check.sh +3 -3
- package/scripts/lib/ui.sh +0 -159
- package/src/audits/catalog.ts +0 -1
- package/src/claude/cases/misc.ts +1 -1
- package/src/claude/cases/setup.ts +4 -0
- package/src/claude/cases/workflow.ts +6 -1
- package/src/claude/seeds.ts +1 -1
- package/src/claude/skills-audit.ts +2 -2
- package/src/cli/help.ts +3 -1
- package/src/cli/ui.ts +2 -3
- package/src/commands/claude.ts +1 -1
- package/src/commands/gov.ts +2 -15
- package/src/commands/labels.ts +326 -7
- package/src/commands/migrate.ts +6 -1
- package/src/commands/pr.ts +1 -1
- package/src/commands/records.ts +13 -399
- package/src/commands/sandbox.ts +3 -6
- package/src/commands/tasks.ts +3 -3
- package/src/context/audit.ts +5 -5
- package/src/context/folders.ts +1 -1
- package/src/design/budget.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/design/document.ts +1 -1
- package/src/design/regen.ts +1 -1
- package/src/design/render.ts +1 -1
- package/src/gate/measures.ts +1 -1
- package/src/gate/sequencer.ts +56 -1
- package/src/gate/stages.ts +1 -7
- package/src/gov/install.ts +2 -3
- package/src/gov/stacks.ts +1 -1
- package/src/hooks/post-merge.ts +1 -1
- package/src/labels/apply.ts +39 -0
- package/src/labels/format.ts +3 -3
- package/src/labels/phase.ts +3 -3
- package/src/labels/sections.ts +43 -0
- package/src/migrate/skill-names.ts +20 -1
- package/src/pr/paths.ts +4 -4
- package/src/records/backup.ts +16 -6
- package/src/records/stale-canonical.ts +31 -1
- package/src/records/validate.ts +2 -188
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/coverage.ts +2 -6
- package/src/sandbox/equivalence.ts +5 -44
- package/src/sandbox/expect.ts +4 -4
- package/src/sandbox/provision.ts +13 -36
- package/src/sandbox/scenario.ts +26 -48
- package/src/sandbox/tree.ts +2 -6
- package/src/standards/read.ts +14 -1
- package/src/sync/git.ts +1 -1
- package/src/tasks/archive.ts +5 -5
- package/src/tasks/branch.ts +3 -3
- package/src/tasks/label.ts +1 -1
- package/src/tasks/record.ts +2 -2
- package/src/tasks/validate.ts +1 -1
- package/standards/index.md +0 -13
- package/standards/standard.md +1 -7
- package/tooling/base/reference.md +1 -1
- package/tooling/base/seeds/.github/pull_request_template.md +2 -2
- package/tooling/claude/reference.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +9 -1
- package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +171 -0
- package/tooling/claude/seeds/.claude/settings.json +9 -0
- package/governance/rules/standards/context.md +0 -14
- package/governance/rules/standards/design.md +0 -12
- package/governance/rules/standards/readme.md +0 -12
- package/governance/rules/standards/rule.md +0 -13
- package/governance/rules/standards/skill.md +0 -21
- package/governance/rules/standards/standard.md +0 -13
- package/scripts/config.sh +0 -11
- package/scripts/lib/gov.sh +0 -14
- package/scripts/lib/sandbox-fixtures.sh +0 -191
- package/scripts/lib/sandbox-git.sh +0 -125
- package/scripts/lib/sandbox-path.sh +0 -50
- package/scripts/sandbox-hook.sh +0 -99
- package/src/gov/standard-rules.ts +0 -179
- package/src/records/migrate.ts +0 -78
- package/src/records/stale.ts +0 -243
- package/src/sandbox/hooks.ts +0 -128
- /package/claude/skills/{canvas → canvas-board}/references/canvas.md +0 -0
- /package/{standards → claude/skills/draft-figure/references}/figures.md +0 -0
- /package/{standards → claude/skills/git-branch/references}/slug.md +0 -0
- /package/{standards → claude/skills/git-commit/references}/commit.md +0 -0
- /package/{standards → claude/skills/git-commit/references}/versioning.md +0 -0
package/src/commands/records.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { readFile, writeFile } from 'node:fs/promises'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
1
|
import type { Command } from 'commander'
|
|
4
2
|
import { pullRecords, pushRecords } from '@/records/backup'
|
|
5
|
-
import { migrateRecord } from '@/records/migrate'
|
|
6
3
|
import {
|
|
7
4
|
type ClaimOutcome,
|
|
8
5
|
claimOrdinal,
|
|
@@ -24,12 +21,6 @@ import {
|
|
|
24
21
|
type SizeOutcome,
|
|
25
22
|
sizeRecords,
|
|
26
23
|
} from '@/records/size'
|
|
27
|
-
import {
|
|
28
|
-
DEFAULT_REVIEW_DAYS,
|
|
29
|
-
type StaleEntry,
|
|
30
|
-
type StaleReport,
|
|
31
|
-
staleMemory,
|
|
32
|
-
} from '@/records/stale'
|
|
33
24
|
import {
|
|
34
25
|
type CanonicalDoc,
|
|
35
26
|
type CanonicalReport,
|
|
@@ -37,12 +28,10 @@ import {
|
|
|
37
28
|
} from '@/records/stale-canonical'
|
|
38
29
|
import {
|
|
39
30
|
type Finding,
|
|
40
|
-
type FindingRemedy,
|
|
41
31
|
isRecordKind,
|
|
42
32
|
isSharedScratch,
|
|
43
33
|
RECORD_KINDS,
|
|
44
34
|
type RecordKind,
|
|
45
|
-
recordsDir,
|
|
46
35
|
type ValidateOutcome,
|
|
47
36
|
validateRecords,
|
|
48
37
|
} from '@/records/validate'
|
|
@@ -62,9 +51,6 @@ import { readLivePlans, stackFindings } from '@/tasks/stack'
|
|
|
62
51
|
/** Returned when a record carries a finding, which is the gating result. */
|
|
63
52
|
const EXIT_FINDINGS = 2
|
|
64
53
|
|
|
65
|
-
/** Returned when a record carries a known transform and `--write` was not passed. */
|
|
66
|
-
const EXIT_MIGRATABLE = 2
|
|
67
|
-
|
|
68
54
|
/** Returned when `--claim` loses every retry to a collision. */
|
|
69
55
|
const EXIT_CONTENDED = 2
|
|
70
56
|
|
|
@@ -78,24 +64,15 @@ interface ValidateCommandOptions {
|
|
|
78
64
|
|
|
79
65
|
type BackupCommandOptions = ValidateCommandOptions
|
|
80
66
|
|
|
81
|
-
interface MigrateCommandOptions extends ValidateCommandOptions {
|
|
82
|
-
readonly write?: boolean
|
|
83
|
-
}
|
|
84
|
-
|
|
85
67
|
interface PruneCommandOptions extends ValidateCommandOptions {
|
|
86
68
|
readonly write?: boolean
|
|
87
69
|
readonly olderThan?: string
|
|
88
70
|
}
|
|
89
71
|
|
|
90
|
-
|
|
91
|
-
readonly days?: string
|
|
92
|
-
}
|
|
72
|
+
type StaleCommandOptions = ValidateCommandOptions
|
|
93
73
|
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
* a canonical doc ages by the releases shipped since its review.
|
|
97
|
-
*/
|
|
98
|
-
const STALE_KINDS = ['memory', 'canonical'] as const
|
|
74
|
+
/** The kinds `stale` reads. A canonical doc ages by the releases shipped since its review. */
|
|
75
|
+
const STALE_KINDS = ['canonical'] as const
|
|
99
76
|
|
|
100
77
|
interface OrdinalCommandOptions extends ValidateCommandOptions {
|
|
101
78
|
readonly claim?: boolean
|
|
@@ -127,7 +104,6 @@ export function register(program: Command): void {
|
|
|
127
104
|
' plans filename, required sections, and the suggested-and-answer contract',
|
|
128
105
|
' groundwork README and current-state files, numbering, dating, and a half-closed track',
|
|
129
106
|
' intake overview file, numbering, dating, and the four bullets every item carries',
|
|
130
|
-
' memory filename and type prefix, frontmatter, and the body shape each type carries',
|
|
131
107
|
' standards frontmatter, the scope section and its handoff list, and a filename',
|
|
132
108
|
' derived from the governed path',
|
|
133
109
|
'',
|
|
@@ -142,7 +118,6 @@ export function register(program: Command): void {
|
|
|
142
118
|
'',
|
|
143
119
|
'Examples:',
|
|
144
120
|
' canon records validate plans',
|
|
145
|
-
' canon records validate memory',
|
|
146
121
|
' canon records validate standards',
|
|
147
122
|
' canon records validate intake --json',
|
|
148
123
|
'',
|
|
@@ -152,44 +127,6 @@ export function register(program: Command): void {
|
|
|
152
127
|
process.exitCode = await runValidate(kind, opts)
|
|
153
128
|
})
|
|
154
129
|
|
|
155
|
-
records
|
|
156
|
-
.command('migrate')
|
|
157
|
-
.description('Rewrite the records a validate finding names a transform for')
|
|
158
|
-
.argument('<kind>', `Record folder: ${RECORD_KINDS.join(', ')}`)
|
|
159
|
-
.helpOption('-h, --help', 'Show this help message')
|
|
160
|
-
.option('--json', 'Add a machine-readable record on stdout')
|
|
161
|
-
.option('--write', 'Rewrite every record a transform can repair')
|
|
162
|
-
.option(
|
|
163
|
-
'--root <path>',
|
|
164
|
-
'Project root, defaulting to the main worktree except on standards',
|
|
165
|
-
)
|
|
166
|
-
.addHelpText(
|
|
167
|
-
'after',
|
|
168
|
-
[
|
|
169
|
-
'',
|
|
170
|
-
'Exit codes:',
|
|
171
|
-
' 0 nothing carries a known transform, or --write repaired every one',
|
|
172
|
-
' 1 refused, with the reason on stderr or in the JSON record, every',
|
|
173
|
-
' candidate it found failed to repair, or --write repaired only',
|
|
174
|
-
' some of them',
|
|
175
|
-
' 2 a record carries a known transform and --write was not passed',
|
|
176
|
-
'',
|
|
177
|
-
'It reports and never writes without --write, matching canon records',
|
|
178
|
-
'validate: a session record has no history to undo a wrong repair from.',
|
|
179
|
-
'A transform is only offered where the old value is recoverable from the',
|
|
180
|
-
'file itself, so a finding with no transform is left for a session to fix.',
|
|
181
|
-
'',
|
|
182
|
-
'Examples:',
|
|
183
|
-
' canon records migrate memory',
|
|
184
|
-
' canon records migrate memory --write',
|
|
185
|
-
' canon records migrate memory --json',
|
|
186
|
-
'',
|
|
187
|
-
].join('\n'),
|
|
188
|
-
)
|
|
189
|
-
.action(async (kind: string, opts: MigrateCommandOptions) => {
|
|
190
|
-
process.exitCode = await runMigrate(kind, opts)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
130
|
records
|
|
194
131
|
.command('ordinal')
|
|
195
132
|
.description(
|
|
@@ -272,51 +209,30 @@ export function register(program: Command): void {
|
|
|
272
209
|
records
|
|
273
210
|
.command('stale')
|
|
274
211
|
.description(
|
|
275
|
-
'Report
|
|
212
|
+
'Report when the requirements record was last reviewed and how many releases have shipped since',
|
|
276
213
|
)
|
|
277
214
|
.argument('<kind>', `Record folder: ${STALE_KINDS.join(', ')}`)
|
|
278
215
|
.helpOption('-h, --help', 'Show this help message')
|
|
279
216
|
.option('--json', 'Add a machine-readable record on stdout')
|
|
280
|
-
.option(
|
|
281
|
-
'--days <n>',
|
|
282
|
-
`Days after a review before a memory entry is due again (default ${DEFAULT_REVIEW_DAYS})`,
|
|
283
|
-
)
|
|
284
|
-
.option(
|
|
285
|
-
'--root <path>',
|
|
286
|
-
'Project root, defaulting to the main worktree except on canonical',
|
|
287
|
-
)
|
|
217
|
+
.option('--root <path>', 'Project root, defaulting to the current worktree')
|
|
288
218
|
.addHelpText(
|
|
289
219
|
'after',
|
|
290
220
|
[
|
|
291
|
-
'',
|
|
292
|
-
'memory: reads the top-level entries of the memory folder, never review/, archive/,',
|
|
293
|
-
'or index.md. An entry is due when it carries no reviewed date, a reviewed',
|
|
294
|
-
'value that is not a date, or one older than --days. A path is a backticked',
|
|
295
|
-
'token holding a / and a file extension, resolved against the project root',
|
|
296
|
-
'after any :line or #heading anchor is stripped. Tokens under .canon/,',
|
|
297
|
-
'scratch, or worktrees, and any holding a placeholder, glob, variable, or',
|
|
298
|
-
'elided ... segment, are never reported.',
|
|
299
|
-
'',
|
|
300
|
-
'Entries are ordered due first, then those citing a missing path, then the',
|
|
301
|
-
'longest unreviewed, then by name, so a review takes the first N as a batch.',
|
|
302
221
|
'',
|
|
303
222
|
'canonical: reads REQUIREMENTS.md at whichever surface root carries it,',
|
|
304
223
|
'in the current worktree since it is tracked. It reports its reviewed date',
|
|
305
224
|
'and the release tags merged into HEAD after that day, or never when it',
|
|
306
|
-
'carries no date.
|
|
225
|
+
'carries no date.',
|
|
307
226
|
'',
|
|
308
227
|
'Exit codes:',
|
|
309
228
|
' 0 the reading completed, whatever it found',
|
|
310
229
|
' 1 refused, with the reason on stderr or in the JSON record',
|
|
311
230
|
'',
|
|
312
|
-
'It gates nothing and writes nothing. A
|
|
313
|
-
'
|
|
314
|
-
'review to judge.',
|
|
231
|
+
'It gates nothing and writes nothing. A release count is a prompt for the',
|
|
232
|
+
'review to judge rather than a failure.',
|
|
315
233
|
'',
|
|
316
234
|
'Examples:',
|
|
317
|
-
' canon records stale
|
|
318
|
-
' canon records stale memory --json',
|
|
319
|
-
' canon records stale memory --days 60 --json',
|
|
235
|
+
' canon records stale canonical',
|
|
320
236
|
' canon records stale canonical --json',
|
|
321
237
|
'',
|
|
322
238
|
].join('\n'),
|
|
@@ -357,8 +273,8 @@ export function register(program: Command): void {
|
|
|
357
273
|
' delete failed',
|
|
358
274
|
' 2 candidates exist and --write was not passed',
|
|
359
275
|
'',
|
|
360
|
-
'It writes nothing until --write is passed,
|
|
361
|
-
'
|
|
276
|
+
'It writes nothing until --write is passed, since a session record has',
|
|
277
|
+
'no history to undo a wrong delete from.',
|
|
362
278
|
'It reads mtime like canon records size, so a machine restored by canon',
|
|
363
279
|
'records pull reads everything as new, which fails safe by offering',
|
|
364
280
|
'nothing.',
|
|
@@ -579,34 +495,7 @@ async function runStale(
|
|
|
579
495
|
)
|
|
580
496
|
}
|
|
581
497
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
const days = Number(opts.days ?? DEFAULT_REVIEW_DAYS)
|
|
585
|
-
|
|
586
|
-
if (!Number.isInteger(days) || days <= 0) {
|
|
587
|
-
return reportRefusal(
|
|
588
|
-
'canon records stale',
|
|
589
|
-
{
|
|
590
|
-
reason: 'bad-days',
|
|
591
|
-
message: `--days must be a positive whole number of days, got ${opts.days}.`,
|
|
592
|
-
},
|
|
593
|
-
emitJson,
|
|
594
|
-
)
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
const root = opts.root ?? (await mainWorktreeRoot())
|
|
598
|
-
const outcome = await staleMemory(root, days)
|
|
599
|
-
|
|
600
|
-
if (!outcome.ok)
|
|
601
|
-
return reportRefusal('canon records stale', outcome, emitJson)
|
|
602
|
-
|
|
603
|
-
if (emitJson) {
|
|
604
|
-
process.stdout.write(`${JSON.stringify(outcome)}\n`)
|
|
605
|
-
return 0
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
reportStale(outcome)
|
|
609
|
-
return 0
|
|
498
|
+
return runStaleCanonical(opts, emitJson)
|
|
610
499
|
}
|
|
611
500
|
|
|
612
501
|
/**
|
|
@@ -618,18 +507,6 @@ async function runStaleCanonical(
|
|
|
618
507
|
opts: StaleCommandOptions,
|
|
619
508
|
emitJson: boolean,
|
|
620
509
|
): Promise<number> {
|
|
621
|
-
if (opts.days !== undefined) {
|
|
622
|
-
return reportRefusal(
|
|
623
|
-
'canon records stale',
|
|
624
|
-
{
|
|
625
|
-
reason: 'bad-days',
|
|
626
|
-
message:
|
|
627
|
-
'--days does not apply to canonical, which counts releases rather than days.',
|
|
628
|
-
},
|
|
629
|
-
emitJson,
|
|
630
|
-
)
|
|
631
|
-
}
|
|
632
|
-
|
|
633
510
|
const root = opts.root ?? (await currentWorktreeRoot())
|
|
634
511
|
const outcome = await staleCanonical(root)
|
|
635
512
|
|
|
@@ -671,48 +548,6 @@ function describeCanonical(
|
|
|
671
548
|
return `${doc.path}: reviewed ${doc.reviewed}, ${since}`
|
|
672
549
|
}
|
|
673
550
|
|
|
674
|
-
function staleRow(entry: StaleEntry): string[] {
|
|
675
|
-
return [
|
|
676
|
-
entry.name,
|
|
677
|
-
entry.reviewed ?? (entry.invalidReviewed ? 'invalid' : 'never'),
|
|
678
|
-
entry.unresolved.join(', '),
|
|
679
|
-
]
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
function reportStale(outcome: StaleReport): void {
|
|
683
|
-
const due = outcome.entries.filter((entry) => entry.due)
|
|
684
|
-
const moved = outcome.entries.filter((entry) => entry.unresolved.length > 0)
|
|
685
|
-
|
|
686
|
-
intro('canon records stale')
|
|
687
|
-
logStep('Due')
|
|
688
|
-
|
|
689
|
-
if (due.length === 0) {
|
|
690
|
-
logInfo(`none, every entry reviewed within ${plural(outcome.days, 'day')}`)
|
|
691
|
-
} else {
|
|
692
|
-
const headers = ['entry', 'reviewed', 'unresolved']
|
|
693
|
-
const rows = due.map(staleRow)
|
|
694
|
-
const widths = headers.map((header, column) =>
|
|
695
|
-
columnWidth(
|
|
696
|
-
header,
|
|
697
|
-
rows.map((row) => row[column]),
|
|
698
|
-
),
|
|
699
|
-
)
|
|
700
|
-
const render = (cells: readonly string[]): string =>
|
|
701
|
-
cells
|
|
702
|
-
.map((cell, column) => cell.padEnd(widths[column]))
|
|
703
|
-
.join(' ')
|
|
704
|
-
.trimEnd()
|
|
705
|
-
|
|
706
|
-
pipeOutput([render(headers), ...rows.map(render)].join('\n'))
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
logStep('Total')
|
|
710
|
-
logInfo(
|
|
711
|
-
`${outcome.due} of ${outcome.total} due, ${moved.length} citing a missing path, in ${outcome.folder}`,
|
|
712
|
-
)
|
|
713
|
-
outro()
|
|
714
|
-
}
|
|
715
|
-
|
|
716
551
|
function pruneRow(entry: PruneUnit): string[] {
|
|
717
552
|
return [
|
|
718
553
|
entry.path,
|
|
@@ -917,8 +752,7 @@ async function runValidate(
|
|
|
917
752
|
|
|
918
753
|
/**
|
|
919
754
|
* Appends the one plans finding that reads across files. It sits in the command
|
|
920
|
-
* layer because `src/records/` sits below `src/tasks
|
|
921
|
-
* `validateRecords` alone, so it never meets a finding with no safe repair.
|
|
755
|
+
* layer because `src/records/` sits below `src/tasks/`.
|
|
922
756
|
*/
|
|
923
757
|
async function validateWithStacks(
|
|
924
758
|
root: string,
|
|
@@ -992,226 +826,6 @@ function describe(found: Finding): string {
|
|
|
992
826
|
return `${scope}${found.subject} ${found.message}`
|
|
993
827
|
}
|
|
994
828
|
|
|
995
|
-
export interface Repair {
|
|
996
|
-
readonly record: string
|
|
997
|
-
readonly remedy: FindingRemedy
|
|
998
|
-
readonly path: string
|
|
999
|
-
readonly text: string
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
export interface Refusal {
|
|
1003
|
-
readonly record: string
|
|
1004
|
-
readonly message: string
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
/** The message a rejected promise leaves, for a record whose read or write failed. */
|
|
1008
|
-
function describeFailure(reason: unknown): string {
|
|
1009
|
-
return reason instanceof Error ? reason.message : String(reason)
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
/**
|
|
1013
|
-
* Runs every finding's transform, without writing anything back.
|
|
1014
|
-
*
|
|
1015
|
-
* `Promise.allSettled` rather than `Promise.all`, so a record whose read
|
|
1016
|
-
* fails, such as one deleted between `validate`'s listing and this read,
|
|
1017
|
-
* becomes a refusal for that one record rather than an unhandled rejection
|
|
1018
|
-
* that `program.parse()` has no top-level catch for.
|
|
1019
|
-
*/
|
|
1020
|
-
async function attemptMigrations(
|
|
1021
|
-
dir: string,
|
|
1022
|
-
findings: readonly Finding[],
|
|
1023
|
-
): Promise<{ repaired: Repair[]; refused: Refusal[] }> {
|
|
1024
|
-
const candidates = findings.filter(
|
|
1025
|
-
(found): found is Finding & { readonly remedy: FindingRemedy } =>
|
|
1026
|
-
found.remedy !== undefined,
|
|
1027
|
-
)
|
|
1028
|
-
|
|
1029
|
-
const settled = await Promise.allSettled(
|
|
1030
|
-
candidates.map(async (found) => {
|
|
1031
|
-
const path = join(dir, found.record)
|
|
1032
|
-
const outcome = migrateRecord(
|
|
1033
|
-
found.remedy,
|
|
1034
|
-
found.record,
|
|
1035
|
-
await readFile(path, 'utf8'),
|
|
1036
|
-
)
|
|
1037
|
-
return { record: found.record, remedy: found.remedy, path, outcome }
|
|
1038
|
-
}),
|
|
1039
|
-
)
|
|
1040
|
-
|
|
1041
|
-
const repaired: Repair[] = []
|
|
1042
|
-
const refused: Refusal[] = []
|
|
1043
|
-
|
|
1044
|
-
settled.forEach((result, index) => {
|
|
1045
|
-
if (result.status === 'rejected') {
|
|
1046
|
-
refused.push({
|
|
1047
|
-
record: candidates[index].record,
|
|
1048
|
-
message: `could not be read: ${describeFailure(result.reason)}`,
|
|
1049
|
-
})
|
|
1050
|
-
return
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
const { record, remedy, path, outcome } = result.value
|
|
1054
|
-
|
|
1055
|
-
if (outcome.ok) {
|
|
1056
|
-
repaired.push({ record, remedy, path, text: outcome.text })
|
|
1057
|
-
} else {
|
|
1058
|
-
refused.push({ record, message: outcome.message })
|
|
1059
|
-
}
|
|
1060
|
-
})
|
|
1061
|
-
|
|
1062
|
-
return { repaired, refused }
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
/**
|
|
1066
|
-
* Writes every repair, independently. `Promise.allSettled` so one record's
|
|
1067
|
-
* write failing does not abort the writes that would otherwise have
|
|
1068
|
-
* succeeded, per the concurrency standard's rule on batched partial failure.
|
|
1069
|
-
*/
|
|
1070
|
-
async function writeRepairs(
|
|
1071
|
-
repaired: readonly Repair[],
|
|
1072
|
-
): Promise<{ written: Repair[]; failed: Refusal[] }> {
|
|
1073
|
-
const settled = await Promise.allSettled(
|
|
1074
|
-
repaired.map((entry) => writeFile(entry.path, entry.text, 'utf8')),
|
|
1075
|
-
)
|
|
1076
|
-
|
|
1077
|
-
const written: Repair[] = []
|
|
1078
|
-
const failed: Refusal[] = []
|
|
1079
|
-
|
|
1080
|
-
settled.forEach((result, index) => {
|
|
1081
|
-
const entry = repaired[index]
|
|
1082
|
-
|
|
1083
|
-
if (result.status === 'fulfilled') {
|
|
1084
|
-
written.push(entry)
|
|
1085
|
-
} else {
|
|
1086
|
-
failed.push({
|
|
1087
|
-
record: entry.record,
|
|
1088
|
-
message: `could not be written: ${describeFailure(result.reason)}`,
|
|
1089
|
-
})
|
|
1090
|
-
}
|
|
1091
|
-
})
|
|
1092
|
-
|
|
1093
|
-
return { written, failed }
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
async function runMigrate(
|
|
1097
|
-
kind: string,
|
|
1098
|
-
opts: MigrateCommandOptions,
|
|
1099
|
-
): Promise<number> {
|
|
1100
|
-
const emitJson = opts.json ?? false
|
|
1101
|
-
|
|
1102
|
-
if (!isRecordKind(kind)) {
|
|
1103
|
-
return reportRefusal(
|
|
1104
|
-
'canon records migrate',
|
|
1105
|
-
{
|
|
1106
|
-
reason: 'unknown-kind',
|
|
1107
|
-
message: `Not a record kind: ${kind}. Expected one of: ${RECORD_KINDS.join(', ')}.`,
|
|
1108
|
-
},
|
|
1109
|
-
emitJson,
|
|
1110
|
-
)
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
const root = opts.root ?? (await defaultRoot(kind))
|
|
1114
|
-
const outcome = await validateRecords(root, kind)
|
|
1115
|
-
|
|
1116
|
-
if (!outcome.ok) {
|
|
1117
|
-
return reportRefusal('canon records migrate', outcome, emitJson)
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
const write = opts.write ?? false
|
|
1121
|
-
const { repaired, refused } = await attemptMigrations(
|
|
1122
|
-
recordsDir(root, kind),
|
|
1123
|
-
outcome.findings,
|
|
1124
|
-
)
|
|
1125
|
-
|
|
1126
|
-
if (!write) {
|
|
1127
|
-
return reportMigrate(root, outcome.kind, repaired, refused, write, emitJson)
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
const { written, failed } = await writeRepairs(repaired)
|
|
1131
|
-
|
|
1132
|
-
return reportMigrate(
|
|
1133
|
-
root,
|
|
1134
|
-
outcome.kind,
|
|
1135
|
-
written,
|
|
1136
|
-
[...refused, ...failed],
|
|
1137
|
-
write,
|
|
1138
|
-
emitJson,
|
|
1139
|
-
)
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
function reportMigrate(
|
|
1143
|
-
root: string,
|
|
1144
|
-
kind: RecordKind,
|
|
1145
|
-
repaired: readonly Repair[],
|
|
1146
|
-
refused: readonly Refusal[],
|
|
1147
|
-
write: boolean,
|
|
1148
|
-
emitJson: boolean,
|
|
1149
|
-
): number {
|
|
1150
|
-
const total = repaired.length + refused.length
|
|
1151
|
-
|
|
1152
|
-
if (emitJson) {
|
|
1153
|
-
process.stdout.write(
|
|
1154
|
-
`${JSON.stringify({
|
|
1155
|
-
ok: true,
|
|
1156
|
-
root,
|
|
1157
|
-
kind,
|
|
1158
|
-
written: write,
|
|
1159
|
-
migrated: repaired.map((entry) => entry.record),
|
|
1160
|
-
refused,
|
|
1161
|
-
})}\n`,
|
|
1162
|
-
)
|
|
1163
|
-
} else {
|
|
1164
|
-
intro('canon records migrate')
|
|
1165
|
-
|
|
1166
|
-
if (total === 0) {
|
|
1167
|
-
logStep('Clean')
|
|
1168
|
-
logInfo('no finding carries a known transform')
|
|
1169
|
-
} else {
|
|
1170
|
-
logStep(write ? 'Rewritten' : 'Would rewrite')
|
|
1171
|
-
if (repaired.length === 0) {
|
|
1172
|
-
logInfo('none, every candidate refused, see below')
|
|
1173
|
-
} else {
|
|
1174
|
-
for (const entry of repaired)
|
|
1175
|
-
logInfo(`${entry.record}: ${entry.remedy}`)
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
if (refused.length > 0) {
|
|
1179
|
-
logStep('Refused')
|
|
1180
|
-
for (const entry of refused)
|
|
1181
|
-
logWarn(`${entry.record}: ${entry.message}`)
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
if (!write && repaired.length > 0) {
|
|
1185
|
-
logInfo('Re-run with --write to apply.')
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
outro()
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
return migrateExitCode(repaired, refused, write)
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
/**
|
|
1196
|
-
* `repaired` carries only records a transform actually fixed, whether this
|
|
1197
|
-
* is a dry run or the set `--write` wrote, so exit 2 (a write is available)
|
|
1198
|
-
* never fires when every candidate refused. A dry run reaching that state
|
|
1199
|
-
* previously returned the same code as a genuine offer to write, telling a
|
|
1200
|
-
* caller `--write` would repair something when it would repair nothing.
|
|
1201
|
-
*/
|
|
1202
|
-
export function migrateExitCode(
|
|
1203
|
-
repaired: readonly Repair[],
|
|
1204
|
-
refused: readonly Refusal[],
|
|
1205
|
-
write: boolean,
|
|
1206
|
-
): number {
|
|
1207
|
-
const total = repaired.length + refused.length
|
|
1208
|
-
|
|
1209
|
-
if (total === 0) return 0
|
|
1210
|
-
if (repaired.length === 0) return 1
|
|
1211
|
-
if (!write) return EXIT_MIGRATABLE
|
|
1212
|
-
return refused.length > 0 ? 1 : 0
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
829
|
async function runOrdinal(
|
|
1216
830
|
kind: string,
|
|
1217
831
|
slug: string,
|
package/src/commands/sandbox.ts
CHANGED
|
@@ -126,13 +126,10 @@ function getCategories(): string[] {
|
|
|
126
126
|
return listCategories(SANDBOX_DIR)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
/** Lists a stem in both forms too, so picking it reaches the refusal that names it. */
|
|
130
129
|
function getCommands(category: string): string[] {
|
|
131
|
-
const { scenarios
|
|
132
|
-
join(SANDBOX_DIR, category),
|
|
133
|
-
)
|
|
130
|
+
const { scenarios } = listScenarioFiles(join(SANDBOX_DIR, category))
|
|
134
131
|
|
|
135
|
-
return
|
|
132
|
+
return scenarios.map((s) => s.command)
|
|
136
133
|
}
|
|
137
134
|
|
|
138
135
|
async function interactivePicker(): Promise<string> {
|
|
@@ -188,7 +185,7 @@ function readEnvelope(path: string | undefined): RunEnvelope | undefined {
|
|
|
188
185
|
|
|
189
186
|
/**
|
|
190
187
|
* Shared by `--writes` and `--escapes`, which are both a newline-delimited
|
|
191
|
-
* path list written by `run
|
|
188
|
+
* path list written by `canon sandbox run`. Undefined when no file was given, which is
|
|
192
189
|
* not the same as a run that produced no paths. Write scope and escape scope
|
|
193
190
|
* both need that distinction: an empty list is a finding, an absent list is a
|
|
194
191
|
* gap in what the caller supplied.
|
package/src/commands/tasks.ts
CHANGED
|
@@ -347,7 +347,7 @@ export function register(program: Command): void {
|
|
|
347
347
|
[
|
|
348
348
|
'',
|
|
349
349
|
'Exit codes:',
|
|
350
|
-
' 0 the branch is derived and conforms to
|
|
350
|
+
' 0 the branch is derived and conforms to claude/skills/git-branch/references/branch.md',
|
|
351
351
|
' 1 refused as no-plan, archived, or bad-input',
|
|
352
352
|
' 2 derived, and conforms is false because the slug breaks a cap',
|
|
353
353
|
'',
|
|
@@ -566,7 +566,7 @@ export function register(program: Command): void {
|
|
|
566
566
|
'same second can take the same answer. --claim reserves the label',
|
|
567
567
|
'under .canon/ordinal-locks/ and counts every reservation in the',
|
|
568
568
|
'scan, so two claims return different labels. A dead claim leaves a',
|
|
569
|
-
'gap, which
|
|
569
|
+
'gap, which claude/skills/git-commit/references/versioning.md permits.',
|
|
570
570
|
'',
|
|
571
571
|
'Examples:',
|
|
572
572
|
' canon tasks next-label',
|
|
@@ -1245,7 +1245,7 @@ function reportBranch(
|
|
|
1245
1245
|
`derived from ${outcome.plan}, ${outcome.words} words and ${outcome.branch.length} characters.`,
|
|
1246
1246
|
)
|
|
1247
1247
|
logError(
|
|
1248
|
-
'The slug breaks a cap in
|
|
1248
|
+
'The slug breaks a cap in claude/skills/git-branch/references/branch.md, so hand the row to a person rather than renaming it.',
|
|
1249
1249
|
)
|
|
1250
1250
|
outro()
|
|
1251
1251
|
|
package/src/context/audit.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { isStubSeed } from '@/tooling/seed-marker'
|
|
|
10
10
|
* Checkpoint quoted from the standard stating it. It is not a cap.
|
|
11
11
|
*
|
|
12
12
|
* Entry length rests on one entry per domain, which is a domain fact, so
|
|
13
|
-
* `
|
|
13
|
+
* `claude/skills/context-fold/references/context.md` keeps it. Depth and bullet weight read the same over
|
|
14
14
|
* any markdown file, so they are stated at the attribute tier and measured by
|
|
15
15
|
* `canon markdown audit` rather than here.
|
|
16
16
|
*/
|
|
@@ -111,7 +111,7 @@ const PROVENANCE: readonly { kind: ProvenanceKind; pattern: RegExp }[] = [
|
|
|
111
111
|
/**
|
|
112
112
|
* Verbs that read the date behind them as stamping a measurement.
|
|
113
113
|
*
|
|
114
|
-
* `
|
|
114
|
+
* `claude/skills/context-fold/references/context.md` cuts a date attached to a change and permits one
|
|
115
115
|
* stamping a measurement, so a pattern matching every ISO date reports against
|
|
116
116
|
* a rule that admits half of what it finds. Separating the two needs the clause
|
|
117
117
|
* rather than the token, since `measured on 2026-08-19` and `overturned on
|
|
@@ -154,7 +154,7 @@ const SENTENCE_END = /[.!?:;]\s(?=[^.!?:;]*$)/
|
|
|
154
154
|
* JSON record publishes as `checkpoints.provenanceFolder` breaks every consumer
|
|
155
155
|
* reading that field for a gain of one word.
|
|
156
156
|
*
|
|
157
|
-
* `
|
|
157
|
+
* `claude/skills/context-fold/references/context.md` opens its scope by handing figures to the
|
|
158
158
|
* `draft-figure` skill, so a marker reported in a diagrams entry would cite a
|
|
159
159
|
* rule that entry's own standard routes elsewhere. The length and table
|
|
160
160
|
* checkpoints are quoted from the same standard and keep reaching every audited
|
|
@@ -164,7 +164,7 @@ const SENTENCE_END = /[.!?:;]\s(?=[^.!?:;]*$)/
|
|
|
164
164
|
* What gates here is a rule only this standard states. Bullet weight does not,
|
|
165
165
|
* since `claude/skills/markdown-craft/references/markdown.md` owns that checkpoint across document types and
|
|
166
166
|
* its remedy sends the overflow to prose, which any entry type can act on.
|
|
167
|
-
* `
|
|
167
|
+
* `claude/skills/context-fold/references/context.md` specializes that remedy for an entry carrying
|
|
168
168
|
* decisions, and specializing a rule narrows the advice rather than the measure.
|
|
169
169
|
*
|
|
170
170
|
* Restating the exclusion in the sibling standards was the alternative for what
|
|
@@ -241,7 +241,7 @@ export interface EntryReport {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
/**
|
|
244
|
-
* The three questions `
|
|
244
|
+
* The three questions `claude/skills/context-fold/references/context.md` asks of an entry past the
|
|
245
245
|
* checkpoint, in the order it states them.
|
|
246
246
|
*
|
|
247
247
|
* The standard calls no entry over the checkpoint wrong. It asks whether the
|
package/src/context/folders.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { SURFACE_ROOTS } from '@/roots/surface'
|
|
|
10
10
|
* A named list rather than the index-plus-entry contract read off disk, so a
|
|
11
11
|
* generated tree satisfying that contract is never measured against a rule
|
|
12
12
|
* written for per-domain narrative. This list names the folders
|
|
13
|
-
* `
|
|
13
|
+
* `claude/skills/context-fold/references/context.md` governs, and `--folder` admits another without an edit
|
|
14
14
|
* here.
|
|
15
15
|
*
|
|
16
16
|
* It doubles as the citation check's scope, since `citationPattern` spells only
|
package/src/design/budget.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The prose budget `
|
|
2
|
+
* The prose budget `claude/skills/canvas-board/references/design.md` sets for a design record, and the
|
|
3
3
|
* counter the `design` gate stage reads it through.
|
|
4
4
|
*
|
|
5
5
|
* The limits live here and in the standard, never in the stage, so the stage
|
package/src/design/components.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* `buildDesignCss`'s `components` option, which is what widening that option
|
|
16
16
|
* from a boolean to `boolean | readonly Component[]` bought.
|
|
17
17
|
*
|
|
18
|
-
* It does not live in `canon/DESIGN.md`. `
|
|
18
|
+
* It does not live in `canon/DESIGN.md`. `claude/skills/canvas-board/references/design.md` keeps CSS class
|
|
19
19
|
* names out of that record and says they live in code, which is here.
|
|
20
20
|
*/
|
|
21
21
|
|
package/src/design/document.ts
CHANGED
|
@@ -94,7 +94,7 @@ function borderRows(tokens: readonly BorderToken[]): string[][] {
|
|
|
94
94
|
* and every reason behind them lives in the entry.
|
|
95
95
|
*/
|
|
96
96
|
const LEAD = [
|
|
97
|
-
'Authoring guidance: `
|
|
97
|
+
'Authoring guidance: `claude/skills/canvas-board/references/design.md`. Rendered from `src/design/tokens.ts` by `canon design regen`, so edit the module and never this file.',
|
|
98
98
|
'Why each value was chosen lives in `canon/context/design/tokens.md`.',
|
|
99
99
|
].join(' ')
|
|
100
100
|
|
package/src/design/regen.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { NEUTRAL_TOKENS } from '@/design/neutral'
|
|
|
16
16
|
* gate stage is what keeps silently out of it.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
/** The rendered record, at the path `
|
|
19
|
+
/** The rendered record, at the path `claude/skills/canvas-board/references/design.md` fixes for it. */
|
|
20
20
|
export const DESIGN_DOCUMENT = join('canon', 'DESIGN.md')
|
|
21
21
|
|
|
22
22
|
/**
|