@symbo.ls/mcp 1.0.13 → 1.0.17

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@symbo.ls/mcp",
3
- "version": "1.0.13",
4
- "description": "MCP server for Symbols.app — documentation search and framework reference",
3
+ "version": "1.0.17",
4
+ "description": "MCP server for Symbols.app — documentation search, code generation, project management, publishing, CLI/SDK reference",
5
5
  "mcpName": "io.github.symbo-ls/symbols-mcp",
6
6
  "files": [
7
7
  "bin/",
@@ -259,3 +259,5 @@ Produce the following deliverables:
259
259
  - Project issues (implementation-level) in project-feedback.md
260
260
 
261
261
  Enforce full DOMQL v3 purity across the entire codebase. No exceptions.
262
+
263
+ **CRITICAL: There is NO concept of "known debt", "accepted violations", or "technical debt exceptions" in Symbols audits. Every violation MUST be fixed. Never label a violation as "known debt" or suggest it can be deferred. If the audit finds a Rule 30 violation (direct DOM manipulation), it must be rewritten using DOMQL declarative syntax — not acknowledged and kept. The same applies to ALL rules (27-33). Zero tolerance.**
@@ -0,0 +1,374 @@
1
+ # Symbols CLI Reference (`@symbo.ls/cli`)
2
+
3
+ The `smbls` command-line interface for the Symbols design platform.
4
+
5
+ **Install:** `npm install -g @symbo.ls/cli`
6
+ **Version:** 3.7.5
7
+ **Global command:** `smbls`
8
+
9
+ ---
10
+
11
+ ## Project Setup
12
+
13
+ ### `smbls init [dest]`
14
+ Initialize or add Symbols to a project.
15
+ - `--non-interactive` — disable prompts (requires flags)
16
+ - `--name <name>` — project name
17
+ - `--location <location>` — where to init: root or subfolder
18
+ - `--v2-action <action>` — v2 project action: migrate, root, or subfolder
19
+ - `-y, --yes` — skip confirmation prompts
20
+
21
+ Auto-detects v2 projects and offers migration path.
22
+
23
+ ### `smbls create [dir]`
24
+ Create and scaffold a new project.
25
+ - `--workspace` — scaffold only symbols source files (no full repo, dir: ".")
26
+ - `--create-new` — force create new platform project
27
+ - `--link-existing` — force link to existing platform project
28
+ - `--local-only` — local-only (no platform)
29
+ - `--non-interactive` — disable prompts (requires flags)
30
+ - `--project-name <name>` — platform project name
31
+ - `--type <projectType>` — platform projectType
32
+ - `--key <projectKey>` — platform project key
33
+ - `--id <projectId>` — platform project id (for link mode)
34
+ - `--visibility <visibility>` — platform visibility (default: private)
35
+ - `--language <language>` — platform language (default: javascript)
36
+ - `--branch <branch>` — local branch (default: main)
37
+ - `--template <gitUrl>` — override template git repo URL
38
+ - `--package-manager <manager>` — npm or yarn (default: npm)
39
+ - `--no-dependencies` — skip installing dependencies
40
+ - `--no-clone` — create folder instead of cloning from git
41
+ - `--blank-shared-libraries` — create project with blank shared libraries
42
+ - `--domql` — use DOMQL template (default: true)
43
+ - `--remote` — clone feature/remote branch (default: true)
44
+ - `--clean-from-git` — remove starter-kit git repository (default: true)
45
+ - `-v, --verbose` — verbose output
46
+
47
+ ### `smbls install`
48
+ Install Symbols into an existing project.
49
+ - `-d, --dev` — run against local server
50
+ - `-f, --fetch` — fetch config after install (default: true)
51
+ - `--framework <framework>` — framework: domql or react
52
+ - `-v, --verbose` — verbose output
53
+
54
+ ### `smbls eject`
55
+ Eject from `@symbo.ls/runner` to explicit bundler dependencies.
56
+ - `--no-install` — skip npm install after ejecting
57
+
58
+ Updates package.json, removes @symbo.ls/runner, adds bundler deps, expands .parcelrc for parcel.
59
+
60
+ ---
61
+
62
+ ## Development
63
+
64
+ ### `smbls start [entry]`
65
+ Start development server.
66
+ - `-p, --port <port>` — port to use (default from symbols.json or 1234)
67
+ - `--no-cache` — disable build cache
68
+ - `--open` — open browser on start
69
+ - `--bundler <bundler>` — force bundler: parcel, vite, or browser
70
+
71
+ Supports pass-through args to underlying bundler. Auto-selects free port if specified port is busy. Browser mode injects importmap and globals script.
72
+
73
+ ### `smbls build [entry]`
74
+ Build project for production.
75
+ - `--no-cache` — disable build cache
76
+ - `--no-optimize` — disable optimization
77
+ - `--no-brender` — skip brender pre-rendering
78
+ - `--out-dir <dir>` — output directory (default from symbols.json or dist)
79
+ - `--bundler <bundler>` — force bundler: parcel, vite, or browser
80
+
81
+ ### `smbls brender [entry]`
82
+ Pre-render static pages to HTML using server-side rendering.
83
+ - `--out-dir <dir>` — output directory (default: brenderDistDir from symbols.json, or dist-brender)
84
+ - `--no-isr` — disable ISR (skip client SPA bundle)
85
+ - `--no-prefetch` — disable SSR data prefetching
86
+ - `-w, --watch` — watch for changes and re-render
87
+
88
+ Output: `dist-brender/` with static HTML, metadata, CSS, optional client bundle.
89
+
90
+ ### `smbls deploy`
91
+ Deploy project to hosting providers.
92
+ - `--provider <provider>` — deploy target: symbols, cloudflare, vercel, netlify, github-pages
93
+ - `--init` — initialize deployment config without deploying
94
+ - `--out-dir <dir>` — output directory for build
95
+ - `--bundler <bundler>` — force bundler: parcel, vite, or browser
96
+
97
+ Creates provider-specific config files (wrangler.jsonc, vercel.json, netlify.toml, GitHub Actions workflow).
98
+
99
+ ---
100
+
101
+ ## Sync & Configuration
102
+
103
+ ### `smbls fetch`
104
+ Pull design system and project config from the Symbols platform.
105
+ - `-d, --dev` — run against local server
106
+ - `-v, --verbose` — verbose output
107
+ - `--convert` — convert fetched config (default: true)
108
+ - `--schema` — include schema (default: false)
109
+ - `--force` — force override local changes
110
+ - `--update` — override local changes from platform
111
+ - `-y, --yes` — skip confirmation prompts
112
+ - `--dist-dir <dir>` — directory to import files to
113
+ - `--skip-confirm` — skip confirmation for local changes
114
+ - `--non-interactive` — disable interactive prompts
115
+
116
+ Includes git-based or mtime heuristic detection of local changes.
117
+
118
+ ### `smbls sync`
119
+ Bidirectional sync with remote server (two-way merge with conflict resolution).
120
+ - `-b, --branch <branch>` — branch to sync
121
+ - `-m, --message <message>` — commit message
122
+ - `-d, --dev` — run against local server
123
+ - `-v, --verbose` — verbose output
124
+ - `--mode <mode>` — sync mode: merge, remote, local, cancel
125
+ - `--conflict-resolution <mode>` — conflict resolution: local or remote
126
+ - `--non-interactive` — disable interactive prompts
127
+ - `-y, --yes` — skip confirmation prompts
128
+
129
+ Uses 3-way merge: local, remote, and base comparison.
130
+
131
+ ### `smbls push`
132
+ Push local changes to the Symbols platform.
133
+ - `-m, --message <message>` — commit message
134
+ - `-v, --verbose` — verbose output
135
+ - `-d, --dev` — run against local server
136
+ - `--non-interactive` — disable interactive prompts
137
+ - `-y, --yes` — skip confirmation prompts
138
+
139
+ Shows diffs before confirmation.
140
+
141
+ ### `smbls publish`
142
+ Build and publish project to preview environments.
143
+ - `--env <envs...>` — environments to publish to (development, staging, production)
144
+ - `--all` — publish to all environments
145
+ - `--non-interactive` — disable prompts (requires --env or --all)
146
+ - `-v, --verbose` — verbose output
147
+
148
+ Preview URLs are auto-generated for each environment.
149
+
150
+ ### `smbls config`
151
+ Interactively configure Symbols project settings.
152
+ - `--non-interactive` — disable prompts
153
+ - `--dist-dir <dir>` — set distribution directory
154
+ - `--owner <owner>` — Symbols username
155
+ - `--key <key>` — project key
156
+ - `--branch <branch>` — default branch
157
+ - `--version <version>` — version
158
+ - `--dir <dir>` — Symbols source directory
159
+ - `--runtime <runtime>` — environment: node, bun, deno, browser
160
+ - `--bundler <bundler>` — build tool: parcel, vite, turbopack, webpack, rollup
161
+ - `--package-manager <pm>` — npm, yarn, pnpm, bun
162
+ - `--api-base-url <url>` — API base URL
163
+ - `--deploy <target>` — deploy target: symbols, cloudflare, vercel, netlify, github-pages
164
+
165
+ Updates `symbols.json` and `.symbols_local/config.json`.
166
+
167
+ ---
168
+
169
+ ## Collaboration & Authentication
170
+
171
+ ### `smbls login`
172
+ Sign in to Symbols. Opens browser for OAuth/auth flow, stores credentials in `~/.smblsrc`.
173
+
174
+ ### `smbls signup`
175
+ Create a new Symbols account.
176
+
177
+ ### `smbls logout`
178
+ Sign out of Symbols (clears local credentials).
179
+
180
+ ### `smbls collab`
181
+ Connect to real-time collaboration socket and live-sync changes.
182
+ - `-b, --branch <branch>` — branch to collaborate on
183
+ - `--no-sync-first` — skip initial sync (not recommended)
184
+ - `-l, --live` — enable live collaboration mode (default: false)
185
+ - `-d, --debounce-ms <ms>` — local changes debounce (default: 200ms)
186
+ - `-v, --verbose` — verbose output
187
+
188
+ ---
189
+
190
+ ## Project Management
191
+
192
+ ### `smbls project <subcommand>`
193
+ Project lifecycle management with subcommands:
194
+
195
+ | Subcommand | Description |
196
+ |---|---|
197
+ | `create` | Create a new project |
198
+ | `link` | Link local project to platform |
199
+ | `delete` | Delete a project |
200
+ | `update` | Update project metadata |
201
+ | `list` | List projects |
202
+ | `duplicate` | Duplicate a project |
203
+ | `restore` | Restore a project |
204
+ | `libs` | Library management (add, remove, list, available) |
205
+ | `members` | Members management (add, remove, list, invite, role, acceptInvite, inviteLink) |
206
+ | `versions` | Versions management (create, get, list, latest, publish, snapshot, update) |
207
+ | `environments` | Environments management (list, activate, publish, upsert, update, delete) |
208
+ | `pipeline` | Pipeline management (promote) |
209
+
210
+ ---
211
+
212
+ ## File Management
213
+
214
+ ### `smbls files <subcommand>`
215
+ Upload, download, and manage project files.
216
+
217
+ | Subcommand | Description | Key Options |
218
+ |---|---|---|
219
+ | `list` | List project-linked files | `--remote`, `--uploads`, `--limit <n>`, `--search <q>` |
220
+ | `upload <paths...>` | Upload files to project | `--key`, `--visibility`, `--tags`, `--metadata`, `--mime`, `--overwrite` |
221
+ | `download` | Download a file | `--key`, `--out <path>`, `--remote` |
222
+ | `rm` | Remove file from project | `--key`, `--local-only`, `--force-remote` |
223
+
224
+ ---
225
+
226
+ ## AI Assistant
227
+
228
+ ### `smbls ask [question...]`
229
+ Chat with AI about your Symbols project.
230
+ - `--provider <provider>` — AI provider: claude, openai, gemini, ollama, symbols
231
+ - `--model <model>` — model name
232
+ - `--init` — configure AI settings and MCP
233
+
234
+ **Supported providers and models:**
235
+ | Provider | Models |
236
+ |---|---|
237
+ | Claude | claude-sonnet-4-6, claude-opus-4-6, claude-haiku-4-5-20251001 |
238
+ | OpenAI | gpt-4o, gpt-4o-mini, o3-mini |
239
+ | Gemini | gemini-2.5-pro, gemini-2.5-flash |
240
+ | Ollama | llama3.3, codellama, mistral, deepseek-coder-v2 (local) |
241
+
242
+ Config stored in `~/.smblsrc`. Environment variables: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`.
243
+
244
+ ---
245
+
246
+ ## Utilities
247
+
248
+ ### `smbls convert [src] [dest]`
249
+ Convert DOMQL components to other frameworks.
250
+ - `--react` — convert to React
251
+ - `--angular` — convert to Angular
252
+ - `--vue2` — convert to Vue 2
253
+ - `--vue3` — convert to Vue 3
254
+ - `-o, --only <components>` — only convert specific components (comma-separated)
255
+ - `-m, --merge <dir>` — recursive merge files into dest
256
+ - `-v, --verbose` — verbose mode
257
+
258
+ ### `smbls migrate`
259
+ Migrate a v2 Symbols project to v3.
260
+ - `--yes` — skip confirmation
261
+ - `--non-interactive` — disable all prompts
262
+
263
+ Renames `.symbols/` to `.symbols_local/`, `smbls/` to `symbols/`, creates missing `symbols/app.js`, rewrites `symbols/index.js` to v3 format.
264
+
265
+ ### `smbls validate [target]`
266
+ Validate DOMQL syntax in source files.
267
+ - Uses esbuild to check JS/TS/JSX/TSX syntax
268
+ - Reports violations, warnings, and compliance scores
269
+
270
+ ### `smbls clean`
271
+ Clean Symbols temporary files.
272
+
273
+ ### `smbls sdk [method] [args...]`
274
+ Proxy SDK service methods from the terminal.
275
+ - `-l, --list` — list all available SDK methods
276
+ - `-s, --service <name>` — filter methods by service name
277
+
278
+ ```bash
279
+ smbls sdk --list # List all methods
280
+ smbls sdk --list --service auth # Filter by service
281
+ smbls sdk getProjects # Call method
282
+ smbls sdk getProjectByKey '{"key":"myapp"}' # Call with arguments
283
+ ```
284
+
285
+ ### `smbls link-packages`
286
+ Link all smbls packages into the project.
287
+ - `-c, --capture` — capture and write all package names
288
+ - `-j, --join` — join all links into one command (default: true)
289
+
290
+ ### `smbls servers`
291
+ List and switch CLI servers (API base URLs).
292
+ - `-s, --select` — interactively select active server
293
+
294
+ ### `smbls completion [shell]`
295
+ Generate shell completion script.
296
+ - `--install` — print install instructions
297
+
298
+ ### `smbls github <subcommand>`
299
+ GitHub integration helpers.
300
+ - `connect` — connect GitHub repository
301
+ - `initActions` — initialize GitHub Actions workflow
302
+ - `sync` — sync with GitHub
303
+
304
+ ---
305
+
306
+ ## Configuration Files
307
+
308
+ ### `symbols.json` (project root)
309
+ Main project configuration:
310
+ - `owner` — Symbols username
311
+ - `key` — project identifier
312
+ - `dir` — symbols source directory
313
+ - `branch` — git branch (default: main)
314
+ - `entry` — bundler entry point
315
+ - `port` — dev server port
316
+ - `distDir` — build output directory
317
+ - `brenderDistDir` — brender output directory
318
+ - `brender` — enable pre-rendering
319
+ - `runtime` — node, bun, deno, or browser
320
+ - `bundler` — parcel, vite, etc.
321
+ - `packageManager` — npm, yarn, pnpm, bun
322
+ - `libraries` / `librariesDir` — shared library config
323
+ - `designSystem` — design system with buckets
324
+
325
+ ### `.symbols_local/config.json` (local)
326
+ Local machine configuration:
327
+ - `owner` — local username
328
+ - `branch` — active branch
329
+ - `projectKey` — linked project key
330
+ - `projectId` — platform project ID
331
+ - `apiBaseUrl` — API endpoint
332
+
333
+ ### `~/.smblsrc` (global)
334
+ Global credentials and AI configuration.
335
+
336
+ ---
337
+
338
+ ## Common Workflows
339
+
340
+ ### New project from scratch
341
+ ```bash
342
+ smbls create my-app
343
+ cd my-app
344
+ smbls start
345
+ ```
346
+
347
+ ### Add Symbols to existing project
348
+ ```bash
349
+ cd existing-project
350
+ smbls init
351
+ smbls install
352
+ smbls start
353
+ ```
354
+
355
+ ### Fetch, edit, push cycle
356
+ ```bash
357
+ smbls fetch # pull latest from platform
358
+ # ... edit components ...
359
+ smbls push -m "updated header"
360
+ ```
361
+
362
+ ### Deploy to production
363
+ ```bash
364
+ smbls build
365
+ smbls deploy --provider cloudflare
366
+ # or
367
+ smbls publish --env production
368
+ ```
369
+
370
+ ### Migrate v2 to v3
371
+ ```bash
372
+ smbls migrate --yes
373
+ smbls start
374
+ ```
@@ -0,0 +1,225 @@
1
+ # Common Mistakes — Wrong vs Correct DOMQL v3 Patterns
2
+
3
+ This is a zero-tolerance reference. Every pattern in the "Wrong" column is FORBIDDEN. The audit tool catches all of them. There is no concept of "known debt" — every violation must be fixed to 100%.
4
+
5
+ ---
6
+
7
+ ## 1. Colors — use design system tokens, never hex/rgb
8
+
9
+ ```js
10
+ // ❌ WRONG — raw hex values
11
+ color: '#202124', background: '#f1f3f4', borderColor: '#dadce0'
12
+
13
+ // ✅ CORRECT — named tokens from designSystem.color
14
+ color: 'text', background: 'headerBg', borderColor: 'border'
15
+ ```
16
+
17
+ ---
18
+
19
+ ## 2. CSS — flatten at root level, never use `style: {}` wrapper
20
+
21
+ ```js
22
+ // ❌ WRONG — CSS inside style: {} block
23
+ FileName: {
24
+ tag: 'input',
25
+ style: { fontSize: '16px', border: 'none', color: '#202124' }
26
+ }
27
+
28
+ // ✅ CORRECT — CSS flat as props
29
+ FileName: {
30
+ tag: 'input',
31
+ fontSize: 'A', border: 'none', color: 'text'
32
+ }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 3. Spacing — use design system tokens, never raw px
38
+
39
+ ```js
40
+ // ❌ WRONG — raw pixel values
41
+ padding: '4px 10px', height: '30px', width: '1px', gap: '4px'
42
+
43
+ // ✅ CORRECT — spacing tokens
44
+ padding: 'X Y', height: 'B', borderLeft: '1px solid border', gap: 'X'
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 4. Icons — use Icon component + `designSystem/icons`, never inline HTML
50
+
51
+ ```js
52
+ // ❌ WRONG — inline HTML strings
53
+ BtnBold: { extends: 'ToolbarBtn', html: '<b>B</b>' }
54
+ BtnColorRed: { html: '<span style="color:#d93025;font-weight:bold">A</span>' }
55
+
56
+ // ✅ CORRECT — Icon component with designSystem/icons
57
+ BtnBold: { extends: 'ToolbarBtn', Icon: { extends: 'Icon', icon: 'bold', width: 'A', height: 'A' } }
58
+ BtnColorRed: { extends: 'ToolbarBtn', color: 'danger', Icon: { extends: 'Icon', icon: 'colorA', width: 'A', height: 'A' } }
59
+
60
+ // designSystem/icons.js:
61
+ // bold: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="..."/></svg>'
62
+ // colorA: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="..."/></svg>'
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 5. Select options — use children + childExtends, never raw HTML
68
+
69
+ ```js
70
+ // ❌ WRONG — raw html string of option tags
71
+ FontSizeSelect: {
72
+ html: '<option value="12">12</option><option value="13" selected>13</option>...'
73
+ }
74
+
75
+ // ✅ CORRECT — declarative children with state
76
+ FontSizeSelect: {
77
+ children: [10, 11, 12, 13, 14, 16, 18, 20, 24, 28, 32].map(sz => ({
78
+ label: String(sz), value: String(sz)
79
+ })),
80
+ childrenAs: 'state',
81
+ childExtends: 'FontSizeOption',
82
+ }
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 6. Grids/tables — declarative DOMQL, never `document.createElement`
88
+
89
+ ```js
90
+ // ❌ WRONG — imperative DOM building
91
+ GridWrapper: {
92
+ onRender: (el) => {
93
+ const table = document.createElement('table')
94
+ const th = document.createElement('th')
95
+ th.textContent = colLabel(c)
96
+ headRow.appendChild(th)
97
+ // ... hundreds of lines of imperative DOM
98
+ document.getElementById(`cell-${r}-${c}`)?.querySelector('input')?.focus()
99
+ }
100
+ }
101
+
102
+ // ✅ CORRECT — fully declarative DOMQL
103
+ BodyRows: {
104
+ children: (el) => {
105
+ const rs = el.getRootState()
106
+ return rs.grid.map((row, r) => ({ cells: row.map((v, c) => ({ v, r, c })) }))
107
+ },
108
+ childrenAs: 'state',
109
+ childExtends: 'SpreadsheetRow',
110
+ }
111
+
112
+ SpreadsheetCell: {
113
+ CellInput: {
114
+ value: (el, s) => s.v,
115
+ onFocus: (e, el, s) => el.call('selectCell', { r: s.r, c: s.c }),
116
+ }
117
+ }
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 7. Dynamic text — reactive `text:` prop, never polling with `el.node.textContent`
123
+
124
+ ```js
125
+ // ❌ WRONG — setInterval polling with el.node.textContent
126
+ CellLabel: {
127
+ onRender: (el) => {
128
+ setInterval(() => {
129
+ el.node.textContent = colLabel(rs.sel.c) + (rs.sel.r + 1)
130
+ }, 50)
131
+ }
132
+ }
133
+
134
+ // ✅ CORRECT — reactive text prop
135
+ CellLabel: {
136
+ text: (el) => {
137
+ const rs = el.getRootState()
138
+ return rs ? el.call('colLabel', rs.sel.c) + (rs.sel.r + 1) : 'A1'
139
+ }
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 8. Input value — reactive `value:` prop, never polling with `el.node.value`
146
+
147
+ ```js
148
+ // ❌ WRONG — setInterval writing el.node.value
149
+ FormulaInput: {
150
+ onRender: (el) => {
151
+ setInterval(() => {
152
+ if (document.activeElement !== el.node) return
153
+ el.node.value = rs.formulaBarValue
154
+ }, 60)
155
+ }
156
+ }
157
+
158
+ // ✅ CORRECT — reactive value prop
159
+ FormulaInput: {
160
+ value: (el) => el.getRootState()?.formulaBarValue || '',
161
+ }
162
+ ```
163
+
164
+ ---
165
+
166
+ ## 9. State — use `s` directly with `childrenAs: 'state'`, never `el.parent.state`
167
+
168
+ ```js
169
+ // ❌ WRONG — parent state traversal
170
+ value: (el) => el.parent.state.v,
171
+ onFocus: (e, el) => el.call('selectCell', { r: el.parent.state.r, c: el.parent.state.c })
172
+
173
+ // ✅ CORRECT — s inherited automatically via childrenAs: 'state'
174
+ value: (el, s) => s.v,
175
+ onFocus: (e, el, s) => el.call('selectCell', { r: s.r, c: s.c })
176
+ ```
177
+
178
+ ---
179
+
180
+ ## 10. Event handlers — correct signature for root vs local state
181
+
182
+ ```js
183
+ // ❌ WRONG — s is local state, not root — breaks for global updates
184
+ onInput: (e, el, s) => s.update({ filename: e.target.value })
185
+
186
+ // ✅ CORRECT — el.getRootState() for global state, s for local inherited state
187
+ onInput: (e, el) => el.getRootState().update({ filename: e.target.value })
188
+ onBlur: (e, el, s) => el.call('commitEdit', { r: s.r, c: s.c, val: e.target.value })
189
+ ```
190
+
191
+ ---
192
+
193
+ ## 11. Rich text — DOMQL children with tokens, never inline `style=`
194
+
195
+ ```js
196
+ // ❌ WRONG — html string with inline style
197
+ PoweredBy: { html: 'Built with <strong style="color:#1a73e8">Symbols</strong>' }
198
+
199
+ // ✅ CORRECT — DOMQL children with token colors
200
+ PoweredBy: {
201
+ flow: 'x',
202
+ gap: 'X',
203
+ Prefix: { text: 'Built with' },
204
+ Sym: { tag: 'strong', color: 'accent', text: 'Symbols' },
205
+ Ver: { tag: 'span', text: ' · smbls@latest' },
206
+ }
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 12. Token alignment — aligned elements must share `fontSize`
212
+
213
+ Spacing tokens are em-based. Mixed `fontSize` on siblings causes the same token to resolve to different px values.
214
+
215
+ ```js
216
+ // ❌ WRONG — mixed fontSize, E resolves differently
217
+ ColHeaderCell: { fontSize: 'Z1', width: 'E', ... }
218
+ SpreadsheetCell: { fontSize: 'Z2', width: 'E', ... } // wider than header!
219
+
220
+ // ✅ CORRECT — all grid elements share the same fontSize
221
+ ColHeaderCell: { fontSize: 'Z1', width: 'E', ... }
222
+ SpreadsheetCell: { fontSize: 'Z1', width: 'E', ... }
223
+ RowNumberCell: { fontSize: 'Z1', width: 'C', ... }
224
+ CornerCell: { fontSize: 'Z1', width: 'C', ... }
225
+ ```
@@ -1341,17 +1341,9 @@ export const CircleButton = {
1341
1341
  ```js
1342
1342
  export const CircleProgress = {
1343
1343
  tag: 'progress',
1344
- attr: {
1345
- max: ({
1346
- props
1347
- }) => props.max,
1348
- progress: ({
1349
- props
1350
- }) => props.progress,
1351
- value: ({
1352
- props
1353
- }) => props.value,
1354
- },
1344
+ max: ({ props }) => props.max,
1345
+ progress: ({ props }) => props.progress,
1346
+ value: ({ props }) => props.value,
1355
1347
  boxSize: 'D D',
1356
1348
  value: 0.73,
1357
1349
  round: '100%',
@@ -2655,17 +2647,9 @@ export const Pills = {
2655
2647
  ```js
2656
2648
  export const Progress = {
2657
2649
  tag: 'progress',
2658
- attr: {
2659
- max: ({
2660
- props
2661
- }) => props.max,
2662
- progress: ({
2663
- props
2664
- }) => props.progress,
2665
- value: ({
2666
- props
2667
- }) => props.value,
2668
- },
2650
+ max: ({ props }) => props.max,
2651
+ progress: ({ props }) => props.progress,
2652
+ value: ({ props }) => props.value,
2669
2653
  height: 'X',
2670
2654
  minWidth: 'F3',
2671
2655
  round: 'Y',
@@ -176,7 +176,7 @@ onClick: (e, el, s) => {
176
176
 
177
177
  ## SPA Navigation — preventDefault Required
178
178
 
179
- When using `tag: 'a'` with `attr: { href: '/' }` AND an `onClick` handler, both the handler and the browser's default navigation fire. Always call `e.preventDefault()`.
179
+ When using `tag: 'a'` with `href: '/'` AND an `onClick` handler, both the handler and the browser's default navigation fire. Always call `e.preventDefault()`.
180
180
 
181
181
  ```js
182
182
  export const NavLink = {