@su-record/vibe 2.8.30 → 2.8.32

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 (34) hide show
  1. package/README.md +3 -3
  2. package/dist/cli/commands/figma.d.ts +2 -2
  3. package/dist/cli/commands/figma.d.ts.map +1 -1
  4. package/dist/cli/commands/figma.js +3 -7
  5. package/dist/cli/commands/figma.js.map +1 -1
  6. package/dist/cli/commands/skills.d.ts.map +1 -1
  7. package/dist/cli/commands/skills.js +10 -0
  8. package/dist/cli/commands/skills.js.map +1 -1
  9. package/dist/infra/lib/figma/api.d.ts +9 -0
  10. package/dist/infra/lib/figma/api.d.ts.map +1 -0
  11. package/dist/infra/lib/figma/api.js +73 -0
  12. package/dist/infra/lib/figma/api.js.map +1 -0
  13. package/dist/infra/lib/figma/extract.d.ts +12 -0
  14. package/dist/infra/lib/figma/extract.d.ts.map +1 -0
  15. package/dist/infra/lib/figma/extract.js +285 -0
  16. package/dist/infra/lib/figma/extract.js.map +1 -0
  17. package/dist/infra/lib/figma/index.d.ts +4 -0
  18. package/dist/infra/lib/figma/index.d.ts.map +1 -0
  19. package/dist/infra/lib/figma/index.js +3 -0
  20. package/dist/infra/lib/figma/index.js.map +1 -0
  21. package/dist/infra/lib/figma/types.d.ts +40 -0
  22. package/dist/infra/lib/figma/types.d.ts.map +1 -0
  23. package/dist/infra/lib/figma/types.js +5 -0
  24. package/dist/infra/lib/figma/types.js.map +1 -0
  25. package/dist/infra/lib/llm-availability.d.ts.map +1 -1
  26. package/dist/infra/lib/llm-availability.js +2 -0
  27. package/dist/infra/lib/llm-availability.js.map +1 -1
  28. package/dist/infra/lib/memory/ReflectionStore.d.ts.map +1 -1
  29. package/dist/infra/lib/memory/ReflectionStore.js +3 -8
  30. package/dist/infra/lib/memory/ReflectionStore.js.map +1 -1
  31. package/hooks/scripts/figma-extract.js +225 -0
  32. package/package.json +1 -2
  33. package/skills/vibe.figma/SKILL.md +68 -60
  34. package/skills/vibe.figma.extract/SKILL.md +76 -114
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/infra/lib/figma/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -1 +1 @@
1
- {"version":3,"file":"llm-availability.d.ts","sourceRoot":"","sources":["../../../src/infra/lib/llm-availability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAqBD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAkBvD;AAED,uBAAuB;AACvB,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAwB;AACxB,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,oBAAoB;AACpB,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
1
+ {"version":3,"file":"llm-availability.d.ts","sourceRoot":"","sources":["../../../src/infra/lib/llm-availability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAsBD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAkBvD;AAED,uBAAuB;AACvB,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAwB;AACxB,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,oBAAoB;AACpB,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
@@ -11,6 +11,8 @@ import os from 'os';
11
11
  let cached = null;
12
12
  function checkCliInstalled(binName, configDir) {
13
13
  const hasDir = fs.existsSync(configDir);
14
+ if (!/^[a-z]+$/.test(binName))
15
+ return hasDir;
14
16
  let hasBin = false;
15
17
  try {
16
18
  execSync(`which ${binName}`, { stdio: 'ignore' });
@@ -1 +1 @@
1
- {"version":3,"file":"llm-availability.js","sourceRoot":"","sources":["../../../src/infra/lib/llm-availability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AAOpB,IAAI,MAAM,GAA2B,IAAI,CAAC;AAE1C,SAAS,iBAAiB,CAAC,OAAe,EAAE,SAAiB;IAC3D,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClD,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;IACD,OAAO,MAAM,IAAI,MAAM,CAAC;AAC1B,CAAC;AAED,SAAS,eAAe,CAAC,SAAiB,EAAE,YAAoB;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACpD,OAAO,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAErD,MAAM,cAAc,GAAG,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE/D,0BAA0B;IAC1B,MAAM,KAAK,GAAG,cAAc,IAAI,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,eAAe,IAAI,CAChC,eAAe,CAAC,SAAS,EAAE,WAAW,CAAC;QACvC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAC7B,CAAC;IAEF,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,gBAAgB;IAC9B,OAAO,qBAAqB,EAAE,CAAC,KAAK,CAAC;AACvC,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,iBAAiB;IAC/B,OAAO,qBAAqB,EAAE,CAAC,MAAM,CAAC;AACxC,CAAC;AAED,oBAAoB;AACpB,MAAM,UAAU,yBAAyB;IACvC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"llm-availability.js","sourceRoot":"","sources":["../../../src/infra/lib/llm-availability.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AAOpB,IAAI,MAAM,GAA2B,IAAI,CAAC;AAE1C,SAAS,iBAAiB,CAAC,OAAe,EAAE,SAAiB;IAC3D,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC;IAC7C,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClD,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;IACD,OAAO,MAAM,IAAI,MAAM,CAAC;AAC1B,CAAC;AAED,SAAS,eAAe,CAAC,SAAiB,EAAE,YAAoB;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACpD,OAAO,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAErD,MAAM,cAAc,GAAG,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE/D,0BAA0B;IAC1B,MAAM,KAAK,GAAG,cAAc,IAAI,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,eAAe,IAAI,CAChC,eAAe,CAAC,SAAS,EAAE,WAAW,CAAC;QACvC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAC7B,CAAC;IAEF,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,gBAAgB;IAC9B,OAAO,qBAAqB,EAAE,CAAC,KAAK,CAAC;AACvC,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,iBAAiB;IAC/B,OAAO,qBAAqB,EAAE,CAAC,MAAM,CAAC;AACxC,CAAC;AAED,oBAAoB;AACpB,MAAM,UAAU,yBAAyB;IACvC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ReflectionStore.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/memory/ReflectionStore.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,aAAa,GAAG,QAAQ,CAAC;AAE9E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CD,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,aAAa,CAAU;gBAEnB,OAAO,EAAE,aAAa;IAKlC;;OAEG;IACI,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAoE3C;;OAEG;IACI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IA2B9D;;OAEG;IACI,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE;IAQpD;;OAEG;IACI,SAAS,CAAC,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IASlD;;OAEG;IACI,YAAY,CAAC,QAAQ,GAAE,MAAY,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IAU7E;;OAEG;IACI,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAK7C;;OAEG;IACI,QAAQ,IAAI,MAAM;IAKzB,OAAO,CAAC,eAAe;CAcxB"}
1
+ {"version":3,"file":"ReflectionStore.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/memory/ReflectionStore.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,aAAa,GAAG,QAAQ,CAAC;AAE9E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CD,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,aAAa,CAAU;gBAEnB,OAAO,EAAE,aAAa;IAKlC;;OAEG;IACI,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAgE3C;;OAEG;IACI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IA2B9D;;OAEG;IACI,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE;IAQpD;;OAEG;IACI,SAAS,CAAC,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IASlD;;OAEG;IACI,YAAY,CAAC,QAAQ,GAAE,MAAY,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IAU7E;;OAEG;IACI,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAK7C;;OAEG;IACI,QAAQ,IAAI,MAAM;IAKzB,OAAO,CAAC,eAAe;CAcxB"}
@@ -60,14 +60,9 @@ export class ReflectionStore {
60
60
  catch (error) {
61
61
  const sqliteError = error;
62
62
  if (sqliteError.code === 'SQLITE_BUSY') {
63
- // Retry once after 100ms
64
- try {
65
- const { execSync } = require('child_process');
66
- execSync('sleep 0.1 2>nul || timeout /t 0 >nul 2>&1', { timeout: 200 });
67
- }
68
- catch {
69
- // sleep not available, just continue
70
- }
63
+ // Retry once after 100ms (synchronous busy-wait for better-sqlite3 sync API)
64
+ const end = Date.now() + 100;
65
+ while (Date.now() < end) { /* busy wait */ }
71
66
  try {
72
67
  this.db.prepare(`
73
68
  INSERT INTO reflections (id, sessionId, type, trigger, insights, decisions, patterns, filesContext, score, createdAt)
@@ -1 +1 @@
1
- {"version":3,"file":"ReflectionStore.js","sourceRoot":"","sources":["../../../../src/infra/lib/memory/ReflectionStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ReflectionStore.js","sourceRoot":"","sources":["../../../../src/infra/lib/memory/ReflectionStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * figma-extract.js — Figma REST API 디자인 추출 도구
5
+ *
6
+ * Usage:
7
+ * node figma-extract.js tree <fileKey> <nodeId> [--depth=10]
8
+ * node figma-extract.js images <fileKey> <nodeId> --out=<dir> [--depth=10]
9
+ * node figma-extract.js screenshot <fileKey> <nodeId> --out=<path>
10
+ *
11
+ * Token: ~/.vibe/config.json → credentials.figma.accessToken
12
+ * 또는 FIGMA_ACCESS_TOKEN env
13
+ */
14
+
15
+ import fs from 'fs';
16
+ import path from 'path';
17
+ import os from 'os';
18
+
19
+ // ─── Config ─────────────────────────────────────────────────────────
20
+
21
+ const FIGMA_API = 'https://api.figma.com/v1';
22
+ const MAX_RETRIES = 3;
23
+ const INITIAL_DELAY_MS = 2000;
24
+
25
+ function loadToken() {
26
+ if (process.env.FIGMA_ACCESS_TOKEN) return process.env.FIGMA_ACCESS_TOKEN;
27
+ const configPath = path.join(os.homedir(), '.vibe', 'config.json');
28
+ try {
29
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
30
+ const token = config?.credentials?.figma?.accessToken;
31
+ if (token) return token;
32
+ } catch { /* ignore */ }
33
+ return null;
34
+ }
35
+
36
+ function fail(msg) { console.error(JSON.stringify({ error: msg })); process.exit(1); }
37
+ function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
38
+
39
+ // ─── HTTP ───────────────────────────────────────────────────────────
40
+
41
+ async function apiFetch(endpoint, token) {
42
+ let lastErr = '';
43
+ for (let i = 0; i < MAX_RETRIES; i++) {
44
+ try {
45
+ const res = await fetch(`${FIGMA_API}${endpoint}`, { headers: { 'X-Figma-Token': token } });
46
+ if (res.status === 429) { await sleep(INITIAL_DELAY_MS * 2 ** i); continue; }
47
+ if (res.status === 403) fail('403 Forbidden — check token permissions');
48
+ if (res.status === 404) fail('404 — check fileKey/nodeId');
49
+ if (!res.ok) {
50
+ lastErr = `HTTP ${res.status}`;
51
+ if (res.status >= 500) { await sleep(INITIAL_DELAY_MS * 2 ** i); continue; }
52
+ fail(lastErr);
53
+ }
54
+ return await res.json();
55
+ } catch (e) {
56
+ lastErr = e.message;
57
+ if (i < MAX_RETRIES - 1) await sleep(INITIAL_DELAY_MS * 2 ** i);
58
+ }
59
+ }
60
+ fail(`Failed after ${MAX_RETRIES} retries: ${lastErr}`);
61
+ }
62
+
63
+ // ─── Color ──────────────────────────────────────────────────────────
64
+
65
+ function toCSS(c) {
66
+ if (!c) return null;
67
+ const r = Math.round(c.r * 255), g = Math.round(c.g * 255), b = Math.round(c.b * 255), a = c.a ?? 1;
68
+ if (a === 1) return `#${r.toString(16).padStart(2,'0')}${g.toString(16).padStart(2,'0')}${b.toString(16).padStart(2,'0')}`;
69
+ return `rgba(${r}, ${g}, ${b}, ${+a.toFixed(2)})`;
70
+ }
71
+
72
+ // ─── CSS Extraction ─────────────────────────────────────────────────
73
+
74
+ function extractCSS(n) {
75
+ const css = {};
76
+ // Layout
77
+ if (n.layoutMode === 'VERTICAL') { css.display = 'flex'; css.flexDirection = 'column'; }
78
+ else if (n.layoutMode === 'HORIZONTAL') { css.display = 'flex'; css.flexDirection = 'row'; }
79
+ const axM = { MIN:'flex-start', CENTER:'center', MAX:'flex-end', SPACE_BETWEEN:'space-between' };
80
+ const crM = { MIN:'flex-start', CENTER:'center', MAX:'flex-end', BASELINE:'baseline' };
81
+ if (n.primaryAxisAlignItems && axM[n.primaryAxisAlignItems]) css.justifyContent = axM[n.primaryAxisAlignItems];
82
+ if (n.counterAxisAlignItems && crM[n.counterAxisAlignItems]) css.alignItems = crM[n.counterAxisAlignItems];
83
+ if (n.itemSpacing > 0) css.gap = `${n.itemSpacing}px`;
84
+ // Padding
85
+ const pt=n.paddingTop||0, pr=n.paddingRight||0, pb=n.paddingBottom||0, pl=n.paddingLeft||0;
86
+ if (pt||pr||pb||pl) css.padding = `${pt}px ${pr}px ${pb}px ${pl}px`;
87
+ // Size
88
+ if (n.absoluteBoundingBox) { css.width = `${Math.round(n.absoluteBoundingBox.width)}px`; css.height = `${Math.round(n.absoluteBoundingBox.height)}px`; }
89
+ // Position / overflow / opacity
90
+ if (n.layoutPositioning === 'ABSOLUTE') css.position = 'absolute';
91
+ if (n.clipsContent) css.overflow = 'hidden';
92
+ if (n.opacity != null && n.opacity < 1) css.opacity = n.opacity.toFixed(2);
93
+ // Blend
94
+ const bm = { MULTIPLY:'multiply', SCREEN:'screen', OVERLAY:'overlay', DARKEN:'darken', LIGHTEN:'lighten', COLOR_DODGE:'color-dodge', COLOR_BURN:'color-burn', HARD_LIGHT:'hard-light', SOFT_LIGHT:'soft-light', DIFFERENCE:'difference', EXCLUSION:'exclusion', HUE:'hue', SATURATION:'saturation', COLOR:'color', LUMINOSITY:'luminosity' };
95
+ if (n.blendMode && bm[n.blendMode]) css.mixBlendMode = bm[n.blendMode];
96
+ // Radius
97
+ if (n.cornerRadius > 0) css.borderRadius = `${n.cornerRadius}px`;
98
+ else if (n.rectangleCornerRadii) { const [a,b,c,d] = n.rectangleCornerRadii; css.borderRadius = `${a}px ${b}px ${c}px ${d}px`; }
99
+ // Fills
100
+ let imgRef;
101
+ for (const f of (n.fills||[]).filter(f=>f.visible!==false)) {
102
+ if (f.type === 'SOLID') css.backgroundColor = toCSS({ ...f.color, a: f.opacity ?? f.color?.a ?? 1 });
103
+ else if (f.type === 'IMAGE') imgRef = f.imageRef;
104
+ }
105
+ // Strokes
106
+ const stroke = (n.strokes||[]).find(s=>s.visible!==false&&s.type==='SOLID');
107
+ if (stroke && n.strokeWeight) css.border = `${n.strokeWeight}px solid ${toCSS(stroke.color)}`;
108
+ // Effects
109
+ const shadows = [];
110
+ for (const e of (n.effects||[]).filter(e=>e.visible!==false)) {
111
+ if (e.type==='DROP_SHADOW'||e.type==='INNER_SHADOW') {
112
+ const ins = e.type==='INNER_SHADOW'?'inset ':'';
113
+ shadows.push(`${ins}${e.offset?.x||0}px ${e.offset?.y||0}px ${e.radius||0}px ${e.spread||0}px ${toCSS(e.color)}`);
114
+ } else if (e.type==='LAYER_BLUR') css.filter = `blur(${e.radius}px)`;
115
+ else if (e.type==='BACKGROUND_BLUR') css.backdropFilter = `blur(${e.radius}px)`;
116
+ }
117
+ if (shadows.length) css.boxShadow = shadows.join(', ');
118
+ // Text
119
+ if (n.type === 'TEXT' && n.style) {
120
+ const s = n.style;
121
+ if (s.fontFamily) css.fontFamily = `'${s.fontFamily}', sans-serif`;
122
+ if (s.fontSize) css.fontSize = `${s.fontSize}px`;
123
+ if (s.fontWeight) css.fontWeight = String(s.fontWeight);
124
+ if (s.lineHeightPx) css.lineHeight = `${s.lineHeightPx}px`;
125
+ if (s.letterSpacing) css.letterSpacing = `${s.letterSpacing}px`;
126
+ const ta = { LEFT:'left', CENTER:'center', RIGHT:'right', JUSTIFIED:'justify' };
127
+ if (s.textAlignHorizontal && ta[s.textAlignHorizontal]) css.textAlign = ta[s.textAlignHorizontal];
128
+ const tf = (n.fills||[]).find(f=>f.visible!==false&&f.type==='SOLID');
129
+ if (tf) css.color = toCSS(tf.color);
130
+ }
131
+ return imgRef ? { ...css, _imageRef: imgRef } : css;
132
+ }
133
+
134
+ // ─── Tree ───────────────────────────────────────────────────────────
135
+
136
+ function walk(node) {
137
+ const css = extractCSS(node);
138
+ const r = { nodeId: node.id, name: node.name||'', type: node.type, size: null, css: {...css}, children: [] };
139
+ if (node.type==='TEXT' && node.characters) r.text = node.characters;
140
+ if (node.absoluteBoundingBox) r.size = { width: Math.round(node.absoluteBoundingBox.width), height: Math.round(node.absoluteBoundingBox.height) };
141
+ if (css._imageRef) { r.imageRef = css._imageRef; delete r.css._imageRef; }
142
+ if (node.children?.length) r.children = node.children.map(walk);
143
+ return r;
144
+ }
145
+
146
+ function collectRefs(node, set = new Set()) {
147
+ if (node.imageRef) set.add(node.imageRef);
148
+ (node.children||[]).forEach(c => collectRefs(c, set));
149
+ return set;
150
+ }
151
+
152
+ // ─── Commands ───────────────────────────────────────────────────────
153
+
154
+ async function cmdTree(token, fk, nid, depth) {
155
+ const dp = depth ? `&depth=${depth}` : '';
156
+ const data = await apiFetch(`/files/${fk}/nodes?ids=${nid}${dp}`, token);
157
+ const nd = data.nodes?.[nid];
158
+ if (!nd?.document) fail(`Node ${nid} not found`);
159
+ console.log(JSON.stringify(walk(nd.document), null, 2));
160
+ }
161
+
162
+ async function cmdImages(token, fk, nid, outDir, depth) {
163
+ if (!outDir) fail('--out required');
164
+ if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
165
+ // tree → refs
166
+ const dp = depth ? `&depth=${depth}` : '';
167
+ const data = await apiFetch(`/files/${fk}/nodes?ids=${nid}${dp}`, token);
168
+ const nd = data.nodes?.[nid];
169
+ if (!nd?.document) fail(`Node ${nid} not found`);
170
+ const tree = walk(nd.document);
171
+ const refs = collectRefs(tree);
172
+ if (!refs.size) { console.log(JSON.stringify({ total: 0, images: {} })); return; }
173
+ // download
174
+ const allImg = await apiFetch(`/files/${fk}/images`, token);
175
+ const urls = allImg.meta?.images || {};
176
+ const imageMap = {};
177
+ const dl = [];
178
+ for (const ref of refs) {
179
+ const url = urls[ref];
180
+ if (!url) continue;
181
+ const out = path.join(outDir, ref.slice(0,16) + '.png');
182
+ dl.push(fetch(url).then(r=>r.arrayBuffer()).then(b=>{
183
+ fs.writeFileSync(out, Buffer.from(b));
184
+ const sz = fs.statSync(out).size;
185
+ if (sz > 0) imageMap[ref] = out;
186
+ }).catch(()=>{}));
187
+ }
188
+ await Promise.all(dl);
189
+ console.log(JSON.stringify({ total: Object.keys(imageMap).length, images: imageMap }, null, 2));
190
+ }
191
+
192
+ async function cmdScreenshot(token, fk, nid, outPath) {
193
+ if (!outPath) fail('--out required');
194
+ const data = await apiFetch(`/images/${fk}?ids=${nid}&format=png&scale=2`, token);
195
+ const url = data.images?.[nid];
196
+ if (!url) fail(`No image for ${nid}`);
197
+ const dir = path.dirname(outPath);
198
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
199
+ const buf = Buffer.from(await (await fetch(url)).arrayBuffer());
200
+ fs.writeFileSync(outPath, buf);
201
+ console.log(JSON.stringify({ path: outPath, size: buf.length }));
202
+ }
203
+
204
+ // ─── CLI ────────────────────────────────────────────────────────────
205
+
206
+ const args = process.argv.slice(2);
207
+ const flags = {};
208
+ const pos = [];
209
+ for (const a of args) {
210
+ if (a.startsWith('--')) { const [k,v] = a.slice(2).split('='); flags[k] = v ?? ''; }
211
+ else pos.push(a);
212
+ }
213
+
214
+ const token = loadToken();
215
+ if (!token) fail('Figma token not found. Run: vibe figma setup <token>');
216
+
217
+ const [cmd, fk, nidRaw] = pos;
218
+ const nid = nidRaw?.replace(/-/g, ':');
219
+
220
+ switch (cmd) {
221
+ case 'tree': await cmdTree(token, fk, nid, flags.depth ? +flags.depth : undefined); break;
222
+ case 'images': await cmdImages(token, fk, nid, flags.out, flags.depth ? +flags.depth : 10); break;
223
+ case 'screenshot': await cmdScreenshot(token, fk, nid, flags.out); break;
224
+ default: console.log('Usage: node figma-extract.js <tree|images|screenshot> <fileKey> <nodeId> [flags]');
225
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.8.30",
3
+ "version": "2.8.32",
4
4
  "description": "AI Coding Framework for Claude Code — 49 agents, 41+ tools, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
@@ -93,7 +93,6 @@
93
93
  "skills/",
94
94
  "hooks/",
95
95
  ".env.example",
96
- ".env",
97
96
  "CLAUDE.md",
98
97
  "README.md",
99
98
  "LICENSE"
@@ -68,14 +68,18 @@ tier: standard
68
68
 
69
69
  ```
70
70
  URL에서 fileKey, nodeId 추출
71
- get_metadata(fileKey, nodeId) → 프레임 목록
72
-
73
- ⚠️ 메타데이터가 클 수 있음 (실전: 291K chars → 파일 저장됨)
74
- 파일 저장 시 Python/Bash로 파싱하여 프레임 목록 추출
75
-
76
- 프레임 분류 (이름 패턴 기반, get_design_context 호출 전에 분류):
77
- SPEC — "기능 정의서", "정책" → get_design_context로 텍스트 추출
78
- CONFIG — "해상도", "브라우저" → get_design_context로 스케일 팩터 계산
71
+ getTree(fileKey, nodeId, depth=2) → 프레임 목록
72
+
73
+ Bash:
74
+ node -e "
75
+ import { getTree } from './dist/infra/lib/figma/index.js';
76
+ const tree = await getTree({ fileKey: '{fileKey}', nodeId: '{nodeId}', depth: 2 });
77
+ console.log(JSON.stringify(tree));
78
+ "
79
+
80
+ 프레임 분류 (name 패턴 기반):
81
+ SPEC — "기능 정의서", "정책" → depth 높여서 텍스트 추출
82
+ CONFIG — "해상도", "브라우저" → 스케일 팩터 계산
79
83
  SHARED — "공통", "GNB", "Footer", "Popup" → 공통 컴포넌트 파악
80
84
  PAGE — "화면설계", "메인 -" → 섹션 목록 + 인터랙션 스펙
81
85
 
@@ -87,8 +91,8 @@ get_metadata(fileKey, nodeId) → 프레임 목록
87
91
  4순위: SHARED (공통 요소, Popup) — 필요 시
88
92
 
89
93
  높이 1500px 이상 프레임:
90
- get_design_context 대신 get_screenshot으로 시각 파악
91
- → 또는 get_metadata로 하위 분할 후 호출
94
+ getScreenshot으로 시각 파악
95
+ → 또는 depth 높여서 하위 분할 조회
92
96
  ```
93
97
 
94
98
  ### 1-2. 레이아웃 + 컴포넌트 구성 (코드 생성)
@@ -224,35 +228,44 @@ SCSS 파일 기본 내용 Write:
224
228
 
225
229
  **각 섹션을 순서대로, 한 섹션을 완전히 완료한 후 다음으로.**
226
230
 
227
- #### a. 참조 코드 획득
231
+ #### a. 노드 트리 + CSS 추출
228
232
 
229
233
  ```
230
- get_design_context(fileKey, 섹션.nodeId)
234
+ Figma REST API로 노드 트리와 CSS 속성을 직접 추출한다.
235
+ MCP 플러그인(get_design_context/get_metadata)은 사용하지 않는다.
236
+
237
+ Bash:
238
+ # [FIGMA_SCRIPT] = ~/.vibe/hooks/scripts/figma-extract.js
239
+ node "[FIGMA_SCRIPT]" tree {fileKey} {섹션.nodeId} --depth=10
231
240
 
232
- 반환:
233
- - const img변수명 = 'URL' (이미지 에셋)
234
- - React+Tailwind JSX (HTML 구조 + CSS 값)
235
- - 스크린샷 (시각 기준점)
236
- - data-name 속성 (레이어 이름: "BG", "Title" 등)
241
+ 반환 (JSON):
242
+ {
243
+ nodeId, name, type, size: {width, height},
244
+ css: { display, flexDirection, gap, fontSize, color, ... },
245
+ text: "텍스트 내용" (TEXT 노드),
246
+ imageRef: "abc123" (이미지 fill),
247
+ children: [...]
248
+ }
237
249
 
238
- 섹션 (높이 1500px+):
239
- get_metadata로 하위 노드 목록 하위 단위로 get_design_context 분할 호출
240
- 타임아웃 시: 1회 재시도 (excludeScreenshot: true) 실패 분할
250
+ CSS는 Figma 노드 속성에서 직접 추출 — Tailwind 역변환 불필요:
251
+ fills background-color effectsbox-shadow, filter
252
+ strokes border stylefont-family, font-size, color
253
+ layoutMode → display:flex itemSpacing → gap
254
+ padding* → padding cornerRadius → border-radius
255
+
256
+ 인스턴스 내부 자식도 depth로 전부 조회 가능 (MCP 한계 해결).
241
257
  ```
242
258
 
243
259
  #### b. 이미지 다운로드 (BLOCKING)
244
260
 
245
261
  ```
246
- 참조 코드의 모든 const img... URL을 추출 다운로드 검증.
247
-
248
- 변수명 → 파일명: imgSnowParticle12 → snow-particle-12.webp
249
- 다운로드: curl -sL "{url}" -o images/{feature}/{파일명}
250
- 검증: ls -la → 모든 파일 존재 + 0byte 아닌지
262
+ 트리에서 imageRef가 있는 노드를 수집Figma API로 다운로드.
251
263
 
252
- 이미지 매핑 생성:
253
- imageMap = { imgTitle: '/images/{feature}/title.webp', ... }
264
+ Bash:
265
+ node "[FIGMA_SCRIPT]" images {fileKey} {섹션.nodeId} --out=images/{feature}/ --depth=10
254
266
 
255
- 전부 완료해야 c 단계로 진행. 하나라도 실패 → 코드 생성 금지.
267
+ 검증: result.total = refs.size (누락 0)
268
+ 전부 완료해야 c 단계로 진행.
256
269
  ```
257
270
 
258
271
  #### c. 클래스 매핑 테이블 생성
@@ -262,38 +275,33 @@ SCSS 작성 전에 반드시 매핑 테이블을 먼저 출력한다.
262
275
  이 테이블 없이 SCSS를 작성하지 않는다.
263
276
 
264
277
  1. Phase 1 컴포넌트의 클래스 목록을 Read로 수집
265
- 2. 참조 코드의 data-name + HTML 구조를 분석
278
+ 2. 트리의 name + css 속성을 분석
266
279
  3. 매핑 테이블 출력:
267
280
 
268
- ┌─────────────────────┬──────────────────┬────────────────────────────┐
269
- │ Phase 1 클래스 │ 참조 data-name │ 핵심 Tailwind
270
- ├─────────────────────┼──────────────────┼────────────────────────────┤
271
- │ .kidSection │ (root) │ flex flex-col gap-[32px]
272
- │ .kidBg │ BG │ absolute mix-blend-multiply
273
- │ .kidLoginBtn │ Btn_Login │ border shadow h-[120px]
274
- │ .kidLoginBtnText │ (텍스트 노드) text-[36px] text-white
275
- │ .kidDivider │ Divider │ h-px w-full
276
- │ .kidSteamLink │ steam_account │ text-[24px] font-semibold
277
- │ .kidSteamNote │ (하위 텍스트) text-[20px] #dadce3
278
- └─────────────────────┴──────────────────┴────────────────────────────┘
281
+ ┌─────────────────────┬──────────────────┬────────────────────────────────────┐
282
+ │ Phase 1 클래스 │ 트리 노드 name │ 추출된 CSS
283
+ ├─────────────────────┼──────────────────┼────────────────────────────────────┤
284
+ │ .kidSection │ KID (root) │ flex, column, gap:32px, pad:48px
285
+ │ .kidBg │ BG │ absolute, 720x800
286
+ │ .kidLoginBtn │ Btn_Login │ flex, border, shadow, 640x148
287
+ │ .kidLoginBtnText │ (TEXT 노드) fontSize:36px, color:#fff, w:700
288
+ │ .kidDivider │ Divider │ 640x1
289
+ │ .kidSteamLink │ steam_account │ fontSize:24px, w:600
290
+ │ .kidSteamNote │ (하위 TEXT) fontSize:20px, color:#dadce3
291
+ └─────────────────────┴──────────────────┴────────────────────────────────────┘
279
292
 
280
293
  매핑 기준:
281
- data-name 일치 → 직접 매핑
282
- data-name 없음 → HTML 위치/텍스트 내용으로 판단
294
+ name 일치 → 직접 매핑
295
+ name 없음 → 트리 위치/text 내용으로 판단
283
296
  Phase 1에 없는 요소 → 클래스 신규 추가 (template에도 반영)
284
- 참조 코드에 없는 클래스 → 스타일 없이 유지
297
+ 트리에 없는 클래스 → 스타일 없이 유지
285
298
  ```
286
299
 
287
300
  #### d. SCSS 작성
288
301
 
289
302
  ```
290
- 매핑 테이블의 각 행을 순서대로 CSS로 변환하여 SCSS 작성.
291
- vibe.figma.extract의 Tailwind→CSS 변환표 참조.
292
-
293
- CSS 변수 패턴 처리:
294
- font-[family-name:var(--font/family/pretendard,...)] → fallback 값 사용
295
- text-[length:var(--font/size/heading/24,24px)] → 24px
296
- text-[color:var(--color/grayscale/300,#dadce3)] → #dadce3
303
+ 매핑 테이블의 각 행에 대해, 트리의 css 속성을 SCSS 작성.
304
+ CSS 값은 트리에서 이미 추출되어 있으므로 변환 불필요 — 그대로 사용.
297
305
 
298
306
  scaleFactor 적용:
299
307
  px 값 → × scaleFactor (font-size, padding, margin, gap, width, height, border-radius)
@@ -308,7 +316,7 @@ scaleFactor 적용:
308
316
  styles/{feature}/_tokens.scss
309
317
  → 새로 발견된 색상/폰트/스페이싱 토큰 추가
310
318
 
311
- BG 레이어 패턴 (참조 코드에서 absolute + inset-0 + object-cover):
319
+ BG 레이어 패턴 (트리에서 position:absolute + 이미지 fill):
312
320
  .{section}Bg → position: absolute; inset: 0; z-index: 0;
313
321
  .{section}Content → position: relative; z-index: 1;
314
322
 
@@ -318,14 +326,14 @@ index.scss에 새 섹션 @import 추가.
318
326
  #### e. template 업데이트
319
327
 
320
328
  ```
321
- Phase 1 컴포넌트의 template을 참조 코드 기반으로 리팩토링.
329
+ Phase 1 컴포넌트의 template을 트리 구조 기반으로 리팩토링.
322
330
  script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
323
331
 
324
- 1. 참조 코드의 HTML 구조를 프로젝트 스택으로 변환:
325
- classNameclass, onClick@click, {조건 && <X/>}v-if 등
332
+ 1. 트리의 HTML 구조를 프로젝트 스택으로 변환:
333
+ FRAME<div>, TEXT<p>/<span>, VECTOR/RECTANGLE with imageRef<img>
326
334
 
327
335
  2. 이미지 경로를 imageMap으로 교체:
328
- src={imgTitle} → src="/images/{feature}/title.webp"
336
+ imageRef "abc123" → src="/images/{feature}/abc123.png"
329
337
 
330
338
  3. BG 레이어 구조 적용:
331
339
  .{section}Bg div (배경) + .{section}Content div (콘텐츠)
@@ -334,7 +342,7 @@ script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
334
342
  v-for, @click, v-if, $emit 등을 새 구조의 적절한 위치에 배치
335
343
 
336
344
  5. 접근성:
337
- 장식 이미지 → alt="" aria-hidden="true"
345
+ 장식 이미지 (BG 내) → alt="" aria-hidden="true"
338
346
  콘텐츠 이미지 → alt="설명적 텍스트"
339
347
 
340
348
  컴포넌트에 <style> 블록 없음. 스타일은 전부 외부 SCSS.
@@ -344,13 +352,12 @@ script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
344
352
 
345
353
  ```
346
354
  Grep 체크:
347
- □ "figma.com/api" in 생성 파일 → 0건
348
355
  □ 'src=""' in 컴포넌트 파일 → 0건
349
356
  □ "<style" in 컴포넌트 파일 → 0건
350
357
 
351
358
  Read 체크:
352
359
  □ 외부 SCSS 파일에 font-size, color 존재 (브라우저 기본 스타일 방지)
353
- □ 이미지 파일 수 = const img... 수 (누락 0)
360
+ □ 이미지 파일 수 = imageRef 수 (누락 0)
354
361
 
355
362
  실패 → 수정 → 재검증
356
363
  ```
@@ -373,13 +380,14 @@ Read 체크:
373
380
 
374
381
  ```
375
382
  Grep 체크:
376
- □ "figma.com/api" in 모든 생성 파일 → 0건
377
383
  □ "<style" in components/{feature}/ → 0건
378
384
  □ 'src=""' in components/{feature}/ → 0건
379
385
  □ Glob: images/{feature}/ → 이미지 파일 존재
380
386
 
381
387
  시각 검증:
382
- 섹션: get_screenshot(nodeId) vs dev 서버/preview 비교
388
+ 섹션 스크린샷:
389
+ node "[FIGMA_SCRIPT]" screenshot {fileKey} {nodeId} --out=/tmp/{section}.png
390
+ → dev 서버/preview와 비교
383
391
  P1 (필수): 이미지 누락, 레이아웃 구조 다름, 텍스트 스타일 미적용
384
392
  P2 (권장): 미세 간격, 미세 색상 차이
385
393
  → P1 수정 → 재검증 (P1=0 될 때까지)