@erclx/canon 5.52.0 → 5.54.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.
Files changed (201) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +11 -13
  3. package/claude/.claude-plugin/plugin.json +1 -1
  4. package/claude/skills/canon-cli/SKILL.md +5 -8
  5. package/claude/skills/context-fold/REQUIREMENT.md +0 -1
  6. package/claude/skills/design-identity/REQUIREMENT.md +2 -2
  7. package/claude/skills/design-identity/SKILL.md +6 -6
  8. package/claude/skills/design-record/REQUIREMENT.md +2 -2
  9. package/claude/skills/design-record/SKILL.md +4 -4
  10. package/claude/skills/design-record/references/folder.md +1 -1
  11. package/claude/skills/design-taste/REQUIREMENT.md +1 -1
  12. package/claude/skills/design-taste/references/kinds.md +0 -1
  13. package/claude/skills/draw-figure/REQUIREMENT.md +3 -4
  14. package/claude/skills/draw-figure/SKILL.md +5 -6
  15. package/claude/skills/draw-figure/references/figures.md +0 -1
  16. package/claude/skills/draw-figure/references/hand-drawn.md +1 -1
  17. package/claude/skills/pick-by-eye/REQUIREMENT.md +4 -5
  18. package/claude/skills/pick-by-eye/SKILL.md +34 -41
  19. package/claude/skills/pick-by-eye/references/board.md +42 -0
  20. package/claude/skills/pick-by-eye/references/live-arms.md +3 -3
  21. package/claude/skills/plan-groundwork/SKILL.md +1 -1
  22. package/claude/skills/teach-craft/REQUIREMENT.md +30 -0
  23. package/claude/skills/teach-craft/SKILL.md +70 -0
  24. package/claude/skills/teach-craft/references/adopted.md +113 -0
  25. package/claude/skills/teach-craft/references/lesson-craft.md +60 -0
  26. package/claude/skills/{teach-workspace → teach-craft}/references/pedagogy.md +41 -6
  27. package/docs/agents/audits.md +0 -1
  28. package/docs/agents/install-and-sync.md +0 -8
  29. package/docs/target/migrations.md +16 -2
  30. package/docs/target/projects.md +1 -1
  31. package/docs/workflow/parallel-features.md +1 -1
  32. package/docs/workflow/skill-map-on-request.md +10 -22
  33. package/docs/workflow/skill-map.md +11 -14
  34. package/docs/workflow/visual-design-workflow.md +1 -4
  35. package/governance/detect.toml +1 -6
  36. package/governance/renames.toml +0 -1
  37. package/package.json +2 -8
  38. package/scripts/core/regen-web-previews.ts +2 -67
  39. package/src/audits/catalog.ts +0 -1
  40. package/src/browser/engine.ts +3 -6
  41. package/src/capture/render.ts +1 -1
  42. package/src/claude/cases/authoring.ts +0 -12
  43. package/src/claude/cases/misc.ts +0 -22
  44. package/src/claude/cases/workflow.ts +2 -38
  45. package/src/claude/skills-audit.ts +1 -1
  46. package/src/cli/help.ts +0 -10
  47. package/src/cli.ts +0 -8
  48. package/src/commands/design.ts +16 -315
  49. package/src/commands/records.ts +0 -1
  50. package/src/commands/serve.ts +2 -2
  51. package/src/commands/sync.ts +4 -5
  52. package/src/design/components.ts +8 -1514
  53. package/src/design/css.ts +5 -6
  54. package/src/design/fonts.ts +3 -5
  55. package/src/design/regen.ts +5 -32
  56. package/src/design/render.ts +1 -1
  57. package/src/design/tokens.ts +3 -2
  58. package/src/driver/drive.ts +3 -4
  59. package/src/driver/steps.ts +2 -5
  60. package/src/gate/stages.ts +4 -10
  61. package/src/gov/audit.ts +1 -6
  62. package/src/inventory/walk.ts +1 -1
  63. package/src/markdown/scope.ts +6 -35
  64. package/src/records/validate.ts +4 -176
  65. package/src/sandbox/equivalence.ts +0 -5
  66. package/src/shipped/references.ts +1 -2
  67. package/src/sync/check.ts +4 -29
  68. package/src/sync/stamp.ts +6 -6
  69. package/src/sync/target.ts +1 -4
  70. package/tooling/claude/reference.md +1 -1
  71. package/tooling/claude/seeds/canon/DESIGN.md +1 -1
  72. package/claude/skills/canvas-board/REQUIREMENT.md +0 -35
  73. package/claude/skills/canvas-board/SKILL.md +0 -143
  74. package/claude/skills/canvas-board/references/canvas.md +0 -170
  75. package/claude/skills/draft-and-pick/REQUIREMENT.md +0 -26
  76. package/claude/skills/draft-and-pick/SKILL.md +0 -11
  77. package/claude/skills/draft-doc/REQUIREMENT.md +0 -26
  78. package/claude/skills/draft-doc/SKILL.md +0 -11
  79. package/claude/skills/draft-figure/REQUIREMENT.md +0 -26
  80. package/claude/skills/draft-figure/SKILL.md +0 -11
  81. package/claude/skills/draft-identity/REQUIREMENT.md +0 -26
  82. package/claude/skills/draft-identity/SKILL.md +0 -11
  83. package/claude/skills/draft-ready/REQUIREMENT.md +0 -26
  84. package/claude/skills/draft-ready/SKILL.md +0 -11
  85. package/claude/skills/draft-screencast/REQUIREMENT.md +0 -26
  86. package/claude/skills/draft-screencast/SKILL.md +0 -11
  87. package/claude/skills/draft-slides/REQUIREMENT.md +0 -26
  88. package/claude/skills/draft-slides/SKILL.md +0 -11
  89. package/claude/skills/make-deck/REQUIREMENT.md +0 -36
  90. package/claude/skills/make-deck/SKILL.md +0 -80
  91. package/claude/skills/make-deck/references/deck.md +0 -183
  92. package/claude/skills/read-frames/REQUIREMENT.md +0 -30
  93. package/claude/skills/read-frames/SKILL.md +0 -55
  94. package/claude/skills/record-screencast/REQUIREMENT.md +0 -35
  95. package/claude/skills/record-screencast/SKILL.md +0 -99
  96. package/claude/skills/script-screencast/REQUIREMENT.md +0 -34
  97. package/claude/skills/script-screencast/SKILL.md +0 -70
  98. package/claude/skills/script-screencast/references/beats-template.md +0 -119
  99. package/claude/skills/teach-workspace/REQUIREMENT.md +0 -34
  100. package/claude/skills/teach-workspace/SKILL.md +0 -196
  101. package/claude/skills/teach-workspace/references/glossary.md +0 -90
  102. package/claude/skills/teach-workspace/references/lesson-build.md +0 -106
  103. package/claude/skills/teach-workspace/references/lesson-craft.md +0 -135
  104. package/claude/skills/teach-workspace/references/promotion-fold.md +0 -35
  105. package/claude/skills/teach-workspace/references/promotion.md +0 -116
  106. package/claude/skills/teach-workspace/references/revisit.md +0 -28
  107. package/claude/skills/teach-workspace/references/teach.md +0 -211
  108. package/claude/skills/video-craft/REQUIREMENT.md +0 -35
  109. package/claude/skills/video-craft/SKILL.md +0 -96
  110. package/claude/skills/video-craft/references/adopted.md +0 -110
  111. package/governance/rules/ui/canvas.md +0 -13
  112. package/src/canvas/address.ts +0 -227
  113. package/src/canvas/arrange.ts +0 -66
  114. package/src/canvas/capture.ts +0 -391
  115. package/src/canvas/client/app.tsx +0 -188
  116. package/src/canvas/client/inspector/align-grid.tsx +0 -162
  117. package/src/canvas/client/inspector/color-field.tsx +0 -398
  118. package/src/canvas/client/inspector/color-inputs.tsx +0 -139
  119. package/src/canvas/client/inspector/color-picker.tsx +0 -668
  120. package/src/canvas/client/inspector/color-space.ts +0 -240
  121. package/src/canvas/client/inspector/field.tsx +0 -263
  122. package/src/canvas/client/inspector/fields.css +0 -763
  123. package/src/canvas/client/inspector/section.tsx +0 -27
  124. package/src/canvas/client/inspector/size-field.tsx +0 -69
  125. package/src/canvas/client/inspector/token-select.tsx +0 -109
  126. package/src/canvas/client/inspector/values.ts +0 -297
  127. package/src/canvas/client/inspector.tsx +0 -692
  128. package/src/canvas/client/keys.ts +0 -71
  129. package/src/canvas/client/layers.tsx +0 -118
  130. package/src/canvas/client/main.tsx +0 -71
  131. package/src/canvas/client/pages-panel.tsx +0 -212
  132. package/src/canvas/client/panel-handle.tsx +0 -90
  133. package/src/canvas/client/selection.tsx +0 -199
  134. package/src/canvas/client/shell.css +0 -762
  135. package/src/canvas/client/state.ts +0 -792
  136. package/src/canvas/client/surface.tsx +0 -803
  137. package/src/canvas/client/theme-panel.tsx +0 -55
  138. package/src/canvas/client/tools.tsx +0 -153
  139. package/src/canvas/content.ts +0 -781
  140. package/src/canvas/edit.ts +0 -575
  141. package/src/canvas/editing.ts +0 -203
  142. package/src/canvas/fit.ts +0 -238
  143. package/src/canvas/global.d.ts +0 -15
  144. package/src/canvas/history.ts +0 -116
  145. package/src/canvas/index.html +0 -20
  146. package/src/canvas/server.ts +0 -766
  147. package/src/canvas/tokens.ts +0 -221
  148. package/src/commands/canvas.ts +0 -1097
  149. package/src/commands/demo.ts +0 -542
  150. package/src/commands/slides.ts +0 -184
  151. package/src/commands/teach.ts +0 -1401
  152. package/src/demo/beats.ts +0 -135
  153. package/src/demo/compile.ts +0 -350
  154. package/src/demo/container.ts +0 -219
  155. package/src/demo/cursors.ts +0 -55
  156. package/src/demo/drive.ts +0 -442
  157. package/src/demo/pointer.ts +0 -178
  158. package/src/demo/theme.ts +0 -112
  159. package/src/demo/timeline.ts +0 -64
  160. package/src/design/adapter.ts +0 -59
  161. package/src/design/base.css +0 -203
  162. package/src/design/brand-favicon.ts +0 -18
  163. package/src/design/neutral.ts +0 -127
  164. package/src/design/project-fonts.ts +0 -392
  165. package/src/slides/convert/chart.ts +0 -165
  166. package/src/slides/convert/deck.ts +0 -244
  167. package/src/slides/convert/export.ts +0 -567
  168. package/src/slides/convert/master.ts +0 -198
  169. package/src/slides/convert/shapes.ts +0 -804
  170. package/src/slides/convert/svg.ts +0 -38
  171. package/src/slides/convert/walk.ts +0 -671
  172. package/src/slides/decks.ts +0 -110
  173. package/src/slides/open.ts +0 -18
  174. package/src/slides/package/fonts.ts +0 -301
  175. package/src/slides/package/motion.ts +0 -316
  176. package/src/slides/package/test-face.ts +0 -113
  177. package/src/teach/browser/compile.ts +0 -44
  178. package/src/teach/browser/dismiss.ts +0 -76
  179. package/src/teach/browser/focus-line.ts +0 -19
  180. package/src/teach/browser/glossary-filter.ts +0 -44
  181. package/src/teach/browser/head.ts +0 -30
  182. package/src/teach/browser/quiz.ts +0 -19
  183. package/src/teach/browser/reload.ts +0 -9
  184. package/src/teach/browser/sidebar.ts +0 -233
  185. package/src/teach/browser/theme.ts +0 -18
  186. package/src/teach/components/code.tsx +0 -24
  187. package/src/teach/components/heading.tsx +0 -11
  188. package/src/teach/components/list.tsx +0 -17
  189. package/src/teach/components/paragraph.tsx +0 -29
  190. package/src/teach/components/refs.tsx +0 -28
  191. package/src/teach/cross-references.ts +0 -78
  192. package/src/teach/fonts.ts +0 -16
  193. package/src/teach/highlight.ts +0 -71
  194. package/src/teach/html/jsx-dev-runtime.ts +0 -13
  195. package/src/teach/html/jsx-runtime.ts +0 -113
  196. package/src/teach/html/raw.ts +0 -28
  197. package/src/teach/lesson.ts +0 -178
  198. package/src/teach/nav.ts +0 -1337
  199. package/src/teach/render.ts +0 -240
  200. package/src/teach/workspace.ts +0 -1164
  201. package/src/teach/write-if-changed.ts +0 -17
