@atelier-ui/create-workspace 0.0.11 → 0.0.12

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@atelier-ui/create-workspace",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Nx preset for Atelier UI workshop workspaces",
5
5
  "keywords": [
6
6
  "nx",
@@ -21,10 +21,10 @@
21
21
  "types": "./src/index.d.ts",
22
22
  "generators": "./generators.json",
23
23
  "dependencies": {
24
- "@nx/devkit": "22.6.1",
24
+ "@nx/devkit": "22.6.5",
25
25
  "tslib": "^2.3.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@nx/angular": ">=22.0.0"
29
29
  }
30
- }
30
+ }
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Design tokens for the LLM-optimized Angular component library.
3
+ * Import this stylesheet once at the application root to activate the token layer.
4
+ *
5
+ * Usage:
6
+ * @import '@atelier-ui/angular/styles/tokens.css';
7
+ */
8
+
9
+ :root {
10
+ /* Typography */
11
+ --ui-font-family: 'Montserrat', 'Inter', ui-sans-serif, system-ui, -apple-system,
12
+ BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
13
+ --ui-font-size-xs: 0.75rem;
14
+ --ui-font-size-sm: 0.875rem;
15
+ --ui-font-size-md: 1rem;
16
+ --ui-font-size-lg: 1.125rem;
17
+ --ui-font-size-xl: 1.25rem;
18
+ --ui-font-size-2xl: 1.5rem;
19
+ --ui-letter-spacing-tight: -0.01em;
20
+ --ui-letter-spacing-normal: 0;
21
+ --ui-letter-spacing-wide: 0.01em;
22
+ --ui-font-weight-normal: 400;
23
+ --ui-font-weight-medium: 500;
24
+ --ui-font-weight-semibold: 600;
25
+ --ui-line-height-tight: 1.25;
26
+ --ui-line-height-normal: 1.5;
27
+
28
+ /* Colors — Primary */
29
+ --ui-color-primary: #00bebe;
30
+ --ui-color-primary-hover: #009696;
31
+ --ui-color-primary-active: #007070;
32
+ --ui-color-primary-light: rgba(0, 190, 190, 0.08);
33
+
34
+ /* Colors — Secondary */
35
+ --ui-color-secondary: #64748b;
36
+ --ui-color-secondary-hover: #475569;
37
+ --ui-color-secondary-active: #334155;
38
+
39
+ /* Colors — Semantic */
40
+ --ui-color-danger: #ef4444;
41
+ --ui-color-danger-hover: #dc2626;
42
+ --ui-color-danger-active: #b91c1c;
43
+ --ui-color-success: #22c55e;
44
+ --ui-color-warning: #f59e0b;
45
+ --ui-color-info: #06b6d4;
46
+
47
+ /* Colors — Surfaces */
48
+ --ui-color-surface: #ffffff;
49
+ --ui-color-surface-raised: #fafafa;
50
+ --ui-color-surface-sunken: #f5f5f5;
51
+
52
+ /* Colors — Borders */
53
+ --ui-color-border: #e5e7eb;
54
+ --ui-color-border-hover: #d1d5db;
55
+
56
+ /* Colors — Text */
57
+ --ui-color-text: #0f172a;
58
+ --ui-color-text-muted: #64748b;
59
+ --ui-color-text-on-primary: #0f172a;
60
+ --ui-color-text-on-secondary: #ffffff;
61
+ --ui-color-text-on-danger: #ffffff;
62
+ --ui-color-text-on-success: #ffffff;
63
+ --ui-color-on-primary: #0f172a;
64
+
65
+ /* Colors — Brand palette */
66
+ --ui-color-brand-corporate: #00bebe;
67
+ --ui-color-brand-agile: #00d296;
68
+ --ui-color-brand-architecture: #009696;
69
+ --ui-color-brand-development: #00b4ff;
70
+ --ui-color-brand-petrol: #005064;
71
+ --ui-color-brand-ai: #b5e61c;
72
+ --ui-color-brand-light-blue: #00ebff;
73
+ --ui-color-brand-light-green: #a0fa50;
74
+ --ui-opacity-disabled: 0.5;
75
+
76
+ /* Border radius */
77
+ --ui-radius-sm: 0.375rem;
78
+ --ui-radius-md: 0.5rem;
79
+ --ui-radius-lg: 0.75rem;
80
+ --ui-radius-xl: 1rem;
81
+ --ui-radius-full: 9999px;
82
+
83
+ /* Spacing */
84
+ --ui-spacing-1: 0.25rem;
85
+ --ui-spacing-2: 0.5rem;
86
+ --ui-spacing-3: 0.75rem;
87
+ --ui-spacing-4: 1rem;
88
+ --ui-spacing-5: 1.25rem;
89
+ --ui-spacing-6: 1.5rem;
90
+ --ui-spacing-8: 2rem;
91
+ --ui-spacing-10: 2.5rem;
92
+ --ui-spacing-12: 3rem;
93
+ --ui-spacing-16: 4rem;
94
+
95
+ /* Shadows — dual-layer (ambient + key light) */
96
+ --ui-shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
97
+ --ui-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.06),
98
+ 0 1px 2px -1px rgba(0, 0, 0, 0.06);
99
+ --ui-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07),
100
+ 0 2px 4px -2px rgba(0, 0, 0, 0.05);
101
+ --ui-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08),
102
+ 0 4px 6px -4px rgba(0, 0, 0, 0.04);
103
+ --ui-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.08),
104
+ 0 8px 10px -6px rgba(0, 0, 0, 0.04);
105
+
106
+ /* Motion — custom easings for polished feel */
107
+ --ui-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
108
+ --ui-ease-in-out: cubic-bezier(0.45, 0, 0.55, 1);
109
+ --ui-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
110
+
111
+ --ui-duration-fast: 150ms;
112
+ --ui-duration-normal: 200ms;
113
+ --ui-duration-slow: 300ms;
114
+
115
+ --ui-transition-fast: var(--ui-duration-fast) var(--ui-ease-out);
116
+ --ui-transition-normal: var(--ui-duration-normal) var(--ui-ease-out);
117
+ --ui-transition-slow: var(--ui-duration-slow) var(--ui-ease-out);
118
+
119
+ /* Focus ring — double-ring for light & dark background compatibility */
120
+ --ui-focus-ring: 0 0 0 2px var(--ui-color-surface),
121
+ 0 0 0 4px var(--ui-color-primary);
122
+
123
+ /* Form controls */
124
+ --ui-color-input-bg: var(--ui-color-surface-sunken);
125
+ --ui-color-input-bg-focus: var(--ui-color-surface);
126
+ --ui-color-input-border: #d1d5db;
127
+ --ui-color-input-border-hover: #9ca3af;
128
+ --ui-color-input-border-focus: var(--ui-color-primary);
129
+ --ui-color-input-border-invalid: var(--ui-color-danger);
130
+ --ui-color-placeholder: #9ca3af;
131
+ --ui-color-error-text: var(--ui-color-danger);
132
+
133
+ /* Z-index scale */
134
+ --ui-z-base: 0;
135
+ --ui-z-dropdown: 100;
136
+ --ui-z-overlay: 200;
137
+ --ui-z-modal: 300;
138
+ --ui-z-toast: 400;
139
+ }
140
+
141
+ @media (prefers-color-scheme: dark) {
142
+ :root {
143
+ --ui-color-primary: #00d0d0;
144
+ --ui-color-primary-hover: #00bebe;
145
+ --ui-color-primary-active: #009696;
146
+ --ui-color-primary-light: rgba(0, 190, 190, 0.15);
147
+
148
+ --ui-color-secondary: #94a3b8;
149
+ --ui-color-secondary-hover: #cbd5e1;
150
+ --ui-color-secondary-active: #e2e8f0;
151
+
152
+ --ui-color-danger: #f87171;
153
+ --ui-color-danger-hover: #fca5a5;
154
+ --ui-color-danger-active: #fecaca;
155
+
156
+ --ui-color-success: #4ade80;
157
+ --ui-color-warning: #fbbf24;
158
+ --ui-color-info: #22d3ee;
159
+
160
+ --ui-color-surface: #28283c;
161
+ --ui-color-surface-raised: #2f2f45;
162
+ --ui-color-surface-sunken: #22222f;
163
+
164
+ --ui-color-border: #3a3a4f;
165
+ --ui-color-border-hover: #4a4a63;
166
+
167
+ --ui-color-text: #f1f5f9;
168
+ --ui-color-text-muted: #94a3b8;
169
+ --ui-color-on-primary: #0f172a;
170
+ --ui-color-text-on-secondary: #0f172a;
171
+
172
+ --ui-opacity-disabled: 0.65;
173
+
174
+ --ui-color-input-border: #4a4a63;
175
+ --ui-color-input-border-hover: #686880;
176
+ --ui-color-placeholder: #686880;
177
+
178
+ --ui-shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
179
+ --ui-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.3),
180
+ 0 1px 2px -1px rgba(0, 0, 0, 0.3);
181
+ --ui-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.35),
182
+ 0 2px 4px -2px rgba(0, 0, 0, 0.25);
183
+ --ui-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4),
184
+ 0 4px 6px -4px rgba(0, 0, 0, 0.2);
185
+ --ui-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.4),
186
+ 0 8px 10px -6px rgba(0, 0, 0, 0.2);
187
+ }
188
+ }
189
+
190
+ [data-theme="dark"] {
191
+ --ui-color-primary: #00d0d0;
192
+ --ui-color-primary-hover: #00bebe;
193
+ --ui-color-primary-active: #009696;
194
+ --ui-color-primary-light: rgba(0, 190, 190, 0.15);
195
+
196
+ --ui-color-secondary: #94a3b8;
197
+ --ui-color-secondary-hover: #cbd5e1;
198
+ --ui-color-secondary-active: #e2e8f0;
199
+
200
+ --ui-color-danger: #f87171;
201
+ --ui-color-danger-hover: #fca5a5;
202
+ --ui-color-danger-active: #fecaca;
203
+
204
+ --ui-color-success: #4ade80;
205
+ --ui-color-warning: #fbbf24;
206
+ --ui-color-info: #22d3ee;
207
+
208
+ --ui-color-surface: #28283c;
209
+ --ui-color-surface-raised: #2f2f45;
210
+ --ui-color-surface-sunken: #22222f;
211
+
212
+ --ui-color-border: #3a3a4f;
213
+ --ui-color-border-hover: #4a4a63;
214
+
215
+ --ui-color-text: #f1f5f9;
216
+ --ui-color-text-muted: #94a3b8;
217
+ --ui-color-on-primary: #0f172a;
218
+ --ui-color-text-on-secondary: #0f172a;
219
+
220
+ --ui-opacity-disabled: 0.65;
221
+
222
+ --ui-color-input-border: #4a4a63;
223
+ --ui-color-input-border-hover: #686880;
224
+ --ui-color-placeholder: #686880;
225
+
226
+ --ui-shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
227
+ --ui-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.3),
228
+ 0 1px 2px -1px rgba(0, 0, 0, 0.3);
229
+ --ui-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.35),
230
+ 0 2px 4px -2px rgba(0, 0, 0, 0.25);
231
+ --ui-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4),
232
+ 0 4px 6px -4px rgba(0, 0, 0, 0.2);
233
+ --ui-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.4),
234
+ 0 8px 10px -6px rgba(0, 0, 0, 0.2);
235
+ }
236
+
237
+ /* Explicit light theme — declared last so it wins over prefers-color-scheme: dark */
238
+ [data-theme="light"] {
239
+ --ui-color-primary: #00bebe;
240
+ --ui-color-primary-hover: #009696;
241
+ --ui-color-primary-active: #007070;
242
+ --ui-color-primary-light: rgba(0, 190, 190, 0.08);
243
+ --ui-color-secondary: #64748b;
244
+ --ui-color-secondary-hover: #475569;
245
+ --ui-color-secondary-active: #334155;
246
+ --ui-color-danger: #ef4444;
247
+ --ui-color-danger-hover: #dc2626;
248
+ --ui-color-danger-active: #b91c1c;
249
+ --ui-color-success: #22c55e;
250
+ --ui-color-warning: #f59e0b;
251
+ --ui-color-info: #06b6d4;
252
+ --ui-color-surface: #ffffff;
253
+ --ui-color-surface-raised: #fafafa;
254
+ --ui-color-surface-sunken: #f5f5f5;
255
+ --ui-color-border: #e5e7eb;
256
+ --ui-color-border-hover: #d1d5db;
257
+ --ui-color-text: #0f172a;
258
+ --ui-color-text-muted: #64748b;
259
+ --ui-color-on-primary: #0f172a;
260
+ --ui-color-input-border: #d1d5db;
261
+ --ui-color-input-border-hover: #9ca3af;
262
+ --ui-color-placeholder: #9ca3af;
263
+ --ui-shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
264
+ --ui-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.06), 0 1px 2px -1px rgba(0, 0, 0, 0.06);
265
+ --ui-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
266
+ --ui-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.04);
267
+ --ui-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 8px 10px -6px rgba(0, 0, 0, 0.04);
268
+ }
269
+
270
+ @media (prefers-reduced-motion: reduce) {
271
+ :root {
272
+ --ui-duration-fast: 0ms;
273
+ --ui-duration-normal: 0ms;
274
+ --ui-duration-slow: 0ms;
275
+ --ui-ease-spring: ease;
276
+ }
277
+ }
@@ -0,0 +1,323 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * preflight.mjs
4
+ *
5
+ * Pre-workshop self-check. Verifies the local environment is ready for the
6
+ * Atelier UI workshop (Figma + Claude Code + Storybook MCP).
7
+ *
8
+ * Run via: node tools/scripts/preflight.mjs
9
+ * (or npm run preflight)
10
+ *
11
+ * Exits non-zero if any hard check fails. Warnings do not block.
12
+ */
13
+
14
+ import { execSync, spawnSync } from 'node:child_process';
15
+ import { createServer } from 'node:net';
16
+ import { readFileSync, existsSync } from 'node:fs';
17
+ import { homedir } from 'node:os';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { dirname, join, resolve } from 'node:path';
20
+
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ const __dirname = dirname(__filename);
23
+ const ROOT = resolve(__dirname, '../..');
24
+
25
+ // ── Styling ──────────────────────────────────────────────────────────
26
+ const supportsColor = process.stdout.isTTY && process.env.NO_COLOR === undefined;
27
+ const c = (code, s) => (supportsColor ? `\x1b[${code}m${s}\x1b[0m` : s);
28
+ const red = (s) => c('31', s);
29
+ const green = (s) => c('32', s);
30
+ const yellow = (s) => c('33', s);
31
+ const dim = (s) => c('2', s);
32
+ const bold = (s) => c('1', s);
33
+
34
+ const OK = green('✓');
35
+ const FAIL = red('✗');
36
+ const WARN = yellow('⚠');
37
+
38
+ // ── Result accumulator ───────────────────────────────────────────────
39
+ const results = [];
40
+ function record(level, label, detail, fix) {
41
+ results.push({ level, label, detail, fix });
42
+ const icon = level === 'ok' ? OK : level === 'fail' ? FAIL : WARN;
43
+ const labelStr = level === 'fail' ? bold(label) : label;
44
+ console.log(` ${icon} ${labelStr}${detail ? dim(` — ${detail}`) : ''}`);
45
+ if (fix && level !== 'ok') {
46
+ console.log(` ${dim('→')} ${fix}`);
47
+ }
48
+ }
49
+ const ok = (label, detail) => record('ok', label, detail);
50
+ const fail = (label, detail, fix) => record('fail', label, detail, fix);
51
+ const warn = (label, detail, fix) => record('warn', label, detail, fix);
52
+
53
+ // ── Helpers ──────────────────────────────────────────────────────────
54
+ function which(cmd) {
55
+ const finder = process.platform === 'win32' ? 'where' : 'which';
56
+ const res = spawnSync(finder, [cmd], { encoding: 'utf8' });
57
+ if (res.status === 0 && res.stdout.trim()) return res.stdout.trim().split('\n')[0];
58
+ return null;
59
+ }
60
+
61
+ function parseMajorMinor(version) {
62
+ const match = /(\d+)\.(\d+)\.?(\d+)?/.exec(version);
63
+ if (!match) return null;
64
+ return { major: +match[1], minor: +match[2], patch: +(match[3] ?? 0) };
65
+ }
66
+
67
+ function isAtLeast(actual, required) {
68
+ if (!actual) return false;
69
+ if (actual.major !== required.major) return actual.major > required.major;
70
+ if (actual.minor !== required.minor) return actual.minor > required.minor;
71
+ return actual.patch >= required.patch;
72
+ }
73
+
74
+ async function httpReachable(url, timeoutMs = 5000) {
75
+ const controller = new AbortController();
76
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
77
+ try {
78
+ const res = await fetch(url, { method: 'GET', signal: controller.signal });
79
+ return { ok: true, status: res.status };
80
+ } catch (err) {
81
+ return { ok: false, error: err?.name === 'AbortError' ? 'timeout' : String(err?.message ?? err) };
82
+ } finally {
83
+ clearTimeout(timer);
84
+ }
85
+ }
86
+
87
+ function portFree(port) {
88
+ return new Promise((resolveP) => {
89
+ const server = createServer();
90
+ server.once('error', () => resolveP(false));
91
+ server.once('listening', () => {
92
+ server.close(() => resolveP(true));
93
+ });
94
+ server.listen(port, '127.0.0.1');
95
+ });
96
+ }
97
+
98
+ function loadMcpEndpoints() {
99
+ const mcpPath = resolve(ROOT, '.mcp.json');
100
+ if (!existsSync(mcpPath)) return [];
101
+ try {
102
+ const config = JSON.parse(readFileSync(mcpPath, 'utf8'));
103
+ const servers = config.mcpServers ?? {};
104
+ return Object.entries(servers)
105
+ .filter(([, v]) => v?.type === 'http' && typeof v?.url === 'string')
106
+ .map(([name, v]) => ({ name, url: v.url }));
107
+ } catch {
108
+ return [];
109
+ }
110
+ }
111
+
112
+ // ── Checks ───────────────────────────────────────────────────────────
113
+ function checkNode() {
114
+ const required = { major: 20, minor: 11, patch: 0 };
115
+ const actual = parseMajorMinor(process.version);
116
+ if (isAtLeast(actual, required)) {
117
+ ok('Node.js', process.version);
118
+ } else {
119
+ fail(
120
+ 'Node.js',
121
+ `found ${process.version}, need >= 20.11.0`,
122
+ 'Install via https://nodejs.org or use `nvm install 20 && nvm use 20`',
123
+ );
124
+ }
125
+ }
126
+
127
+ function checkNpm() {
128
+ const required = { major: 10, minor: 0, patch: 0 };
129
+ const path = which('npm');
130
+ if (!path) {
131
+ fail('npm', 'not found on PATH', 'npm ships with Node.js — reinstall Node if missing');
132
+ return;
133
+ }
134
+ try {
135
+ const version = execSync('npm --version', { encoding: 'utf8' }).trim();
136
+ const actual = parseMajorMinor(version);
137
+ if (isAtLeast(actual, required)) {
138
+ ok('npm', `v${version}`);
139
+ } else {
140
+ warn('npm', `found v${version}, recommend >= 10.0.0`, 'Run `npm install -g npm@latest`');
141
+ }
142
+ } catch (err) {
143
+ fail('npm', String(err?.message ?? err), 'Reinstall Node.js');
144
+ }
145
+ }
146
+
147
+ function checkGit() {
148
+ const path = which('git');
149
+ if (!path) {
150
+ fail('git', 'not found on PATH', 'Install from https://git-scm.com or `brew install git`');
151
+ return;
152
+ }
153
+ try {
154
+ const version = execSync('git --version', { encoding: 'utf8' }).trim();
155
+ ok('git', version);
156
+ } catch {
157
+ warn('git', 'installed but version check failed', 'Verify install with `git --version`');
158
+ }
159
+ }
160
+
161
+ function checkClaudeCli() {
162
+ const path = which('claude');
163
+ if (!path) {
164
+ fail(
165
+ 'Claude Code CLI',
166
+ 'not found on PATH',
167
+ 'Install: https://docs.claude.com/en/docs/claude-code/setup',
168
+ );
169
+ return;
170
+ }
171
+ try {
172
+ const version = execSync('claude --version', { encoding: 'utf8', timeout: 5000 }).trim();
173
+ ok('Claude Code CLI', version);
174
+ } catch {
175
+ warn('Claude Code CLI', 'installed but `claude --version` failed', 'Try `claude doctor`');
176
+ }
177
+ }
178
+
179
+ async function checkFigmaSetup() {
180
+ // 1. Desktop Bridge plugin manifest — the primary channel.
181
+ const manifestPath = join(homedir(), '.figma-console-mcp', 'plugin', 'manifest.json');
182
+ if (existsSync(manifestPath)) {
183
+ ok('Figma Desktop Bridge plugin', `manifest at ${manifestPath}`);
184
+ } else {
185
+ warn(
186
+ 'Figma Desktop Bridge plugin',
187
+ 'manifest not found',
188
+ 'Run `npx -y figma-console-mcp@latest --help` once, then Figma → Plugins → Development → Import plugin from manifest…',
189
+ );
190
+ }
191
+
192
+ // 2. Bridge WebSocket port range — at least one port must be usable.
193
+ const bridgePorts = [9223, 9224, 9225, 9226, 9227, 9228, 9229, 9230, 9231, 9232];
194
+ let freeCount = 0;
195
+ for (const p of bridgePorts) {
196
+ if (await portFree(p)) freeCount += 1;
197
+ }
198
+ if (freeCount === bridgePorts.length) {
199
+ ok('Bridge port range 9223–9232', 'all free (MCP will bind on first launch)');
200
+ } else if (freeCount > 0) {
201
+ ok('Bridge port range 9223–9232', `${freeCount}/10 free (bridge connection OK)`);
202
+ } else {
203
+ warn(
204
+ 'Bridge port range 9223–9232',
205
+ 'entire range in use',
206
+ 'Close unrelated processes holding these ports, or see /troubleshooting#figma-bridge-port-conflict',
207
+ );
208
+ }
209
+
210
+ // 3. REST token — optional, only affects metadata reads.
211
+ const token = process.env.FIGMA_ACCESS_TOKEN;
212
+ if (!token) {
213
+ warn(
214
+ 'FIGMA_ACCESS_TOKEN (optional)',
215
+ 'not set — REST reads disabled, plugin tools still work',
216
+ 'See https://atelier.pieper.io/figma-token if you need metadata reads',
217
+ );
218
+ return;
219
+ }
220
+ if (token.length < 20) {
221
+ warn(
222
+ 'FIGMA_ACCESS_TOKEN',
223
+ 'set but suspiciously short',
224
+ 'Regenerate at https://www.figma.com/developers/api#access-tokens',
225
+ );
226
+ return;
227
+ }
228
+ ok('FIGMA_ACCESS_TOKEN', `set (${token.length} chars, REST reads enabled)`);
229
+ }
230
+
231
+ async function checkMcpEndpoints() {
232
+ const endpoints = loadMcpEndpoints();
233
+ if (endpoints.length === 0) {
234
+ warn(
235
+ 'MCP endpoints',
236
+ 'none configured in .mcp.json',
237
+ 'Scaffold a workspace with `npx create-atelier-ui-workspace`',
238
+ );
239
+ return;
240
+ }
241
+ for (const { name, url } of endpoints) {
242
+ const res = await httpReachable(url);
243
+ if (res.ok && res.status < 500) {
244
+ ok(`MCP: ${name}`, `${url} (HTTP ${res.status})`);
245
+ } else if (res.ok) {
246
+ warn(`MCP: ${name}`, `${url} (HTTP ${res.status})`, 'Server reachable but returned 5xx — retry later');
247
+ } else {
248
+ fail(
249
+ `MCP: ${name}`,
250
+ `${url} unreachable (${res.error})`,
251
+ 'Check your network or proxy settings',
252
+ );
253
+ }
254
+ }
255
+ }
256
+
257
+ async function checkPorts() {
258
+ const ports = [4200, 4201, 4202, 6006];
259
+ for (const p of ports) {
260
+ const free = await portFree(p);
261
+ if (free) ok(`Port ${p}`, 'free');
262
+ else warn(`Port ${p}`, 'in use', `Run \`lsof -ti :${p} | xargs kill\` (macOS/Linux)`);
263
+ }
264
+ }
265
+
266
+ // ── Main ─────────────────────────────────────────────────────────────
267
+ function header(title) {
268
+ console.log('');
269
+ console.log(bold(title));
270
+ }
271
+
272
+ async function main() {
273
+ console.log('');
274
+ console.log(bold('Atelier UI Preflight'));
275
+ console.log(dim('Checking your environment for the workshop…'));
276
+
277
+ header('Runtime');
278
+ checkNode();
279
+ checkNpm();
280
+ checkGit();
281
+
282
+ header('Claude Code');
283
+ checkClaudeCli();
284
+
285
+ header('Figma');
286
+ await checkFigmaSetup();
287
+
288
+ header('MCP reachability');
289
+ await checkMcpEndpoints();
290
+
291
+ header('Local ports');
292
+ await checkPorts();
293
+
294
+ // Summary
295
+ const failures = results.filter((r) => r.level === 'fail').length;
296
+ const warnings = results.filter((r) => r.level === 'warn').length;
297
+ const passes = results.filter((r) => r.level === 'ok').length;
298
+
299
+ console.log('');
300
+ if (failures === 0) {
301
+ console.log(
302
+ green(`All hard checks passed`) + dim(` · ${passes} ok, ${warnings} warning(s)`),
303
+ );
304
+ if (warnings > 0) {
305
+ console.log(dim('Warnings are non-blocking — see https://atelier.pieper.io/troubleshooting'));
306
+ }
307
+ console.log('');
308
+ process.exit(0);
309
+ } else {
310
+ console.log(
311
+ red(`${failures} check(s) failed`) + dim(` · ${passes} ok, ${warnings} warning(s)`),
312
+ );
313
+ console.log(dim('Fix the items above, then re-run `npm run preflight`.'));
314
+ console.log(dim('Full troubleshooting guide: https://atelier.pieper.io/troubleshooting'));
315
+ console.log('');
316
+ process.exit(1);
317
+ }
318
+ }
319
+
320
+ main().catch((err) => {
321
+ console.error(red('Preflight crashed:'), err);
322
+ process.exit(2);
323
+ });
@@ -3,7 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.presetGenerator = presetGenerator;
4
4
  const tslib_1 = require("tslib");
