atomsystem 0.4.3 → 0.5.1

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/dist/cli.cjs CHANGED
@@ -1,23 +1,447 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var fs = require('fs');
5
- var path = require('path');
4
+ var fs2 = require('fs');
5
+ var path2 = require('path');
6
6
  var url = require('url');
7
+ var http = require('http');
7
8
 
8
9
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
11
 
11
- var fs__default = /*#__PURE__*/_interopDefault(fs);
12
- var path__default = /*#__PURE__*/_interopDefault(path);
12
+ var fs2__default = /*#__PURE__*/_interopDefault(fs2);
13
+ var path2__default = /*#__PURE__*/_interopDefault(path2);
14
+ var http__default = /*#__PURE__*/_interopDefault(http);
13
15
 
16
+ // src/tokenCompiler.ts
17
+ function compileTokensToCss(tokenJson) {
18
+ const cssVars = [];
19
+ function traverse(obj) {
20
+ if (!obj || typeof obj !== "object") return;
21
+ if (obj.variable && obj.$value !== void 0) {
22
+ cssVars.push(` ${obj.variable}: ${obj.$value};`);
23
+ return;
24
+ }
25
+ for (const key of Object.keys(obj)) {
26
+ if (key.startsWith("$")) continue;
27
+ traverse(obj[key]);
28
+ }
29
+ }
30
+ traverse(tokenJson);
31
+ return `:root {
32
+ ${cssVars.join("\n")}
33
+ }
34
+ `;
35
+ }
36
+
37
+ // src/studioServer.ts
38
+ function startLocalTokenStudio(options = {}) {
39
+ const port = options.port || 4e3;
40
+ const cwd = options.cwd || process.cwd();
41
+ const tokenJsonPath = path2__default.default.join(cwd, "tokens", "token.json");
42
+ const cssPath = path2__default.default.join(cwd, "css", "atom-ui.css");
43
+ path2__default.default.join(cwd, "atom.design.md");
44
+ const server = http__default.default.createServer((req, res) => {
45
+ res.setHeader("Access-Control-Allow-Origin", "*");
46
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
47
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
48
+ if (req.method === "OPTIONS") {
49
+ res.writeHead(200);
50
+ res.end();
51
+ return;
52
+ }
53
+ const url = new URL(req.url || "/", `http://localhost:${port}`);
54
+ if (url.pathname === "/api/tokens" && req.method === "GET") {
55
+ let data = {};
56
+ if (fs2__default.default.existsSync(tokenJsonPath)) {
57
+ try {
58
+ data = JSON.parse(fs2__default.default.readFileSync(tokenJsonPath, "utf-8"));
59
+ } catch (e) {
60
+ data = { error: "Failed to parse tokens/token.json" };
61
+ }
62
+ }
63
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
64
+ res.end(JSON.stringify(data));
65
+ return;
66
+ }
67
+ if (url.pathname === "/api/tokens" && req.method === "POST") {
68
+ let body = "";
69
+ req.on("data", (chunk) => {
70
+ body += chunk;
71
+ });
72
+ req.on("end", () => {
73
+ try {
74
+ const newTokens = JSON.parse(body);
75
+ const tokensDir = path2__default.default.dirname(tokenJsonPath);
76
+ if (!fs2__default.default.existsSync(tokensDir)) fs2__default.default.mkdirSync(tokensDir, { recursive: true });
77
+ fs2__default.default.writeFileSync(tokenJsonPath, JSON.stringify(newTokens, null, 2), "utf-8");
78
+ const compiledCss = compileTokensToCss(newTokens);
79
+ const cssDir = path2__default.default.dirname(cssPath);
80
+ if (!fs2__default.default.existsSync(cssDir)) fs2__default.default.mkdirSync(cssDir, { recursive: true });
81
+ fs2__default.default.writeFileSync(cssPath, compiledCss, "utf-8");
82
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
83
+ res.end(JSON.stringify({ success: true, message: "Tokens and CSS compiled successfully!" }));
84
+ } catch (err) {
85
+ res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
86
+ res.end(JSON.stringify({ success: false, error: err.message }));
87
+ }
88
+ });
89
+ return;
90
+ }
91
+ if (url.pathname === "/" || url.pathname === "/index.html") {
92
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
93
+ res.end(getStudioHtml());
94
+ return;
95
+ }
96
+ res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
97
+ res.end("Not Found");
98
+ });
99
+ server.listen(port, () => {
100
+ console.log(`
101
+ \u{1F3A8} AtomSystem Local Token Studio running at:`);
102
+ console.log(` \u{1F449} http://localhost:${port}
103
+ `);
104
+ console.log(` Tokens file: ${path2__default.default.relative(cwd, tokenJsonPath)}`);
105
+ console.log(` Compiled CSS: ${path2__default.default.relative(cwd, cssPath)}`);
106
+ console.log(`
107
+ Press Ctrl+C to stop the studio server.
108
+ `);
109
+ });
110
+ return server;
111
+ }
112
+ function getStudioHtml() {
113
+ return `<!DOCTYPE html>
114
+ <html lang="ko">
115
+ <head>
116
+ <meta charset="UTF-8">
117
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
118
+ <title>AtomSystem Local Token Studio</title>
119
+ <style>
120
+ :root {
121
+ --bg: #0a0a0a;
122
+ --card-bg: #141414;
123
+ --border: #262626;
124
+ --text: #ededed;
125
+ --muted: #888888;
126
+ --accent: #3182f6;
127
+ --radius: 8px;
128
+ }
129
+ * { box-sizing: border-box; margin: 0; padding: 0; }
130
+ body {
131
+ background: var(--bg);
132
+ color: var(--text);
133
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Pretendard, sans-serif;
134
+ padding: 32px 20px;
135
+ line-height: 1.5;
136
+ }
137
+ .container { max-width: 1100px; margin: 0 auto; }
138
+ header {
139
+ display: flex;
140
+ justify-content: space-between;
141
+ align-items: flex-end;
142
+ padding-bottom: 24px;
143
+ border-bottom: 1px solid var(--border);
144
+ margin-bottom: 32px;
145
+ }
146
+ h1 { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
147
+ p.desc { font-size: 13px; color: var(--muted); margin-top: 4px; }
148
+ .badge {
149
+ font-size: 11px;
150
+ font-family: monospace;
151
+ padding: 3px 8px;
152
+ background: #1a1a1a;
153
+ border: 1px solid var(--border);
154
+ border-radius: 4px;
155
+ color: var(--muted);
156
+ }
157
+ .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
158
+ @media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
159
+ .card {
160
+ background: var(--card-bg);
161
+ border: 1px solid var(--border);
162
+ border-radius: var(--radius);
163
+ padding: 20px;
164
+ }
165
+ h2 { font-size: 15px; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; }
166
+ .field { margin-bottom: 16px; }
167
+ label { display: block; font-size: 12px; font-weight: 500; margin-bottom: 6px; color: var(--text); }
168
+ .meta { font-size: 11px; color: var(--muted); font-family: monospace; margin-top: 4px; }
169
+ .input-row { display: flex; gap: 8px; align-items: center; }
170
+ input[type="text"], select {
171
+ flex: 1;
172
+ background: #1e1e1e;
173
+ border: 1px solid var(--border);
174
+ color: var(--text);
175
+ padding: 8px 12px;
176
+ font-size: 13px;
177
+ border-radius: 6px;
178
+ outline: none;
179
+ }
180
+ input[type="color"] {
181
+ -webkit-appearance: none;
182
+ border: 1px solid var(--border);
183
+ width: 38px;
184
+ height: 38px;
185
+ border-radius: 6px;
186
+ background: none;
187
+ cursor: pointer;
188
+ padding: 2px;
189
+ }
190
+ .btn-save {
191
+ background: var(--text);
192
+ color: var(--bg);
193
+ border: none;
194
+ padding: 10px 20px;
195
+ font-size: 13px;
196
+ font-weight: 600;
197
+ border-radius: 6px;
198
+ cursor: pointer;
199
+ transition: opacity 0.2s;
200
+ }
201
+ .btn-save:hover { opacity: 0.9; }
202
+ .preview-box {
203
+ border: 1px solid var(--border);
204
+ border-radius: 8px;
205
+ padding: 20px;
206
+ background: #0f0f0f;
207
+ display: flex;
208
+ flex-direction: column;
209
+ gap: 12px;
210
+ }
211
+ .preview-btn {
212
+ padding: 10px 18px;
213
+ border-radius: var(--sample-radius, 8px);
214
+ background: var(--sample-primary, #3182f6);
215
+ color: #ffffff;
216
+ border: none;
217
+ font-size: 13px;
218
+ font-weight: 600;
219
+ cursor: pointer;
220
+ display: inline-flex;
221
+ align-items: center;
222
+ justify-content: center;
223
+ gap: 6px;
224
+ }
225
+ .preview-card {
226
+ padding: 16px;
227
+ border-radius: var(--sample-radius, 8px);
228
+ background: var(--sample-surface, #18181b);
229
+ border: 1px solid var(--border);
230
+ color: var(--text);
231
+ font-size: 13px;
232
+ }
233
+ .toast {
234
+ position: fixed;
235
+ bottom: 24px;
236
+ right: 24px;
237
+ background: #10b981;
238
+ color: #000;
239
+ padding: 10px 18px;
240
+ border-radius: 6px;
241
+ font-size: 13px;
242
+ font-weight: 600;
243
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5);
244
+ display: none;
245
+ }
246
+ </style>
247
+ </head>
248
+ <body>
249
+ <div class="container">
250
+ <header>
251
+ <div>
252
+ <div class="badge" style="margin-bottom: 8px; display: inline-block;">W3C DTCG Zero-Runtime</div>
253
+ <h1>AtomSystem Local Token Studio</h1>
254
+ <p class="desc">\uB85C\uCEEC \uD658\uACBD(tokens/token.json)\uC758 \uD1A0\uD070\uC744 GUI\uB85C \uC9C1\uC811 \uC218\uC815\uD558\uACE0 \uC2E4\uC2DC\uAC04\uC73C\uB85C css/atom-ui.css\uB85C \uC7AC\uCEF4\uD30C\uC77C\uD569\uB2C8\uB2E4.</p>
255
+ </div>
256
+ <button class="btn-save" onclick="saveTokens()">\uC800\uC7A5 \uBC0F CSS \uC7AC\uCEF4\uD30C\uC77C</button>
257
+ </header>
258
+
259
+ <div class="grid">
260
+ <!-- 1. Color Tokens -->
261
+ <div class="card">
262
+ <h2>\u{1F3A8} \uC2DC\uB9E8\uD2F1 \uBE0C\uB79C\uB4DC & \uC11C\uD53C\uC2A4 \uD1A0\uD070</h2>
263
+
264
+ <div class="field">
265
+ <label>\uBE0C\uB79C\uB4DC \uB300\uD45C \uC0C9\uC0C1 (Primary Color)</label>
266
+ <div class="input-row">
267
+ <input type="color" id="picker-primary" oninput="onColorChange('primary', this.value)">
268
+ <input type="text" id="val-primary" oninput="onColorChange('primary', this.value)">
269
+ </div>
270
+ <div class="meta">var(--atom-color-primary)</div>
271
+ </div>
272
+
273
+ <div class="field">
274
+ <label>\uD638\uBC84 \uC0C1\uD0DC \uC0C9\uC0C1 (Primary Hover)</label>
275
+ <div class="input-row">
276
+ <input type="color" id="picker-primary-hover" oninput="onColorChange('primary-hover', this.value)">
277
+ <input type="text" id="val-primary-hover" oninput="onColorChange('primary-hover', this.value)">
278
+ </div>
279
+ <div class="meta">var(--atom-color-primary-hover)</div>
280
+ </div>
281
+
282
+ <div class="field">
283
+ <label>\uC11C\uD53C\uC2A4 \uBC30\uACBD (Surface Background)</label>
284
+ <div class="input-row">
285
+ <input type="color" id="picker-bg-surface" oninput="onColorChange('bg-surface', this.value)">
286
+ <input type="text" id="val-bg-surface" oninput="onColorChange('bg-surface', this.value)">
287
+ </div>
288
+ <div class="meta">var(--atom-bg-surface)</div>
289
+ </div>
290
+
291
+ <div class="field">
292
+ <label>\uAE30\uBCF8 \uBAA8\uC11C\uB9AC \uACE1\uB960 (Border Radius)</label>
293
+ <select id="val-radius" onchange="onRadiusChange(this.value)">
294
+ <option value="4px">4px (Sharp Minimal)</option>
295
+ <option value="6px">6px (Swiss Modern)</option>
296
+ <option value="8px">8px (Standard Clean)</option>
297
+ <option value="12px">12px (Rounded Friendly)</option>
298
+ <option value="16px">16px (Toss Soft)</option>
299
+ </select>
300
+ <div class="meta">var(--atom-radius-md)</div>
301
+ </div>
302
+ </div>
303
+
304
+ <!-- 2. Live Previewer -->
305
+ <div class="card">
306
+ <h2>\u26A1 \uC2E4\uC2DC\uAC04 \uD1A0\uD070 \uBC18\uC601 \uD504\uB9AC\uBDF0</h2>
307
+ <div class="preview-box" id="preview-box">
308
+ <div class="preview-card" id="sample-card">
309
+ <div style="font-weight: 600; margin-bottom: 4px;">\uB300\uC2DC\uBCF4\uB4DC \uC704\uC82F \uCEF4\uD3EC\uB10C\uD2B8</div>
310
+ <div style="color: var(--muted); font-size: 12px; margin-bottom: 14px;">
311
+ \uD1A0\uD070 \uBCC0\uACBD \uC2DC \uC2E4\uC2DC\uAC04\uC73C\uB85C \uB514\uC790\uC778\uC774 \uBC18\uC601\uB418\uBA70 \uC989\uC2DC CSS \uD30C\uC77C\uC5D0 \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4.
312
+ </div>
313
+ <button class="preview-btn" id="sample-btn">\uD655\uC778 \uBC0F \uC2B9\uC778</button>
314
+ </div>
315
+
316
+ <div style="font-size: 11px; font-family: monospace; color: var(--muted); background: #161616; padding: 12px; border-radius: 6px; border: 1px solid var(--border);">
317
+ <div>// \uCEF4\uD30C\uC77C \uB300\uC0C1 \uD30C\uC77C</div>
318
+ <div style="color: #60a5fa; margin-top: 4px;">tokens/token.json (W3C DTCG)</div>
319
+ <div style="color: #34d399; margin-top: 2px;">css/atom-ui.css (0KB Pure CSS)</div>
320
+ </div>
321
+ </div>
322
+ </div>
323
+ </div>
324
+ </div>
325
+
326
+ <div id="toast" class="toast">\u2713 \uD1A0\uD070 \uBC0F CSS\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC7AC\uCEF4\uD30C\uC77C\uB418\uC5C8\uC2B5\uB2C8\uB2E4!</div>
327
+
328
+ <script>
329
+ let currentTokens = {};
330
+
331
+ async function loadTokens() {
332
+ try {
333
+ const res = await fetch('/api/tokens');
334
+ currentTokens = await res.json();
335
+ populateFields();
336
+ updatePreview();
337
+ } catch (e) {
338
+ console.error('Failed to fetch tokens', e);
339
+ }
340
+ }
341
+
342
+ function populateFields() {
343
+ const primary = currentTokens?.color?.brand?.['color-primary']?.$value || '#3182f6';
344
+ const hover = currentTokens?.color?.brand?.['color-primary-hover']?.$value || '#1b64da';
345
+ const surface = currentTokens?.color?.surface?.['bg-surface']?.$value || '#18181b';
346
+ const radius = currentTokens?.borderRadius?.md?.$value || '8px';
347
+
348
+ document.getElementById('picker-primary').value = primary.startsWith('#') ? primary : '#3182f6';
349
+ document.getElementById('val-primary').value = primary;
350
+
351
+ document.getElementById('picker-primary-hover').value = hover.startsWith('#') ? hover : '#1b64da';
352
+ document.getElementById('val-primary-hover').value = hover;
353
+
354
+ document.getElementById('picker-bg-surface').value = surface.startsWith('#') ? surface : '#18181b';
355
+ document.getElementById('val-bg-surface').value = surface;
356
+
357
+ document.getElementById('val-radius').value = radius;
358
+ }
359
+
360
+ function onColorChange(key, val) {
361
+ if (!currentTokens.color) currentTokens.color = {};
362
+ if (key === 'primary') {
363
+ document.getElementById('picker-primary').value = val.startsWith('#') ? val : '#3182f6';
364
+ document.getElementById('val-primary').value = val;
365
+ if (!currentTokens.color.brand) currentTokens.color.brand = {};
366
+ if (!currentTokens.color.brand['color-primary']) currentTokens.color.brand['color-primary'] = { variable: '--atom-color-primary' };
367
+ currentTokens.color.brand['color-primary'].$value = val;
368
+ }
369
+ if (key === 'primary-hover') {
370
+ document.getElementById('picker-primary-hover').value = val.startsWith('#') ? val : '#1b64da';
371
+ document.getElementById('val-primary-hover').value = val;
372
+ if (!currentTokens.color.brand) currentTokens.color.brand = {};
373
+ if (!currentTokens.color.brand['color-primary-hover']) currentTokens.color.brand['color-primary-hover'] = { variable: '--atom-color-primary-hover' };
374
+ currentTokens.color.brand['color-primary-hover'].$value = val;
375
+ }
376
+ if (key === 'bg-surface') {
377
+ document.getElementById('picker-bg-surface').value = val.startsWith('#') ? val : '#18181b';
378
+ document.getElementById('val-bg-surface').value = val;
379
+ if (!currentTokens.color.surface) currentTokens.color.surface = {};
380
+ if (!currentTokens.color.surface['bg-surface']) currentTokens.color.surface['bg-surface'] = { variable: '--atom-bg-surface' };
381
+ currentTokens.color.surface['bg-surface'].$value = val;
382
+ }
383
+ updatePreview();
384
+ }
385
+
386
+ function onRadiusChange(val) {
387
+ if (!currentTokens.borderRadius) currentTokens.borderRadius = {};
388
+ if (!currentTokens.borderRadius.md) currentTokens.borderRadius.md = { variable: '--atom-radius-md' };
389
+ currentTokens.borderRadius.md.$value = val;
390
+ updatePreview();
391
+ }
392
+
393
+ function updatePreview() {
394
+ const primary = document.getElementById('val-primary').value;
395
+ const surface = document.getElementById('val-bg-surface').value;
396
+ const radius = document.getElementById('val-radius').value;
397
+
398
+ const btn = document.getElementById('sample-btn');
399
+ const card = document.getElementById('sample-card');
400
+
401
+ btn.style.backgroundColor = primary;
402
+ btn.style.borderRadius = radius;
403
+ card.style.backgroundColor = surface;
404
+ card.style.borderRadius = radius;
405
+ }
406
+
407
+ async function saveTokens() {
408
+ try {
409
+ const res = await fetch('/api/tokens', {
410
+ method: 'POST',
411
+ headers: { 'Content-Type': 'application/json' },
412
+ body: JSON.stringify(currentTokens)
413
+ });
414
+ const result = await res.json();
415
+ if (result.success) {
416
+ showToast();
417
+ } else {
418
+ alert('\uC800\uC7A5 \uC2E4\uD328: ' + result.error);
419
+ }
420
+ } catch (e) {
421
+ alert('\uC11C\uBC84 \uD1B5\uC2E0 \uC624\uB958: ' + e.message);
422
+ }
423
+ }
424
+
425
+ function showToast() {
426
+ const toast = document.getElementById('toast');
427
+ toast.style.display = 'block';
428
+ setTimeout(() => { toast.style.display = 'none'; }, 2500);
429
+ }
430
+
431
+ loadTokens();
432
+ </script>
433
+ </body>
434
+ </html>`;
435
+ }
436
+
437
+ // src/cli.ts
14
438
  function getPkgRoot() {
15
439
  try {
16
440
  if (typeof __dirname !== "undefined") {
17
- return path__default.default.resolve(__dirname, "..");
441
+ return path2__default.default.resolve(__dirname, "..");
18
442
  }
19
443
  const currentFile = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
20
- return path__default.default.resolve(path__default.default.dirname(currentFile), "..");
444
+ return path2__default.default.resolve(path2__default.default.dirname(currentFile), "..");
21
445
  } catch {
22
446
  return process.cwd();
23
447
  }
@@ -25,43 +449,190 @@ function getPkgRoot() {
25
449
  var PKG_ROOT = getPkgRoot();
26
450
  var args = process.argv.slice(2);
27
451
  var command = args[0] || "help";
452
+ var targetName = args[1];
28
453
  function copyFileSafe(src, dest, label) {
29
- const targetDir = path__default.default.dirname(dest);
30
- if (!fs__default.default.existsSync(targetDir)) {
31
- fs__default.default.mkdirSync(targetDir, { recursive: true });
454
+ const targetDir = path2__default.default.dirname(dest);
455
+ if (!fs2__default.default.existsSync(targetDir)) {
456
+ fs2__default.default.mkdirSync(targetDir, { recursive: true });
32
457
  }
33
- fs__default.default.copyFileSync(src, dest);
34
- console.log(` \u2713 Created ${label} -> ${path__default.default.relative(process.cwd(), dest)}`);
458
+ fs2__default.default.copyFileSync(src, dest);
459
+ console.log(` \u2713 ${label} -> ${path2__default.default.relative(process.cwd(), dest)}`);
35
460
  }
36
461
  function handleInit() {
37
462
  const cwd = process.cwd();
38
- console.log("\n\u{1F680} Initializing AtomSystem in your project...\n");
39
- const srcSkill = path__default.default.join(PKG_ROOT, "skills", "atomsystem.skill.md");
40
- const destSkill = path__default.default.join(cwd, ".agents", "skills", "atomsystem", "SKILL.md");
41
- if (fs__default.default.existsSync(srcSkill)) {
42
- copyFileSafe(srcSkill, destSkill, "AI Skill (.agents/skills/atomsystem/SKILL.md)");
463
+ console.log("\n\u{1F680} Initializing AtomSystem Universal Design System...\n");
464
+ const srcAgentGuide = path2__default.default.join(PKG_ROOT, "presets", "agents.guide.md");
465
+ if (fs2__default.default.existsSync(srcAgentGuide)) {
466
+ copyFileSafe(srcAgentGuide, path2__default.default.join(cwd, "AGENTS.md"), "Universal AI Guide (AGENTS.md)");
467
+ copyFileSafe(srcAgentGuide, path2__default.default.join(cwd, "CLAUDE.md"), "Claude Code Guidelines (CLAUDE.md)");
468
+ copyFileSafe(srcAgentGuide, path2__default.default.join(cwd, ".cursorrules"), "Cursor Rules (.cursorrules)");
469
+ }
470
+ const srcSkill = path2__default.default.join(PKG_ROOT, "skills", "atomsystem.skill.md");
471
+ if (fs2__default.default.existsSync(srcSkill)) {
472
+ copyFileSafe(srcSkill, path2__default.default.join(cwd, ".agents", "skills", "atomsystem", "SKILL.md"), "Agent Skill (.agents/skills/atomsystem/SKILL.md)");
473
+ }
474
+ const specs = [
475
+ { src: path2__default.default.join(PKG_ROOT, "presets", "default.design.md"), dest: path2__default.default.join(cwd, "atom.design.md"), label: "Design Tokens (atom.design.md)" },
476
+ { src: path2__default.default.join(PKG_ROOT, "presets", "components.md"), dest: path2__default.default.join(cwd, "atom.components.md"), label: "Components Spec (atom.components.md)" },
477
+ { src: path2__default.default.join(PKG_ROOT, "presets", "blocks.md"), dest: path2__default.default.join(cwd, "atom.blocks.md"), label: "Design Blocks Spec (atom.blocks.md)" },
478
+ { src: path2__default.default.join(PKG_ROOT, "presets", "uxPattern.md"), dest: path2__default.default.join(cwd, "atom.uxPattern.md"), label: "UX Patterns (atom.uxPattern.md)" }
479
+ ];
480
+ specs.forEach((s) => {
481
+ if (fs2__default.default.existsSync(s.src)) {
482
+ copyFileSafe(s.src, s.dest, s.label);
483
+ }
484
+ });
485
+ const srcToken = path2__default.default.join(PKG_ROOT, "tokens", "token.json");
486
+ if (fs2__default.default.existsSync(srcToken)) {
487
+ copyFileSafe(srcToken, path2__default.default.join(cwd, "tokens", "token.json"), "W3C DTCG Token JSON (tokens/token.json)");
488
+ }
489
+ const srcCss = path2__default.default.join(PKG_ROOT, "css", "atom-ui.css");
490
+ if (fs2__default.default.existsSync(srcCss)) {
491
+ copyFileSafe(srcCss, path2__default.default.join(cwd, "css", "atom-ui.css"), "Zero-Runtime Semantic CSS (css/atom-ui.css)");
492
+ }
493
+ console.log("\n\u2728 AtomSystem initialization completed successfully!");
494
+ console.log("\n\u{1F3A8} Local Token Studio Available:");
495
+ console.log(' Run "npx atomsystem studio" to launch the local web customizer GUI.');
496
+ console.log(" You can visually edit tokens and immediately recompile css/atom-ui.css.");
497
+ console.log("\n\u{1F4CC} How AI Coding Works Now:");
498
+ console.log(" Any AI assistant (Claude Code, Cursor, Copilot, Antigravity) will now");
499
+ console.log(" AUTOMATICALLY detect the design tokens, components, and UX patterns.");
500
+ console.log("\n\u{1F4CC} You can now ask your AI:");
501
+ console.log(' "\uB300\uC2DC\uBCF4\uB4DC \uD654\uBA74\uC5D0 \uC2E4\uC2DC\uAC04 \uCC28\uD2B8\uC640 \uAC00\uACA9 \uC815\uCC45 \uBE14\uB85D\uC744 \uB808\uACE0\uCC98\uB7FC \uC870\uB9BD\uD574\uC918."');
502
+ console.log(' "atom.design.md\uC758 \uC0C9\uC0C1 \uD1A0\uD070\uC744 \uBC14\uD0D5\uC73C\uB85C \uACB0\uC81C \uD655\uC778 \uBAA8\uB2EC\uC744 \uB9CC\uB4E4\uC5B4\uC918."\n');
503
+ }
504
+ var COMPONENT_MAP = {
505
+ button: "Button.tsx",
506
+ card: "Card.tsx",
507
+ badge: "Badge.tsx",
508
+ input: "Input.tsx",
509
+ table: "Table.tsx",
510
+ tabs: "Tabs.tsx",
511
+ switch: "Switch.tsx",
512
+ modal: "Modal.tsx",
513
+ container: "Container.tsx",
514
+ layout: "Layout.tsx"
515
+ };
516
+ var BLOCK_MAP = {
517
+ "realtime-chart": { file: "RealtimeChartBlock.tsx", deps: ["card", "button", "badge"] },
518
+ "interactive-chat": { file: "InteractiveChatBlock.tsx", deps: ["card", "input", "button", "badge"] },
519
+ "pricing-table": { file: "PricingPlanBlock.tsx", deps: ["card", "button", "badge"] },
520
+ "card-list": { file: "CardListBlock.tsx", deps: ["card", "input", "button", "badge"] },
521
+ "interactive-slider": { file: "SliderShowcaseBlock.tsx", deps: ["card", "button", "badge"] },
522
+ "metric-stats": { file: "MetricStatsBlock.tsx", deps: ["card", "badge"] },
523
+ "file-explorer": { file: "FileExplorerBlock.tsx", deps: ["card", "button", "badge"] }
524
+ };
525
+ function handleAdd(name) {
526
+ if (!name) {
527
+ console.error("\n\u274C Please specify an item to add. Example: npx atomsystem add button\n");
528
+ handleList();
529
+ return;
530
+ }
531
+ const cwd = process.cwd();
532
+ const normalized = name.toLowerCase().trim();
533
+ if (COMPONENT_MAP[normalized]) {
534
+ const fileName = COMPONENT_MAP[normalized];
535
+ const src = path2__default.default.join(PKG_ROOT, "components", "ui", fileName);
536
+ const dest = path2__default.default.join(cwd, "components", "ui", fileName);
537
+ if (fs2__default.default.existsSync(src)) {
538
+ copyFileSafe(src, dest, `Component (${fileName})`);
539
+ console.log(`
540
+ \u2705 Added ${normalized} component to components/ui/${fileName}
541
+ `);
542
+ } else {
543
+ console.error(`
544
+ \u274C Source component file not found: ${src}
545
+ `);
546
+ }
547
+ return;
43
548
  }
44
- const srcDesign = path__default.default.join(PKG_ROOT, "presets", "default.design.md");
45
- const destDesign = path__default.default.join(cwd, "atom.design.md");
46
- if (fs__default.default.existsSync(srcDesign)) {
47
- copyFileSafe(srcDesign, destDesign, "Design Guide (atom.design.md)");
549
+ if (BLOCK_MAP[normalized]) {
550
+ const { file, deps } = BLOCK_MAP[normalized];
551
+ console.log(`
552
+ \u{1F4E6} Adding block "${normalized}" and its dependent components...
553
+ `);
554
+ deps.forEach((dep) => {
555
+ const depFile = COMPONENT_MAP[dep];
556
+ if (depFile) {
557
+ const srcDep = path2__default.default.join(PKG_ROOT, "components", "ui", depFile);
558
+ const destDep = path2__default.default.join(cwd, "components", "ui", depFile);
559
+ if (fs2__default.default.existsSync(srcDep)) {
560
+ copyFileSafe(srcDep, destDep, `Dependent Component (${depFile})`);
561
+ }
562
+ }
563
+ });
564
+ const srcBlock = path2__default.default.join(PKG_ROOT, "components", "blocks", file);
565
+ const destBlock = path2__default.default.join(cwd, "components", "blocks", file);
566
+ if (fs2__default.default.existsSync(srcBlock)) {
567
+ copyFileSafe(srcBlock, destBlock, `Block (${file})`);
568
+ console.log(`
569
+ \u2705 Block "${normalized}" successfully added to components/blocks/${file}
570
+ `);
571
+ } else {
572
+ console.error(`
573
+ \u274C Source block file not found: ${srcBlock}
574
+ `);
575
+ }
576
+ return;
48
577
  }
49
- const srcPattern = path__default.default.join(PKG_ROOT, "presets", "uxPattern.md");
50
- const destPattern = path__default.default.join(cwd, "atom.uxPattern.md");
51
- if (fs__default.default.existsSync(srcPattern)) {
52
- copyFileSafe(srcPattern, destPattern, "UX Pattern Guide (atom.uxPattern.md)");
578
+ console.error(`
579
+ \u274C Unknown item: "${name}".`);
580
+ handleList();
581
+ }
582
+ function handleList() {
583
+ console.log(`
584
+ Available Components:
585
+ - button (Button, ButtonVariants)
586
+ - card (Card container)
587
+ - badge (Status badge)
588
+ - input (Input with status)
589
+ - table (Table, Header, Row, Cell)
590
+ - tabs (TabsList, TabsTrigger)
591
+ - switch (A11y Switch toggle)
592
+ - modal (Dialog with Esc key support)
593
+
594
+ Available Design Blocks:
595
+ - realtime-chart (Live streaming candlestick/line chart)
596
+ - interactive-chat (AI chatbot feed with suggestions)
597
+ - pricing-table (Monthly/annual tier pricing table)
598
+ - card-list (Responsive grid & list filter)
599
+ - interactive-slider (Cost simulation calculator & carousel)
600
+ - metric-stats (4 KPI executive metric cards)
601
+ - file-explorer (Hierarchical directory tree explorer)
602
+
603
+ Install any item:
604
+ npx atomsystem add <item-name>
605
+ `);
606
+ }
607
+ function handleBuildTokens() {
608
+ const cwd = process.cwd();
609
+ const tokenJsonPath = path2__default.default.join(cwd, "tokens", "token.json");
610
+ const cssPath = path2__default.default.join(cwd, "css", "atom-ui.css");
611
+ if (!fs2__default.default.existsSync(tokenJsonPath)) {
612
+ console.error(`
613
+ \u274C tokens/token.json not found at ${tokenJsonPath}. Run 'npx atomsystem init' first.
614
+ `);
615
+ return;
53
616
  }
54
- const srcToken = path__default.default.join(PKG_ROOT, "tokens", "token.json");
55
- const destToken = path__default.default.join(cwd, "tokens", "token.json");
56
- if (fs__default.default.existsSync(srcToken)) {
57
- copyFileSafe(srcToken, destToken, "Token JSON (tokens/token.json)");
617
+ try {
618
+ const tokens = JSON.parse(fs2__default.default.readFileSync(tokenJsonPath, "utf-8"));
619
+ const css = compileTokensToCss(tokens);
620
+ const cssDir = path2__default.default.dirname(cssPath);
621
+ if (!fs2__default.default.existsSync(cssDir)) fs2__default.default.mkdirSync(cssDir, { recursive: true });
622
+ fs2__default.default.writeFileSync(cssPath, css, "utf-8");
623
+ console.log(`
624
+ \u2728 Successfully compiled tokens to ${path2__default.default.relative(cwd, cssPath)}!
625
+ `);
626
+ } catch (err) {
627
+ console.error(`
628
+ \u274C Failed to compile tokens: ${err.message}
629
+ `);
58
630
  }
59
- console.log("\n\u2728 AtomSystem initialization completed!");
60
- console.log("\n\u{1F4CC} Next Steps:");
61
- console.log("1. Import AtomSystem CSS in your app (e.g. layout.tsx, App.vue, index.html):");
62
- console.log(' import "atomsystem/css/atom-ui.css";');
63
- console.log("2. Ask your AI coding assistant (Antigravity, Cursor, Copilot) to build UI:");
64
- console.log(' "atom.design.md\uC640 atom.uxPattern.md\uB97C \uCC38\uACE0\uD558\uC5EC \uACB0\uC81C \uD654\uBA74 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB9CC\uB4E4\uC5B4\uC918."\n');
631
+ }
632
+ function handleStudio() {
633
+ const portArg = args.find((a) => a.startsWith("--port="));
634
+ const port = portArg ? parseInt(portArg.split("=")[1], 10) : 4e3;
635
+ startLocalTokenStudio({ port, cwd: process.cwd() });
65
636
  }
66
637
  function showHelp() {
67
638
  console.log(`
@@ -71,24 +642,45 @@ Usage:
71
642
  npx atomsystem <command> [options]
72
643
 
73
644
  Commands:
74
- init Initialize AtomSystem assets (AI Skill, design.md, uxPattern.md, token.json)
75
- help Display this help message
76
- version Print version info
645
+ init Initialize AI guidelines, tokens, specs, and CSS in your project
646
+ studio Launch Local Web Token Studio GUI (interactive token customizer)
647
+ build:tokens Compile tokens/token.json into zero-runtime css/atom-ui.css
648
+ add <name> Add a component or block directly to your project
649
+ list List all available components and blocks
650
+ help Display this help message
651
+ version Print version info
652
+
653
+ Options for studio:
654
+ --port=<port> Port for the local studio server (default: 4000)
77
655
  `);
78
656
  }
79
657
  function showVersion() {
80
- const pkgPath = path__default.default.join(PKG_ROOT, "package.json");
81
- if (fs__default.default.existsSync(pkgPath)) {
82
- const pkg = JSON.parse(fs__default.default.readFileSync(pkgPath, "utf-8"));
658
+ const pkgPath = path2__default.default.join(PKG_ROOT, "package.json");
659
+ if (fs2__default.default.existsSync(pkgPath)) {
660
+ const pkg = JSON.parse(fs2__default.default.readFileSync(pkgPath, "utf-8"));
83
661
  console.log(`atomsystem v${pkg.version}`);
84
662
  } else {
85
- console.log("atomsystem v0.4.3");
663
+ console.log("atomsystem v0.5.1");
86
664
  }
87
665
  }
88
666
  switch (command) {
89
667
  case "init":
90
668
  handleInit();
91
669
  break;
670
+ case "studio":
671
+ case "editor":
672
+ handleStudio();
673
+ break;
674
+ case "build:tokens":
675
+ case "compile":
676
+ handleBuildTokens();
677
+ break;
678
+ case "add":
679
+ handleAdd(targetName);
680
+ break;
681
+ case "list":
682
+ handleList();
683
+ break;
92
684
  case "version":
93
685
  case "-v":
94
686
  case "--version":