@@ -1,53 +1,30 @@
1
- import { copyFileSync, existsSync, mkdirSync } from 'node:fs'
2
- import { basename, join, relative, resolve } from 'node:path'
1
+ import { existsSync } from 'node:fs'
2
+ import { join, relative } from 'node:path'
3
3
  import type { Command } from 'commander'
4
- import {
5
- createDesignAdapter,
6
- DESIGN_INSTALL_DIR,
7
- DESIGN_PROJECT_SUBDIR,
8
- } from '@/design/adapter'
9
4
  import { buildDesignCss } from '@/design/css'
10
5
  import { HAND_DRAWN_FONT_FACES } from '@/design/fonts'
11
- import { addProjectFace, listProjectFaces } from '@/design/project-fonts'
12
- import { renderDesignDoc } from '@/design/render'
13
- import { DESIGN_BASE_CSS, DESIGN_DOCUMENT, regenDesign } from '@/design/regen'
6
+ import { DESIGN_DOCUMENT, regenDesign } from '@/design/regen'
14
7
  import { checkoutMismatchWarning, PROJECT_ROOT } from '@/roots/project'
15
- import { creationRel, SCRATCH } from '@/roots/record'
16
- import { surfaceDir } from '@/roots/surface'
17
- import { recordStamp, runDomainSync } from '@/sync/engine'
18
- import { isDirectory, resolveTarget } from '@/targets/validate'
19
- import {
20
- intro,
21
- logAdd,
22
- logError,
23
- logInfo,
24
- logWarn,
25
- outro,
26
- palette,
27
- } from '@/cli/ui'
8
+ import { logWarn, palette } from '@/cli/ui'
28
9
 