5
5
  const devkit_1 = require("@nx/devkit");
6
- const SITE_URL = 'https://atelier-ui.netlify.app';
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ function readTemplate(relativePath) {
9
+ return (0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, 'files', relativePath), 'utf-8');
10
+ }
11
+ const SITE_URL = 'https://atelier.pieper.io';
7
12
  function presetGenerator(tree, options) {
8
13
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
9
14
  var _a, _b;
@@ -18,7 +23,6 @@ function presetGenerator(tree, options) {
18
23
  const appName = `workshop-${framework}`;
19
24
  if (framework === 'angular') {
20
25
  yield (0, devkit_1.ensurePackage)('@nx/angular', devkit_1.NX_VERSION);
21
- // eslint-disable-next-line @typescript-eslint/no-var-requires
22
26
  const { applicationGenerator: angularAppGenerator } = require('@nx/angular/generators');
23
27
  yield angularAppGenerator(tree, {
24
28
  name: appName,
@@ -61,10 +65,15 @@ function presetGenerator(tree, options) {
61
65
  });
62
66
  deps['@atelier-ui/vue'] = 'latest';
63
67
  }
64
- // Inject CSS tokens import into the app's global stylesheet
68
+ // Copy design tokens into the scaffolded app so attendees can edit them
69
+ // directly. They're not imported from the @atelier-ui/<fw> npm package
70
+ // because (a) those published packages don't ship tokens.css, and (b) a
71
+ // workshop attendee editing colors in node_modules is a bad experience.
72
+ tree.write(`${appName}/src/styles/tokens.css`, readTemplate('styles/tokens.css'));
73
+ // Prepend the tokens import to the app's global stylesheet
65
74
  const stylesPath = `${appName}/src/styles.css`;
66
75
  const existing = tree.exists(stylesPath) ? ((_b = tree.read(stylesPath, 'utf-8')) !== null && _b !== void 0 ? _b : '') : '';
67
- tree.write(stylesPath, `@import '@atelier-ui/${framework}/styles/tokens.css';\n\n${existing}`);
76
+ tree.write(stylesPath, `@import './styles/tokens.css';\n\n${existing}`);
68
77
  }
69
78
  // Write CLAUDE.md with framework-specific guidance
70
79
  const frameworkSections = frameworks
@@ -93,47 +102,95 @@ function presetGenerator(tree, options) {
93
102
  return '';
94
103
  })
95
104
  .join('\n\n');
105
+ const mcpSection = frameworks
106
+ .map((f) => `### \`storybook-${f}\` MCP
107
+ Before using any component:
108
+ 1. Call \`list-all-documentation\` to get valid component IDs
109
+ 2. Call \`get-documentation\` with the ID — never invent props
110
+ 3. Call \`get-documentation-for-story\` for a specific variant
111
+ 4. Do not use a component that is not in the docs`)
112
+ .join('\n\n');
96
113
  tree.write('CLAUDE.md', `# Atelier UI Workshop
97
114
 
98
- This workspace contains Atelier UI component library apps for hands-on AI development training.
115
+ This workspace uses Atelier UI for all UI components.
116
+ Full API reference: ${SITE_URL}/llms-full.txt
99
117
 
100
- ## MCP Tools — always use these before writing component code
118
+ ## MCP Servers
101
119
 
102
- The MCP servers are pre-configured in \`.mcp.json\` and connect automatically.
120
+ The servers are pre-configured in \`.mcp.json\` and connect automatically.
103
121
 
104
- | Tool | When to call it |
105
- |---|---|
106
- | \`get_component_docs(component)\` | Before using any component — returns exact props, types, defaults |
107
- | \`list_components()\` | To see all 22 available components grouped by category |
108
- | \`search_components(query)\` | When you know the intent ("form input") but not the component name |
109
- | \`get_stories(component)\` | To see real usage examples and variants |
110
- | \`get_theming_guide()\` | Before customising colors, spacing, or dark mode |
111
-
112
- **Rule:** call the MCP server first, then write code. Never guess prop names.
122
+ ${mcpSection}
113
123
 
114
124
  ## Component Libraries
115
125
 
116
126
  ${frameworkSections}
117
127
 
118
- ## Global styles
128
+ ## Design Tokens
129
+
130
+ All colors, spacing, and radii use CSS custom properties. Never use
131
+ hardcoded hex values or pixel sizes — always reference a token.
119
132
 
120
- CSS design tokens are imported in each app's \`src/styles.css\`.
121
- All \`--ui-*\` custom properties are available globally (colors, spacing, radius, typography, shadows).
133
+ Key tokens:
134
+ - Colors: --ui-color-primary, --ui-color-text, --ui-color-surface-raised, --ui-color-border
135
+ - Spacing: --ui-spacing-4 (1rem), --ui-spacing-6 (1.5rem), --ui-spacing-8 (2rem)
136
+ - Radius: --ui-radius-sm (0.375rem), --ui-radius-md (0.5rem), --ui-radius-lg (0.75rem)
137
+
138
+ ## Rules
139
+ - Prefer component props over custom CSS
140
+ - When custom styling is needed, use --ui-color-* and --ui-spacing-* tokens
141
+ - Do not install other UI component libraries alongside Atelier UI
142
+ - Do not add inline hex colors or hardcoded spacing values
122
143
 
123
144
  ## Apps
124
145
 
125
146
  ${frameworks.map((f) => `- \`workshop-${f}\` — run with \`npx nx serve workshop-${f}\``).join('\n')}
