@erclx/canon 5.23.0 → 5.25.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 (98) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
  3. package/claude/skills/backlog-triage/SKILL.md +19 -6
  4. package/claude/skills/canon-operator/REQUIREMENT.md +1 -0
  5. package/claude/skills/canon-operator/SKILL.md +5 -1
  6. package/claude/skills/canvas/REQUIREMENT.md +49 -0
  7. package/claude/skills/canvas/SKILL.md +106 -0
  8. package/claude/skills/design-extract/REQUIREMENT.md +1 -1
  9. package/claude/skills/draft-doc/REQUIREMENT.md +2 -1
  10. package/claude/skills/draft-doc/references/readme/agent-facing.md +59 -0
  11. package/claude/skills/draft-doc/references/readme/application.md +66 -0
  12. package/claude/skills/draft-doc/references/readme/cli.md +64 -0
  13. package/claude/skills/draft-doc/references/readme/library.md +57 -0
  14. package/claude/skills/draft-doc/references/readme/plugin.md +66 -0
  15. package/claude/skills/draft-doc/references/readme.md +33 -4
  16. package/claude/skills/draft-figure/REQUIREMENT.md +14 -3
  17. package/claude/skills/draft-figure/SKILL.md +24 -51
  18. package/claude/skills/draft-figure/references/architecture-set.md +35 -0
  19. package/claude/skills/draft-figure/references/hand-drawn.md +31 -0
  20. package/claude/skills/draft-figure/references/mermaid.md +55 -0
  21. package/claude/skills/git-followup/SKILL.md +17 -6
  22. package/claude/skills/git-pr/references/evidence.md +4 -2
  23. package/claude/skills/git-split/SKILL.md +1 -1
  24. package/claude/skills/index-lookup/SKILL.md +2 -2
  25. package/claude/skills/review-address/SKILL.md +6 -13
  26. package/claude/skills/review-address/references/rest-reads.md +43 -0
  27. package/claude/skills/review-craft/references/ui.md +7 -1
  28. package/claude/skills/review-pr/REQUIREMENT.md +1 -0
  29. package/claude/skills/review-pr/SKILL.md +9 -3
  30. package/claude/skills/review-pr/references/close-out.md +2 -2
  31. package/claude/skills/review-pr/references/post.md +17 -5
  32. package/claude/skills/review-pr/references/scope.md +10 -8
  33. package/claude/skills/review-ui/SKILL.md +12 -4
  34. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +30 -1
  35. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +4 -0
  36. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +4 -4
  37. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +6 -0
  38. package/claude/skills/role-orchestrator/scripts/poll.ts +90 -27
  39. package/claude/skills/role-orchestrator/scripts/repo.ts +3 -5
  40. package/claude/skills/role-orchestrator/scripts/watch.ts +4 -7
  41. package/docs/agents/canvas.md +6 -2
  42. package/docs/agents/commands.md +45 -45
  43. package/docs/agents/context-audit-checks.md +2 -2
  44. package/docs/agents/index.md +0 -1
  45. package/docs/agents/key-changes.md +3 -3
  46. package/docs/agents/pr-evidence.md +11 -2
  47. package/docs/agents/pr-reads.md +5 -4
  48. package/docs/target/projects.md +4 -4
  49. package/docs/workflow/ai-workflow.md +0 -1
  50. package/docs/workflow/skill-map.md +3 -3
  51. package/docs/workflow/visual-design-workflow.md +2 -1
  52. package/governance/renames.toml +0 -4
  53. package/governance/rules/standards/markdown.md +1 -0
  54. package/package.json +1 -2
  55. package/scripts/core/install-check.sh +1 -1
  56. package/src/audits/catalog.ts +2 -2
  57. package/src/canvas/client/inspector/field.tsx +200 -0
  58. package/src/canvas/client/inspector/fields.css +151 -0
  59. package/src/canvas/client/inspector/section.tsx +27 -0
  60. package/src/canvas/client/inspector/values.ts +60 -0
  61. package/src/canvas/client/inspector.tsx +192 -111
  62. package/src/canvas/client/shell.css +0 -94
  63. package/src/canvas/tokens.ts +9 -1
  64. package/src/claude/cases/misc.ts +5 -0
  65. package/src/claude/cases/workflow.ts +1 -1
  66. package/src/claude/seeds.ts +0 -1
  67. package/src/commands/canvas.ts +29 -0
  68. package/src/commands/design.ts +2 -64
  69. package/src/commands/pr.ts +219 -202
  70. package/src/context/audit.ts +7 -6
  71. package/src/design/budget.ts +149 -0
  72. package/src/design/document.ts +22 -10
  73. package/src/design/render.ts +11 -1
  74. package/src/design/tokens.ts +40 -61
  75. package/src/gate/measures.ts +49 -0
  76. package/src/gate/stages.ts +5 -1
  77. package/src/help.ts +2 -2
  78. package/src/migrate/skill-names.ts +7 -1
  79. package/src/pr/evidence.ts +25 -5
  80. package/src/pr/rest.ts +137 -0
  81. package/standards/canvas.md +112 -0
  82. package/standards/context.md +2 -1
  83. package/standards/design.md +13 -3
  84. package/standards/figures.md +0 -1
  85. package/standards/index.md +1 -1
  86. package/standards/markdown.md +1 -0
  87. package/standards/mermaid.md +1 -7
  88. package/tooling/claude/reference.md +0 -5
  89. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +1 -1
  90. package/claude/skills/draft-diagram/REQUIREMENT.md +0 -45
  91. package/claude/skills/draft-diagram/SKILL.md +0 -177
  92. package/docs/agents/design-board.md +0 -33
  93. package/governance/rules/standards/diagrams.md +0 -14
  94. package/governance/rules/standards/mermaid.md +0 -15
  95. package/scripts/core/check-gallery-exclusion.sh +0 -50
  96. package/src/design/board.ts +0 -576
  97. package/standards/diagrams.md +0 -132
  98. package/tooling/claude/seeds/.claude/diagrams/index.md +0 -8