29
10
  export function register(program: Command): void {
30
11
  const design = program
31
12
  .command('design')
32
13
  .helpOption('-h, --help', 'Show this help message')
33
- .description(
34
- 'Design system commands (regen, css, render, install, sync, fonts)',
35
- )
14
+ .description('Design system commands (regen, css)')
36
15
 
37
16
  design
38
17
  .command('regen')
39
18
  .helpOption('-h, --help', 'Show this help message')
40
- .description(
41
- 'Rewrite canon/DESIGN.md and the base stylesheet from src/design/tokens.ts',
42
- )
19
+ .description('Rewrite canon/DESIGN.md from src/design/tokens.ts')
43
20
  .addHelpText(
44
21
  'after',
45
22
  [
46
23
  '',
47
- 'Unlike install and sync, this runs against the toolkit checkout rather',
48
- 'than a target. It rewrites the record and the base stylesheet from the',
49
- 'token module and refuses where the record is absent, which is what the',
50
- 'CLI installed into a project as a dependency looks like.',
24
+ 'This runs against the toolkit checkout rather than a target. It',
25
+ 'rewrites the record from the token module and refuses where the record',
26
+ 'is absent, which is what the CLI installed into a project as a',
27
+ 'dependency looks like.',
51
28
  '',
52
29
  ].join('\n'),
53
30
  )
@@ -60,10 +37,10 @@ export function register(program: Command): void {
60
37
  // so each emits it after its own opener rather than ahead of the branch.
61
38
  const mismatch = checkoutMismatchWarning(process.cwd())
62
39
 
63
- // Both outputs resolve from `PROJECT_ROOT`, which is the installed
40
+ // The output resolves from `PROJECT_ROOT`, which is the installed
64
41
  // package directory when the CLI runs out of a target's `node_modules`.
65
- // The record is the one output that is already committed here and ships
66
- // with no package, so its absence is what separates the two.
42
+ // The record is already committed here and ships with no package, so
43
+ // its absence is what separates the two.
67
44
  if (!existsSync(join(PROJECT_ROOT, DESIGN_DOCUMENT))) {
68
45
  process.stderr.write(`${GREY}┌${NC}\n`)
69
46
  if (mismatch !== undefined) logWarn(mismatch)
@@ -79,11 +56,9 @@ export function register(program: Command): void {
79
56
  )
80
57
  if (mismatch !== undefined) logWarn(mismatch)
81
58
  const result = regenDesign(PROJECT_ROOT)
82
- for (const path of [result.documentPath, result.cssPath]) {
83
- process.stderr.write(
84
- `${GREY}│${NC} ${GREEN}✓${NC} ${relative(PROJECT_ROOT, path)}\n`,
85
- )
86
- }
59
+ process.stderr.write(
60
+ `${GREY}│${NC} ${GREEN}✓${NC} ${relative(PROJECT_ROOT, result.documentPath)}\n`,
61
+ )
87
62
  process.stderr.write(`${GREY}└${NC}\n`)
88
63
  })
89
64
 
@@ -107,278 +82,4 @@ export function register(program: Command): void {
107
82
  }),