126
147
 
148
+ ## Troubleshooting
149
+
150
+ Run the preflight self-check to verify your environment:
151
+
152
+ \`\`\`bash
153
+ npm run preflight
154
+ \`\`\`
155
+
156
+ It checks Node, Claude CLI, \`FIGMA_ACCESS_TOKEN\`, MCP endpoint reachability, and port availability.
157
+ Full troubleshooting guide: ${SITE_URL}/troubleshooting
158
+ ${options.figmaMcp
159
+ ? `
160
+ ## Figma Setup
161
+
162
+ The \`figma-console\` MCP is enabled in \`.mcp.json\`. It needs the Figma Desktop Bridge
163
+ plugin installed in the Figma desktop app before the server can respond.
164
+
165
+ Setup guide: ${SITE_URL}/figma-token
166
+
167
+ A \`FIGMA_ACCESS_TOKEN\` is optional — only required for REST-backed reads (screenshots,
168
+ file exports). The Desktop Bridge covers creation and inspection without a token.
169
+ `
170
+ : ''}
127
171
  ## Reference
128
172
 
129
- - Component browser + exercises: ${SITE_URL}
173
+ - Component browser + docs: ${SITE_URL}
130
174
  - MCP Playground (inspect tool responses): ${SITE_URL}/mcp