@@ -320,29 +320,6 @@ code {
320
320
  outline-offset: 6px;
321
321
  }
322
322
 
323
- .box {
324
- display: grid;
325
- grid-template-columns: 1fr 1fr;
326
- gap: var(--space-xs) var(--space-md);
327
- margin: var(--space-xs) 0 0;
328
- }
329
-
330
- .box-row {
331
- display: flex;
332
- justify-content: space-between;
333
- gap: var(--space-sm);
334
- }
335
-
336
- .box dt {
337
- color: var(--color-muted);
338
- }
339
-
340
- .box dd {
341
- margin: 0;
342
- color: var(--color-text);
343
- font-variant-numeric: tabular-nums;
344
- }
345
-
346
323
  .toolbar {
347
324
  position: absolute;
348
325
  right: var(--space-md);
@@ -436,77 +413,6 @@ code {
436
413
  white-space: nowrap;
437
414
  }
438
415
 
439
- /* One property a row, since a computed color or font stack outgrows a half. */
440
- .styles {
441
- grid-template-columns: 1fr;
442
- }
443
-
444
- .styles dd {
445
- min-width: 0;
446
- overflow: hidden;
447
- text-overflow: ellipsis;
448
- white-space: nowrap;
449
- }
450
-
451
- .styles .box-row {
452
- align-items: center;
453
- }
454
-
455
- .styles dt {
456
- flex: none;
457
- width: 4.5rem;
458
- }
459
-
460
- .styles dd {
461
- flex: 1;
462
- }
463
-
464
- .field-cell {
465
- display: flex;
466
- gap: var(--space-xs);
467
- }
468
-
469
- .field,
470
- .token-picker {
471
- min-width: 0;
472
- min-height: 24px;
473
- padding: 2px var(--space-xs);
474
- border: 1px solid var(--color-border);
475
- border-radius: var(--radius-action);
476
- background: var(--color-surface);
477
- color: var(--color-text);
478
- font: inherit;
479
- font-variant-numeric: tabular-nums;
480
- }
481
-
482
- .field {
483
- flex: 1;
484
- width: 100%;
485
- }
486
-
487
- .token-picker {
488
- flex: none;
489
- width: 4.5rem;
490
- cursor: pointer;
491
- }
492
-
493
- .field:hover,
494
- .token-picker:hover {
495
- border-color: var(--color-muted);
496
- }
497
-
498
- .field:disabled,
499
- .token-picker:disabled {
500
- opacity: 0.5;
501
- cursor: not-allowed;
502
- }
503
-
504
- .saved {
505
- margin-left: var(--space-sm);
506
- color: var(--color-success);
507
- font-weight: 400;
508
- }
509
-
510
416
  .tabs {
511
417
  display: flex;
512
418
  gap: 2px;
@@ -138,7 +138,15 @@ export function resolveFrameTokens(
138
138
  options: TokenOptions = {},
139
139
  ): FrameTokens {
140
140
  if (options.isOwnCheckout ?? isOwnCheckout(root)) {
141
- return { source: 'toolkit', css: buildDesignCss() }
141
+ /*
142
+ * Faces embedded, since the type tokens name `Geist Variable` and a
143
+ * machine with only static Geist installed renders every frame in the
144
+ * fallback. An installed base owns its fonts, so that branch gets none.
145
+ */
146
+ return {
147
+ source: 'toolkit',
148
+ css: buildDesignCss(undefined, { embedFonts: true }),
149
+ }
142
150
  }
143
151
 
144
152
  const files = installedFiles(root)
@@ -27,6 +27,11 @@ export const MISC_CASES: readonly SkillCase[] = [
27
27
  "I found two sites whose look I want us to draw from. Put them side by side and let's settle which one the design should follow before anyone writes a token.",
28
28
  expect: 'sketch-design',
29
29
  },
30
+ {
31
+ prompt:
32
+ 'Draw the signup screen as a frame on the canvas, then restyle the element I just selected there.',
33
+ expect: 'canvas',
34
+ },
30
35
  {
31
36
  prompt: 'Fire up the dev server the way this project documents it.',
32
37
  expect: 'project-commands',
@@ -26,7 +26,7 @@ export const WORKFLOW_CASES: readonly SkillCase[] = [
26
26
  },
27
27
  {
28
28
  prompt: 'Draw me a diagram of how the pieces of this system connect.',
29
- expect: 'draft-diagram',
29
+ expect: 'draft-figure',
30
30
  },
31
31
  {
32
32
  prompt:
@@ -20,7 +20,6 @@ const HOOKS = 'hooks'
20
20
  export const SUBDIRS: readonly string[] = [
21
21
  HOOKS,
22
22
  'context',
23
- 'diagrams',
24
23
  'memory',
25
24
  'tasks',
26
25
  'wireframes',
@@ -20,6 +20,7 @@ import {
20
20
  STYLE_PROPERTIES,
21
21
  } from '@/canvas/edit'
22
22
  import { CANVAS_PORT, startCanvas } from '@/canvas/server'
23
+ import { PROJECT_ROOT } from '@/project-root'
23
24
  import { resolveFrameTokens } from '@/canvas/tokens'
24
25
  import { displayPath, parsePort, waitForInterrupt } from '@/serve/report'
25
26
  import {
@@ -49,9 +50,35 @@ interface Refused {
49
50
  | 'no-root'
50
51
  | 'no-server'
51
52
  | 'capture-failed'
53
+ | 'missing-client-deps'
52
54
  readonly detail: string
53
55
  }
54
56
 
57
+ const CLIENT_DEPS = ['preact', '@preact/signals'] as const
58
+
59
+ /**
60
+ * Refuses when the shell's client packages do not resolve from `from`, since
61
+ * the bundler then answers `/` with an empty page rather than an error. The
62
+ * caller passes the package root the binary runs from, never the served
63
+ * project's, so a global install serving a target finds its own copies.
64
+ */
65
+ export function missingClientDeps(from: string): Refused | undefined {
66
+ const missing = CLIENT_DEPS.filter((name) => {
67
+ try {
68
+ Bun.resolveSync(name, from)
69
+ return false
70
+ } catch {
71
+ return true
72
+ }
73
+ })
74
+ if (missing.length === 0) return undefined
75
+ return {
76
+ ok: false,
77
+ reason: 'missing-client-deps',
78
+ detail: `${missing.join(', ')} not installed in ${from}, so the canvas shell cannot load. Run bun install there`,
79
+ }
80
+ }
81
+
55
82
  type RootOutcome = { readonly ok: true; readonly root: string } | Refused
56
83
 
57
84
  /**
@@ -637,6 +664,8 @@ async function runServe(
637
664
  return refuseServe(resolved.reason, resolved.detail, emitJson)
638
665
  }
639
666
  const { root } = resolved
667
+ const missing = missingClientDeps(PROJECT_ROOT)
668
+ if (missing) return refuseServe(missing.reason, missing.detail, emitJson)
640
669
  /*
641
670
  * Imported here rather than at the top, so a command module the test runner
642
671
  * loads never asks it for an HTML module it cannot parse.
@@ -6,30 +6,22 @@ import {
6
6
  DESIGN_INSTALL_DIR,
7
7
  DESIGN_PROJECT_SUBDIR,
8
8
  } from '@/design/adapter'
9
- import { generateBoard } from '@/design/board'
10
9
  import { buildDesignCss } from '@/design/css'
11
10
  import { HAND_DRAWN_FONT_FACES } from '@/design/fonts'
12
11
  import { renderDesignDoc } from '@/design/render'
13
12
  import { DESIGN_BASE_CSS, DESIGN_DOCUMENT, regenDesign } from '@/design/regen'
14
- import {
15
- checkoutMismatchWarning,
16
- isOwnCheckout,
17
- PROJECT_ROOT,
18
- } from '@/project-root'
13
+ import { checkoutMismatchWarning, PROJECT_ROOT } from '@/project-root'
19
14
  import { creationRel, SCRATCH } from '@/record-root'
20
15
  import { surfaceDir } from '@/surface-root'
21
16
  import { recordStamp, runDomainSync } from '@/sync/engine'
22
17
  import { resolveTarget } from '@/target'
23
18
  import { intro, logAdd, logError, logInfo, logWarn, outro, palette } from '@/ui'
24
- import { mainWorktreeRoot } from '@/worktree'
25
19
 
26
20
  export function register(program: Command): void {
27
21
  const design = program
28
22
  .command('design')
29
23
  .helpOption('-h, --help', 'Show this help message')
30
- .description(
31
- 'Design system commands (regen, css, render, board, install, sync)',
32
- )
24
+ .description('Design system commands (regen, css, render, install, sync)')
33
25
 
34
26
  design
35
27
  .command('regen')
@@ -145,60 +137,6 @@ export function register(program: Command): void {
145
137
  )
146
138
  })
147
139
 
148
- design
149
- .command('board')
150
- .helpOption('-h, --help', 'Show this help message')
151
- .description(
152
- 'Generate the design board, an index over a project’s design surfaces',
153
- )
154
- .option(
155
- '-o, --out <path>',
156
- 'Output directory',
157
- creationRel(process.cwd(), SCRATCH, 'render', 'board'),
158
- )
159
- .option('--root <path>', 'Project root, defaulting to the main worktree')
160
- .addHelpText(
161
- 'after',
162
- [
163
- '',
164
- 'Reads its sources from --root, defaulting to the main worktree of',
165
- 'whatever project the caller stands in, and writes a static page',
166
- 'set, never installed or synced. The surfaces panel’s landing-page',
167
- 'half and the whole components panel render only when that root is',
168
- 'this toolkit’s own checkout. Open the result with canon serve <out>.',
169
- '',
170
- ].join('\n'),
171
- )
172
- .action(async (opts: { out: string; root?: string }) => {
173
- const outDir = resolve(process.cwd(), opts.out)
174
- const root = opts.root
175
- ? resolve(process.cwd(), opts.root)
176
- : await mainWorktreeRoot()
177
- const isToolkitCheckout = isOwnCheckout(root)
178
- const { GREEN, GREY, NC, RED, WHITE } = palette(process.stderr)
179
- const mismatch = checkoutMismatchWarning(process.cwd())
180
- process.stderr.write(
181
- `${GREY}┌${NC}\n${GREY}│${NC} ${WHITE}Generate design board${NC}\n`,
182
- )
183
- if (mismatch !== undefined) logWarn(mismatch)
184
- const result = generateBoard(
185
- root,
186
- outDir,
187
- process.cwd(),
188
- isToolkitCheckout,
189
- )
190
- if (!result.ok) {
191
- process.stderr.write(
192
- `${GREY}│${NC} ${RED}✗${NC} ${result.detail}\n${GREY}└${NC}\n`,
193
- )
194
- process.exitCode = 1
195
- return
196
- }
197
- process.stderr.write(
198
- `${GREY}│${NC} ${GREEN}✓${NC} ${relative(process.cwd(), result.indexPath)}\n${GREY}│${NC} Open with: canon serve ${relative(process.cwd(), result.outDir)}\n${GREY}└${NC}\n`,
199
- )
200
- })
201
-
202
140
  design
203
141
  .command('install')
204
142
  .description('Install the base stylesheet into a project')