108
83
  )
109
84
  })
110
-
111
- design
112
- .command('render')
113
- .helpOption('-h, --help', 'Show this help message')
114
- .description('Render DESIGN.md tokens to HTML and CSS preview')
115
- .option(
116
- '-s, --source <path>',
117
- 'Source DESIGN.md path',
118
- relative(process.cwd(), surfaceDir(process.cwd(), 'DESIGN.md')),
119
- )
120
- .option(
121
- '-o, --out <path>',
122
- 'Output directory',
123
- creationRel(process.cwd(), SCRATCH, 'render', 'design'),
124
- )
125
- .option(
126
- '--embed-fonts',
127
- 'Declare each vendored face the typography table names, and set the page body in the body stack',
128
- )
129
- .action((opts: { source: string; out: string; embedFonts?: boolean }) => {
130
- const sourcePath = resolve(process.cwd(), opts.source)
131
- const outDir = resolve(process.cwd(), opts.out)
132
- const { GREEN, GREY, NC, RED, WHITE } = palette(process.stderr)
133
- if (!existsSync(sourcePath)) {
134
- process.stderr.write(
135
- `${GREY}┌${NC}\n${GREY}│${NC} ${RED}✗${NC} ${opts.source} not found\n${GREY}└${NC}\n`,
136
- )
137
- process.exitCode = 1
138
- return
139
- }
140
- process.stderr.write(
141
- `${GREY}┌${NC}\n${GREY}│${NC} ${WHITE}Render design tokens${NC}\n`,
142
- )
143
- const result = renderDesignDoc(sourcePath, outDir, {
144
- embedFonts: opts.embedFonts,
145
- })
146
- process.stderr.write(
147
- `${GREY}│${NC} ${GREEN}✓${NC} ${result.htmlPath}\n${GREY}│${NC} ${GREEN}✓${NC} ${result.cssPath}\n${GREY}└${NC}\n`,
148
- )
149
- })
150
-
151
- design
152
- .command('install')
153
- .description('Install the base stylesheet into a project')
154
- .argument('[target]', 'Target directory', '.')
155
- .helpOption('-h, --help', 'Show this help message')
156
- .addHelpText(
157
- 'after',
158
- [
159
- '',
160
- 'Installs one toolkit-owned file and creates no override. A project',
161
- `overrides a value by writing ${join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR)}/`,
162
- 'itself, which sync never touches. Nothing arrives on a project that',
163
- 'has not run this, so a design value reaches a target on an install',
164
- 'rather than on the next sync. A base stylesheet already installed is',
165
- 'replaced.',
166
- '',
167
- 'Exit codes:',
168
- ' 0 the stylesheet was installed',
169
- ' 1 the target is missing or is the toolkit root, or the toolkit',
170
- ' source is absent',
171
- '',
172
- ].join('\n'),
173
- )
174
- .action(async (target: string) => {
175
- process.exitCode = await runInstall(target)
176
- })
177
-
178
- design
179
- .command('sync')
180
- .description(
181
- 'Update the base stylesheet already installed under .claude/design/',
182
- )
183
- .argument('[target]', 'Target directory', '.')
184
- .helpOption('-h, --help', 'Show this help message')
185
- .addHelpText(
186
- 'after',
187
- [
188
- '',
189
- 'Replaces the shipped design files under .claude/design/ with the',
190
- 'toolkit copy, edited or not, and leaves',
191
- `${join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR)}/ alone. It deletes nothing it finds no`,
192
- 'source for.',
193
- '',
194
- 'Exit codes:',
195
- ' 0 synced, already up to date, or the prompt was cancelled',
196
- ' 1 the target is missing or is the toolkit root',
197
- '',
198
- ].join('\n'),
199
- )
200
- .action(async (target: string) => {
201
- process.exitCode = await runDomainSync(
202
- createDesignAdapter(PROJECT_ROOT),
203
- target,
204
- { protectedRoot: PROJECT_ROOT },
205
- )
206
- })
207
-
208
- registerFonts(design)
209
- }
210
-
211
- const FONTS_DIR = join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR, 'fonts')
212
-
213
- interface FontsRefused {
214
- readonly ok: false
215
- readonly reason: string
216
- readonly detail: string
217
- }
218
-
219
- function writeJson(record: unknown): void {
220
- process.stdout.write(`${JSON.stringify(record)}\n`)
221
- }
222
-
223
- function refuseFonts(
224
- title: string,
225
- refusal: FontsRefused,
226
- emitJson: boolean,
227
- ): number {
228
- if (emitJson) writeJson(refusal)
229
- intro(title)
230
- logError(refusal.detail)
231
- outro()
232
- return 1
233
- }
234
-
235
- /** A target that is a directory, or the refusal naming the path given. */
236
- function fontsTarget(target: string): string | FontsRefused {
237
- const resolved = resolve(target)
238
- if (!isDirectory(resolved)) {
239
- return {
240
- ok: false,
241
- reason: 'no-target',
242
- detail: `Target directory not found: ${target}`,
243
- }
244
- }
245
- return resolved
246
- }
247
-
248
- function registerFonts(design: Command): void {
249
- const fonts = design
250
- .command('fonts')
251
- .helpOption('-h, --help', 'Show this help message')
252
- .description(`Read and add the project's own faces under ${FONTS_DIR}/`)
253
- .addHelpText(
254
- 'after',
255
- [
256
- '',
257
- `Faces are declared as @font-face rules in ${join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR)}/fonts.css,`,
258
- 'which the canvas embeds into every frame. Sync never writes the folder.',
259
- '',
260
- ].join('\n'),
261
- )
262
-
263
- fonts
264
- .command('list')
265
- .helpOption('-h, --help', 'Show this help message')
266
- .description('List each face the project override sheets declare')
267
- .argument('[target]', 'Target directory', '.')
268
- .option('--json', 'Emit the record on stdout')
269
- .action((target: string, opts: { json?: boolean }) => {
270
- const title = 'canon design fonts list'
271
- const resolved = fontsTarget(target)
272
- if (typeof resolved !== 'string') {
273
- process.exitCode = refuseFonts(title, resolved, Boolean(opts.json))
274
- return
275
- }
276
- const faces = listProjectFaces(resolved)
277
- if (opts.json) writeJson({ ok: true, faces })
278
- intro(title)
279
- if (faces.length === 0) logInfo(`No faces declared under ${FONTS_DIR}/`)
280
- for (const face of faces) {
281
- const line = `${face.family} ${face.weight} ${face.style}: ${face.file} in ${face.sheet}`
282
- if (face.present) logInfo(line)
283
- else logWarn(`${line} (${face.problem ?? 'missing'})`)
284
- }
285
- outro()
286
- })
287
-
288
- fonts
289
- .command('add')
290
- .helpOption('-h, --help', 'Show this help message')
291
- .description(
292
- `Copy a woff2, woff, ttf, or otf face into ${FONTS_DIR}/ and declare it`,
293
- )
294
- .argument('<file>', 'Font file to copy')
295
- .argument('[target]', 'Target directory', '.')
296
- .requiredOption('--family <name>', 'Family name the face declares')
297
- .option('--weight <n>', "Weight, or a range such as '100 900'", '400')
298
- .option('--style <style>', 'normal or italic', 'normal')
299
- .option('--json', 'Emit the record on stdout')
300
- .action(
301
- (
302
- file: string,
303
- target: string,
304
- opts: { family: string; weight: string; style: string; json?: boolean },
305
- ) => {
306
- const title = 'canon design fonts add'
307
- const emitJson = Boolean(opts.json)
308
- const resolved = fontsTarget(target)
309
- if (typeof resolved !== 'string') {
310
- process.exitCode = refuseFonts(title, resolved, emitJson)
311
- return
312
- }
313
- if (resolved === PROJECT_ROOT) {
314
- process.exitCode = refuseFonts(
315
- title,
316
- {
317
- ok: false,
318
- reason: 'toolkit-root',
319
- detail:
320
- 'Cannot run against toolkit root. Files here are the source of truth.',
321
- },
322
- emitJson,
323
- )
324
- return
325
- }
326
- const outcome = addProjectFace(resolved, resolve(file), {
327
- family: opts.family,
328
- weight: opts.weight,
329
- style: opts.style,
330
- })
331
- if (!outcome.ok) {
332
- process.exitCode = refuseFonts(title, outcome, emitJson)
333
- return
334
- }
335
- if (emitJson) writeJson(outcome)
336
- intro(title)
337
- logAdd(join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR, outcome.file))
338
- logInfo(
339
- `Declared ${outcome.family} ${outcome.weight} ${outcome.style} in ${outcome.sheet}`,
340
- )
341
- outro()
342
- },
343
- )
344
- }
345
-
346
- /**
347
- * Copies the base and stops. The override folder is deliberately not created:
348
- * an empty override is a file the project did not ask for and did not write,
349
- * the three-way merge already handles a missing side, and an empty file invites
350
- * a target to fill it before it has an opinion.
351
- */
352
- async function runInstall(target: string): Promise<number> {
353
- intro('canon design install')
354
-
355
- const resolved = resolveTarget(target, PROJECT_ROOT)
356
- if (typeof resolved === 'number') {
357
- outro()
358
- return resolved
359
- }
360
-
361
- const source = join(PROJECT_ROOT, DESIGN_BASE_CSS)
362
- if (!existsSync(source)) {
363
- logError(
364
- `No base stylesheet at ${DESIGN_BASE_CSS}. Run canon design regen.`,
365
- )
366
- outro()
367
- return 1
368
- }
369
-
370
- const dir = join(resolved, DESIGN_INSTALL_DIR)
371
- mkdirSync(dir, { recursive: true })
372
-
373
- const dest = join(dir, basename(source))
374
- copyFileSync(source, dest)
375
- logAdd(relative(resolved, dest))
376
-
377
- await recordStamp(createDesignAdapter(PROJECT_ROOT), resolved, new Date())
378
-
379
- logInfo(
380
- `Override a value in ${join(DESIGN_INSTALL_DIR, DESIGN_PROJECT_SUBDIR)}/, which sync leaves alone.`,
381
- )
382
- outro()
383
- return 0
384
85
  }