175
+ - CLAUDE.md template: ${SITE_URL}/claude-md
131
176
  `);
132
177
  // Install selected @atelier-ui/* packages
133
178
  const installTask = (0, devkit_1.addDependenciesToPackageJson)(tree, deps, {});
134
179
  // Remove the preset package itself — create-nx-workspace adds it automatically
135
180
  // but it's a build-time tool and should not be in the workspace's dependencies
136
181
  const removePresetTask = (0, devkit_1.removeDependenciesFromPackageJson)(tree, ['@atelier-ui/create-workspace'], []);
182
+ // Write preflight script into the scaffolded workspace
183
+ tree.write('tools/scripts/preflight.mjs', readTemplate('tools/scripts/preflight.mjs'));
184
+ // Add `preflight` npm script to the generated workspace's package.json.
185
+ // create-nx-workspace guarantees package.json exists before the preset runs,
186
+ // so we write unconditionally — a missing package.json here should fail loudly,
187
+ // not silently drop the npm script the workshop docs tell attendees to run.
188
+ (0, devkit_1.updateJson)(tree, 'package.json', (pkg) => {
189
+ var _a;
190
+ pkg.scripts = (_a = pkg.scripts) !== null && _a !== void 0 ? _a : {};
191
+ pkg.scripts.preflight = 'node tools/scripts/preflight.mjs';
192
+ return pkg;
193
+ });
137
194
  // Write .claude/settings.json with MCP servers for selected frameworks
138
195
  const mcpServers = {
139
196
  'nx-mcp': {
@@ -148,6 +205,18 @@ ${frameworks.map((f) => `- \`workshop-${f}\` — run with \`npx nx serve worksho
148
205
  url: `${SITE_URL}/storybook-${framework}/mcp`,
149
206
  };
150
207
  }
208
+ if (options.figmaMcp) {
209
+ // Desktop Bridge plugin (installed separately). FIGMA_ACCESS_TOKEN is
210
+ // optional — only needed for REST-backed reads. See ${SITE_URL}/figma-token.
211
+ mcpServers['figma-console'] = {
212
+ command: 'npx',
213
+ args: ['-y', 'figma-console-mcp@latest'],
214
+ env: {
215
+ FIGMA_ACCESS_TOKEN: '${FIGMA_ACCESS_TOKEN:-}',
216
+ ENABLE_MCP_APPS: 'true',
217
+ },
218
+ };
219
+ }
151
220
  (0, devkit_1.writeJson)(tree, '.mcp.json', { mcpServers });
152
221
  // Write README
153
222
  tree.write('README.md', `# Atelier UI Workshop
@@ -1 +1 @@
1
- {"version":3,"file":"preset.js","sourceRoot":"","sources":["../../../../../../libs/create-workspace/src/generators/preset/preset.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"preset.js","sourceRoot":"","sources":["../../../../../../libs/create-workspace/src/generators/preset/preset.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export interface PresetGeneratorSchema {
2
2
  name: string;
3
3
  frameworks?: string;
4
+ figmaMcp?: boolean;
4
5
  }
@@ -16,6 +16,11 @@
16
16
  "type": "string",
17
17
  "description": "Comma-separated list of frameworks to scaffold: angular,react,vue",
18
18
  "default": "angular"
19
+ },
20
+ "figmaMcp": {
21
+ "type": "boolean",
22
+ "description": "Add the figma-console-mcp server (Figma Desktop Bridge) to .mcp.json",
23
+ "default": false
19
24
  }
20
25
  },
21
26
  "required": ["name"]