@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,244 +0,0 @@
1
- import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs'
2
- import { basename, isAbsolute, join, relative, resolve } from 'node:path'
3
-
4
- /**
5
- * What belongs to the deck rather than to one slide, read from `deck.json`
6
- * beside the slides. A slide overrides a band through attributes on its own
7
- * `<body>`, which `walk.ts` reads.
8
- */
9
-
10
- export const DECK_FILE = 'deck.json'
11
-
12
- export const BAND_SLOTS = ['left', 'center', 'right'] as const
13
- export type BandSlot = (typeof BAND_SLOTS)[number]
14
-
15
- export interface Band {
16
- readonly show: boolean
17
- readonly left?: string
18
- readonly center?: string
19
- readonly right?: string
20
- }
21
-
22
- export interface DeckConfig {
23
- readonly title: string
24
- readonly header: Band
25
- readonly footer: Band
26
- /** Drawn at the right of the footer, so they show only where it does. */
27
- readonly slideNumbers: boolean
28
- /** Absolute, resolved against the deck folder. */
29
- readonly mark?: string
30
- /** The faces the package step embeds, in the order the deck lists them. */
31
- readonly fonts: readonly DeckFont[]
32
- }
33
-
34
- export interface DeckFont {
35
- readonly family: string
36
- readonly weight: number
37
- readonly style: 'normal' | 'italic'
38
- /** Absolute, resolved against the deck folder and kept inside it. */
39
- readonly path: string
40
- /** The path as `deck.json` wrote it, which a refusal names. */
41
- readonly source: string
42
- }
43
-
44
- export type DeckRead =
45
- | { readonly status: 'read'; readonly deck: DeckConfig }
46
- | {
47
- readonly status: 'refused'
48
- readonly field: string
49
- readonly message: string
50
- }
51
-
52
- const DECK_FIELDS = new Set([
53
- 'title',
54
- 'header',
55
- 'footer',
56
- 'slideNumbers',
57
- 'mark',
58
- 'fonts',
59
- ])
60
- const BAND_FIELDS = new Set<string>(['show', ...BAND_SLOTS])
61
- const FONT_FIELDS = new Set(['family', 'weight', 'style', 'path'])
62
-
63
- class FieldError extends Error {
64
- constructor(
65
- readonly field: string,
66
- message: string,
67
- ) {
68
- super(message)
69
- }
70
- }
71
-
72
- const isRecord = (value: unknown): value is Record<string, unknown> =>
73
- typeof value === 'object' && value !== null && !Array.isArray(value)
74
-
75
- function rejectUnknown(
76
- record: Record<string, unknown>,
77
- known: ReadonlySet<string>,
78
- prefix: string,
79
- ): void {
80
- const unknown = Object.keys(record).find((key) => !known.has(key))
81
- if (unknown !== undefined) {
82
- throw new FieldError(
83
- `${prefix}${unknown}`,
84
- `unknown field ${prefix}${unknown}`,
85
- )
86
- }
87
- }
88
-
89
- function stringField(value: unknown, field: string): string | undefined {
90
- if (value === undefined) return undefined
91
- if (typeof value !== 'string') {
92
- throw new FieldError(field, `${field} must be a string`)
93
- }
94
- return value
95
- }
96
-
97
- function booleanField(value: unknown, field: string): boolean | undefined {
98
- if (value === undefined) return undefined
99
- if (typeof value !== 'boolean') {
100
- throw new FieldError(field, `${field} must be true or false`)
101
- }
102
- return value
103
- }
104
-
105
- /**
106
- * A declared band merges over its default, so `{ "center": "x" }` keeps the
107
- * footer's title on the left. Declaring any text turns a band on unless it
108
- * also says `show: false`.
109
- */
110
- function band(value: unknown, field: string, fallback: Band): Band {
111
- if (value === undefined) return fallback
112
- if (!isRecord(value)) {
113
- throw new FieldError(field, `${field} must be an object`)
114
- }
115
- rejectUnknown(value, BAND_FIELDS, `${field}.`)
116
- const slots: { -readonly [slot in BandSlot]?: string } = {}
117
- for (const slot of BAND_SLOTS) {
118
- const text = stringField(value[slot], `${field}.${slot}`)
119
- if (text !== undefined) slots[slot] = text
120
- }
121
- const show =
122
- booleanField(value.show, `${field}.show`) ??
123
- (Object.keys(slots).length > 0 || fallback.show)
124
- return { ...fallback, ...slots, show }
125
- }
126
-
127
- function parse(raw: unknown, folder: string): DeckConfig {
128
- if (!isRecord(raw)) {
129
- throw new FieldError(DECK_FILE, `${DECK_FILE} must hold an object`)
130
- }
131
- rejectUnknown(raw, DECK_FIELDS, '')
132
- const title = stringField(raw.title, 'title') ?? basename(folder)
133
- const header = band(raw.header, 'header', { show: false })
134
- const footer = band(raw.footer, 'footer', { show: true, left: title })
135
- const slideNumbers = booleanField(raw.slideNumbers, 'slideNumbers') ?? true
136
- if (slideNumbers && footer.right !== undefined) {
137
- throw new FieldError(
138
- 'footer.right',
139
- 'footer.right is where slide numbers sit. Set slideNumbers to false to use it',
140
- )
141
- }
142
- const markPath = stringField(raw.mark, 'mark')
143
- let mark: string | undefined
144
- if (markPath !== undefined) {
145
- mark = join(folder, markPath)
146
- if (!existsSync(mark) || !statSync(mark).isFile()) {
147
- throw new FieldError('mark', `mark ${mark} does not exist`)
148
- }
149
- }
150
- const fonts = fontList(raw.fonts, folder)
151
- return { title, header, footer, slideNumbers, mark, fonts }
152
- }
153
-
154
- function isWithin(folder: string, path: string): boolean {
155
- const inside = relative(folder, path)
156
- return inside !== '' && !inside.startsWith('..') && !isAbsolute(inside)
157
- }
158
-
159
- /**
160
- * A face is read from the deck folder only, so a `deck.json` cannot point the
161
- * export at a file elsewhere on the machine and carry it out inside the deck.
162
- */
163
- function fontList(value: unknown, folder: string): DeckFont[] {
164
- if (value === undefined) return []
165
- if (!Array.isArray(value)) {
166
- throw new FieldError('fonts', 'fonts must be a list')
167
- }
168
- return value.map((entry: unknown, index): DeckFont => {
169
- const field = `fonts[${index}]`
170
- if (!isRecord(entry)) {
171
- throw new FieldError(field, `${field} must be an object`)
172
- }
173
- rejectUnknown(entry, FONT_FIELDS, `${field}.`)
174
- const family = stringField(entry.family, `${field}.family`)
175
- if (!family) {
176
- throw new FieldError(`${field}.family`, `${field}.family is required`)
177
- }
178
- const weight = entry.weight ?? 400
179
- if (
180
- typeof weight !== 'number' ||
181
- !Number.isInteger(weight) ||
182
- weight < 1 ||
183
- weight > 1000
184
- ) {
185
- throw new FieldError(
186
- `${field}.weight`,
187
- `${field}.weight must be a whole number from 1 to 1000`,
188
- )
189
- }
190
- const style = entry.style ?? 'normal'
191
- if (style !== 'normal' && style !== 'italic') {
192
- throw new FieldError(
193
- `${field}.style`,
194
- `${field}.style must be normal or italic`,
195
- )
196
- }
197
- const source = stringField(entry.path, `${field}.path`)
198
- if (!source) {
199
- throw new FieldError(`${field}.path`, `${field}.path is required`)
200
- }
201
- const path = resolve(folder, source)
202
- const outside = new FieldError(
203
- `${field}.path`,
204
- `${field}.path ${source} lies outside the deck folder`,
205
- )
206
- if (!isWithin(folder, path)) throw outside
207
- if (!existsSync(path) || !statSync(path).isFile()) {
208
- throw new FieldError(
209
- `${field}.path`,
210
- `${field}.path ${path} does not exist`,
211
- )
212
- }
213
- // A link inside the folder can still lead out of it.
214
- if (!isWithin(realpathSync(folder), realpathSync(path))) throw outside
215
- return { family, weight, style, path, source }
216
- })
217
- }
218
-
219
- export function readDeck(folder: string): DeckRead {
220
- const path = join(folder, DECK_FILE)
221
- let raw: unknown = {}
222
- if (existsSync(path)) {
223
- try {
224
- raw = JSON.parse(readFileSync(path, 'utf8'))
225
- } catch (error) {
226
- const reason = error instanceof Error ? error.message : String(error)
227
- return {
228
- status: 'refused',
229
- field: DECK_FILE,
230
- message: `${path}: not valid JSON (${reason})`,
231
- }
232
- }
233
- }
234
- try {
235
- return { status: 'read', deck: parse(raw, folder) }
236
- } catch (error) {
237
- if (!(error instanceof FieldError)) throw error
238
- return {
239
- status: 'refused',
240
- field: error.field,
241
- message: `${path}: ${error.message}`,
242
- }
243
- }
244
- }