@@ -127,7 +127,6 @@ export function register(program: Command): void {
127
127
  'Examples:',
128
128
  ' canon records validate plans',
129
129
  ' canon records validate plans feature-records-by-heading',
130
- ' canon records validate teach',
131
130
  ' canon records validate intake --json',
132
131
  '',
133
132
  ].join('\n'),
@@ -40,8 +40,8 @@ export function register(program: Command): void {
40
40
  'starts it in the background and reads the record off stdout.',
41
41
  '',
42
42
  'Examples:',
43
- ' canon serve .canon/teach',
44
- ' canon serve .canon/teach --entry 03-fde-system-design/index.html',
43
+ ' canon serve site',
44
+ ' canon serve site --entry guide/index.html',
45
45
  ' canon serve dist --port 4000 --json',
46
46
  ' canon serve .canon/groundwork --index',
47
47
  '',
@@ -35,7 +35,6 @@ import { describeSkew } from '@/version/skew'
35
35
 
36
36
  const SYNC_ARGS: Record<SyncDomain, readonly string[]> = {
37
37
  governance: ['gov', 'sync'],
38
- design: ['design', 'sync'],
39
38
  claude: ['claude', 'sync'],
40
39
  }
41
40
 
@@ -58,10 +57,10 @@ export function register(program: Command): void {
58
57
  'after',
59
58
  [
60
59
  '',
61
- 'Runs `canon gov sync`, `canon design sync`, and `canon claude sync`',
62
- 'on each domain installed, so each carries its own replace behavior:',
63
- 'governance replaces an edited rule and deletes a retired one, design',
64
- 'replaces its shipped files, and claude writes .gitignore alone.',
60
+ 'Runs `canon gov sync` and `canon claude sync` on each domain',
61
+ 'installed, so each carries its own replace behavior: governance',
62
+ 'replaces an edited rule and deletes a retired one, and claude writes',
63
+ '.gitignore alone.',
65
64
  'Tooling is not synced. Refuses a dirty working tree.',
66
65
  '',
67
66
  'Exit codes:',