/devup starts devup_project_plan intake for projects, features, bug fixes,
Figma pages and refactors. Read sources, settle every question, confirm the ERD
and plan, then split supervisor work units; Figma screen planning is one branch.
Rust-native MCP server that reads Figma designs and generates DevupUI artifacts. One binary acts as a local stdio MCP server and a read-only client of Figma Remote MCP.
์ ์ฅ์๋ Cargo workspace์ด๋ฉฐ devup-mcp ์คํ crate, OAuthยทupstreamยทsnapshot์ ๋ด๋นํ๋ devup-mcp-figma, TSXยทtheme projection์ ๋ด๋นํ๋ devup-mcp-devup-ui, PNG ๋น๊ต library/CLI์ธ devup-mcp-visual๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋ณ๋ IR/auth/server crate ์์ด MCP ์ ํ ์ค์น ๋จ์๋ devup-mcp ํ๋์
๋๋ค.
Figma ์ชฝ 5๊ฐ, ํ๋ก์ ํธ ์ชฝ 7๊ฐ, ์คํฌ 1๊ฐ, ๋ชจ๋ 13๊ฐ์ ๋๋ค.
devup_figma_export: Figma๋ฅผ ํ ๋ฒ ์์งํด ์์ฒญํoutputs๋ง ํฌ์ํฉ๋๋ค. TSX๊ฐ ์ฐ์ถ๋ฌผ์ด๊ณ ,componentTsxยทresponsiveTsxยทdevup.jsonยทsource mapยทasset manifestยทreference PNG๋ฅผ ๊ฐ์ ์์ง์์ ํจ๊ป ์ป๊ฑฐ๋,cache.artifactId๋ก ์ฌ์์ง ์์ด ์ถ๊ฐ ํฌ์ํ ์ ์์ต๋๋ค. raw snapshotยทraw payload๋ ๊ตฌํ์ด ์๋๋ผ ์ง๋จ์ ์ฐ๋ ๊ฒ์ด๋ผdebug: true๋ก๋ง ์ด๋ฆฝ๋๋ค.devup_figma_search: page, section, frame, component๋ฅผ ์ด๋ฆ์ผ๋ก ํ์. URL์node-id๊ฐ ์์ผ๋ฉด ๊ทธ ๋ ธ๋์ ๊ทธ ์๋๋ก ๋ฒ์๋ฅผ ์ขํ๊ณ , ์์ผ๋ฉด ํ์ผ ์ ์ฒด๋ฅผ ๊ฒ์ํฉ๋๋ค. ๋ ์ค ๋ฌด์์ ํ๋์ง๋ ์๋ต์scope๊ฐ ์๋ ค์ค๋๋คdevup_figma_explore: ๋งํฌ๋ ์๊ตฌ์ฌํญ/๋ผ๋ฒจ ์ฃผ๋ณ์ ์ค์ ํ๋ฉด ํ๋ณด๋ฅผ ๊ณต๊ฐ ์์๋ก ํ์devup_figma_auth: Figma์ ๋ฟ๋ ๋ ๊ฒฝ๋ก(๋ธ๋ฆฌ์ง ํ๋ฌ๊ทธ์ธยทdirect OAuth)๋ฅผ ํจ๊ป ๋ณด๊ณ (status) โ ๋ถ์ด ์๋ ํ๋ฌ๊ทธ์ธ์ ํ์ผยทํ์ฌ ํ์ด์งยท์ ํ๊น์ง. ๊ทธ ๋ฐ์ ๋ธ๋ผ์ฐ์ OAuth ๋ก๊ทธ์ธ, ๋ก๊ทธ์์, ์ฌ์ ๋ฑ๋ก ์๊ฒฉ์ฆ๋ช ์ฃผ์ (configure), ์ฐธ์กฐ ๋ฐ์ดํฐ๊น์ง ๋ถ์ธdoctor. ๋ก๊ทธ์ธ์ ์์ฒญํ๊ธฐ ์ ์status๋ถํฐ ๋ถ๋ฅด์ธ์ โ ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ์ ํ์ ์์ต๋๋คdevup_skills: devup-mcp๊ฐ ๋ด๋๋ ์ฝ๋์ ํ์ํ ์์ด์ ํธ ์คํฌ์ด ์ด ์ํฌ์คํ์ด์ค์ ์๋์ง ๋ณด๊ณ (status)ํ๊ณ , devup-mcp๊ฐ ํ๊ณ ์๋ ๊ฒ์ ์ค์น(install). ํ ์คํธ๋ฅผ ์๋ต์ ์ค์ด ๋ณด๋ด๋ ๊ฒ ์๋๋ผ ์คํฌ ๋๋ ํฐ๋ฆฌ์ ์ค์นํด์ ์์ด์ ํธ ์์ ์ ๋ก๋๊ฐ ์ฝ๊ฒ ํฉ๋๋ค โ ํ ๋ฒ ์ฝ์ ๋ฌธ์๋ ํ ๋ฒ ์ฐ์ด์ง๋ง, ์ค์น๋ ์คํฌ์ ์ดํ ๋ชจ๋ ์ธ์ ์ ๊ณ์ ์ ์ฉ๋ฉ๋๋ค. ์ด๋ ๋๋ ํฐ๋ฆฌ์ธ์ง๋clientInfo๋ก ํ๋ณํ ๋ฐํ์์ด ์ ํ๊ณ ,projectRoot๋ก ์ด๋ ํ๋ก์ ํธ์ธ์ง ์ง์ ํฉ๋๋คdevup_project_context: ํ๋ก์ ํธ์ ์ค์ devup.jsonํ ํฐ,openapi.json์๋ํฌ์ธํธ, Vespertide ๋ชจ๋ธ์ ์ฝ์. ์ค์ฒฉ ์ฒดํฌ์์๊ณผ ๋น๋ ์ฐ์ถ๋ฌผ ๋๋ ํฐ๋ฆฌ๋ ์ค์บ์์ ์ ์ธํ๊ณ ๋ฌด์์ ์ ์ธํ๋์ง ๋ณด๊ณdevup_ui_validate: ์์ฑํ TSX๋ฅผ ํ๋ก์ ํธ์ ์ค์ devup.json์ ๋์กฐํด ๊ฒ์ฆ.ok๋ ๊ฐ์๊ฐ ์๋๋ผ ์ฌ๊ฐ๋๋ก ํ์ devup_stack_diff: DB ๋ชจ๋ธ๋ถํฐ ์์ฑ๋ API ํด๋ผ์ด์ธํธ๊น์ง์ ์ธต๊ฐ ๋๋ฆฌํํธ ํ์ง. ๋ชจ๋ ๋ฐ๊ฒฌ์ ๋ช ์์ confidence๋ฅผ ๊ฐ์งdevup_visual_compare: ์๋น์๊ฐ ๋ง๋actual.png๋ฅผ reference PNG ํ๋์ ๋น๊ต. ์ค์ค๋ก ๋ ๋ํ์ง ์๊ณ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ์ง๋ ๋ช ๋ น์ ์คํํ์ง๋ ์์ต๋๋ค โ ๊ฒฝ๋ก๋ allowlist ์์ด์ด์ผ ํฉ๋๋ค. ๊ธฐ๋ณธ threshold๋ 0.005(0.5%). renderer ํ๊ฒฝ manifest๊ฐ ์๊ฑฐ๋ ๋ถ์์ ํ๊ฑฐ๋ ์ ํจํ์ง ์์ผ๋ฉดvisual.passed๊ฐ true์ฌ๋ ํ์ ์inconclusive์ ๋๋คdevup_feature_trace: ๋ช ์์ anchor(routePath,figmaNodeId/artifactId,operationId๋๋apiPath+method,componentPath,tableName)์์ ์ถ๋ฐํด ํ๋ฉดโAPIโ๋ผ์ฐํธโ๋ชจ๋ธโ์ปฌ๋ผ ์ฌ๋ผ์ด์ค์ acceptance matrix๋ฅผ ์ฝ์ด๋. ์๊ตฌ์ฌํญ ์ฐ๋ฌธ๋ง ์ฃผ๋ฉด ๊ฑฐ์ ํฉ๋๋ค. ๊ฐ hop์ ๊ทผ๊ฑฐ๊ฐ ์๊ฑฐ๋UNVERIFIED๋ก ํ์๋๊ณ , ์์ฑ ์ฐ์ถ๋ฌผ ์์ ๊ถยทUI ์ฌ์ฌ์ฉ ์์ยท์๋ฆผ ์ํ์ ํจ๊ป ๋ณด๊ณ ํฉ๋๋คdevup_runtime_audit: ์์ฑํ ํ๋ฉด์ ์ฌ๋ฌ viewport ํญ์์ ์ฌ ๋ณผ ๋ธ๋ผ์ฐ์ ์คํ ๊ณํ์ ๊ฒ์ฆํด ์ฐ๊ณ (plan), ์๋น์ ํ๋ก์ ํธ์ ์คํ๊ธฐ(harness/runtime-audit)๊ฐ ์ด ๋ณด๊ณ ์๋ฅผ ๊ทธ ๊ณํ์ ๋ฌถ์ด ๊ฒ์ฆํฉ๋๋ค(ingest). ์๋ฒ๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ์ง๋ ๋ช ๋ น์ ์คํํ์ง๋ ์์ต๋๋ค โ ๊ณํ์ ์ ์ธํ ๋ฐ์ดํฐ๋ฟ์ด๊ณ , ๊ณํ id์ ํ์ผ ํด์์ ๋ฌถ์ด์ง ์์ ๋ณด๊ณ ์๋ ๊ฑฐ์ ํ๋ฉฐ ๋ชจ๋ ๊ฐ์๋ฅผ ํญ๋ชฉ์์ ๋ค์ ์ ๋๋คdevup_screen_plan: ํ์ด์ง๋ฅผ ์ฐ๊ธฐ ์ ์ Figma ํ๋ฉด๋ง๋ค ์ด๋ URL์ด ๋ ์ง ๊ณํํ๊ณ (draft), ์ด๋ฆฐ ๊ฒฐ์ ์ ๊ตฌํ ์ ์ ์ง๋ฌธ ๋ผ์ด๋๋ก ์ฐ๋ฌ์ ๋ชจ๋ ๋ฌผ์ ๋ค ํ์ ํ๊ณ (confirm), ํ์ ๋ ๊ณํ์ ์ค์ ๋ผ์ฐํธ์ runtime audit ๋ณด๊ณ ์์ ๋์กฐํด URL ร ํญ ํ๋ก ๋ณด๊ณ (status). ๋ผ์ฐํธ๋ ๊ทผ๊ฑฐ(๊ทธ ํ๋ ์์ผ๋ก ๋ง๋ ๊ธฐ์กด ํ์ด์ง, ๊ธฐ์กด href์ ๋ฌถ์ธ nav ๋ผ๋ฒจ,navigationTargets, ํ๋ก์ ํธ ์ค์ )๋ก๋ง ์ ์ํ๊ณ , ๋ ์ด์ด ์ด๋ฆ์ผ๋ก ์ถ์ ํ ๊ฒ์name-match๋ก ๋๋ฌ๋ด ๋ฌป๊ณ , ๋๋จธ์ง๋UNVERIFIED์ง๋ฌธ์ด ๋ฉ๋๋ค. ํ์ ๋ค์๋ ๋ฌป์ง ์๊ณ ๊ฐ์ (assume)์ผ๋ก ๊ธฐ๋กํ๋ฉฐ,auditPlan์ผ๋ก URL๋ง๋ค ํ์ด์งยท์น์ ยท์์ ยท์์นยท์ํ๋ฅผ ๋ชจ๋ ๊ฒ์ฆํ๋ audit ๊ณํ์ ์ฐ๊ณdefer๋ก ๊ฒฐ์ ์ ๋ฏธ๋ค ๋๊ณ ๋ฉ์ถ์ง ์์ต๋๋ค
devup_figma_to_ui์ devup_figma_to_json์ ๊ฐ๊ฐ devup_figma_export์ outputs: ["tsx"], outputs: ["devupJson"]์ ๋๊ธด ๊ฒ๊ณผ ๊ฐ์์ ์ ๊ฑฐํ์ต๋๋ค. ๋๊ตฌ๊ฐ ์
์ด๋ฉด ๋ชจ๋ ํด๋ผ์ด์ธํธ๊ฐ ์ธ ๊ฐ์ ์คํค๋ง๋ฅผ ์ปจํ
์คํธ์ ์ฃ๊ณ ๋ ์ด๋ ๊ฒ์ ๋ถ๋ฅผ์ง ๋งค๋ฒ ํ๋จํด์ผ ํ์ต๋๋ค.
devup-mcp๋ Figma Plugin API์ readable data property๋ฅผ raw JSON์ผ๋ก ๋ณด์กดํ๊ณ , ์๋ ค์ง์ง ์์ runtime field๋ extra, ์คํจํ getter๋ fieldErrors๋ก ์ ์งํฉ๋๋ค.
devup_figma_export๋ ์์ฒญํ outputs๊ฐ ๋ง๋๋ ํค๋ง ์ถ๊ฐํฉ๋๋ค. outputs๋ฅผ ์๋ตํ์ ๋์ ์คํค๋ง ๊ธฐ๋ณธ๊ฐ์ ["tsx"] ํ๋๋ฟ์ด๋ฉฐ, ์๋ ํ๋ ๋ฌด์์ ๋ ์์ฒญํ ์ ์๋์ง์ ๋ํ ๋ ํผ๋ฐ์ค์ด์ง ํ ๋ฒ์ ์ ๋ถ ์์ฒญํ๋ผ๋ ๋ชฉ๋ก์ด ์๋๋๋ค.
devupJson์ ๊ธฐ๋ณธ๊ฐ์์ ๋น ์ก์ต๋๋ค. ํ๋ก์ ํธ์ ์ด๋ฏธ devup.json์ด ์์ผ๋ฉด ์ฝ๋๊ฐ ๋ง์ถฐ์ผ ํ ๋์์ ๊ทธ ํ์ผ์ด์ง Figma์์ ์๋ก ๋ฝ์ ์ด๋ฆ ์งํฉ์ด ์๋๊ณ , ๊ทธ ํ์ผ์ ์ฝ๋ ๋๊ตฌ๋ devup_project_context์
๋๋ค. devupJson์ ํ๋ก์ ํธ์ ์์ง devup.json์ด ์๊ฑฐ๋, ๊ทธ ํ์ผ์ด ์ ์ํ์ง ์์ ํ ํฐ์ ์๋ก ๋ค์ผ ๋๋ง ํจ๊ป ์์ฒญํ์ธ์.
| output | ์ถ๊ฐ๋๋ ํค |
|---|---|
tsx |
tsx |
componentTsx |
componentTsx |
responsiveTsx |
responsiveTsx, responsiveSlots, (ํํ ๋ถ๊ฐํ ๊ฐ์ด ์์ผ๋ฉด) responsiveUnrepresented |
devupJson |
devupJson, themeCounts, themeCompleteness, conflicts, unresolvedVariables |
sourceMap / assetManifest |
๊ฐ์ ์ด๋ฆ์ ํค |
referencePng |
referencePng, (ํ๋ฌ๊ทธ์ธ์ด get_screenshot๊ณผ ๊ฐ์ ๊ทธ๋ฆผ์ ๋ค ๊ทธ๋ฆฌ์ง ๋ชปํด ์บ๋ฒ์ค์ ๊ทธ ์๋ฆฌ๋ฅผ ๊ทธ๋ ธ์ผ๋ฉด) referencePngNote |
rawSnapshot / rawPayload |
๊ฐ์ ์ด๋ฆ์ ํค โ debug: true ํ์ |
๊ทธ ๋ฐ์ ํญ์ ๋ถ๋ ๊ฒ์ status, quality, completeness, cache, collection, source, targetKind, failures, assetSummary, outputPaths๋ฟ์
๋๋ค.
์กฐ๊ฑด์ด ๋ง์ ๋๋ง ๋ถ๋ ํค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
| ํค | ๋์ค๋ ์กฐ๊ฑด |
|---|---|
fidelity / completenessReport |
๊ฒฐ๊ณผ๊ฐ exact/complete๊ฐ ์๋ ๋, ๋๋ includeDiagnostics: true์ผ ๋ |
deliverable |
status๊ฐ complete์ด๊ณ TSX๋ฅผ ๋ง๋ค์์ ๋ |
warnings |
์จ๊น ๋ ธ๋์ฒ๋ผ ์คํจ๊ฐ ์๋ ์์ฐ ๋ฌธ์ ๊ฐ ์์ ๋ |
frames |
Section์์ ์ฌ๋ฌ ํ๋ฉด์ ํ ๋ฒ์ exportํ์ ๋ |
selection / nextAction |
status๊ฐ selection_required์ผ ๋ |
widthBehavior |
tsx(Section ๋ฐฐ์น์์๋ componentTsx๋)๋ฅผ ๋ง๋ค์์ ๋. ๋จ์ผ ํ๋ฉด์ ์ต์์, Section ๋ฐฐ์น๋ frames[] ๊ฐ ํญ๋ชฉ (๊ทธ๋ฆฐ ํญ์ด ์๋ ํญ) |
verificationScope |
์์ฑ TSX์ ํญ(widthBehavior.designWidth, ๋ฐ์ํ์ด๋ฉด ์์งํ ํญ๋ค)์ ์ ๋ |
fidelity์ completenessReport๋ฅผ ๊ธฐ๋ณธ์์ ๋บ ์ด์ ๋ ๊นจ๋ํ ๊ฒฐ๊ณผ์์ quality๊ฐ ์ด๋ฏธ ํ ๋ง์ ๋ํ์ดํ ๋ฟ์ด๊ธฐ ๋๋ฌธ์ด๊ณ , ๊ทธ๋งํผ(์ธก์ ๊ฐ 797 B) ๋งค ์๋ต์ด ๊ฐ๋ฒผ์์ง๋๋ค.
์์ฐ์ ์๋ ๊ฒ๊ณผ ๋ชป ๋ฐ์ ๊ฒ์ด ์ ํ ๋ค๋ฅธ ์ํฉ์ธ๋ฐ ์์ ์๋ ๋ ๋ค ๋น ๋ชฉ๋ก์ผ๋ก ๋ณด์์ต๋๋ค. ์ง๊ธ์ assetSummary๊ฐ ๊ตฌ๋ถํด ์ค๋๋ค.
status:none(์์ฐ์ด ์๋ค) ยทunknown(์ค๋ ์ท์ด ๋ถ์์ ํด ํ๋จ ๋ถ๊ฐ) ยทnot-collectedยทpartialยทcollecteddiscovery:complete|incomplete,discoveryReason:index-only|snapshot-incompletediscoveredCount/collectedCount/manifestIncludedunavailable[]: ํญ๋ชฉ๋ง๋คassetId,nodeId,errorCode์reasonโhidden-node(์จ๊น ๋ ธ๋) ยทexport-failed(export ์คํจ) ยทnot-requested(์ ์ด์ ์์ฒญํ์ง ์์) ยทcapture-not-in-artifact(์์ฒญํ์ง๋ง ์ด artifact์ ๊ทธ format/scale์ด ์์)export-failed์๋errorDetail์ด ๋ถ์ต๋๋ค โ ์คํจํ ๋จ๊ณ, ๊ฑธ๋ฆฐ ์๊ฐ, Figma๋ ์ ์ก์ด ํ ๋ง ๊ทธ๋๋ก(์ต๋ 500์). ์์ ์๋ ํ๋ฌ๊ทธ์ธ ์คํฌ๋ฆฝํธ๊ฐ ์์ธ๋ฅผ ๋ฒ๋ ค์ ์ฝ๋๋ง ๋จ์๊ณ , ์ธ์คํด์ค ์์ชฝ ๋ ์ด์ด ์ฌ์ฏ ๊ฐ๊ฐ ๊ฐ๊ฐ 11์ด์ฉ ๊ฑธ๋ ค ์คํจํ ์ด์ ๋ฅผ ์๋ฌด๋ ์ ์ ์์์ต๋๋ค.failures[]์ ๊ฐ์ ํญ๋ชฉ์๋errorDetail์ด ์ค๋ฆฌ๊ณ , Figma ๋ฐํ์์ด ๋ณด๊ณ ์๋ ํ์ด์ง ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค์ง ๋ชปํ ๊ฒฝ์ฐ๋ฉดhint๊ฐ ํ ์ผ์ ๋งํฉ๋๋ค
์จ๊น ๋
ธ๋ ์คํจ๋ failures[]๊ฐ ์๋๋ผ warnings[]๋ก ๊ฐ๋๋ค. ๊ตฌํ์ ๋ง๋ ์คํจ๊ฐ ์๋๊ธฐ ๋๋ฌธ์
๋๋ค.
๊ทธ ์ฌ์ฏ ๊ฐ์ ์์ธ์ Figma ๋ฐ์คํฌํฑ ์ฑ์ ํญ์ด์์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ๋๋ ํ์ผ์ ํญ์ด ๋ค๋ฅธ ํ์ผ์ ํญ ๋ค์ ๋์ฌ ์๋ ๋์, Figma ๋ฐํ์์ ์์ง ๋ถ๋ฌ์ค์ง ์์ ๋ฐ์ดํฐ๊ฐ ํ์ํ ์ฝ๊ธฐ โ ์ธ์คํด์ค ์์ชฝ ๋ ์ด์ด์ export, ๋ค๋ฅธ ํ์ด์ง์ ๋ฉ์ธ ์ปดํฌ๋ํธ, id๋ก ์ฐพ๋ ๋ณ์์ ์คํ์ผ โ ๋ง๋ค 10์ด๋ฅผ ๊ธฐ๋ค๋ฆฐ ๋ค "Unable to establish connection to Figma after 10 seconds"๋ก ๋ตํ์ต๋๋ค. ๊ทธ ํญ์ ๋๋ฅด์ ๊ฐ์ ์ฝ๊ธฐ๊ฐ ๊ณง๋ฐ๋ก ๋ตํ์ต๋๋ค โ ๊ทธ ๋ฌธ๊ตฌ๋ก 10.4 s ๋ง์ ์คํจํ๋ ๊ฒ์์ด 0.2 s์ ๋ตํ๊ณ , ๊ณต์ง ํ๋ฉด์ด ์ฐ๋ ๋ณ์ยท์คํ์ผ์ด 0/14ยท0/23์์ 14ยท23์ผ๋ก ๋์์์ต๋๋ค. ๋ถ ๋จ์๋ก ๋ค์ ์ฌ ๋ณด๋ ํญ์ด ๋ค๋ก ๊ฐ ์ง 1๋ถ์งธ๋ ๋ตํ๊ณ 2๋ถ์งธ๋ถํฐ ๊ฐ์ ๋ฌธ๊ตฌ๋ก ์คํจํ๊ณ , ํญ์ ์์ ๋ ์ฑ ์ฐฝ๋ง ์ต์ํํด๋ 3๋ถ์งธ๋ถํฐ ๊ฐ์์ต๋๋ค โ ๊ทธ ํ์ผ์ด ํ๋ฉด์ ๋ณด์ด์ง ์๋ ๊ฒ์ด ์์ธ์
๋๋ค(์๋ "๊ทธ ํ์ผ์ ํ๋ฉด์ ๋์ ๋์ธ์"). ์ฒ์์๋ ๋ช ์๊ฐ ์ด์ด ๋ ํ๋ฌ๊ทธ์ธ ์ฐฝ์ ์์ธ์ผ๋ก ๋ณด์์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ ๊ทธ ํ์ผ์ ํญ์์๋ง ์คํ๋๋ฏ๋ก, ๋ค์ ์คํํ๋ ์ฒ๋ฐฉ์ด ํตํ ๊ฒ๋ ํ์ผ์ด ์์ผ๋ก ์๊ธฐ ๋๋ฌธ์ผ๋ก ๋ณด์
๋๋ค. ์ด ๋ฌธ๊ตฌ๊ฐ ์ค๋ฉด hint(์์ฐ)์ nextAction.how(์ฝ๊ธฐ)๊ฐ ์ฐฝ์ ์ด๊ณ ๊ทธ ํ์ผ์ ํญ์ ๋๋ฅด๋ผ๊ณ ๋งํ๊ณ , ํด์ํ์ง ๋ชปํ ๋ณ์ยท์คํ์ผ์ด ์์ผ๋ฉด completenessReport.resources์ Figma๊ฐ ํ ๋ง(lookupError)๊ณผ ๊ฐ์ hint๊ฐ ์ค๋ฆฝ๋๋ค.
rawSnapshot๊ณผ rawPayload๋ ์์งํ ๋์์ธ์ raw๋ก ๋ด์ ๊ฒ์ด๋ผ debug: true ์์ด๋ ๊ฑฐ์ ๋ฉ๋๋ค. ํ๋ฉด์ ๊ตฌํํ๋ ๋ฐ๋ ํ์ ์์ต๋๋ค โ ์ค์ ์บก์ฒ 10๊ฐ ํ๋ฉด์์ tsx๊ฐ nodeยทtextยทtypographyยทassetยทlayout ๊ธฐ๋์น๋ฅผ 100% ๋ด๊ณ ์์ต๋๋ค. ์ฐ๋ ์๋ฆฌ๋ ํ๋์
๋๋ค: ํ๋ฉด์ด ์ด์ํด ๋ณด์ผ ๋ ์์ฑ๊ธฐ ํ์ธ์ง ๋์์ธ์ด ์๋ ๊ทธ๋ฐ์ง ํ์ ํ๋ ๊ฒ. ๊ทธ๋๋ ๋์์ธ์ ์ฝ๋ ์์ ๋๊ณ ์ฝ์ด์ผ ํ๊ณ , ๊ทธ๊ฒ ์ด ํ๋๊ทธ์
๋๋ค.
์๋ฌ๋ ํธ์ถ ์์ฒด๊ฐ ์๋ชป๋ ๊ฒฝ์ฐ(DEVUP_INVALID_INPUT, ์๋ node/ํ์ผ, ๋ง๋ฃยท๋ถ์ ํฉํ artifactId ๋ฑ) JSON-RPC -32602 INVALID_PARAMS๋ก, ๊ทธ ๋ฐ์ ์คํจ๋ -32603 INTERNAL_ERROR๋ก ์ต๋๋ค. ์ธ์๋ฅผ ๊ณ ์ณ ๋ค์ ๋ถ๋ฅผ ์ผ์ธ์ง ๋ฉ์ถ๊ณ ๋ณด๊ณ ํ ์ผ์ธ์ง๋ฅผ ๋ฉ์์ง๋ฅผ ํ์ฑํ์ง ์๊ณ ๊ตฌ๋ถํ ์ ์์ต๋๋ค. ์ ํํ code์ retryable์ ์์ ์ฒ๋ผ data์ ๊ทธ๋๋ก ์ค๋ฆฝ๋๋ค.
์ด ๊ตฌ๋ถ์ ํ๋ฌ๊ทธ์ธ์ด ๋์ง ์ค๋ฅ์๋ ์ ์ฉ๋ฉ๋๋ค. ์คํฌ๋ฆฝํธ๊ฐ ๋์ง๋ ์ฝ๋๋ 25์ข
์ธ๋ฐ ๊ทธ์ค JSON payload๋ฅผ ํจ๊ป ์ฃ๋ ๊ฒ์ ๋๋ฟ์ด๋ผ, ๋๋จธ์ง๋ pluginCode: null์ ์ผ๋ฐ ์๋ด๋ง ๋ฌ๋ ค ๋์ฐฉํ์ต๋๋ค. ์ง๊ธ์ ๋ฉ์์ง์์ ์ฝ๋๋ฅผ ์ฝ์ด pluginCode์ ์ฑ์ฐ๊ณ , ํธ์ถ์๊ฐ ๊ณ ์น ์ ์๋ ๊ฒ๋ง ๊ทธ์ ๋ง๋ code๋ก ์ฌ๋ฆฝ๋๋ค.
| ํ๋ฌ๊ทธ์ธ ์ฝ๋ | code |
JSON-RPC |
|---|---|---|
DEVUP_NODE_NOT_FOUND ยท DEVUP_PAGE_NOT_FOUND |
DEVUP_FIGMA_NODE_NOT_FOUND |
-32602 |
DEVUP_ENVELOPE_TOO_LARGE ยท DEVUP_EXPLORE_PROJECTION_TOO_LARGE |
DEVUP_FIGMA_RESPONSE_TOO_LARGE |
-32603 |
| ๊ทธ ๋ฐ(์์ง ๋ด๋ถ ์กฐ๊ฑด) | DEVUP_SNAPSHOT_UNSUPPORTED |
-32603 |
์๋ node๋ฅผ ๊ฐ๋ฆฌํค๋ ๋งํฌ๋ ๊ฐ์ฅ ํํ ์ค์์ธ๋ฐ ์์ ์๋ -32603 INTERNAL_ERROR๋ก ์์, ์ ๋ฌธ๋จ์ด ์ฝ์ํ ๊ตฌ๋ถ์ด ๋ฐ๋ก ๊ทธ ์ง์ ์์ ๊นจ์ก์ต๋๋ค. ๋ด๋ถ ์์ง ์กฐ๊ฑด๊น์ง ํธ์ถ์ ์ค์๋ก ์ฌ๋ฆฌ์ง๋ ์์ต๋๋ค โ ๊ณ ์น ๊ฒ์ด ์๋ ์ฌ๋์๊ฒ ์ธ์๋ฅผ ๊ณ ์น๋ผ๊ณ ๋ณด๋ด๋ ์
์ด๊ธฐ ๋๋ฌธ์
๋๋ค.
devup-mcp๋ Figma Remote MCP์ ์ง์ ๋ถ์ต๋๋ค โ OAuth discovery, Dynamic Client Registration, PKCE S256, ์ผ์์ ์ธ 127.0.0.1 callback์ ๊ตฌํํฉ๋๋ค. Figma๋ MCP Catalog์ ์น์ธ๋ client์ registration๋ง ํ์ฉํ๋ฏ๋ก ๋ฑ๋ก์ allowlist์ ์๋ client_name์ผ๋ก ์ด๋ฃจ์ด์ง๋๋ค(๊ธฐ๋ณธ๊ฐ Codex). Figma PAT๋ ์ฌ์ฉ์๊ฐ ๋ง๋ OAuth app์ ํ์ํ์ง ์์ต๋๋ค.
๋ฆด๋ฆฌ์ค๋ง๋ค devup-mcp-<version>.mcpb ํ์ผ ํ๋๊ฐ ํจ๊ป ์ฌ๋ผ๊ฐ๋๋ค. ์ด ํ๋์ Linux x86_64, Windows x86_64, macOS universal ๋ฐ์ด๋๋ฆฌ๊ฐ ๋ชจ๋ ๋ค์ด ์๊ณ , manifest.json์ server.mcp_config.platform_overrides๊ฐ ์คํ ์์ ์ ํธ์คํธ์ ์ด์์ฒด์ ์ ๋ง๋ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๊ณ ๋ฆ
๋๋ค. ์ด์์ฒด์ ๋ณ๋ก ์ด๋ค ํ์ผ์ ๋ฐ์์ผ ํ๋์ง ๊ณ ๋ฅผ ํ์๊ฐ ์๊ณ , Rust ํด์ฒด์ธ๋ Node ๋ฐํ์๋ cargo install๋ ํ์ํ์ง ์์ต๋๋ค.
- Releases์์
devup-mcp-<version>.mcpb๋ฅผ ๋ฐ์ต๋๋ค. .mcpb๋ฅผ ์ง์ํ๋ ํธ์คํธ(์: Claude for macOS/Windows)์์ ํ์ผ์ ์ฝ๋๋ค.- ์ค์น ๋ํ์์์ Workspace directory์ ์ฝ๋๋ฅผ ์์ฑํ ํ๋ก์ ํธ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ง์ ํฉ๋๋ค. ์ด ๋๋ ํฐ๋ฆฌ๊ฐ devup-mcp๊ฐ ํ์ผ์ ์ธ ์ ์๋ ์ ์ผํ ์์น์ด๋ฉฐ,
..ยท๋ค๋ฅธ driveยทsymlink๋ก ๊ทธ ๋ฐ์ ๊ฐ๋ฆฌํค๋ ๊ฒฝ๋ก๋ ๊ธฐ๋ก ์ ์ ๊ฑฐ์ ๋ฉ๋๋ค. ์ฌ๋ฌ root๊ฐ ํ์ํ๋ฉด ์๋ stdio ์ค์ ์ผ๋ก--allow-write-root๋ฅผ ๋ฐ๋ณตํด ๋ฑ๋กํ์ธ์.
.mcpb๋ ๊ทธ๋ฅ zip์ด๋ฏ๋ก unzip -l๋ก ๋ด์ฉ์ ํ์ธํ ์ ์๊ณ , ์์ ๋ฐ์ด๋๋ฆฌ๋ ๊ฐ์ ๋ฆด๋ฆฌ์ค์ ๋ฐ๋ก ์ฌ๋ผ๊ฐ๋ ๊ฒ๊ณผ ๊ฐ์ ํ์ผ์
๋๋ค. CI๋ pack ์งํ ์์นด์ด๋ธ๋ฅผ ๋ค์ ์ฝ์ด Unix ๋ฐ์ด๋๋ฆฌ์ ์คํ ๋นํธ๊ฐ ๋จ์ ์๋์ง ํ์ธํ๊ณ , ์์ผ๋ฉด ๋ฆด๋ฆฌ์ค๋ฅผ ๊ฒ์ํ์ง ์์ต๋๋ค. ๊ทธ๋ผ์๋ macOS์์ ์ค์น ์งํ ์๋ฒ๊ฐ EACCES๋ก ์คํจํ๋ค๋ฉด ํธ์คํธ๊ฐ ์์ถ์ ํ๋ฉด์ ๊ถํ์ ์ง์ด ๊ฒฝ์ฐ์ด๋ฉฐ(mcpb#294), ๊ทธ๋๋ ๊ฐ์ ๋ฆด๋ฆฌ์ค์ devup-mcp-macos-universal ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ง์ ๋ฐ์ ์๋ stdio ์ค์ ์ผ๋ก ๋ฑ๋กํ๋ฉด ๋ฉ๋๋ค.
Rust 1.98 ์ด์์ด ํ์ํฉ๋๋ค. compile-in Figma ํ์ ํ๋ fixture๋ฅผ ์ง์ ์คํํ๋ ค๋ฉด CI์ ๋์ผํ Node.js 24๊ฐ ํ์ํ๋ฉฐ ์ ํ binary์๋ Node๊ฐ ํ์ํ์ง ์์ต๋๋ค.
cargo install --git https://github.com/dev-five-git/devup-mcp.git --branch owjs3901/figma-remote-mcp devup-mcp์ค์น ๋๋ binary ๊ต์ฒด ํ์๋ ๋จผ์ ๋ก์ปฌ ์ง๋จ์ ์คํํฉ๋๋ค.
devup-mcp --version
devup-mcp --self-check--version์ package version๊ณผ build ID๋ฅผ, --self-check๋ network/OAuth ์์ด binary,
credential backend ์ด๊ธฐํ์ server ๊ตฌ์ฑ์ ์์ ํ JSON์ผ๋ก ํ์ธํฉ๋๋ค. ๋ ๋ค ์ฑ๊ณตํ์ง๋ง
๋ฑ๋ก๋ connector๊ฐ Transport closed๋ฅผ ๋ฐํํ๋ฉด MCP host๊ฐ ๊ต์ฒด ์ process์ ์ข
๋ฃ๋
stdio pipe๋ฅผ ๋ณด์ ํ ์ํ์ด๋ฏ๋ก host์ MCP ์ฐ๊ฒฐ์ ์ฌ์์ํ๊ฑฐ๋ ๋ค์ ๋ฑ๋กํด์ผ ํฉ๋๋ค.
์๋ก ์คํ๋ server๊ฐ host๊ฐ ๋ณด์ ํ ์ด์ pipe๋ฅผ ์ค์ค๋ก ๋ณต๊ตฌํ ์๋ ์์ต๋๋ค.
์ง์ ์ฌ๋ ค ๋์ง ์์๋ ์ต์ ๋ฆด๋ฆฌ์ค๋ก ์๋ ดํฉ๋๋ค. ๋ฆด๋ฆฌ์ค ํ์ธ(24์๊ฐ ์ฃผ๊ธฐ, ์ฒซ ํ์ธ์ initialize 20์ด ๋ค)์ด ์ ๋ฒ์ ์ ์ฐพ์ผ๋ฉด ์ด ํ๋ซํผ์ ์์
์ ๋ฐ์ devup-mcp.exe.staged๋ก ๋๊ณ , ๊ทธ ํ์ผ์ด ์ค์ ๋ก ์คํ๋ผ --self-check์ ๋ตํด์ผ๋ง ๊ทธ ์๋ฆฌ์์ ์คํ ํ์ผ์ ์ด๋ฆ์ ๋๊ฒจ๋ฐ์ต๋๋ค.
์ ์ฉ์ ๋ค์ ์คํ๋ถํฐ์ ๋๋ค. ์ฌ์์ ํ ๋ฒ์ด๋ฉด ๋ฉ๋๋ค.
| ์์ | ์ผ์ด๋๋ ์ผ | ๊ทธ ์ธ์ ์ด ๋๋ build |
|---|---|---|
| ์ธ์ N | ๊ฐ์ง โ ๋ค์ด๋ก๋ โ ๊ฒ์ฆ โ ๊ต์ฒด | ์ด์ build (์ด๋ฏธ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋จ) |
| ์ธ์ N+1 | โ | ์ build |
์คํ ์ค์ธ ํ๋ก์ธ์ค๋ ์ ๋ ๊ต์ฒดํ์ง ์์ต๋๋ค. ์ ๋ฌธ๋จ์ด ๋งํ ๊ทธ๋๋ก, ์ด๋ฏธ host๊ฐ ์ฅ stdio pipe๋ ๊ต์ฒด๋ binary๊ฐ ๋ณต๊ตฌํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ฐ๊พธ๋ ๊ฒ์ ๋์คํฌ์ ํ์ผ๋ฟ์ด๊ณ , ์ด ํ๋ก์ธ์ค๊ฐ ์คํ ์ค์ธ image๋ spawn ์์ ์ ๋ก๋๋ ๊ฒ์ด๋ผ rename์ด ๋ฟ์ง ์์ต๋๋ค. ๊ทธ๋์ ๊ฒ์ฆ ์งํ ๋ฐ๋ก ๊ต์ฒดํด๋ ์์ ํ๋ฉฐ, ๊ต์ฒด๊ฐ ์ผ์ด๋ ์ธ์ ์ stderr์ ๊ทธ ์ฌ์ค์ ์ ๊ณ ๊ณ์ ์ด์ build๋ก ๋๋๋ค.
๊ธฐ๋ ์์ ์ ์น๊ฒฉ์ ์ด์ ๋ณต๊ตฌ ๊ฒฝ๋ก์ ๋๋ค โ ๊ฒ์ฆ๊น์ง ๋๋ธ ํ์ผ์ ๋๊ณ ํ๋ก์ธ์ค๊ฐ ์ฃฝ์ ๊ฒฝ์ฐ์๋ง ์ฐ์ ๋๋ค.
| ์ํ | ๋ป |
|---|---|
owned |
์ด ํ๋ก์ธ์ค๊ฐ ์ค์น ์์น์ ์ฃผ์ธ์ด๋ผ ์คํ ์ด์งํฉ๋๋ค |
package-managed |
binary๊ฐ ํจํค์ง ๋งค๋์ ๋๋ ํฐ๋ฆฌ(_npx, node_modules, .cargo ๋ฑ) ์์ ์์ต๋๋ค. ๊ทธ์ชฝ์ด ์๊ธฐ ์ฃผ๊ธฐ๋ก ๊ฐฑ์ ํ๋ฏ๋ก ๊ฑด๋๋ฆฌ์ง ์์ต๋๋ค |
not-writable |
์ค์น ๋๋ ํฐ๋ฆฌ์ ์ธ ์ ์์ผ๋ฏ๋ก ์ค์นํ ์ฃผ์ฒด์ ๋ชซ์ ๋๋ค |
unsupported-platform |
์ด ํ๋ซํผ/์ํคํ ์ฒ์ฉ์ผ๋ก ๋ฐํ๋ ์์ ์ด ์์ต๋๋ค |
disabled |
DEVUP_MCP_NO_AUTO_UPDATE๋ก ๊ป๊ฑฐ๋, DEVUP_MCP_NO_UPDATE_CHECK๋ก ๋ฆด๋ฆฌ์ค ํ์ธ ์์ฒด๋ฅผ ๊ป์ต๋๋ค. ํ์๋ฉด ์ ๋ฆด๋ฆฌ์ค๋ฅผ ๋ฐ๊ฒฌํ๋ ์ผ์ด ์์ด ์คํ
์ด์ง์ด ํ ์ผ์ด ์์ผ๋ฏ๋ก, ์คํ
์ด์ง์ ๋์ง ์์์ด๋ ๊ฒฐ๊ณผ๋ ๊บผ์ง ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. note๊ฐ ๋ ์ค ์ด๋ ์ชฝ์ธ์ง ์๋ ค์ค๋๋ค |
server.updateAvailable.autoUpdate๊ฐ ์ด ์ํ์ stagedForNextStart, ์ด ํ๋ซํผ์ asset, ๊ทธ๋ฆฌ๊ณ **๊ต์ฒดํ ํ์ผ์ ์ค์ ๊ฒฝ๋ก์ธ installedPath**๋ฅผ ํจ๊ป ๋ณด๊ณ ํฉ๋๋ค. ์๋์ด ๋ฌผ๋ฌ๋ ๊ฒฝ์ฐ ์ฌ๋์ด ๋ฌด์์ ๊ณ ์ณ์ผ ํ๋์ง๊ฐ ์๋ต ์์ ์์ต๋๋ค.
๊ฒ์ฆ๋์ง ์์ bytes๋ ์ด๋ฆ์ ๋๊ฒจ๋ฐ์ง ๋ชปํ๊ณ ๊ทธ ์๋ฆฌ์์ ์ญ์ ๋ฉ๋๋ค โ ๋งค ์์๋ง๋ค ๊ฐ์ ํ์ผ์ ๋ค์ ๊ฒ์ฌํ์ง ์๊ธฐ ์ํด์์
๋๋ค. ์น๊ฒฉ์ ์ญ์ ๊ฐ ์๋๋ผ rename์ด๋ผ ์ง์ binary๊ฐ devup-mcp.exe.previous๋ก ๋จ๊ณ , ๋๋๋ฆฌ๋ ์ผ์ rename ํ ๋ฒ์
๋๋ค.
๋ฐ์ฒ๋ก ์ค์นํ๋ค๋ฉด ์ด ๊ธฐ๋ฅ์ ํ์ ์์ต๋๋ค. npx ... @latest ๊ฐ์ ๋ฐ์ฒ๋ ๋งค ์คํ๋ง๋ค ์ต์ ์ ํด๊ฒฐํ๋ฏ๋ก ๊ทธ์ชฝ์ด ๋ ๋์ ๋ฐฉ๋ฒ์ด๊ณ , ๋ ๊ฐฑ์ ์ฃผ์ฒด๊ฐ ํ ๊ฒฝ๋ก๋ฅผ ๋๊ณ ๋คํฌ๋ ๊ฒ์ด ๋ ์ค ํ๋๋ง ์๋ ๊ฒ๋ณด๋ค ๋์ฉ๋๋ค. ๊ทธ๋ฐ ์ค์น๋ ์ ํ์ package-managed๋ก ์ค์ค๋ก ๋ฌผ๋ฌ๋๋ฉฐ, ์๋๋ผ๋ฉด DEVUP_MCP_NO_AUTO_UPDATE=1๋ก ๋์ญ์์ค.
์๋ฒ ์์ ์ OAuth ์ค๋น๊ฐ ์คํจํ๋ฉด ํ๋ก์ธ์ค๊ฐ ์ฃฝ์ง ์๊ณ ์ง๋จ ๊ฐ๋ฅํ ์ค๋ฅ๋ก ๋์ต๋๋ค. HTTP ํด๋ผ์ด์ธํธ ์ด๊ธฐํ๊ฐ ์คํจํ๋ฉด DEVUP_FIGMA_DIRECT_UNAVAILABLE๋ก Cannot start Figma OAuth: HTTP client initialization failed. Check TLS configuration and system certificate initialization, then restart devup-mcp.์ ํจ๊ป ์์ธ ์ฒด์ธ์ ๋ถ์ฌ ๋๋ ค์ค๋๋ค. endpoint URL์ด ์๋ชป๋์ผ๋ฉด DEVUP_INVALID_INPUT์
๋๋ค. ์์ ์๋ ์ด ๊ฒฝ๋ก๊ฐ panic์ด๋ผ ๋ฌด์์ด ์๋ชป๋๋์ง ์ ์ ์์์ต๋๋ค โ TLS๋ ์์คํ
์ธ์ฆ์ ์ค์ ์ ๋จผ์ ํ์ธํ์ธ์.
์์ค์์ ๊ฒ์ฆํ๋ ค๋ฉด ๋ค์์ ์คํํฉ๋๋ค.
cargo fmt --all -- --check
node --test crates/devup-mcp-figma/tests/explore_script_behavior.mjs plugin/tests/withdraw.test.mjs harness/runtime-audit/test/checks.test.mjs
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo test -p devup-mcp --test stdio_smoke
cargo insta test --workspace --all-features --check
cargo build --workspace --releasestdio MCP๋ฅผ ์ง์ํ๋ ํด๋ผ์ด์ธํธ์ ๋ค์๊ณผ ๊ฐ์ด ๋ฑ๋กํฉ๋๋ค.
{
"mcpServers": {
"devup-mcp": {
"command": "devup-mcp",
"args": ["--allow-write-root", "/absolute/path/to/workspace"]
}
}
}์์คํ
๋ธ๋ผ์ฐ์ ๋ devup_figma_auth์ login์ ๋ช
์์ ์ผ๋ก ํธ์ถํ ๋๋ง ์ด๋ฆฝ๋๋ค. ๋ณํ ๋๊ตฌ๋ ์๊ฒฉ์ฆ๋ช
์ด ์์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๋ฅผ ์ด์ง ์๊ณ ๋ก๊ทธ์ธ์ด ํ์ํ๋ค๋ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ์ธ์ฆ ์ ๋ณด๋ ์ด์์ฒด์ credential store์๋ง ์ ์ฅ๋๋ฉฐ logout์ ํด๋น ์ ๋ณด๋ง ์ญ์ ํฉ๋๋ค. DEVUP_FIGMA_CREDENTIAL_STORE=memory๋ก ์์ํ๋ฉด ์ด์์ฒด์ ์ ์ฅ์๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ ๋น์ด ์๋ ๋ฉ๋ชจ๋ฆฌ ์ ์ฅ์๋ก ์์ํฉ๋๋ค โ ์ ์ฅ๋ ๋ก๊ทธ์ธ์ ์ง์ฐ์ง ์๊ณ ๋ก๊ทธ์ธ ์๋ ๋์์ ํ์ธํ ๋ ์๋๋ค.
{ "action": "status" }action์ status, login, logout, configure, doctor ์ค ํ๋์ด๋ฉฐ, ์คํค๋ง๊ฐ ์ด ๋ชฉ๋ก์ ๊ทธ๋๋ก ๊ฒ์ํฉ๋๋ค. status๋ OAuth ์ํ๊ฐ ์๋๋ผ Figma์ ๋ฟ๋ ๊ฒฝ๋ก ์ ์ฒด๋ฅผ ๋ณด๊ณ ํฉ๋๋ค. login/logout๋ ๋์์ ๋ง์น ๋ค ๊ฐ์ ๋ณด๊ณ ๋ฅผ ๋๋ ค์ค๋๋ค.
{
"connected": true,
"status": "connected",
"activePath": "bridge",
"preferredPath": "bridge",
"paths": {
"bridge": {
"available": true,
"role": "relay",
"listening": false,
"port": 1993,
"host": { "pid": 32536, "version": "0.12.0", "buildId": "f1962d5", "thisProcess": false },
"attachedFiles": [{
"fileKey": null,
"fileName": "Landing",
"currentPage": { "id": "0:1", "name": "Page 1" },
"selection": [{ "id": "1:2", "name": "Hero", "type": "FRAME" }],
"selectionCount": 1,
"fileKeyNote": "This plugin could not report its file key ..."
}],
"attachedFilesNote": "The files the attached plugins have open, with the page in view and what is selected on it - as the devup-mcp holding the bridge port sees them ...",
"reason": "Another devup-mcp on this machine (pid 32536, ...) holds the bridge port 1993 and the plugins attach to it; this process reads through it. ..."
},
"direct": {
"available": false,
"credentialSource": "none",
"credentialSourceNote": "Where the OAuth *client registration* credential came from ...",
"tokenState": "absent",
"callbackPort": { "port": null, "free": null },
"registrationClientName": { "value": "Codex", "isDefault": true },
"reason": "No access token is stored. ... While a bridge plugin is attached this path is needed only for ..."
}
},
"nextAction": {
"tool": "devup_figma_export",
"arguments": { "outputs": ["tsx"] },
"note": "One Devup Bridge plugin is attached, so no url is needed: ..."
}
}connected/activePathโ ์ง๊ธ ์ฝ๊ธฐ๊ฐ ์ค์ ๋ก ์ด๋ ๊ฒฝ๋ก๋ก ๊ฐ๋์ง. ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์์ผ๋ฉดbridge, ์๋๋ฉด ํ ํฐ์ด ์์ ๋direct, ๋ ๋ค ์์ผ๋ฉดnull์ ๋๋ค.- ์ต์์
status๊ฐdisconnected์ธ ๊ฒ์ ๋ ๊ฒฝ๋ก๊ฐ ๋ชจ๋ ๋งํ์ ๋๋ฟ์ ๋๋ค. ์์ ์๋ direct(OAuth) ํ๋๋ง ๋ณด๊ณdisconnected๋ผ๊ณ ๋ตํด์, ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์๋๋ฐ๋ ์์ด์ ํธ๊ฐ ์ฌ์ฉ์์๊ฒ ๋ก๊ทธ์ธ์ ์์ฒญํ์ต๋๋ค.statusํค๋ ๊ทธ๋๋ก๋ผ ๊ทธ ๊ฐ๋ง ์ฝ๋ ํธ์ถ์๋ ๊นจ์ง์ง ์์ต๋๋ค. paths.bridge.attachedFilesโ ๋ถ์ด ์๋ ํ๋ฌ๊ทธ์ธ๋ง๋ค ํ์ผ ์ด๋ฆ, ๋ณด๊ณ ์๋ ํ์ด์ง, ์ ํํ ๋ ธ๋(์ 20๊ฐ)์ ์ ์ฒด ์. ํ์ผ ํค๋ฅผ ๋ณด๊ณ ํ์ง ๋ชปํ ํ๋ฌ๊ทธ์ธ(์: manifest์enablePrivatePluginApi๊ฐ ์๋ ์์ ๋น๋)์fileKey: null์ด๋ฉฐ, ํ์ด์งยท์ ํ์ ๋ณด๊ณ ํ๊ธฐ ์ ์ ๋น๋๋ ํ๋ฌ๊ทธ์ธ์selection: null์ ๋๋ค.inView๋ Figma๊ฐ ๊ทธ ํ์ผ์ ์ง๊ธ ํ๋ฉด์ ๋ณด์ฌ ์ฃผ๋์ง์ด๊ณ ,false๋ฉดinViewNote๊ฐ ํ ์ผ์ ๋งํฉ๋๋ค(์๋ "๊ทธ ํ์ผ์ ํ๋ฉด์ ๋์ ๋์ธ์").nextActionโ ์ง๊ธ ์ํ์์ ํ ๋ค์ ํธ์ถ. ํ๋ฌ๊ทธ์ธ ํ๋๋ฉด url ์๋devup_figma_export, direct๋ง ์ด๋ ค ์์ผ๋ฉด frame ๋งํฌ๊ฐ ํ์ํ export, ๋ ๋ค ๋งํ์ผ๋ฉดoptions์ ํ๋ฌ๊ทธ์ธ ์คํ(๊ถ์ฅ)๊ณผ ๋ก๊ทธ์ธ์ ์ฐจ๋ก๋ก ๋ด์ต๋๋ค.
login์ ๋ง์ง ์๊ณ ๊ฒฝ๊ณ ํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์์ ๋ ๋ถ๋ฅด๋ฉด ๋ก๊ทธ์ธ์ ๊ทธ๋๋ก ์งํํ๊ณ , ์๋ต์ warning์ด ๋ถ์ต๋๋ค โ ๋ธ๋ฆฌ์ง๊ฐ ๋ชจ๋ ์ฝ๊ธฐ๋ฅผ ๋งก์ผ๋ฉฐ, ๋ก๊ทธ์ธ์ ํ๋ฌ๊ทธ์ธ์ด ๋ค ๋ตํ์ง ๋ชปํ ์ฝ๊ธฐ(ํ์ผ์ด ํ๋ฉด์ ๋ณด์ด์ง ์๋ ๋์ Figma๊ฐ ๋ด์ฃผ์ง ์์ ๋ฐ์ดํฐ, get_screenshot์ฒ๋ผ ๊ทธ๋ฆฌ์ง ๋ชปํ ์ฐธ์กฐ PNG, ์ค๋๋ ํ๋ฌ๊ทธ์ธ์ด ๋ชจ๋ฅด๋ ์ฝ๊ธฐ)๋ฅผ ํ๋๋ฅผ ์ฐ๋ direct ๊ฒฝ๋ก๋ก ๋ค์ ์ฝ๊ฒ ํ ๋ฟ์ด๋ผ๋ ๋ด์ฉ์
๋๋ค.
{ "action": "doctor" }doctor๋ ๊ฐ์ ๋ณด๊ณ ์ preferredPathNote์ ํด๋ผ์ด์ธํธ ์ค์ ์ฐธ์กฐ ๋ฐ์ดํฐ(clientSetup)๋ฅผ ๋ํฉ๋๋ค. status์ doctor ๋ชจ๋ ๋คํธ์ํฌ ํธ์ถ์ ์ ํ ํ์ง ์์ต๋๋ค.
์ฐ๊ฒฐ์ "์ธ์ฆ"๊ณผ ๋ผ์ด ๋์ผ๋ ค๊ณ ๋ณ๋ ๋๊ตฌ(devup_figma_connection ๋ฑ)๋ฅผ ๋๋ ๋ฐฉ์๋ ๊ฒํ ํ์ง๋ง ๋์ง ์์์ต๋๋ค. ๋๊ตฌ๊ฐ ํ๋ ๋๋ฉด ๋ชจ๋ ํด๋ผ์ด์ธํธ๊ฐ ๋งค ์ธ์
๊ทธ ์คํค๋ง๋ฅผ ์ฃ๊ณ , ์ด๋ฆ์ ๋ฐ๊พธ๋ฉด ๊ธฐ์กด ํธ์ถ์ด ๊นจ์ง๋๋ค. ๋์ devup_figma_auth์ ์ค๋ช
๊ณผ status์ ์๋ต์ด ๋ ๊ฒฝ๋ก๋ฅผ ๋จผ์ ๋งํฉ๋๋ค.
๊ฒฝ๋ก๋ ๋์ด๊ณ ๋๋ฑํ์ง ์์ต๋๋ค. preferredPath๊ฐ ์ธ์ ๋ bridge์ธ ์ด์ ์
๋๋ค โ ๋ธ๋ฆฌ์ง๋ ๋ก๊ทธ์ธ๋ ํ์ ์๊ณ Figma ํ๋๋ ์ฐ์ง ์์ต๋๋ค.
ํ ๊ธฐ๊ธฐ์ devup-mcp๊ฐ ์ฌ๋ฟ ๋ ์์ด๋(MCP ํด๋ผ์ด์ธํธยท์ธ์
๋ง๋ค ํ๋์ฉ ๋จ๋ ๊ฒ์ด ์ ์์
๋๋ค) ๋ชจ๋๊ฐ ๊ฐ์ ํ๋ฌ๊ทธ์ธ์ ์๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ๋ถ๋ ํฌํธ๋ฅผ ์ก์ ํ๋ก์ธ์ค๊ฐ ํธ์คํธ๊ฐ ๋๊ณ , ๋๋จธ์ง๋ ํธ์คํธ๋ฅผ ํตํด ์ฝ์ต๋๋ค. paths.bridge.role์ด ์ด ํ๋ก์ธ์ค๊ฐ ๋ฌด์์ ํ๋์ง ๋งํ๊ณ , ์ํ๋ง๋ค ๊ณ ์น๋ ๋ฐฉ๋ฒ์ด ๋ค๋ฅด๋ ๊ตฌ๋ถํด์ ์ฝ์ด์ผ ํฉ๋๋ค.
role |
๋ป | ํ ์ผ |
|---|---|---|
host |
์ด ํ๋ก์ธ์ค๊ฐ ํฌํธ๋ฅผ ์ฅ์๊ณ (listening: true) ํ๋ฌ๊ทธ์ธ์ด ์ฌ๊ธฐ์ ๋ถ์ต๋๋ค |
attachedFiles๊ฐ ๋น์ด ์์ผ๋ฉด ๋์ ํ์ผ์์ Devup Bridge ํ๋ฌ๊ทธ์ธ์ ์คํํ์ธ์ |
relay |
๋ค๋ฅธ devup-mcp๊ฐ ์ฅ ํฌํธ๋ฅผ ํตํด ์ฝ์ต๋๋ค. host๊ฐ ๊ทธ ํ๋ก์ธ์ค์ pidยท๋ฒ์ ยทbuildId์
๋๋ค |
ํธ์คํธ์ ๊ฐ์ต๋๋ค. attachedFiles๋ ์ด๋ ํ๋ก์ธ์ค์์ ๋ณด๋ ๊ฐ์ต๋๋ค |
connecting |
ํฌํธ๋ฅผ ์ฅ ํ๋ก์ธ์ค๊ฐ ๋ฐฉ๊ธ ๋ ๋ ์ด์ด๋ฐ๊ฑฐ๋ ๋ค์ ๋ถ๋ ์ค์
๋๋ค(handoverFrom์ด ๋ ๋ ํ๋ก์ธ์ค) |
๋ช ์ด ๋ค status๋ฅผ ๋ค์ ๋ถ๋ฅด์ธ์. ํ๋ฌ๊ทธ์ธ์ 2์ด๋ง๋ค ์ค์ค๋ก ๋ค์ ๋ถ์ต๋๋ค |
unavailable |
์ด ํ๋ก์ธ์ค๋ ์ง๊ธ ๋ธ๋ฆฌ์ง๋ฅผ ์ธ ์ ์์ต๋๋ค. issue๊ฐ ์ด์ ์
๋๋ค |
reason๊ณผ nextAction์ ์ฒซ ํญ๋ชฉ์ด ๊ณ ์น๋ ๋ฐฉ๋ฒ์
๋๋ค |
off |
DEVUP_FIGMA_BRIDGE_PORT๊ฐ off/0์ด๊ฑฐ๋ ํฌํธ ๋ฒํธ๊ฐ ์๋๋๋ค |
๋ธ๋ฆฌ์ง๋ฅผ ์ฐ๋ ค๋ฉด ๊ทธ ๊ฐ์ ์ง์ฐ์ธ์ |
issue๋ ๋ค์ ์ค ํ๋์
๋๋ค โ legacy-host(์ด ๊ธฐ๋ฅ ์ด์ ์ devup-mcp๊ฐ ํฌํธ๋ฅผ ์ฅ์์ต๋๋ค. ๊ทธ ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์์ยท๊ฐฑ์ ํ๋ฉด ์ด ํ๋ก์ธ์ค๊ฐ ์ค์ค๋ก ์ด์ด๋ฐ์ต๋๋ค), foreign-program(devup-mcp๊ฐ ์๋ ํ๋ก๊ทธ๋จ), incompatible-protocol(์ค๊ณ ๊ท์ฝ์ ํ์ด ๋ค๋ฅธ devup-mcp โ ํ๋ฆฐ ๋ต์ ๋ด๋๋ ์์ง ์์ต๋๋ค), authentication-failed(๊ฐ์ ์ฌ์ฉ์์ devup-mcp์์ ์ฆ๋ช
ํ์ง ๋ชปํจ), secret-unavailable, bind-failed. ์ด๋ ๊ฒฝ์ฐ๋ status๋ ๋ช ์ด ์์ ๋ตํ๊ณ ๊ธฐ๋ค๋ฆฌ์ง ์์ต๋๋ค.
legacy-host์ foreign-program์ ํฌํธ๋ฅผ ์ฅ ์ชฝ์ด ์์ ์ ๋ฐํ์ง ์์ผ๋ฏ๋ก, ์ด์์ฒด์ ์ ๊ทธ ํฌํธ์์ ๋ฃ๋ ํ๋ก์ธ์ค๋ฅผ ๋ฌผ์ด pidยท์ด๋ฆยท์คํ ํ์ผ ๊ฒฝ๋ก๋ฅผ ๋ถ์
๋๋ค โ ์์ devup-mcp๋ฉด host์(๋ฒ์ ์ ์ ์ ์์ด null), ๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ด๋ฉด holder์ ์ฃ๊ณ reason์๋ ์ ์ต๋๋ค. ์คํ ํ์ผ ๊ฒฝ๋ก๋ฅผ ๋ณด๋ฉด ์ด๋ ํด๋ผ์ด์ธํธ๊ฐ ์ค์นํ ๊ฒ์ธ์ง ๋๋ฌ๋ฉ๋๋ค. ๋ฌป๋ ๋ฐ๋ ์ธ๋ถ ๋ช
๋ น(Windows netstatยทtasklistยทPowerShell, macOS lsofยทps, Linux /proc)์ด ๋ค์ด์, status๋ ๊ทธ๊ฒ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋จผ์ ๋ตํ ๋ค ์๊ฒ ๋๋ ๋๋ก ๋ง๋ถ์
๋๋ค. ํฌํธ๋ฅผ ์ฅ ํ๋ก๊ทธ๋จ์ ์ด ์ฌ์ฉ์ ๊ถํ์ผ๋ก ์คํํด ๋ณด์ง๋ ์์ต๋๋ค.
available: true๋ ์ง๊ธ ์ค์ ๋ก ์ฝ๊ธฐ๋ฅผ ๋ณด๋ผ ์ ์์ ๋๋ง์
๋๋ค โ ํ๋ฌ๊ทธ์ธ์ด ๋ณด์ด๊ณ , ๊ทธ๊ฒ์ ๋ฟ๋ ๊ธธ(์ด ํ๋ก์ธ์ค์ ํฌํธ, ๋๋ ํฌํธ๋ฅผ ์ฅ ํ๋ก์ธ์ค์์ ์ฐ๊ฒฐ)์ด ์์ ๋. ์ด ์ํ๋ฉด ๋ก๊ทธ์ธ ์์ด ๊ทธ ํ์ผ์ ์์ง์ด ๊ทธ๋๋ก ๋๊ณ , ์ค๊ณ ํ๋ก์ธ์ค์์๋ ๋ก๊ทธ์ธํ๋ผ๋ ์๋ด๋ฅผ ํ์ง ์์ต๋๋ค.
paths.direct์ ์ธ ํ๋๋ ์๋ก ๋ค๋ฅธ ๊ฒ์ ๋งํ๋ฏ๋ก ํจ๊ป ์ฝ์ด์ผ ํฉ๋๋ค.
credentialSourceโ client ๋ฑ๋ก ์๊ฒฉ์ฆ๋ช (client_id/client_secret)์ด ์ด๋์ ์๋์ง.cli-arg,env,credential-store,none์ค ํ๋์ ๋๋ค.tokenStateโ ์ฌ์ฉ์์ access token ์ํ.valid,expired,absent์ค ํ๋์ ๋๋ค.availableโ ์ง๊ธ direct ๊ฒฝ๋ก๋ฅผ ์ธ ์ ์๋์ง.
credentialSource: "none"์ "์ฌ์ ๋ฑ๋ก๋ client๊ฐ ์ฃผ์
๋์ง ์์๋ค"๋ ๋ป์ผ ๋ฟ์ด๋ฉฐ, ๊ทธ ๊ฒฝ์ฐ ๋ก๊ทธ์ธ์ registrationClientName์ ์ด๋ฆ์ผ๋ก ๋์ ๋ฑ๋กํฉ๋๋ค. ๊ทธ๋ ๊ฒ ๋ก๊ทธ์ธํ ์ ์ ์ธ์
์ credentialSource: "none"๊ณผ tokenState: "valid"๋ฅผ ๋์์ ๋ณด์
๋๋ค. ์์ ์๋ ์ด ์กฐํฉ์ด ๋ชจ์์ฒ๋ผ ๋ณด์๋๋ฐ, ์ง๊ธ์ credentialSourceNote๊ฐ ์๋ต ์์์ ์ง์ ์ค๋ช
ํฉ๋๋ค.
callbackPort๋ --figma-callback-port๋ฅผ ์ง์ ํ์ ๋๋ง ์ค์ธกํ port/free๋ฅผ ๋ด๊ณ , registrationClientName์ DCR์ด ๋ณด๋ผ ์ด๋ฆ(value)๊ณผ ๊ทธ๊ฒ์ด ๊ธฐ๋ณธ๊ฐ์ธ์ง(isDefault)๋ฅผ ์๋ ค์ค๋๋ค. ์์ธํ ์ ์ฝ์ ์๋ "Figma ์ฐ๊ฒฐ ์ค์ " ์ ์ ์ฐธ๊ณ ํ์ธ์.
Figma MCP Catalog์ ์น์ธ๋ client(์: ์ง์ waitlist๋ก ๋ฑ๋กํด ๋ฐ๊ธ๋ฐ์ client)์ client_id/client_secret์ ์ด๋ฏธ ๊ฐ์ง๊ณ ์๋ค๋ฉด, devup-mcp์ ๋ค์ ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ ์ค ํ๋๋ก ์ฃผ์
ํด Dynamic Client Registration์ ์์ ํ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์ฐ์ ์์๋ ์์ ์ธ์ > ํ๊ฒฝ๋ณ์ > configure๋ก ์ ์ฅํ ๊ฐ์
๋๋ค.
- ์์ ์ธ์:
devup-mcp --figma-client-id <id> --figma-client-secret <secret> - ํ๊ฒฝ๋ณ์:
DEVUP_FIGMA_CLIENT_ID,DEVUP_FIGMA_CLIENT_SECRET - ๋๊ตฌ:
devup_figma_auth { "action": "configure", "clientId": "...", "clientSecret": "..." }โ OS credential store(์์ ์ธ์/ํ๊ฒฝ๋ณ์์๋ ๋ณ๋ ํญ๋ชฉ)์ ์ ์ฅ๋์ด ํ๋ก์ธ์ค๋ฅผ ์ฌ์์ํด๋ ์ ์ง๋ฉ๋๋ค.
์๊ฒฉ์ฆ๋ช
์ด ํด์๋๋ฉด devup_figma_auth { "action": "login" }์ registration ์๋ํฌ์ธํธ๋ฅผ ์ ํ ํธ์ถํ์ง ์๊ณ ๋ฐ๋ก authorization_code + PKCE ํ๋ฆ์ผ๋ก ์ง์
ํฉ๋๋ค. ์๊ฒฉ์ฆ๋ช
์ด ์์ผ๋ฉด DCR์ ์๋ํ๊ณ , 403์ด๋ฉด ๊ทธ๋๋ก ๋ณด๊ณ ํฉ๋๋ค. DCR ์์ฒญ์ client_name ๊ธฐ๋ณธ๊ฐ์ "Codex"์
๋๋ค(DEFAULT_CLIENT_NAME). allowlist๋ ์ด๋ฆ์ ์ ํํ ์ผ์น์์ผ ํ์ ํ๊ณ "devup-mcp"๋ ๊ฑฐ๊ธฐ์ ์์ผ๋ฏ๋ก, ๊ทธ ์ด๋ฆ์ผ๋ก ๋ณด๋ด๋ฉด ๋ฑ๋ก์ด 403์ผ๋ก ๊ฑฐ์ ๋์ด direct ๊ฒฝ๋ก ์์ฒด๊ฐ ์ฑ๋ฆฝํ์ง ์์ต๋๋ค. ์ด ๋ฑ๋ก์ Figma์๊ฒ devup-mcp๊ฐ ์๋๋ผ Codex๋ก ๊ธฐ๋ก๋ฉ๋๋ค. ๋ณธ์ธ client๊ฐ ์นดํ๋ก๊ทธ์ ์น์ธ๋๋ฉด --figma-client-name ๋๋ DEVUP_FIGMA_CLIENT_NAME์ผ๋ก ๊ทธ ์ด๋ฆ์ ๋๊ธฐ์ธ์. client_secret์ ๋ก๊ทธ, ์๋ฌ, MCP ์๋ต, doctor ์ถ๋ ฅ ์ด๋์๋ ๋
ธ์ถ๋์ง ์์ผ๋ฉฐ doctor๋ credentialSource๋ก ์กด์ฌ ์ฌ๋ถ๋ง ๋ณด๊ณ ํฉ๋๋ค.
devup-mcp๊ฐ ๋๋ ค์ฃผ๋ TSX๋ devup-ui ์ฝ๋์
๋๋ค. devup-mcp๋ง ๊น๋ฆฐ ๊ธฐ๊ณ์ ์์ด์ ํธ๋ devup-ui๋ฅผ ๋ณธ ์ ์ด ์์ต๋๋ค โ @devup-ui/react ์ปดํฌ๋ํธ๊ฐ ๋น๋ ํ์ placeholder๋ผ๋ ๊ฒ๋, $token์ด devup.json์ ๊ฐ๋ฆฌํจ๋ค๋ ๊ฒ๋, ์คํ์ผ prop์ด ๋ฐ์ํ ๋ฐฐ์ด์ ๋ฐ๋๋ค๋ ๊ฒ๋ ๋ชจ๋ฆ
๋๋ค. ๊ทธ๋์ ์ง์ด๋
๋๋ค. ์ด ์๋ฒ๋ ๊ทธ ์ถ์ธก์ ๋ณผ ์๋ ๊ณ ์น ์๋ ์์ต๋๋ค.
์๋ต์ ๊ท์น์ ๋ถ์ฌ ๋ณด๋ด๋ ๊ฒ์ผ๋ก๋ ๋ถ์กฑํฉ๋๋ค. ์์ด์ ํธ ๋ฐํ์์๋ ์ด๋ฏธ SKILL.md๋ฅผ ์ฝ์ด ์๊ธฐ ํธ๋ฆฌ๊ฑฐ๋ก ๊บผ๋ด ์ฃผ๋ ๋ก๋๊ฐ ์๊ณ , ํ ๋ฒ ๋์ ธ์ค ๋ฌธ์๋ ํ ๋ฒ ์ฝํ์ง๋ง ์ค์น๋ ์คํฌ์ ๊ทธ ๋ค ๋ชจ๋ ์ธ์
์ ๊ณ์ ์ ์ฉ๋ฉ๋๋ค. ๊ทธ๋์ devup_skills๋ ํ
์คํธ๋ฅผ ๋์ง์ง ์๊ณ ์ค์น ์ฌ๋ถ๋ฅผ ๋ณด๊ณ ํ๊ณ ์ค์นํฉ๋๋ค.
{ "action": "status" }์คํฌ๋ง๋ค installed์, ์๋๋ผ๋ฉด ๊ทธ๊ฒ์ ๋ฉ์ฐ๋ ํ ๊ฐ์ง ๋์์ ๋๋ ค์ค๋๋ค. ์ถ์ฒ์ ๋ฐ๋ผ ๋์์ด ๋ค๋ฆ
๋๋ค.
| ์คํฌ | ์ถ์ฒ | devup-mcp๊ฐ ํ๋ ์ผ |
|---|---|---|
devup-ui ยท vespera ยท vespertide |
dev-five-git (์ฐ๋ฆฌ ๊ฒ) | ๋ฐ์ด๋๋ฆฌ์ ๋ด์ฅ. {"action":"install"}์ด upstream ์ต์ ๋ฌธ์๋ฅผ ์ฐ์ ๊ฐ์ ธ์ค๊ณ , ์คํจํ๋ฉด ๋ด์ฅ๋ณธ์ ์คํฌ ๋๋ ํฐ๋ฆฌ์ ์๋๋ค |
vercel-react-best-practices ยท vercel-react-view-transitions |
vercel-labs/agent-skills | ๋ด์ฅํ์ง ์์. ์ค์น ๋ช
๋ น npx skills add vercel-labs/agent-skills๋ฅผ ๋๊ธธ ๋ฟ, ์คํํ์ง ์์ต๋๋ค |
vercel ๊ฒ์ ๋ด์ฅํ์ง ์๋ ์ด์ ๋ ๋ ๊ฐ์ง์
๋๋ค. vercel-labs/agent-skills์๋ LICENSE ํ์ผ์ด ์์ด ์ฌ๋ฐฐํฌํ ๊ถ๋ฆฌ๊ฐ ์๊ณ , ๊ทธ ์คํฌ๋ค์ ๋จ์ผ ํ์ผ์ด ์๋๋ผ SKILL.md + AGENTS.md + ๊ท์น ํ์ผ ์์ญ ๊ฐ(ํฉ์ณ ~350 KB)๋ผ์ ์ ์ด์ ๋์ ธ์ค ๋ฌผ๊ฑด์ด ์๋๋ผ ์ค์นํ ๋ฌผ๊ฑด์
๋๋ค.
devup-mcp๋ ๊ทธ ๋ช ๋ น์ ๋์ ์คํํ์ง ์์ต๋๋ค. ๋์์ธโ์ฝ๋ ์๋ฒ๊ฐ ํจํค์ง ์ค์น๊ธฐ๋ฅผ ์คํํ๋ฉด, ๋ ์ง์คํธ๋ฆฌ ํญ๋ชฉ ํ๋๊ฐ ์ค์ผ๋์ ๋ ํ๋ฉด์ exportํ ๋ชจ๋ ๊ธฐ๊ณ์์ ์์ ์คํ์ด ๋ฉ๋๋ค.
์ค์น ์์น๋ ํ๋ก์ ํธ ์์ ๋๋ค. ํ๋ก์ ํธ ๋ฃจํธ๋ devup-mcp๊ฐ ์ธ ์ ์๋ ์ ์ผํ ๊ณณ์ด๋ผ ์ ๊ถํ์ด ํ์ ์๊ณ , ์คํฌ์ด ์ ์ฅ์๋ฅผ ๋ฐ๋ผ๋ค๋๋๋ค. ์ด๋ฏธ ๊น๋ ค ์์ผ๋ฉด ๋ค์ ์ฐ์ง ์์ต๋๋ค.
์ด๋ ๋๋ ํฐ๋ฆฌ์ธ์ง๋ ๋ถ์ด ์๋ ๋ฐํ์์ด ์ ํฉ๋๋ค. ๋ฐํ์๋ง๋ค ์ฝ๋ ๊ณณ์ด ๋ค๋ฅด๊ณ , ์ฝ์ง ์๋ ๊ณณ์ ์ค์นํ๋ ๊ฒ์ ์กฐ์ฉํ ์คํจ์ด๊ธฐ ๋๋ฌธ์
๋๋ค โ ํธ์ถ์ ์ฑ๊ณต์ ๋ณด๊ณ ํ๊ณ , ํ์ผ์ ๋์คํฌ์ ์๊ณ , ์คํฌ์ ๋๋ด ๋ก๋๋์ง ์์ต๋๋ค. Codex์์ ์ฌ๋ผ์จ ๋ณด๊ณ ๊ฐ ์ ํํ ์ด ๋ชจ์์ด์์ต๋๋ค. ์ ํ๋ก์ ํธ์๋ ์คํฌ ๋ฃจํธ๊ฐ ์์ ์์ผ๋ ์ ํ์ด ๋ชฉ๋ก์ ์ฒซ ํญ๋ชฉ์ธ .claude/skills๋ก ๋จ์ด์ก๊ณ , Codex๋ ๊ทธ๊ณณ์ ์ฝ์ง ์์ต๋๋ค.
๋๊ตฌ์ธ์ง๋ MCP initialize๊ฐ ๋ณด๋ด๋ clientInfo ์ด๋ฆ์ผ๋ก ์๋๋ค.
| ๋ฐํ์ | ์ค์น ์์น | ๋จธ์ ์ ์ฒด(์ฝ๊ธฐ๋ง) |
|---|---|---|
| Claude Code | .claude/skills |
~/.claude/skills |
| Codex | .agents/skills |
~/.agents/skills, ~/.codex/skills |
| opencode | .opencode/skill |
~/.config/opencode/skill |
| Cursor | .cursor/skills |
~/.cursor/skills |
| Zed | .agents/skills |
~/.agents/skills |
| Windsurf | .windsurf/skills |
~/.codeium/windsurf/skills |
| VS Code / Copilot | .github/skills |
~/.copilot/skills |
| Gemini CLI | .gemini/skills |
~/.gemini/skills |
| Cline | .cline/skills |
~/.cline/skills, ~/.agents/skills |
| Continue | .continue/skills |
~/.continue/skills |
| Amp | .agents/skills |
~/.config/agents/skills |
| Goose | .agents/skills |
~/.agents/skills |
| ์ด๋ฆ์ ์ ๋ฐํ ํด๋ผ์ด์ธํธ | ์ธ ๊ณณ ๋ชจ๋ (.claude/skillsยท.opencode/skillยท.agents/skills) |
์ ๋ถ ์ฝ์ต๋๋ค |
๊ฐ ๋ฐํ์์ ํ์ ํ ๊ณณ๋ง์ด ์๋๋ผ ์๊ธฐ๊ฐ ์ฝ๋ ๊ณณ ์ ๋ถ๋ฅผ ๊ฒ์ฌํฉ๋๋ค(๋๋ถ๋ถ .agents/skills๋ฅผ ํธํ์ผ๋ก ์ฝ์ต๋๋ค). ํ์ ์ ์ ๊ฒ์ ์๋ก ์ค์นํ ๋ ๊ณ ๋ฅด๋ ์๋ฆฌ์
๋๋ค.
Cline์ด ์ด ํ๊ฐ ํ์ํ ์ด์ ์
๋๋ค. ๋ค๋ฅธ ๋๋ถ๋ถ์ .agents/skills๋ฅผ ์ฝ์ด์ ๊ณต์ฉ ๊ท์ฝ์ด ํตํ๋๋ฐ, Cline์ ๊ทธ๊ฑธ ํ์์๋ง ์ฝ์ต๋๋ค. ํ๋ก์ ํธ์ .agents/skills๋ Cline์ด ์ด์ง ์๋ ๋๋ ํฐ๋ฆฌ์
๋๋ค.
JetBrains AI Assistant๋ ์ผ๋ถ๋ฌ ๋ฃ์ง ์์์ต๋๋ค. ์๋ ํ์ ๋๋ ํฐ๋ฆฌ๊ฐ ์๊ณ ์ฌ๋์ด ์ค์ ์์ ์ง์ ๋ฑ๋กํด์ผ ํด์, ์๋ฌด ๊ฒฝ๋ก๋ ๋ฃ๋ ๊ฒ์ ์์ ํ fallback๋ณด๋ค ๋์ฉ๋๋ค.
ํ์ ์ ๋ฐ์ ๊ด์ธก๊ฐ์
๋๋ค. CursorยทWindsurfยทVS CodeยทAmp๋ ๋ซํ ์์ค๋ผ clientInfo.name์ ์์ค๋ก ํ์ธํ ์ ์์ต๋๋ค. ๊ทธ ์ถ์ธก์ด ํ๋ฆฌ๋ฉด ๋งค์นญ์ด ์ ๋๊ณ unknown์ผ๋ก ๋จ์ด์ง๋๋ฐ โ ์์ ํ์ง๋ง ์์ ํ ์กฐ์ฉํฉ๋๋ค. devup-mcp๊ฐ ์ ๋ง ๋ชจ๋ฅด๋ ํด๋ผ์ด์ธํธ์ ๊ตฌ๋ณ์ด ์ ๋ฉ๋๋ค.
๊ทธ๋์ ์๋ต์ runtime.clientName์ด ๋ฐ์ ์ด๋ฆ์ ๊ทธ๋๋ก ๋๋ ค์ค๋๋ค. detected๊ฐ unknown์ด๋ฉด ifDetectedIsUnknown์ด ๊ทธ๊ฒ ํ๋ฆฐ ๊ฒ ์๋๋ผ ์์ ํ ์ํ๋ผ๋ ๊ฒ๊ณผ, ์๊ธฐ ์คํฌ ๋๋ ํฐ๋ฆฌ๊ฐ ์๋ ํด๋ผ์ด์ธํธ๋ผ๋ฉด ๊ทธ ์ด๋ฆ์ ์๋ ค๋ฌ๋ผ๋ ๊ฒ์ ํจ๊ป ๋ต๋๋ค. ํ๊ฐ ๊ณ ์ณ์ง๋ ์ ์ผํ ๊ฒฝ๋ก์
๋๋ค.
์ด๋ฆ์ด ์๊ณ ๊ธฐ์กด ๋ฃจํธ๋ ์์ผ๋ฉด ๊ณ ๋ฅผ ๊ทผ๊ฑฐ๊ฐ ์์ต๋๋ค. ์ ์ค ํ๋๋ฅผ ์ฐ๋ ๊ฒ์ ์๋ฌด๋ ์ ๋ณด๋ ๊ณณ์ ์ธ ํ๋ฅ ์ด 3๋ถ์ 2์ด๊ณ , ์ฌ๋ณธ ํ๋๋ ํ๋ก์ ํธ๊ฐ ์ด๋ฏธ ์์ ํ ๋๋ ํฐ๋ฆฌ ์์์ ๋ช KB์ ๋๋ค. ๊ทธ๋์ ์ ๋ถ ์๋๋ค. ๋ค๋ง ์ฝ์ ๋๋ ์๋ ๊ท์ฝ ์ ๋ถ๋ฅผ ๋ด ๋๋ค โ ๋๊ฐ ์ด๋ฏธ ๊น์๋ ๊ฒ์ ๋ชป ์ฐพ๊ณ ๊ทธ ์์ ๋ ๋ฒ์งธ ์ฌ๋ณธ์ ์ฐ๋ ๊ฒ์ด ๋ ๋์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์์ ์๋ is_file() ํ๋๋ก ํ์ ํด์, ๋ฐ๋
์ devup-mcp๊ฐ ์ด SKILL.md๋, ๋๊ฐ ํ ์ค ์ ์ด๋ ์๋ฆฌํ์์๋ ํ์ฌ ๋ฌธ์์ ๊ตฌ๋ณ๋์ง ์์์ต๋๋ค. ๋ ๋๋นด๋ ๊ฑด install์ด ์ด๋ฏธ ์์ผ๋ฉด ๊ฑด๋๋ฐ์ด์ ๊ฐฑ์ ํ ๋ฐฉ๋ฒ์ด ์์ ์์๋ค๋ ์ ์
๋๋ค โ ๊ธฐ๊ณ๊ฐ ์ฒ์ ํ ์ค์น๊ฐ ๋ง์ง๋ง ์ค์น์์ต๋๋ค.
์ง๊ธ์ ๋์คํฌ์ ๋ฐ์ดํธ๋ฅผ ์ด ๋น๋๊ฐ ์ธ ๋ฐ์ดํธ์ ๋์กฐํด installState.revision์ผ๋ก ๋ตํฉ๋๋ค.
| revision | ๋ป | install์ด ํ๋ ์ผ |
|---|---|---|
current |
์ง๊ธ ์ค์นํ๋ฉด ๋์ฌ ๊ฒ๊ณผ ๊ฐ์. ๋๋ upstream์์ ๋ฐ์์จ ๊ฒ(๋ด์ฅ๋ณธ๋ณด๋ค ์ต์ํ ์๊ฒ์ด๋ผ ๋คํธ์ํฌ ์์ด ๋ ๋ฐ์ง ์ ์์) | ์๋ฌด๊ฒ๋ ์ ํจ |
older |
devup-mcp์ provenance ์ฃผ์์ ์๋๋ฐ ์ด ๋น๋์ ๊ฒ์ด ์๋ | ์ ์๋ฆฌ์์ ๋ค์ ์๋๋ค |
incomplete |
SKILL.md๋ ์ด ๋น๋ ๊ฒ์ธ๋ฐ ๋งํฌํ ๋ฌธ์๊ฐ ์๊ฑฐ๋ ๋ค๋ฆ โ ์ค์น๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ณ ๋งํฌ๋ ๋๊ธด ์ํ |
๋ค์ ์๋๋ค |
foreign |
devup-mcp provenance ์ฃผ์์ด ์์. ๋๊ฐ ์ง์ ์ด ๊ฒ | ๊ฑด๋๋ฆฌ์ง ์๊ณ ๋ณด๊ณ ๋ง ํฉ๋๋ค |
foreign์ ๋ฎ์ด์ฐ์ง ์๋ ์ด์ ๋ ํ๋์
๋๋ค. ์ด ์๋ฒ๊ฐ ํ์ง ์์ ์์
์ ์ง์ฐ๋ ์ผ์ด๊ณ , ์ค์น๋ ๊ทธ๊ฒ ์ค์์๋์ง ํ๋จํ ์๋ฆฌ๊ฐ ์๋๋๋ค. devup-mcp์ ์ฌ๋ณธ์ ๋ฐ๊ณ ์ถ์ผ๋ฉด ๋จผ์ ์ง์ฐ๋ฉด ๋ฉ๋๋ค.
report์ outdated๊ฐ ์ด ์ํ์ธ ์คํฌ ์ด๋ฆ์ ๋ชจ์ ์ค๋๋ค. missing๊ณผ ๋ฐ๋ก ์ธ๋ ์ด์ ๋ ๋์ด ๋ค๋ฅธ ๋ง์ ํ์๋ก ํ๊ธฐ ๋๋ฌธ์
๋๋ค โ ํ๋๋ ์์ด์ ํธ๊ฐ ๋ณธ ์ ์๋ ์คํฌ์ด๊ณ , ๋ค๋ฅธ ํ๋๋ ์ง๊ธ ์ฝ๊ณ ์์ผ๋ฉด์ ๋ก์ ๊ท์น์ ๋ฐฐ์ฐ๊ณ ์๋ ์คํฌ์
๋๋ค.
๋จธ์ ์ ์ฒด ๋ฃจํธ๋ ์ฝ๊ธฐ๋ง ํฉ๋๋ค. devup-mcp๋ ํ์ฉ๋ write root ์์๋ง ์ฐ๊ณ ํ ๋๋ ํฐ๋ฆฌ๋ ๊ฑฐ๊ธฐ์ ์์ต๋๋ค โ ๊ทธ ๊ฒฝ๊ณ๋ ๊ทธ๋๋ก์
๋๋ค. ๋ค๋ง ~/.codex/skills์ ์๋ ์คํฌ์ ์ค์ ๋ก ๋ก๋๋๋ฏ๋ก ์๋ค๊ณ ๋ณด๊ณ ํ๋ฉด ์ ๋ฉ๋๋ค. ์์ ์๋ devup-ui๋ฅผ ~/.agents/skillsยท~/.claude/skillsยท~/.codex/skillsยท~/.config/opencode/skill ๋ค ๊ณณ์ (์ ๋ถ ๊ฐ์์ ๋ฐํ์์ด ์ฝ๋ ์ํ๋ก) ๊ฐ๊ณ ์๋ ๊ธฐ๊ณ๊ฐ installedCount: 0์ ๋ฐ์์ต๋๋ค.
๋ฐ๋ ์ค์๋ ๋๊ฐ์ด ์กฐ์ฉํฉ๋๋ค. ์ด ๋ฐํ์์ด ์ด์ง ์๋ ๋๋ ํฐ๋ฆฌ์ ์๋ ํ์ผ์ ๋ก๋๋์ง ์์ผ๋ฏ๋ก installed๋ก ์ธ์ง ์์ต๋๋ค.
projectRoot๋ฅผ ๋๊ธฐ์ธ์. ์๋ตํ๋ฉด ์๋ฒ ์์ ์ write root๋ก ๋จ์ด์ง๋๋ฐ, ๋์ ๊ฐ๊ฒ ์ค์ ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ๊ทธ๊ฑด ํ๋ก์ ํธ๊ฐ ์๋๋๋ค. ๊ณต์ฉ ๋ถ๋ชจ ํ๋๋ฅผ write root๋ก ์ค ํธ์คํธ(Orca worktree ํ, ๋ชจ๋
ธ๋ ํฌ ์ฒดํฌ์์)์์๋ ๋ชจ๋ ํธ์ถ์ด ๊ทธ ๋ถ๋ชจ๋ฅผ ๋ณด๊ณ ํ๊ณ , ๊ฑฐ๊ธฐ์ ์ด๋ค ๋ฐํ์๋ ์คํฌ์ ์ฐพ์ผ๋ฌ ๊ฐ์ง ์์ต๋๋ค.
ํ๋ก์ ํธ๋ง๋ค ํ ๋ฒ์ฉ ์ค์นํ๋ ๊ฒ์ด ๊ธฐ๋ณธ์ด๊ณ , ๋งค export๊ฐ ๋น ์ง ๊ฒ์ ๋ค์ ์๋ ค์ฃผ๋ฏ๋ก ์ค์ค๋ก ๋ณต๊ตฌ๋ฉ๋๋ค. ๊ทธ๋๋ ๊ธฐ๊ณ ํ๋์ ํ ๋ฒ์ด ๋ซ๋ค๋ฉด โ devup-mcp๋ ๊ทธ ๊ฒฝ๋ก๋ฅผ ์๋ ค์ฃผ๊ธฐ๋ง ํฉ๋๋ค. ์๋ต์ machineWide๊ฐ ์ด ๋ฐํ์์ ํ ๋๋ ํฐ๋ฆฌ์ ํจ๊ป action: "run-this-yourself"๋ฅผ ๋๋ ค์ค๋๋ค.
ํ์ ํ์ฉ๋ write root ๋ฐ์ด๊ณ , ๋์์ธโ์ฝ๋ ์๋ฒ๊ฐ $HOME์ ์ธ ์ ์๋๋ก ๊ทธ ๊ฒฝ๊ณ๋ฅผ ๋ํ๋ ๊ฒ์ ํธ์์ ๋ฐ๊ฟ ๋งํ ๊ฑฐ๋๊ฐ ์๋๋๋ค. ๊ทธ๋์ ๊ฒฝ๋ก๋ ๋๊ธฐ๊ณ ์คํ์ ์ฌ๋ ๋ชซ์
๋๋ค. ๊ทธ ๋๋ ํฐ๋ฆฌ์ ๋ค์ด๊ฐ ์คํฌ์ ์ดํ ๋ชจ๋ ํ๋ก์ ํธ์์ ์ค์น๋จ์ผ๋ก ๋ณด๊ณ ๋ฉ๋๋ค.
์ค์น ์๋ต์ installed[].source๋ fetched ๋๋ embedded์ด๋ฉฐ, ๋ด์ฅ๋ณธ์ ์ผ๋ค๋ฉด reason๋ ๋ฐํํฉ๋๋ค. ๊ฐ์ ธ์ค๊ธฐ๋ manifest์ ์ ์ฅ์์ ๋ฌธ์ ๊ฒฝ๋ก์์ ๋ง๋ https://raw.githubusercontent.com/REPO/HEAD/PATH๋ฅผ ์ฌ์ฉํ๋ฉฐ, ํธ์ถ ์ ์ฒด์ ๋คํธ์ํฌ ๋๊ธฐ๋ ์ต๋ 4์ด์
๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ, HTTP ์ค๋ฅ, ETag ๋๋ฝ์ ๋ด์ฅ๋ณธ์ผ๋ก ๋์๊ฐ๊ณ , 404๋ upstream ๊ฒฝ๋ก๊ฐ ๋ฐ๋์์ ์ ์์ผ๋ฏ๋ก warnings์๋ ์๋ฆฝ๋๋ค. ์ฌ๋ฌ ๋ฌธ์ ์ค ํ๋๋ผ๋ ์คํจํ๋ฉด ๊ทธ ์คํฌ ์ ์ฒด๋ฅผ ๋ด์ฅ๋ณธ์ผ๋ก ์ค์นํฉ๋๋ค.
DEVUP_MCP_SKILLS_OFFLINE=1๋ก ์๋ฒ๋ฅผ ์์ํ๋ฉด ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์๋ตํฉ๋๋ค. ์ด ์ค์ ์ ํ๋ก์ธ์ค์์ ํ ๋ฒ ์ฝ์ผ๋ฉฐ 0, false, ๋น ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ํ์ฉํฉ๋๋ค. own ์คํฌ์ ํญ์ ๋ฐ์ด๋๋ฆฌ์์, external ์คํฌ์ ์ฌ์ ํ ์ค์น ๋ช
๋ น ์๋ด๋ง ํฉ๋๋ค. --self-check์ ์คํฌ resource ์ฝ๊ธฐ, status๋ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์คํํ์ง ์์ต๋๋ค. ๋ณ๋ CLI์ธ --install-skills์ devup-ui/HOME ์ค์น ๊ณ์ฝ์ ๊ทธ๋๋ก์
๋๋ค.
๊ฐ์ ธ์จ ๋ฌธ์์ ์ฃผ์์ ๊ณ ์ ์ปค๋ฐ์ ์ฃผ์ฅํ์ง ์๊ณ URL, ๊ฐ์ ธ์จ ์๊ฐ(Unix seconds), ETag, ์ฃผ์ ์ถ๊ฐ ์ SHA-256์ ๊ธฐ๋กํฉ๋๋ค. ์๋ต์ installed[].documents[].provenance๋ ๊ฐ์ ์ ๋ณด๋ฅผ ๋ด์ต๋๋ค. ๋ด์ฅ๋ณธ์ ์ค์นํ๊ฑฐ๋ resource๋ก ์ฝ์ ๋๋ ๊ธฐ์กด ์ปค๋ฐ ์ ๋ณด๋ฅผ ์ ์งํฉ๋๋ค.
๋ด์ฅ๋ณธ์ ๊ฐ ๋ ํฌ์ SKILL.md๋ฅผ ๊ทธ๋๋ก ๋ณต์ฌํ ๊ฒ์ด๊ณ , ์๋ต๊ณผ ์ค์น๋ ํ์ผ ๋ชจ๋ ์ด๋ ์ปค๋ฐ์ธ์ง์ ์ต์ ๋ณธ URL์ ํจ๊ป ๋ต๋๋ค. ์ฌ๋ณธ์ ๋ก์ต๋๋ค โ ๊ทธ๊ฒ ๋ด์ฅ์ ์ ์งํ ๋น์ฉ์ด๊ณ , node scripts/refresh-skills.mjs๊ฐ ๊ทธ๊ฑธ ๊ฐฑ์ ํ๋ ๋ฐฉ๋ฒ์
๋๋ค(--check๋ ์ฐ์ง ์๊ณ ๋๋ฆฌํํธ๋ง ๋ณด๊ณ ). ์ฃผ์์ YAML frontmatter ๋ค์ ๋ค์ด๊ฐ๋๋ค. ---๋ 0๋ฒ์งธ ๋ฐ์ดํธ์ ์์ด์ผ ๋ก๋๊ฐ ์ฝ์ต๋๋ค.
์ค์นํ์ง ์๊ณ ์ฝ๊ธฐ๋ง ํ๋ ค๋ฉด devup://skill/devup-ui ๋ฆฌ์์ค๋ ์์ต๋๋ค. ๋ค๋ง ๊ทธ๊ฑด fallback์
๋๋ค โ ์ค์นํด์ผ ๋ก๋๊ฐ ์์์ ๊บผ๋ด ์ค๋๋ค.
์ ๋๋ ๋ค ๊ณณ์์ ํฉ๋๋ค. ์ด๋ฏธ ๊น๋ ค ์๊ณ ์ต์ ์ธ ์ฌ๋์๊ฒ ๊น๋ผ๊ณ ํ๋ ๊ฒ์ ๊ทธ ํ๋๋ฅผ ๋ฌด์ํ๊ฒ ๋ง๋๋ ์์์ด๋ฏ๋ก, ๋ท ๋ค ์ด ๋ฐํ์์ด ์ค์ ๋ก ๋ก๋ํ์ง ๋ชปํ๊ฑฐ๋ ๋ก์ ๊ฒ์ ๋ก๋ํ ๋๋ง ๋น๋๋ค.
-
devup_figma_export์ tool description. ๊ฐ์ฅ ์ค์ํ ์๋ฆฌ์ ๋๋ค โ ๋ชจ๋ ์์ด์ ํธ์๊ฒ ๋๋ฌํ๋ ์ ์ผํ ์ฑ๋์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.instructions๋ ๊ทธ๋ ์ง ์์ต๋๋ค:task()๋ก ๋์ด ์๋ธ์์ด์ ํธ๋ tool schema๋ง ๋ฐ๊ณ ์๋ฒinstructions๋ ๋ฐ์ง ๋ชปํ๋ฉฐ, Codex์์instructions๋ ์์คํ ํ๋กฌํํธ ํ ์คํธ๊ฐ ์๋๋ผ ๋ค์์คํ์ด์ค ์ค๋ช ํ ์ค์ด ๋ฉ๋๋ค. ์ค์ ๋ก ์ฝ๋๋ฅผ ์ฐ๋ ์ฃผ์ฒด๊ฐ ๊ทธ ๋ ๊ฒฝ์ฐ์ธ๋ฐ, ์์ ์๋ ๊ฐ์ฅ ๊ฐํ ๋ฌธ์ฅ์ด ๋ถ๋ฅผ ์ด์ ๊ฐ ์๋ ๋๊ตฌ์ธdevup_skills์์ ์ description์๋ง ์์์ต๋๋ค.๊ฐ์ ์ด์ ๋ก ๊ฐ์ด๋์ ๊ท์น 3ยท4ยท6๋ ์ด description์ผ๋ก ์ฎ๊ฒผ์ต๋๋ค. ์คํฌ๋ฆฐ์ท์ ๊ฒ์ฆ์ด์ง ์ ์์ด ์๋๋ผ๋ ๊ฒ, ๋ ธ๋ ํธ๋ฆฌ๋ฅผ ์ง์ ์ฝ์ด ์์ผ๋ก ์ฐ์ง ๋ง๋ผ๋ ๊ฒ, ๊ฐ์ ์ ๋ ์ง์ด๋ด์ง ๋ง๋ผ๋ ๊ฒ โ ์ ์ ์ด๊ธฐ๋ฉด ์๋ต์ด ๋๋น ์ง๋ ๊ฒ ์๋๋ผ ์๋ชป๋ ์ฝ๋๊ฐ ๋์ค๋ ๊ท์น์ธ๋ฐ, Codex๊ฐ blurb ํ ์ค๋ก ์ ์ด ๋ฒ๋ฆฌ๋ ๋ฆฌ์์ค์๋ง ์์์ต๋๋ค.
-
devup_figma_export์๋ต์skillGap. TSX๋ฅผ ๋๋ ค์ค ์๋ต์ ๋ถ์ต๋๋ค.projectRoot๋ฅผ ์ ๋๊ฒจ๋ ๋ถ์ต๋๋ค โ devup-ui๋ฅผ ๋ชจ๋ฅด๋ ํธ์ถ์๊ฐ ๋ฐ๋ก ๊ทธ ์ธ์๋ฅผ ์ ๋ณด๋ด๋ ์ฌ๋์ด๋ผ, ๊ฑฐ๊ธฐ์ ๊ฑธ์ด๋๋ฉด ํ์ํ ์ฌ๋์๊ฒ๋ง ์ ํํ ์ ๋ณด์ ๋๋ค.missing๊ณผoutdated๋ฅผ ๋๋ ๋ด์ต๋๋ค. -
devup_project_context์๋ต์skillGap. 2๋ฒ์ด devup-mcp๊ฐ ์ฐ๋ ์ฝ๋๋ฅผ ๋งก๋๋ค๋ฉด ์ด์ชฝ์ ์ฝ๋ ํ์ผ์ ๋งก์ต๋๋ค โdevup.json์ devup-ui์ ํ ๋ง ํ์์ด๊ณ , scopeapi์openapi.json์ vespera ๋ผ์ฐํธ๊ฐ ๋ง๋ค๋ฉฐ, scopedb์models/*.json์ vespertide ์คํค๋ง์ ๋๋ค. ๊ทธ scope๊ฐ ์ค์ ๋ก ํ์ผ์ ์ฐพ์์ ๋๋ง ๋น๋๋ค.openapi.json์ด ์๋ ํ๋ก์ ํธ์ vespera๋ฅผ ๊ถํ๋ ๊ฑด ์์์ ๋๋ค. -
devup_ui_validate์skillGap. ์๋ฐ์ด ์์ ๋. ์ด๊ฑด ๋ถ๊ฒ์ ๋๋ค: devup-ui๋ฅผ ๋ชจ๋ฅด๋ ์์ด์ ํธ๋ validator๋ ๋ถ๋ฅด์ง ์์ผ๋ฏ๋ก ์ด๊ฒ๋ง์ผ๋ก๋ ๋ฟ์ง ์์ต๋๋ค. 1~3๋ฒ์ด ์ฝ๋๋ฅผ ์ฐ๊ธฐ ์ ์ ๋งก๊ณ , 4๋ฒ์ ์ด๋ฏธ ์ด ์ฝ๋๊ฐ ๊ฑฐ์ ๋นํ ์๊ฐ์ ๋งก์ต๋๋ค.
devup-mcp๊ฐ Figma์ ๋ถ๋ ๊ฒฝ๋ก๋ ๋์ด๊ณ , ๋๋ฑํ์ง ์์ต๋๋ค.
| ๊ฒฝ๋ก | ๋ก๊ทธ์ธ | Figma ํ๋ | ์ธ์ ์ฐ๋ |
|---|---|---|---|
๋ธ๋ฆฌ์ง (bridge) |
ํ์ ์์ | ์ฐ์ง ์์ | ๊ธฐ๋ณธ. ๋ฐ์คํฌํฑ ์ฑ์์ ํ๋ฌ๊ทธ์ธ์ ๋์ ๋๋ฉด ๊ทธ์ชฝ์ผ๋ก ์ฝ์ต๋๋ค |
์ง์ (direct) |
devup_figma_auth { action: "login" } |
์๋๋ค | ๋ธ๋ฆฌ์ง๊ฐ ๋ชป ํ๋ ์ฝ๊ธฐ์, ํ๋ฌ๊ทธ์ธ์ ๋์ธ ์ ์๋ ํ๊ฒฝ(CI ๋ฑ) |
๋ธ๋ฆฌ์ง๋ฅผ ๋จผ์ ์ฐ์ญ์์ค. direct๋ Figma๊ฐ ์ฌ์ฉ๋์ ์ธ๋ ๊ฒฝ๋ก์ด๊ณ , ํ๋ฉด ํ๋๊ฐ ์ฌ๋ฌ ๋ฒ์ ์ฝ๊ธฐ๋ฅผ ์ฐ๋ฏ๋ก ํ๋๊ฐ ๊ธ๋ฐฉ ๋ฐ๋ฅ๋ฉ๋๋ค. ๊ทธ๋์ direct๋ก ๊ฐ๋ ์ฝ๊ธฐ๋ ํ๋์ ๋ง์ถ ์๋(DEVUP_FIGMA_CALLS_PER_MINUTE, ๊ธฐ๋ณธ ๋ถ๋น 8ํ)๋ก ๋ฆ์ถฐ ๋ณด๋ด์ง๋ง, ๋ธ๋ฆฌ์ง๋ก ๊ฐ๋ ์ฝ๊ธฐ๋ ๋ฆ์ถ์ง ์์ต๋๋ค. ์์ ์๋ ๋ธ๋ฆฌ์ง ์ฝ๊ธฐ๊น์ง ๊ฐ์ ์๋๋ก ๋ฌถ์ฌ, ๊ฐ์ ์๋ฒ์ ๋ ๋ฒ์งธ export๊ฐ ์ฐ์ง๋ ์๋ ํ๋๋ฅผ 1๋ถ ๊ฐ๊น์ด ๊ธฐ๋ค๋ ธ์ต๋๋ค.
ํ๋ฌ๊ทธ์ธ์ด ์ด ํ์ผ์ ๋งก๊ณ ์์ผ๋ฉด ๋ก๊ทธ์ธ์ ์๊ตฌํ์ง ์์ต๋๋ค. ์์ ์๋ ์์ง์ ์์ํ๊ธฐ ์ ์ ํ ํฐ๋ถํฐ ํ์ธํด์, ํ๋๋ฅผ ์๋ผ๋ ค๊ณ ํ๋ฌ๊ทธ์ธ์ ๋์ด ์ฌ๋์๊ฒ "๋จผ์ ํ๋ ์ฐ๋ ๊ฒฝ๋ก๋ฅผ ์ฌ์ธ์"๋ผ๊ณ ๊ฑฐ์ ํ์ต๋๋ค. ์ง๊ธ์ ๋ธ๋ฆฌ์ง๋ฅผ ๋จผ์ ๋ณด๊ณ , ์ด ํ์ผ์ ๋งก์ ํ๋ฌ๊ทธ์ธ์ด ์์ ๋๋ง ๋ก๊ทธ์ธ์ ์๊ตฌํฉ๋๋ค. ์์ง ๋์ค ํ๋ฌ๊ทธ์ธ์ด ๋ค ๋ตํ์ง ๋ชปํ ์ฝ๊ธฐ๋ ๋ก๊ทธ์ธ์ด ๋์ด ์์ผ๋ฉด direct ๊ฒฝ๋ก๊ฐ ๋ค์ ์ฝ๊ณ , ์๋๋ฉด ํ๋ฌ๊ทธ์ธ์ ๋ต์ด ๊ทธ ์ด์ ์ ํจ๊ป ๊ทธ๋๋ก ์ต๋๋ค(์๋).
์ง๊ธ ์ด๋ ๊ฒฝ๋ก๊ฐ ์ด์ ์๋์ง๋ devup_figma_auth { action: "status" }์ activePath์ paths.bridge/paths.direct๋ก ํ์ธํ์ธ์. ์ฐ๊ฒฐ ์์๋ bridge โ direct์
๋๋ค โ ๋ก๊ทธ์ธ์ ์์ฒญํ๊ธฐ ์ ์ ์ด๊ฒ๋ถํฐ ๋ถ๋ฅด์ธ์.
๋ธ๋ฆฌ์ง๋ ์์ง์ด ํ๋ ๋ชจ๋ ์ฝ๊ธฐ๋ฅผ ๋งก์ต๋๋ค. scope: "file"์ ๋
ธ๋ ์๋ metadata ์ฝ๊ธฐ(์ต์์ ํ์ด์ง ๋ชฉ๋ก)๋ ํ๋ฌ๊ทธ์ธ์ ํ์ด์ง ๋ชฉ๋ก์ ๊ณต์ get_metadata์ ๊ฐ์ ๊ธ๋ก ์ฎ๊ฒจ ๋ตํ๋ฏ๋ก, ์์ง๊ธฐ๋ ๋ ๊ฒฝ๋ก์ ๋ต์ ๊ฐ์ ํ์๋ก ๋ฐ์ต๋๋ค. direct ๊ฒฝ๋ก๋ ํ๋ฌ๊ทธ์ธ์ด ๋ค ๋ตํ์ง ๋ชปํ ์ฝ๊ธฐ๋ง ๋ค์ ์ฝ์ต๋๋ค โ ๋ก๊ทธ์ธ์ด ๋์ด ์์ ๋๋ง, ํ๋์ ์๋์ ๋ง์ถฐ์์
๋๋ค. ๋ค์ ์ฝ์ ์ด์ ๋ ์๋ต์ source.directFallbackReasons์ ์ค๋ฆฝ๋๋ค. ๋ ๊ฒฝ๋ก๋ ๊ฐ์ ๋ฌธ์๋ฅผ ์ฝ์ต๋๋ค. Figma์ MCP๋ ์ธ์คํด์ค ์์ ์จ๊ธด ๋ ์ด์ด๋ฅผ childrenยทfindAllยทgetNodeByIdAsync์์ ๋นผ๊ณ ํ์ด์ง๋ฅผ ๋ถ๋ฌ ๋์ง ์์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ๋๋ฆฌ๋๋ฐ, ํ๋ฌ๊ทธ์ธ์ ๋ ๋ค ๋ด
๋๋ค. ๊ทธ๋์ ๋
ธ๋๋ฅผ ์ฝ๋ ์คํฌ๋ฆฝํธ๋ figma.skipInvisibleInstanceChildren = false๋ก ์์ํ๊ณ , ํ์ผ ์ ์ฒด ํ
๋ง๋ ๋ชจ๋ ํ์ด์ง๋ฅผ ๋ถ๋ฌ์จ ๋ค ํ์ต๋๋ค.
| ์ด์ | ํ๋ฌ๊ทธ์ธ์ด ๋ตํ ๊ฒ | ๋ก๊ทธ์ธ์ด ์์ผ๋ฉด |
|---|---|---|
file-out-of-sight |
ํ์ผ์ด ํ๋ฉด์ ๋ณด์ด์ง ์์ Figma๊ฐ ๋ถ๋ฌ์ค์ง ์์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ฃผ์ง ์์("Unable to establish connection to Figma", ์๋ "๊ทธ ํ์ผ์ ํ๋ฉด์ ๋์ ๋์ธ์") | ํ๋ฌ๊ทธ์ธ์ ๋ต๊ณผ ํ ์ผ(hintยทnextAction.how) |
reference-png-approximate |
get_screenshot๊ณผ ๊ฐ์ ๊ทธ๋ฆผ์ ๋ค ๊ทธ๋ฆฌ์ง ๋ชปํ ์ฐธ์กฐ PNG(์๋ "referencePng๋ ํ๋ฌ๊ทธ์ธ์ด ๊ทธ๋ฆฝ๋๋ค") |
์บ๋ฒ์ค๊ฐ ๋ณด์ฌ ์ฃผ๋ ๊ทธ๋ฆผ๊ณผ referencePngNote |
plugin-older-than-server |
์ด devup-mcp๋ณด๋ค ๋จผ์ ๋น๋๋ ํ๋ฌ๊ทธ์ธ์ด ๋ชจ๋ฅด๋ ์ฝ๊ธฐ | ํ๋ฌ๊ทธ์ธ์ ๋ต๊ณผ ํ ์ผ(ํ๋ฌ๊ทธ์ธ ๊ฐฑ์ ) |
plugin-answer-too-large |
์กฐ๊ฐ์ผ๋ก ๋ด์ฃผ๊ธฐ ์ ํ๋ฌ๊ทธ์ธ์ด ๋ต ํ๋์ ๋ด์ง ๋ชปํ ์ฐธ์กฐ PNG | ํ๋ฌ๊ทธ์ธ์ ๋ต |
value-from-direct-path |
direct๊ฐ ์ฝ์ ํฐ ๊ฐ์ ์ด์ด ์ฝ๊ธฐ โ ๊ทธ ๋ฐ์ดํธ๋ direct์ ๋ ๋๋ฌ์์๋ง ๋์ด | ์๊ธฐ์ง ์์ |
๋ค์ ์ฝ๋ ์ผ โ ๋ก๊ทธ์ธ ํ์ธ, ํ๋ ์๋ฆฌ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ, direct์ ๋ต๊น์ง โ ์ 40์ด ์์, ๊ทธ๋ฆฌ๊ณ ํ๋ฌ๊ทธ์ธ์ ์ฝ๊ธฐ์ ํฉ์ณ export ์์ ์ด ์ฝ๊ธฐ ํ๋์ ์ฃผ๋ 90์ด๋ณด๋ค 5์ด ๋จผ์ ๋๋์ผ ํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์ฝ๊ธฐ๊ฐ ์ค๋ ๊ฑธ๋ ธ์ผ๋ฉด ๊ทธ๋งํผ ๋ ๊ธฐ๋ค๋ฆฌ๊ณ , ๋จ์ ์๊ฐ์ด ์์ผ๋ฉด ๋ค์ ์ฝ์ง ์์ต๋๋ค.
- ํ๋ฌ๊ทธ์ธ์ ๋ต์ ๊ทธ๋๋ก ์ฐ๋ ๊ฒฝ์ฐ: ๊ทธ ์๊ฐ์ ๋๊ธฐ๊ฑฐ๋, direct์ ๋ต์ด ์ค๋ฅ์ด๊ฑฐ๋, ํ๋์ ๊ฑธ๋ ธ๋ค๋ ๋ฌธ์ฅ ํ๋์ด๊ฑฐ๋(
isError์์ด ์ค๊ธฐ๋ ํฉ๋๋ค), ๊ณต์ MCP์ ํ ์คํธ ์ํ(20 KB)์์ ์๋ ธ์ ๋์ ๋๋ค. ์ธ ์ ์๋ ๋ต์ ๋ฒ๋ฆฌ๊ณ ์คํจ๋ฅผ ์ฌ๋ฆฌ์ง๋ ์์ต๋๋ค. - ํ๋๊ฐ ์ฐฌ ๊ฒ์ผ๋ก ์๋ฆฌ๋ ๊ฒฝ์ฐ: ํ๋ฌ๊ทธ์ธ์ด ์์ ๋ตํ์ง ๋ชปํ ์ฝ๊ธฐ(์ค๋๋ ํ๋ฌ๊ทธ์ธ ๋ฑ)๊ฐ ์๊ฐ ์์ ์๋ฆฌ๋ฅผ ์ป์ง ๋ชปํ๋ฉด, ํ๋๊ฐ ์ฐฌ ๊ฒ์ผ๋ก ์๋ ค(
DEVUP_FIGMA_RATE_LIMITED, ๋ค์ ํด ๋ณผ ์ ์์) ์์ง์ด ํ๋๊ฐ ๋น๊ธฐ๋ฅผ ๊ธฐ๋ค๋ ธ๋ค ๋ค์ ํฉ๋๋ค. file-out-of-sight๋ก ๋ณด๋ ๊ฒฝ์ฐ: "Unable to establish connection to Figma"๊ฐ ํ๋ฌ๊ทธ์ธ ๋ต์ ์ค๋ฅ ์๋ฆฌ์ ์์ ๋๋ง์ ๋๋ค โ ๊ฐ์ ์ฝ์ง ๋ชปํ$error,fieldErrors, ๋ฏธํด์ ๋ฆฌ์์ค์error, ์์ฐ์errorDetail, ๋๋ ์คํจ๋ก ๋๋ ๋ต์ ๋๋ค. ๋์์ธ์ ๊ธ์ด๋ ์ด๋ฆ์ ๊ฐ์ ๋ฌธ์ฅ์ด ์์ด๋ ๋ค์ ์ฝ์ง ์์ต๋๋ค.
ํ๋ฌ๊ทธ์ธ์ด ์ ํํ ํ๋ ๋ถ์ด ์์ผ๋ฉด url์ ์ฃผ์ง ์์๋ ๋ฉ๋๋ค.
| ๋๊ตฌ | url ์์ด ๋ถ๋ฅด๋ฉด |
|---|---|
devup_figma_export |
ํ๋ฌ๊ทธ์ธ์ด ์ฐ ํ์ผ์, Figma์์ ์ ํํ ๋
ธ๋. frameIds๋ฅผ ํ๋ ์ฃผ๋ฉด ๊ทธ ํ๋ ์์ด๊ณ , ์ฌ๋ฟ์ด๋ฉด ์ ํํ Section ์์ ํ๋ฉด๋ค์
๋๋ค |
devup_figma_search |
ํ๋ฌ๊ทธ์ธ์ด ์ฐ ํ์ผ ์ ์ฒด |
devup_figma_explore |
Figma์์ ์ ํํ ๋ ธ๋๋ฅผ ๊ธฐ์ค์ผ๋ก |
{ "outputs": ["tsx"] }๋งํฌ ์๋ฆฌ๊ฐ ๊ผญ ํ์ํ๋ฉด ๊ณต์ ์๋ฆฌํ์์ **figma-bridge://current**๋ฅผ ์ฐ์ธ์. ?node-id=1-2๋ก ๋
ธ๋๋ฅผ ์ง์ ํ ์ ์๊ณ , ํ์ผ ํค๋ฅผ ๋ชจ๋ฅผ ๋ ์๋ต์ด ๋๋ ค์ฃผ๋ ๋งํฌ(canonicalUrl, nextAction)๋ ์ด ํํ๋ก ์ต๋๋ค. Figma ํ์ผ ํค๋ฅผ ์ง์ด๋ด์ง ๋ง์ธ์. ํค๋ฅผ ๋ณด๊ณ ํ์ง ๋ชปํ ํ๋ฌ๊ทธ์ธ์ ํผ์ ๋ถ์ด ์์ ๋ ์๋ฌด ํค๋ ๋ฐ์ ์ฃผ๋ฏ๋ก ์ง์ด๋ธ ํค๋ก๋ ์ฝ๊ธฐ๋ ์ฑ๊ณตํ๊ณ , ๊ทธ ํค๊ฐ ํ์ผ์ ํค๋ก ์ค์ธ๋ฉ๋๋ค. ์ค์ ์ธ์
์์ ์์ด์ ํธ๊ฐ /design/bridge/bridge๋ฅผ ์ง์ด๋ธ ๊ฒฝ์๊ฐ ์ด๊ฒ์
๋๋ค.
ํ๋ฌ๊ทธ์ธ์ด ์๊ฑฐ๋ ์ฌ๋ฟ์ด๋ฉด url ์๋ ํธ์ถ์ ๊ฑฐ์ ๋๊ณ , ๊ฑฐ์ ์ details.nextAction์ด ๋ค์ ๊ฑธ์์ ๋ด์ต๋๋ค. ์์ผ๋ฉด options์ ํ๋ฌ๊ทธ์ธ ์คํ(๊ถ์ฅ, ๋ก๊ทธ์ธ ๋ถํ์)๊ณผ direct ๊ฒฝ๋ก(ํ ํฐ์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ ํ ๋งํฌ)๋ฅผ, ์ฌ๋ฟ์ด๋ฉด ๋ถ์ด ์๋ ํ์ผ๋ง๋ค ๊ทธ ํ์ผ์ ๊ฐ๋ฆฌํค๋ ์์ ์ธ์๋ฅผ ์ค๋๋ค. ์ ํ์ด ๋น์๊ฑฐ๋ ์ฌ๋ฟ์ด๊ฑฐ๋ ํ๋ฌ๊ทธ์ธ์ด ์ ํ์ ๋ณด๊ณ ํ์ง ์์ผ๋ฉด, ๋
ธ๋๋ฅผ ์ง์ ํ๋ ์์(figma-bridge://current?node-id=...)๋ฅผ ์ค๋๋ค.
๋ธ๋ฆฌ์ง๊ฐ ๋ตํ ์๋ต์ ๊ทธ๋ ๋ค๊ณ ๋งํฉ๋๋ค.
"source": {
"kind": "bridge",
"bridgePort": 1993,
"fileKey": null,
"fileKeyReason": "The Devup Bridge plugin that served this could not report its file key ...",
"fileName": "Landing",
"pageName": "Page 1",
"nodeId": "1:2",
"bridgeReads": 3
}fileKey๋ ํ๋ฌ๊ทธ์ธ์ด ๋ณด๊ณ ํ ํค๋ฟ์ ๋๋ค. ๋ณด๊ณ ํ์ง ๋ชปํ์ผ๋ฉดnull๊ณผfileKeyReason์ด ์ค๊ณ , ์์ฒญ์ ์ค๋ ค ์จ ํค๊ฐ ์์๋ค๋ฉดrequestedFileKey๋ก ๋ฐ๋ก ๋ณด๊ณ ํฉ๋๋ค โ ๊ทธ ํค๋ฅผ ํ์ผ์ ํค๋ก ๋ด์ธ์ฐ์ง ์์ต๋๋ค.sourceMap.source.fileKey๋ ๊ฐ์ ๊ท์น์ ๋ฐ๋ฆ ๋๋ค.bridgeReads๋ ์ด ์์ง์์ ํ๋ฌ๊ทธ์ธ์ด ๋ตํ ์ฝ๊ธฐ ์์ ๋๋ค.collection.figmaToolCalls๋ณด๋ค ์์ผ๋ฉด ๋๋จธ์ง๋ direct ๊ฒฝ๋ก๊ฐ ๋ตํ์ต๋๋ค.directFallbacksยทdirectFallbackReasonsยทdirectFallbackHint๋ ํ๋ฌ๊ทธ์ธ์ด ๋ตํ์ง๋ง direct ๊ฒฝ๋ก๊ฐ ๋ค์ ์ฝ์ด ๊ทธ ๋ต์ ์ด ์ฝ๊ธฐ์ ์, ๊ทธ ์ด์ (์ ํ), ๊ทธ๋ฆฌ๊ณ ์ฌ๋์ด ํ ์ผ์ ๋๋ค. ๋ค์ ์ฝ์ ๊ฒ์ด ์์ผ๋ฉด ๋์ค์ง ์์ต๋๋ค. ์ด ๊ฐ์ ์๋ํ ๋คํธ์ํฌ ํธ์ถ์ ์๊ฐ ์๋๋ผ ๋ต์ ์ถ์ฒ์ ๋๋ค. ๋ค์ ์ฝ์์ง๋ง ํ๋ฌ๊ทธ์ธ์ ๋ต์ ์ด ์ฝ๊ธฐ๋ ์ธ์ง ์์ต๋๋ค. ๋DEVUP_FIGMA_CALL_CACHE๋ก ์์ ๋ ํธ์ถ์ ๋ค์ ์ฐ๋ฉด,bridgeReads์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ทธ ์ถ์ฒ๊ฐ ๊ทธ๋๋ก ๋ค์ ์ค๋ฆฝ๋๋ค.- ์บ์๋ ์์ง์ ๋ค์ ํฌ์ํ ์๋ต์
kind: "artifact"๋ฅผ ์ ์งํ๊ณorigin: "bridge"์ ๊ฐ์ ์ถ์ฒ ์ ๋ณด๋ฅผ ๋ต๋๋ค.
๊ทธ๋์ ์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ Figma ํ๋ฌ๊ทธ์ธ์ ํตํด ๊ฐ์ ์ฝ๊ธฐ๋ฅผ ํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ๋ก๋ ํ๋๋ฅผ ์ฐ์ง ์์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์์ผ๋ฉด ์คํฌ๋ฆฝํธ ์ฝ๊ธฐ๊ฐ ๊ทธ์ชฝ์ผ๋ก ๊ฐ๊ณ , ์ ๋ถ์ด ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๊ณ ๊ทธ๋๋ก ์๊ฒฉ ๊ฒฝ๋ก๋ก ๊ฐ๋๋ค. ์ค์นํ์ง ์์ ์ฌ๋์ ๋์์ ๋ฐ๋์ง ์์ต๋๋ค.
๋น๋๋ ํ๋ฌ๊ทธ์ธ์ด ์ ์ฅ์์ ๋ค์ด ์์ต๋๋ค(plugin/dist/). npm๋ Node๋ ํ์ ์๊ณ , ์ ์ฅ์๋ฅผ ๋ฐ์ ๋์๋ค๋ฉด ๋ฐ๋ก ๋ค์ ๋จ๊ณ๋ก ๊ฐ๋๋ค.
1. Figma ๋ฐ์คํฌํฑ ์ฑ์์ ๋ถ๋ฌ์ต๋๋ค
Figma์ ํ๋ฌ๊ทธ์ธ ๋ฑ๋ก์ ๋ฐ์คํฌํฑ ์ฑ์ ๋ฉ๋ด ๋์์ด๋ผ ์คํฌ๋ฆฝํธ๋ก ๋์ ํ ์ ์์ต๋๋ค. ์ด ์ธ ๋จ๊ณ๋ง ์ง์ ํ์๋ฉด ๋ฉ๋๋ค.
- Figma ๋ฐ์คํฌํฑ ์ฑ์ ์ฝ๋๋ค (๋ธ๋ผ์ฐ์ ํ์ ๋ก์ปฌ ํ๋ฌ๊ทธ์ธ์ ๋ชป ๋ถ๋ฌ์ต๋๋ค)
- ๋ฉ๋ด์์ Plugins โ Development โ Import plugin from manifest...
- ์ด ์ ์ฅ์์
plugin/manifest.json์ ์ ํํฉ๋๋ค
ํ ๋ฒ๋ง ํ๋ฉด ๋ฉ๋๋ค. ์ดํ์๋ ํ๋ฌ๊ทธ์ธ ๋ชฉ๋ก์ Devup Bridge๋ก ๋จ์ต๋๋ค.
์ปค๋ฐ๋ ๋ฒ๋ค์ด ์์ค์ ์ด๊ธ๋์ง ์๋๋ก CI๊ฐ ๋งค๋ฒ ๋ค์ ๋น๋ํด byte ๋จ์๋ก ๋์กฐํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ ์์ค๋ฅผ ๊ณ ์ณค๋ค๋ฉด
cd plugin && npm install && npm run buildํdist/๋ฅผ ํจ๊ป ์ปค๋ฐํด์ผ ํฉ๋๋ค.
2. ์ฝ์ผ๋ ค๋ ํ์ผ์์ ํ๋ฌ๊ทธ์ธ์ ์คํํฉ๋๋ค
Figma์์ ๋์ ํ์ผ์ ์ด๊ณ Devup Bridge๋ฅผ ์คํํ๋ฉด ์ฐฝ์ด ํ๋ ๋น๋๋ค. ๊ทธ ์ฐฝ์ด ์ด๋ ค ์๋ ๋์๋ง ๋ธ๋ฆฌ์ง๊ฐ ๋์ํฉ๋๋ค. ๋ซ์ผ๋ฉด ๋ค์ ์ฝ๊ธฐ๋ถํฐ ์๊ฒฉ ๊ฒฝ๋ก๋ก ๋์๊ฐ๋๋ค.
ํ๋ฌ๊ทธ์ธ ์ฐฝ์ ํ์๋ฑ์ผ๋ก ํ๋จํฉ๋๋ค.
| ํ์ | ๋ป |
|---|---|
| ์ด๋ก | devup-mcp์ ์ฐ๊ฒฐ๋จ. ์ด ํ์ผ์ ์ฝ๊ธฐ๋ ํ๋๋ฅผ ์ฐ์ง ์์ต๋๋ค |
| ํ์ | devup-mcp๋ฅผ ์ฐพ์ง ๋ชปํจ. 2์ด๋ง๋ค ๋ค์ ์๋ํฉ๋๋ค |
ํ์์์ ์ ๋ฐ๋๋ฉด devup-mcp๊ฐ ์คํ ์ค์ธ์ง, ๊ทธ๋ฆฌ๊ณ DEVUP_FIGMA_BRIDGE_PORT=off๋ก ๊บผ ๋์ง ์์๋์ง ํ์ธํ์ธ์.
-
๊ธฐ๋ณธ์ผ๋ก ์ผ์ ธ ์์ต๋๋ค. devup-mcp๋ ์์ํ ๋
127.0.0.1:1993์ ๋๊ธฐํฉ๋๋ค. ๊ทธ ํฌํธ๋ฅผ ๋ค๋ฅธ devup-mcp๊ฐ ์ด๋ฏธ ์ฅ๊ณ ์์ผ๋ฉด ๊ทธ ํ๋ก์ธ์ค๋ฅผ ํตํด ๊ฐ์ ํ๋ฌ๊ทธ์ธ์ ์ฝ๊ณ , ๊ทธ ํ๋ก์ธ์ค๊ฐ ๋๋๋ฉด ๋จ์ devup-mcp ๊ฐ์ด๋ฐ ํ๋๊ฐ ํฌํธ๋ฅผ ์ด์ด๋ฐ์ต๋๋ค(ํ๋ฌ๊ทธ์ธ์ 2์ด ์์ ์ ํธ์คํธ์ ๋ค์ ๋ถ์ต๋๋ค). ๋๋ ค๋ฉดDEVUP_FIGMA_BRIDGE_PORT=off. -
ํฌํธ๊ฐ ๋์ด๊ฐ๋ ์์ง์ ์ด์ด์ง๋๋ค. ๊ทธ๋ ์งํ ์ค์ด๋ ์ฝ๊ธฐ๋ ์คํจ๋ก ๋๋์ง ์๊ณ , ํ๋ฌ๊ทธ์ธ์ด ์ ํธ์คํธ์ ๋ค์ ๋ถ๋ ๋๋ก ๋ค์ ๋ณด๋ ๋๋ค(์ฝ๊ธฐ๋ ๋ฌธ์๋ฅผ ๋ฐ๊พธ์ง ์์ ๋ ๋ฒ ๋์๋ ํด๊ฐ ์์ต๋๋ค). ํ๋ฌ๊ทธ์ธ์ด 10์ด ์์ ๋์์ค์ง ์์ผ๋ฉด ๊ทธ๋ ์คํจํฉ๋๋ค. ์์ฒญํ ์ชฝ์ด ๋ ๋๊ฑฐ๋ ์๊ฐ์ด ๋ค ๋ ์ฝ๊ธฐ๋ ํ๋ฌ๊ทธ์ธ์ ์ทจ์๋ฅผ ๋ณด๋ด, ์ฐจ๋ก๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์์ ์ ๋๋ฆฌ์ง ์์ต๋๋ค.
-
์ฌ๋ฌ devup-mcp๊ฐ ๋๋ ์ฐ๋ ๊ฒ์ ๊ฐ์ ์ฌ์ฉ์์ ๊ฒ๋ผ๋ฆฌ์ ๋๋ค. ์ค๊ณ๋ ๊ทธ ์ฌ์ฉ์๋ง ์ฝ์ ์ ์๋ ๋น๋ฐ๊ฐ์ผ๋ก ์๋ก๋ฅผ ์ฆ๋ช ํด์ผ ์ด์ด์ง๊ณ , ๋น๋ฐ๊ฐ ์์ฒด๋ ์ฐ๊ฒฐ๋ก ์ค๊ฐ์ง ์์ต๋๋ค. ๋น๋ฐ๊ฐ์ Windows
%USERPROFILE%\AppData\Local\devup-mcp\bridge-relay.key, macOSยทLinux/tmp/devup-mcp-<uid>/bridge-relay.key์ ์์ต๋๋ค. Unix์์ ํ๊ฒฝ ๋ณ์(HOME)๊ฐ ์๋๋ผ ์ฌ์ฉ์ ๋ฒํธ๋ก ์๋ฆฌ๋ฅผ ์ ํ๋ ๊ฒ์ MCP ํด๋ผ์ด์ธํธ๋ง๋ค ์๋ฒ์ ๋๊ธฐ๋HOME์ด ๋ฌ๋ผ(์๋๋ฐ์ค๋ก ๋ฐ๊ฟ ๋์ฐ๋ ํด๋ผ์ด์ธํธ๋ ์์ต๋๋ค) ๊ฐ์ ์ฌ์ฉ์์ ํ๋ก์ธ์ค๊ฐ ์๋ก๋ฅผ ์์๋ณด์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋๋ค./tmp๋ ๋๊ตฌ๋ ์ฐ๋ ๊ณณ์ด๋ผ, ๊ทธ ๋๋ ํฐ๋ฆฌ๊ฐ ์ด ์ฌ์ฉ์์ ๊ฒ์ด๊ณ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ๋ค์ด์ฌ ์ ์๋์ง ์ธ ๋๋ง๋ค ํ์ธํฉ๋๋ค โ ์ด๋ ค ์์์ผ๋ฉด ๋ซ๊ณ ๋น๋ฐ๊ฐ์ ์๋ก ๋ง๋ค๋ฉฐ, ๋ค๋ฅธ ์ฌ์ฉ์์ ๊ฒ์ด๊ฑฐ๋ ๋งํฌ๋ฉด ์ฐ์ง ์์ต๋๋ค(๊ทธ๋๋secret-unavailable). ์ฌ๋ถํ ํ๋ฉด ์ง์์ง์ง๋ง ๊ทธ๋๋ ๊ทธ ๋น๋ฐ๊ฐ์ ์๋ ํ๋ก์ธ์ค๋ ๋ชจ๋ ๋๋ ๋ค์ ๋๋ค. -
๋ธ๋ผ์ฐ์ ํ์ด์ง๋ ๋ถ์ง ๋ชปํฉ๋๋ค. ์ค๊ณ ๋ฌธ์
Origin์ด ๋ถ์ ์์ฒญ์ ๋ชจ๋ ๊ฑฐ์ ํ๊ณ , ํ๋ฌ๊ทธ์ธ ๋ฌธ(/plugin)์ Figma ํ๋ฌ๊ทธ์ธ ์ฐฝ(Origin: null)๊ณผfigma.com๋ง ๋ฐ์ต๋๋ค. ํํ ์น ํ์ด์ง๊ฐ ํ๋ฌ๊ทธ์ธ์ธ ์ฒ ์ฝ๊ธฐ๋ฅผ ๊ฐ๋ก์ฑ์ง ๋ชปํ๊ฒ ํ๋ ค๋ ๊ฒ์ธ๋ฐ, ์๋๋ฐ์ค iframe์ด๋file://ํ์ด์ง๋null์ ์ค์ผ๋ฏ๋ก ๊ทธ๋ฐ ํ์ด์ง๊น์ง ๋ง์ง๋ ๋ชปํฉ๋๋ค. -
์ฝ๊ธฐ ์ ์ฉ์ ๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ์คํํ๋ ์คํฌ๋ฆฝํธ๋ ๋น๋ ์์ ์ ํ๋ฌ๊ทธ์ธ ์์ ๋ฐํ ์๊ณ , devup-mcp๋ ๊ทธ์ค ์ด๋ ๊ฒ์ ์คํํ ์ง ์ด๋ฆ๋ง ๋ณด๋ ๋๋ค. ์์ผ์ผ๋ก ์ฝ๋๊ฐ ์ค๊ฐ์ง ์์ผ๋ฉฐ Figma ๋ฌธ์๋ฅผ ๋ฐ๊พธ๋ ํธ์ถ์ ์กด์ฌํ์ง ์์ต๋๋ค.
-
์ด ๊ธฐ๊ธฐ์์๋ง ๋ฉ๋๋ค. ๋๊ธฐ ์ฃผ์๋
127.0.0.1์ด๋ผ ๋ค๋ฅธ ๊ธฐ๊ธฐ์์๋ ๋ถ์ ์ ์๊ณ , ์๊ฒฉ CI์์๋ ๋ธ๋ฆฌ์ง๊ฐ ์์ผ๋ ์๋์ผ๋ก ์๊ฒฉ ๊ฒฝ๋ก๋ฅผ ์๋๋ค. -
ํ์ผ์ ํ ๋ฒ์ ํ๋์ ๋๋ค. ํ๋ฌ๊ทธ์ธ์
figma.fileKey๋ก ์๊ธฐ ํ์ผ์ ์๋ฆฌ๋๋ฐ, Figma๋ ์ด ๊ฐ์ private plugin์๋ง ์ค๋๋ค. ๊ทธ๋์ manifest์enablePrivatePluginApi๋ฅผ ์ ์ด ๋์๊ณ , ์ด ์ค์ด ์๋ ์์ ๋น๋๋ ํค๋ฅผ ๋ณด๊ณ ํ์ง ๋ชปํ์ต๋๋ค(fileKey: null). ํค ์๋ ํ๋ฌ๊ทธ์ธ์ ํผ์ ๋ถ์ด ์์ ๋๋ง ์ฝ๊ธฐ๋ฅผ ๋ฐ์ต๋๋ค. ๋ ๊ฐ ์ด์์ด๋ฉด ์ด๋ ํ์ผ์ธ์ง ์ ์ ์์ผ๋ฏ๋ก ์๊ฒฉ ๊ฒฝ๋ก๋ก ๋์ด๊ฐ๋๋ค. -
ํฌํธ๋ฅผ ๋ฐ๊พธ๋ ค๋ฉด ์ธ ๊ณณ์ ๊ฐ์ด ๊ณ ์ณ์ผ ํฉ๋๋ค. Figma๋ ํ๋ฌ๊ทธ์ธ์ด ์ ์ํ ์ ์๋ ์ฃผ์๋ฅผ manifest์ ๋ฏธ๋ฆฌ ์ ์ด ๋๊ฒ ํ๊ณ ์คํ ์ค์๋ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
manifest.json์allowedDomains,src/code.ts์PORT, ๊ทธ๋ฆฌ๊ณ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ชจ๋ ๊ณ ์น ๋ค ํ๋ฌ๊ทธ์ธ์ ๋ค์ ๋น๋ยท์ค์นํด์ผ ํฉ๋๋ค. ํ๋๋ง ๋ฐ๊พธ๋ฉด ์๋ฌด ๋ง ์์ด ์๊ฒฉ ๊ฒฝ๋ก๋ก ๋์๊ฐ ํ๋๋ฅผ ๊ทธ๋๋ก ์๋๋ค. -
ws://127.0.0.1์ ์ธ ์ ์์ต๋๋ค. Figma์allowedDomains๊ฐ ๊ทธ ์ฃผ์๋ฅผ ๊ฑฐ๋ถํด manifest ์ ์ฒด๊ฐ ๋ฌดํจ๊ฐ ๋๊ณ ํ๋ฌ๊ทธ์ธ์ด ์์ ๋ก๋๋์ง ์์ต๋๋ค.localhost์ฌ์ผ ํฉ๋๋ค. -
ํ ํ๋ฉด์ ํ ๋ฒ์ ์ฝ๊ธฐ๋ก ์ต๋๋ค. ๋ธ๋ฆฌ์ง๋ ํ๋ฌ๊ทธ์ธ์๊ฒ ํ๋ฉด ํ๋๋ฅผ ๋ดํฌ ํ๋(์ต๋ 8 MiB)์ ๋ด์ ๋ฌ๋ผ๊ณ ํ๊ณ , ๋์ฝ๋๋ ๊ทธ ํฌ๊ธฐ๊น์ง ๋ฐ์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ด ํ์ผ ํค๋ฅผ ๋ณด๊ณ ํ์ง ๋ชปํ๋ฉด ๋ดํฌ ์์ ํค ์๋ฆฌ(
sourceยทsnapshot)๋ฅผ ์์ฒญํ ํ์ผ๋ก ์ฑ์๋๋ค. ์์ ์๋ ๋ ๋ค ๋ง์ง ์์ 64 KiB๊ฐ ๋๋ ํ๋ฉด์ด๋ ํค ์๋ ํ๋ฌ๊ทธ์ธ์ ๋ดํฌ๊ฐ ๋ชจ๋ ๋ฒ๋ ค์ง๊ณ , ๋ ธ๋๋ง๋ค ์ฝ๋ ์์ ๊ฒฝ๋ก๋ก ๋จ์ด์ก์ต๋๋ค. ๊ทธ ๊ฒฝ๋ก๋ breakpoint ํ์ ํญ์ ๋ชจ์ผ์ง ์์responsiveTsx๋ ๋์ค์ง ์์์ต๋๋ค. ์ค์ ๊ณต์ง ํ๋ฉด์ 4๋ฒ ์ฝ๋ ๊ฒ์ด 1๋ฒ์ด ๋๊ณ , ์ธ ํญ์ด ํจ๊ป ์์ง๋ฉ๋๋ค. -
Figma ์ฐฝ์ ๋ค๋ก ๋ณด๋ด๋ฉด ๋๋ ค์ง๋๋ค. ๋ธ๋ผ์ฐ์ ๊ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ๋ฌ๊ทธ์ธ์ ๋ถ๋น ํ ๋ฒ๊ผด๋ก ๊นจ์ฐ๊ธฐ ๋๋ฌธ์, ์์์ 160ms์ธ snapshot์ด ๋ค์์๋ 11์ด๊ฐ ๋ฉ๋๋ค. ์์ง ์ค์๋ Figma๋ฅผ ์์ ๋์ธ์.
-
๊ทธ ํ์ผ์ ํ๋ฉด์ ๋์ ๋์ธ์. ํ๋ฌ๊ทธ์ธ์ด ๋๋ ํ์ผ์ด ํ๋ฉด์์ 2
3๋ถ ์ฌ๋ผ์ง๋ฉด โ ํญ์ด ๋ค๋ฅธ ํ์ผ์ ํญ ๋ค๋ก ๊ฐ๊ฑฐ๋, ํญ์ ์์ ๋ ์ฑ Figma ์ฐฝ์ ์ต์ํํ๊ฑฐ๋, ์ฐฝ์ด ๋ค๋ฅธ ์ฐฝ์ ๊ฐ๋ฆฌ๊ธฐ๋ง ํด๋ โ Figma ๋ฐํ์์ ์์ง ๋ถ๋ฌ์ค์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ๋๋ง๋ค 10์ด ๋ค "Unable to establish connection to Figma"๋ก ๋ตํฉ๋๋ค(์ค์ธก: ํญ์ด ๋ค์ ๊ฐ ๋ค 1๋ถ์งธ๋ ์ ์, 2๋ถ์งธ๋ถํฐ ์คํจ. ์ฐฝ๋ง ์ต์ํํ๋ฉด 2๋ถ์งธ ์ ์, 3๋ถ์งธ๋ถํฐ ์คํจ). ์ด๋ฏธ ๋ถ๋ฌ์จ ๋ณ์ยท์คํ์ผ์ ํ๋์ ๋ตํ์ง๋ง(10๋ถ์งธ๋ ํด์) ๊ทธ๊ฒ๋ง์ ๋น ์ง๋ฉด ํ๋ฉด์ ๋ฐ์์ง๋๋ฐ ํ ํฐ ๋์ ๊ฐ์ด ๋ค์ด๊ฐ๋๋ค(๊ณต์ง ํ๋ฉด: 37๊ฐ ์ค 0๊ฐ ํด์). ์ฐฝ์ ์์ผ๋ก ๊ฐ์ ธ์ ๊ทธ ํ์ผ์ ํญ์ ๋๋ฅด๋ฉด ๊ณง๋ฐ๋ก ํ๋ฆฌ๋ฉฐ, ์๋ต์7๋ถ ๋ค ํ์ผ ์ ์ฒด ๊ฒ์ ๋ ๋ฒ์์ ๊ฐ๊ฐ ํ๋ฌ๊ทธ์ธ์ ์ฝ๊ธฐ ํ๋๊ฐ ๊ทธ๋ ๊ฒ ๋์์ direct๊ฐ ๋ค์ ์ฝ์๊ณ , ๊ทธ์ค Figma๋ฅผ ์์ ๋๊ณ ๋ค์ ํ ๊ฒ์์ ๊ฒฐ๊ณผ(100๊ฑด)๊ฐ ๊ฐ์์ต๋๋ค(15 s, ์์ ๋๋ฉด 0.4 s). ์ง๊ธ์ ํ๋ฌ๊ทธ์ธ์ด ์์ํ ๋์ Figma๊ฐ ๊ทธ ํ์ผ์ ๋ค์ ๋ณด์ฌ ์ค ๋๋ง๋ค ๋ชจ๋ ํ์ด์ง์ ๋ก์ปฌ ๋ณ์ยท์คํ์ผ์ ๋ฏธ๋ฆฌ ๋ถ๋ฌ ๋ก๋๋ค. ๋ถ๋ฌ ๋ ๋ฐ์ดํฐ๋ ๊ฐ๋ ค์ง ๋์์๋ ๋ตํ๋ฏ๋ก, direct๋ฅผ ๋ฟ์ ์ ์๊ฒ ํ ์ฑ Figma๋ฅผ ๋ค๋ฅธ ์ฐฝ์ผ๋ก 5๋ถยท8๋ถ ๊ฐ๋ฆฌ๊ณ ํ ํ์ผ ์ ์ฒด ๊ฒ์ยท๊ณต์ง ๋ชจ๋ฐ์ผ TSXยท์ฐธ์กฐ PNG ๋ ๊ฐ๊ฐ ์์ ๋ ๊ฒ๊ณผ ๊ฐ์ ๋ต(๊ฒ์ 100๊ฑด๊ณผ ๊ทธ id, TSXยทPNG ํด์)์ด์๊ณ "Unable to establish connection"์ ํ ๋ฒ๋ ์์์ต๋๋ค. ์ง๊ธ ๋ณด์ด๋์ง๋hintยทnextAction.how๊ฐ ๊ทธ๋ ๊ฒ ๋งํฉ๋๋ค. ๋ก๊ทธ์ธ์ด ๋์ด ์์ผ๋ฉด ๊ทธ ์ฝ๊ธฐ๋ direct ๊ฒฝ๋ก๊ฐ ๋ค์ ์ฝ์ด(ํ๋๋ฅผ ์๋๋ค) ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง์ง ์๊ณ ,source.directFallbackReasons์file-out-of-sight์directFallbackHint๊ฐ ๊ทธ ์ฌ์ค๊ณผ ํ ์ผ์ ๋งํฉ๋๋ค. ๋ฏธ๋ฆฌ ๋ถ๋ฌ ๋๊ธฐ(์๋) ์ ์ ์ค์ธก: Figma ์ฐฝ์ ๋ค๋ฅธ ์ฐฝ์ ๊ฐ๋ฆฐ ์ง 5attachedFiles[].inView๊ฐ ์๋ฆฝ๋๋ค(์ด ๊ธฐ๋ฅ ์ ์ devup-mcp๊ฐ ํฌํธ๋ฅผ ์ฅ๊ณ ์์ผ๋ฉด ๊ทธ ํ๋๊ฐ ๋น ์ง๋๋ค). -
ํ๋ฌ๊ทธ์ธ์ด ๋ตํ ์คํจ๋ ํ๋ฌ๊ทธ์ธ์ ๋ต์ผ๋ก ์ต๋๋ค. ์คํฌ๋ฆฝํธ๊ฐ ๋์ง ์ฝ๋๋ Figma ๋ฐํ์์ ๋ง์ ์๊ฒฉ
use_figma์ ๊ฐ์ ๋ชจ์์ผ๋ก ์ฌ๋ผ๊ฐ, ๋ ๊ฒฝ๋ก๊ฐ ๊ฐ์ ์ค๋ฅ๋ก ๋ถ๋ฅ๋ฉ๋๋ค โ ์๋ ๋ ธ๋๋DEVUP_FIGMA_NODE_NOT_FOUND(-32602), ๊ทธ ๋ฐ์stage: "plugin-execution". ์์ ์๋ ๋ธ๋ฆฌ์ง๋ฅผ ๊ฑฐ์น ๋ชจ๋ ์คํจ๊ฐDEVUP_FIGMA_DIRECT_UNAVAILABLE์ด์ด์, Figma ๋ฐํ์์ด ๋ณด๊ณ ์๋ ํ์ด์ง ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค์ง ๋ชปํ๋ค๋ "Unable to establish connection to Figma after 10 seconds"๊ฐ direct ๊ฒฝ๋ก์ ์ฅ์ ๋ก ์ฝํ์ต๋๋ค โ ๊ทธ ์ฝ๊ธฐ๋ direct ๊ฒฝ๋ก์ ๊ฐ ์ ์ด ์์ต๋๋ค. ์ด ๋ฌธ๊ตฌ์๋nextAction.how๊ฐ ํ ์ผ(๊ทธ ํ์ผ์ ํญ ๋๋ฅด๊ธฐ)์ ๋ต๋๋ค. ํฌํธ๋ฅผ ์ฅ ํธ์คํธ๋ฅผ ๊ฑฐ์น ์คํจ๋ ๊ฐ์ต๋๋ค. ํธ์คํธ๊ฐscriptError๋ก ์๋ฆฌ๊ณ , ๊ทธ ํ์๋ฅผ ๋ณด๋ด์ง ์๋ ์์ ํธ์คํธ๋ฉด ํธ์คํธ๊ฐ ์ค์ค๋ก ์ฐ๋ ๋ฌธ๊ตฌ์ธ์ง๋ก ๊ฐ๋ฆฝ๋๋ค. -
referencePng๋ ํ๋ฌ๊ทธ์ธ์ด ๊ทธ๋ฆฝ๋๋ค โ ๊ฑฐ์ ํ์ง ์์ต๋๋ค.get_screenshot์ ๋ ธ๋๋ฅผ ์กฐ์๋ค์ ๋งฅ๋ฝ โ ์ฑ์(๊ทธ๋ผ๋์ธํธยท์ฌ์ง ํฌํจ), ์๋ผ ๋ด๊ธฐ, ๋ถํฌ๋ช ๋, ๋ธ๋ ๋ ๋ชจ๋, ๋ ์ด์ด ๋ธ๋ฌ, ๋๋กญ ์๋ โ ์์์ ๊ทธ๋ฆฌ๋ ๋ค๋ฅธ ๋ ์ด์ด๋ ๋ชจ๋ ๋นผ๊ณ , ๋ ธ๋์ ๋ ๋ ์์ญ(๊ทธ๋ฆผ์ยท๋ฐ์ผ๋ก ๋์น ์์ ํฌํจ, ์๋ผ ๋ด๋ ์กฐ์์ด ์๋ฅธ ๋งํผ)์ผ๋ก ๊ทธ๋ฆฝ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ๊ทธ ์์ญ์ ๋ ๊ฐ์ ์ค์ (useAbsoluteBounds: false, scale 1์ด๋ ๊ธด ๋ณ์ direct์maxDimension๊ณผ ๊ฐ์ 8192px๊น์ง, sRGB)์ผ๋ก exportํฉ๋๋ค.- ๊ทธ ์์ญ์ ๋ค๋ฅธ ๋ ์ด์ด๊ฐ ๋ฟ์ง ์์ผ๋ฉด ์บ๋ฒ์ค์ ๊ทธ ์๋ฆฌ(
contentsOnly: false)๊ฐ ๊ณง ๊ทธ ๊ทธ๋ฆผ์ ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ๊ทธ๊ฒ๊ณผ export์ ๋น ์ง๋ ํ์ด์ง ๋ฐฐ๊ฒฝ์ ๋ณด๋ด๊ณ , ๋ธ๋ฆฌ์ง๊ฐ ๊ทธ ์๋ก ํํํ๊ฒ ๋ฎ์ต๋๋ค. - ๋ฟ์ผ๋ฉด ํ๋ฌ๊ทธ์ธ์ ๋
ธ๋๋ง(
contentsOnly: true) exportํ๊ณ ์กฐ์๋ค์ ์ค๋ช ํฉ๋๋ค โ ๋ณํยทํฌ๊ธฐยท๋ชจ์๋ฆฌ, ์ฑ์, ๋ถํฌ๋ช ๋ยท๋ธ๋ ๋, ์๋ผ ๋ด๊ธฐ, ํจ๊ณผ, ๋ง์คํฌ, ์ฑ์์ ์ด ์ฌ์ง์ ์๋ณธ. ๋๋จธ์ง๋ devup-mcp๊ฐ ๊ทธ๋ฆฝ๋๋ค: ๋จ์ยท๊ทธ๋ผ๋์ธํธ(์ ํยท๋ฐฉ์ฌยท๊ฐยท๋ง๋ฆ๋ชจ)ยท์ฌ์ง(PNGยทJPEGยทGIF, FILLยทFITยทTILEยทCROP) ์ฑ์, ๋ฅ๊ทผ ๋ชจ์๋ฆฌ๋ก ์๋ผ ๋ด๊ธฐ, ๋ธ๋ ๋ ๋ชจ๋ 18๊ฐ์ง, ์ํยท๋ฐ๊ธฐ ๋ง์คํฌ, ๋ ์ด์ด ๋ธ๋ฌ, ๋๋กญ ์๋(spread ํฌํจ, ๋ ์ด์ด ๋ค๋ก ๋ณด์ด์ง ์๊ฒ ํ ๊ทธ๋ฆผ์๋ ๋ ์ด์ด ์๋๋ฅผ ์๋ผ ๋)์ ์์ชฝ ๊ทธ๋ฆผ์, ์ฌ๊ฐํ ์กฐ์์ ํ ๋๋ฆฌ(๋จ์ยท๊ทธ๋ผ๋์ธํธ, ์ ์ ์์, ๋ชจ์๋ฆฌ๊ฐ ๊ฐ์ง ๊ฒ), ์กฐ์๊ณผ ๋ ธ๋ ์์ ์ ๋ฐฐ๊ฒฝ ๋ธ๋ฌ. ๋ ธ๋์ ๋ฐฐ๊ฒฝ ๋ธ๋ฌ๊ฐ ์๋ ๋ ์ด์ด๋ฅผ ๋จธ๊ธ์ผ๋ฉด ๋ ธ๋๋ฅผ ์ ์ฑ์๊ณผ ์์๋ค์ export๋ก ๊ทธ๋ฆฌ๊ณ , ๋ ธ๋์ ๋ง์คํฌ๋ ๊ทธ ์ ๋ถ(์ฑ์ยท๋ฐฐ๊ฒฝ ๋ธ๋ฌยท์์)๋ฅผ ์๋ฆ ๋๋ค. ๋ง์คํฌ๋ Figma๊ฐ ๋ ๋ ์์ญ์ ์ฃผ์ง ์์ผ๋ฏ๋ก ์ ์์๋ก exportํด ๋๊ณ , ๋ง์คํฌ๋ฅผ ์ด๋ฃจ๋ ๋ ์ด์ด ์์ ๋ ธ๋๋get_screenshot์ฒ๋ผ ๊ทธ๋ฆฌ์ง ์์ต๋๋ค(๊ทธ ์๋๋ง ๋ณด์ ๋๋ค). devup-mcp๊ฐ ๋์ฝ๋ฉํ์ง ์๋ ์ฌ์ง โ PNGยทJPEGยทGIF๊ฐ ์๋ ๊ฒ(WebP ๋ฑ), ๊ธด ๋ณ์ด 8192px๋ฅผ ๋๋ ๊ฒ, ๋๋ถ๋ถ์ด ๋ฉํ๋ฐ์ดํฐ์ธ ๊ฒ โ ์ ํ๋ฌ๊ทธ์ธ ์ฐฝ(๋ธ๋ผ์ฐ์ )์ด ๋์ฝ๋ฉํด ๊ธด ๋ณ 8192px ์ดํ์ PNG๋ก ๋๋ ค์ฃผ๊ณ , ํฉ์ฑ๊ธฐ๋ ์๋ณธ ํฌ๊ธฐ์ ๋ง์ถฐ ๋ฐฐ์นํฉ๋๋ค. ์ฐฝ์ ํ ๋ฒ์ ํ๋๋ง ๋์ฝ๋ฉํ๊ณ , ์ฅ๋ฉด ํ๋์ ์ฌ์ง๋ค์ด ๋ณํ ์๊ฐ 20์ด๋ฅผ ๋๋ ์๋๋ค. ๋ฐ๊พธ๋ ๋ฐ 512 MiB๊ฐ ๋๊ฒ ๋ค ์ฌ์ง(๋ณํ์ด ๋ง๋๋ ๋ฒํผ๋ฅผ ๋จผ์ ํ๋ฆฌ๋ ๊ฒ ์์ด ๋ชจ๋ ๋ํจ: ์ฌ์ง ๋ฐ์ดํธ์ ์ฌ๋ณธ ๋ค์ฏ โ ์ด์ชฝ์ ์๋ณธ, ์ฐฝ์ผ๋ก ๊ฐ๋ ๋ฉ์์ง, ์ฐฝ์ด ๋ฐ์ ์ฌ๋ณธ, Blob, ๋์ฝ๋๊ฐ ์ฝ๋ ๊ฒ โ, ๋์ฝ๋ฉํ ๊ทธ๋ฆผ๊ณผ ์ค์ผ ๋์ ์ฌ๋ณธ, ์บ๋ฒ์ค, ๊ทธ ์บ๋ฒ์ค๋ก ๋ง๋ PNG์ ๊ทธ ์ฌ๋ณธ ์ )๊ณผ ์๊ฐ์ด ๋ค ๋ ๋ค์ ์ฌ์ง์ ์๋ ๋ฐ์ดํธ๋ก ๋ณด๋ ๋๋ค. - ๊ทธ๋ฆฌ์ง ๋ชปํ๋ ๊ฒ์ด ์์ผ๋ฉด ์บ๋ฒ์ค์ ๊ทธ ์๋ฆฌ๋ฅผ ๊ทธ๋ฆฌ๊ณ , ์๋ต์
referencePngNote๊ฐ ์ด์ ์ ๋ฟ์ ๋ ์ด์ด๋ฅผ ๋๋๋ค. ๋ค์์ด ์ฌ๊ธฐ์ ๋ญ๋๋ค. ๋ก๊ทธ์ธ์ด ๋์ด ์์ผ๋ฉด direct์get_screenshot์ด ๋์ ๋ตํฉ๋๋ค(reference-png-approximate).- ์ฌ๊ฐํ์ด ์๋ ์กฐ์์ ํ ๋๋ฆฌ, ์ ์ ํ ๋๋ฆฌ, ๋ชจ์๋ฆฌ ์ด์์ด ๋ฅ๊ธ๊ฑฐ๋ ๊น์ธ ๋ฐ๊นฅยท๊ฐ์ด๋ฐ ํ ๋๋ฆฌ, ๋จ์ยท๊ทธ๋ผ๋์ธํธ๊ฐ ์๋ ํ ๋๋ฆฌ
- ์๋ ๋ ์ด์ด๋ฅผ ๋จธ๊ธ๋ ๋ฐฐ๊ฒฝ ๋ธ๋ฌ๊ฐ ๋ ธ๋ ์์ ๋ ์ด์ด์ ์๊ฑฐ๋, ์์์ ๋ ์ ์๋ ๋ ธ๋(์ฌ๊ฐํยท๋ฒกํฐ ๋ฑ)๋ ํ ๋๋ฆฌ๊ฐ ์๋ ๋ ธ๋์ ์๋ ๊ฒฝ์ฐ
- ํ์ ยทํํฐ๊ฐ ์๋ ์ฌ์ง ์ฑ์, ๊ทธ ๋ฐ์ ์น , ๋ ธ์ด์ฆยทํ ์ค์ฒ์ฒ๋ผ devup-mcp๊ฐ ๋ชจ๋ฅด๋ ํจ๊ณผ
- 8M ํฝ์ ์ด ๋๋ ์์ญ, ํฉ์ณ 64 MiB๊ฐ ๋๋ ์ฌ์ง
- ์คํ์ ๊ณผ spread๋ฅผ ํฉ์ณ ์์ญ ๋๋ ์ ๊ทธ๋ ค ๋ ์ฌ๋ฐฑ(์ต๋ 512px)๋ณด๋ค ๋จผ ๊ณณ์์ ๋๋ฆฌ์์ง๋ ๊ทธ๋ฆผ์
- ๊ทธ๋ฆฌ๋ ๋ฐ 1.5 GiB๊ฐ ๋๋ ๋ฉ๋ชจ๋ฆฌ๋ 40์ต ๋ฒ์ด ๋๋ ๋ธ๋ฌยท๊ทธ๋ฆผ์ spread ๊ณ์ฐ์ด ๋๋ ๊ฒฝ์ฐ โ ๊ทธ๋ฆฌ๊ธฐ ์ ์, ๋ ์ด์ด๋ง๋ค ๋จ๋ ๋ง์คํฌ์ ๊ทธ๋ฆผยท์ฌ์ง์ ๋์ฝ๋ฉ๊น์ง ์ ๋๋ค. ๋์ฝ๋ฉ์ ๋์ฝ๋๋ฅผ ๋ง๋ค๊ธฐ ์ ์ ํค๋๋ง ์ฝ๊ณ ์ ๋๋ค. PNGยทGIF ๋์ฝ๋์๋ ๊ทธ ํ์ฉ๋์ ๊ฑธ๊ณ , PNG ๋์ฝ๋๊ฐ ๊ทธ ๋ฐ์์ ์ก๋ ๊ฒ(ํ์ด๋ด๋ ํ, ํ ์คํธ ์ฒญํฌ๋ง๋ค์ ํญ๋ชฉ)๋ ์ ๋๋ค. JPEG ๋์ฝ๋๋ ์ํ์ ๋ฐ์ง ์์ผ๋ฏ๋ก, ํ๋ ์ ํค๋์ ์ํ๋ง์ผ๋ก ์ผ ๊ณ์ ๋ฒํผ์ ๋ฐ์ดํธ ์ฌ๋ณธ๊น์ง ์ ๋๋ค. ํ๋ ์ ํค๋ ์์ ๋จ๋ ๋ง์ปค(SOIยทRSTยท์ฑ์ 0)๊ฐ ์๋ JPEG๋ ๋์ฝ๋ฉํ์ง ์์ต๋๋ค
- ํ๋ฌ๊ทธ์ธ ์ฐฝ์ด PNG๋ก ๋ฐ๊ฟ ์ฃผ์ง ๋ชปํ ์ฌ์ง(์ฐฝ๋ ๋์ฝ๋ฉํ์ง ๋ชปํ๊ฑฐ๋, ๋ฐ๊พธ๋ ๋ฐ 512 MiB๊ฐ ๋๊ฒ ๋ค๊ฑฐ๋, ๋ณํ ์๊ฐ์ด ๋ค ๋๊ฑฐ๋, ์ด ๋์ฝ๋ฉ ์ ์ ๋น๋๋ ํ๋ฌ๊ทธ์ธ์ด๊ฑฐ๋, ํ๋ฌ๊ทธ์ธ์ด ํ์ยทํฌ๊ธฐยท๋ฐ์ดํธ ์๋ก ์์๋ณด์ง ๋ชปํ ๊ฒฝ์ฐ) ๊ฐ์ด๋ฐ PNGยทJPEGยทGIF๊ฐ ์๋ ๊ฒ(WebP โ ๊ทธ ๋์ฝ๋๋ ์ํ์ ๋ฐ์ง ์๊ณ , ํค๋๋ก ์ ์ ์๋ ๋ฒํผ๋ฅผ ์ก์ต๋๋ค), 8192px๋ณด๋ค ๋์ PNG(๋์ ์ธํฐ๋ ์ด์ค 16๋นํธ PNG๋ ๋์ฝ๋๊ฐ ํ์ด๋ด๋ ํ์ด ํ์ฉ๋์ ๋์ต๋๋ค), ํ์ฉ๋ ์์์ ๋์ฝ๋ฉ๋์ง ์๋ PNGยทGIF(ํฐ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง PNG ๋ฑ)
- ํค๋๋ฅผ ์ฝ์ ์ ์๋ ๊ทธ๋ฆผยท์ฌ์ง
- ํ๋ฌ๊ทธ์ธ์ด exportํ์ง ๋ชปํ ๋ถ๋ถ, ๊ทธ๋ฆฌ๋ค ๋ฉ์ถ ๊ฒฝ์ฐ
- ๋ต ํ๋(6 MiB)์ ๋ค์ด๊ฐ์ง ์๋ ๋ต์ ํ๋ฌ๊ทธ์ธ์ด ๋ถ๋ค์ด ๋๊ณ 4 MiB ์กฐ๊ฐ์ผ๋ก ๋ด์ฃผ๋ฉฐ, ๋ธ๋ฆฌ์ง๊ฐ ์ด์ด ๋ฐ์ต๋๋ค. ์กฐ๊ฐ์ ์์น๊ฐ ์ด๊ธ๋์ง ์๋๋ก ๋ถ๋ค์ด ๋ ๊ธ์ ASCII๋ก ์๋๋ค. ๋ ์ด์ด ์ด๋ฆ์ ํํ ํ๊ธ์
๋๋ค.
- ๋ถ๋ ๋ต: ๋ค ์ฝํ๊ฑฐ๋ 2๋ถ์ด ์ง๋ ๋๊น์ง ๋จ๊ณ , ๋ค๋ฅธ ์์ฒญ ๋๋ฌธ์ ๋ฐ๋ ค๋์ง ์์ต๋๋ค.
- ๋ฐ์ ๋: ๋ถ๋ ๋ต์ด 192 MiB ์ด์ ์์ฌ ์์ผ๋ฉด ํ๋ฌ๊ทธ์ธ์ ์ ๊ทธ๋ฆผ์ ๊ทธ๋ฆฌ์ง ์๊ณ ๋ฐ์๋ค๊ณ ๋ตํ๋ฉฐ(
DEVUP_REFERENCE_PNG_BUSY), ๋ธ๋ฆฌ์ง๋ 45์ด๊น์ง ๋ค์ ๋ฌป์ต๋๋ค. ๊ทธ ์ฌ์ด์๋ ๋ค๋ฅธ ์์ฒญ์ ์กฐ๊ฐ ์ฝ๊ธฐ๋ ์ฒ๋ฆฌ๋ฉ๋๋ค. 192 MiB๋ ์ ๊ทธ๋ฆผ์ ๋ฐ์๋ค์ด๋ ๋ฌธํฑ์ด์ง ์ํ์ด ์๋๋๋ค โ ๊ทธ ์๋์์ ๋ฐ์๋ค์ธ ๋ต ํ๋(์ต๋ 90 MiB)๋งํผ ๋์ ์ ์์ต๋๋ค. - ์ฌ๋ผ์ง ๋ต: ์ฝ๊ธฐ ์ ์ ์ฌ๋ผ์ง ๋ต(ํ๋ฌ๊ทธ์ธ์ ๋ค์ ์คํํ ๊ฒฝ์ฐ ๋ฑ)์ ํ ๋ฒ ๋ค์ ๋ฐ์ต๋๋ค.
- ๋๋ฌด ํฐ ๋ต: ์กฐํฉ์ ๋๋ ๊ฒ๊น์ง ์ค์ ๋ต์ด 90 MiB(๋ธ๋ฆฌ์ง๊ฐ ๋ฐ๋ 96 MiB ์๋)๋ฅผ ๋์ผ๋ฉด ์กฐํฉ์ ๋ฒ๋ฆฌ๊ณ ์บ๋ฒ์ค ๊ทธ๋ฆผ๋ง ์ด์ ์ ํจ๊ป ๋ณด๋ ๋๋ค.
๋ธ๋ฆฌ์ง๋
get_screenshot๊ณผ ๊ฐ์ ์ด๋ฏธ์ง ๋ธ๋ก ํ๋๋ก ๋๋ ค์ฃผ๊ณ , ์์ง๊ธฐ๋ ๋ ๊ฒฝ๋ก์ ๋ต์ ๊ฐ์ ๊ฒ์ฆ์ผ๋ก ๋ฐ์ต๋๋ค. - ๊ทธ ์์ญ์ ๋ค๋ฅธ ๋ ์ด์ด๊ฐ ๋ฟ์ง ์์ผ๋ฉด ์บ๋ฒ์ค์ ๊ทธ ์๋ฆฌ(
-
devup-mcp๋ณด๋ค ์ค๋๋ ํ๋ฌ๊ทธ์ธ์ ์ ์ฝ๊ธฐ๋ฅผ ๋ชจ๋ฅธ๋ค๊ณ ๋ตํฉ๋๋ค(
DEVUP_BRIDGE_UNKNOWN_SCRIPT). ์๋์กฐ์ฐจ ๋์ง ์์ ์ฝ๊ธฐ๋ผ, ํ๋ฌ๊ทธ์ธ์ด ํ์ผ ํค๋ฅผ ๋ณด๊ณ ํ๊ณ ๋ก๊ทธ์ธ์ด ๋์ด ์์ผ๋ฉด ๊ทธ ์ฝ๊ธฐ๋ง direct ๊ฒฝ๋ก๊ฐ ๋์ ์ฝ์ต๋๋ค(ํ๋๋ฅผ ์๋๋ค). ๋ก๊ทธ์ธ์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ ์๊ตฌ๊ฐ ์๋๋ผ ํ๋ฌ๊ทธ์ธ์ ๋ต๊ณผ ํ ์ผ โ ํ๋ฌ๊ทธ์ธ์ ๋ถ๋ฌ์จ ์ ์ฅ์๋ฅผ ๊ฐฑ์ ํ๊ณ ๋ค์ ์คํ โ ์ด ์ต๋๋ค. ์กฐ๊ฐ์ผ๋ก ๋ด์ฃผ๊ธฐ ์ ์ ํ๋ฌ๊ทธ์ธ์ด ์ฐธ์กฐ PNG๋ฅผ ๋ธ๋ฆฌ์ง ๋ต ํ๋(8 MiB)์ ๋ด์ง ๋ชปํ ๋(DEVUP_REFERENCE_PNG_TOO_LARGE, direct๋ 16 MiB๊น์ง ๋ฐ์ต๋๋ค)๋ ๊ฐ์ ๊ธธ์ ๊ฐ๋๋ค.
์์ธํ ๋ด๋ถ ๊ตฌ์กฐ์ ์คํฌ๋ฆฝํธ ์์ฑ ๋ฐฉ์์ plugin/README.md์ ์์ต๋๋ค.
Figma ๋ฐ์คํฌํฑ ์ฑ์ ๋ก์ปฌ Dev Mode MCP(http://127.0.0.1:3845/mcp)๋ ์ธ ๋ฒ์งธ ๊ฒฝ๋ก๋ก ์๋ดํ์ผ๋ ์ ๊ฑฐํ์ต๋๋ค. ์ฝ๊ธฐ ๋๊ตฌ 6๊ฐ(get_design_context, get_variable_defs, get_screenshot, get_motion_context, get_metadata, get_figjam)๋ง ์ ๊ณตํ๊ณ ๊ทธ์ค์ use_figma๊ฐ ์์ต๋๋ค. devup-mcp์ ์์ง์ snapshotยทexploreยทsection indexยทtheme ๋ชจ๋ use_figma๋ก ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฏ๋ก ๋ก์ปฌ์์๋ ์คํํ ๋๊ตฌ ์์ฒด๊ฐ ์์ต๋๋ค. ๋๊ตฌ๋ค์ด fileKey๋ฅผ ๋ฐ์ง ์๊ณ ๋ฐ์คํฌํฑ ์ฑ์ ์ด๋ ค ์๋ ํ์ผ๋ง ๊ฐ๋ฆฌํค๋ ๊ฒ๋ ๊ฐ์ ์ด์ ๋ก ๋ง์ง ์์ต๋๋ค. "OAuth ์์ด ๋ฐ๋ก ์ธ ์ ์๋ค"๋ ์๋ด๋ ํ์ ์ ์ฐจ์ ํ๋ฆฐ ์๋ด์๊ณ , ๋ฏฟ์ ์ชฝ์ด ํ ํด์ ๋ฒ๋ฆฐ ๋ค์์ผ ์๊ฒ ๋ฉ๋๋ค.
Figma Remote MCP ๋ฑ๋ก ์๋ํฌ์ธํธ๋ POST https://api.figma.com/v1/oauth/mcp/register์
๋๋ค. ์์ฒญ ๋ณธ๋ฌธ์ client_name์ ์ ํํ ์ผ์นํ๋ allowlist๋ก๋ง ์น์ธ๋ฉ๋๋ค.
| client_name | ๊ฒฐ๊ณผ |
|---|---|
Codex |
200 (client_id + client_secret ๋ฐ๊ธ) |
Claude Code |
403 (2026-09-06 ์ค์ธก; ์ด์ ํ์๋ 200์ผ๋ก ์ ํ ์์์) |
OpenCode |
403 |
opencode |
403 |
Cursor |
403 |
VS Code |
403 |
403 ์๋ต ๋ณธ๋ฌธ์ JSON์ด ์๋๋ผ ํ๋ฌธ Forbidden์
๋๋ค. ๊ทธ๋์ ๋ง์ ํด๋ผ์ด์ธํธ๊ฐ Invalid OAuth error response ... Raw body: Forbidden์ผ๋ก ํ์ฑ๊น์ง ๊นจ์ง๋๋ค. X-Figma-Plugin-Bundle ํค๋๋ User-Agent๋ฅผ ๋ฐ๊ฟ๋ ๊ฒฐ๊ณผ๋ ๋ฐ๋์ง ์์ต๋๋ค. ์ ๊ท client ๋ฑ๋ก์ waitlist๋ฅผ ํตํด์๋ง ๊ฐ๋ฅํฉ๋๋ค: https://www.figma.com/mcp-catalog/.
redirect_uri๋ ํํ๊ฐ ๊ณ ์ ๋์ด ์์ต๋๋ค.
| redirect_uri | ๊ฒฐ๊ณผ |
|---|---|
http://127.0.0.1:<port>/callback |
200 |
http://127.0.0.1:<port>/mcp/oauth/callback |
400 |
http://localhost:<port>/mcp/oauth/callback |
400 |
๊ฒฝ๋ก๋ ์ ํํ /callback์ด์ด์ผ ํ๊ณ ํธ์คํธ๋ 127.0.0.1์ด์ด์ผ ํฉ๋๋ค (localhost ๋ถ๊ฐ). Figma PAT(figd_...)๋ Authorization: Bearer, X-Figma-Token ์ด๋ ๋ฐฉ์์ผ๋ก๋ ์๊ฒฉ MCP์์ ์ง์๋์ง ์์ต๋๋ค.
๋ก์ปฌ OAuth ์ฝ๋ฐฑ์ด ์ฐ๋ ํฌํธ๋ฅผ OS๋ ๋ณด์ ์ํํธ์จ์ด(์: ์ฌ๋ด ๋ณด์ ์์ด์ ํธ)๊ฐ ์ด๋ฏธ ์ ์ ํ๊ณ ์์ผ๋ฉด, ๋ธ๋ผ์ฐ์ ๋ ๋ฆฌ๋ค์ด๋ ํธ์ "์ฑ๊ณต"ํ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ๊ทธ ์์ฒญ์ ๋ค๋ฅธ ํ๋ก์ธ์ค๋ก ์ ๋ฌ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ๋ ์๋ฌด ์๋ฌ ์์ด Waiting for authorization... ์ํ๋ก ์์ํ ๋จ์ต๋๋ค. ๋ก๊ทธ์ธ์ด ๋ฉ์ถ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ฉด ๊ฐ์ฅ ๋จผ์ ์ฝ๋ฐฑ ํฌํธ๋ฅผ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ฐ๊ณ ์์ง ์์์ง ํ์ธํ์ธ์.
๊ธฐ๋ณธ๊ฐ์ OS๊ฐ ๋งค๋ฒ ๋น ์์ ํฌํธ๋ฅผ ๊ณจ๋ผ์ฃผ๋ฏ๋ก(0) ์ด ์ถฉ๋์ ํผํฉ๋๋ค. ์ฌ์ ๋ฑ๋กํ client์ redirect_uri๊ฐ ๊ณ ์ ํฌํธ๋ก ๋ฑ๋ก๋์ด ์์ด ํน์ ํฌํธ๋ฅผ ๊ณ ์ ํด์ผ ํ๋ค๋ฉด devup-mcp --figma-callback-port <port>๋ฅผ ์ง์ ํ์ธ์. ์ด ๊ฒฝ์ฐ devup-mcp๋ ๊ทธ ํฌํธ๊ฐ ์ด๋ฏธ ์ฌ์ฉ ์ค์ด๋ฉด ์ฐ๊ฒฐ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ DEVUP_FIGMA_CALLBACK_PORT_IN_USE ์ค๋ฅ๋ฅผ ์ฆ์ ๋ฐํํฉ๋๋ค. devup_figma_auth { "action": "doctor" }์ paths.direct.callbackPort.free์์๋ ์ง์ ํ ํฌํธ๊ฐ ์ค์ ๋ก ๋น์ด ์๋์ง ์ค์ธกํ ๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค.
Dynamic Client Registration์ ๊ฑด๋๋ฐ๋ ค๋ฉด mcp.<name>.oauth์ ์ด๋ฏธ ๋ฐ๊ธ๋ฐ์ clientId/clientSecret์ ์ง์ ์ง์ ํฉ๋๋ค.
{
"mcp": {
"figma": {
"type": "remote",
"url": "https://mcp.figma.com/mcp",
"oauth": {
"clientId": "<allowlist๋ client_name์ผ๋ก ๋ฑ๋กํด ๋ฐ๊ธ๋ฐ์ client_id>",
"clientSecret": "<allowlist๋ client_name์ผ๋ก ๋ฑ๋กํด ๋ฐ๊ธ๋ฐ์ client_secret>",
"scope": "mcp:connect",
"callbackPort": 19876,
"redirectUri": "http://127.0.0.1:19876/callback"
}
}
}
}Codex๋ allowlist์ ์์ด ๋ณ๋ ์ค์ ์์ด ๋ฑ๋กํ ์ ์์ต๋๋ค. Claude Code๋ ํ๋
200์ด์์ผ๋ 2026-09-06 ์ค์ธก์์ 403์ผ๋ก ๊ฑฐ์ ๋์ต๋๋ค โ allowlist๋ Figma๊ฐ ๋ฐ๊ฟ ์
์์ผ๋ฉฐ, ์ ํ๋ ์ธก์ ์์ ์ ๊ธฐ๋ก์
๋๋ค.
devup-mcp๋ ์ง์ ๊ฒฝ๋ก๋ง ์๋๋ค. ํธ์คํธ(Codex)์ ๋ฑ๋ก๋ ๊ณต์ Figma MCP๋ฅผ ๋น๋ฆฌ๋
์ฐํ ๊ฒฝ๋ก๋ ๋ง๋ค์ง ์์ต๋๋ค โ devup-mcp๊ฐ ์ค์ค๋ก Codex๋ก ๋ฑ๋กํด Figma ์๊ฒฉ MCP์
๋ถ๊ณ , ์์ง์ ํ์ํ use_figma๋ฅผ ๊ทธ ์ฐ๊ฒฐ๋ก ์ง์ ๋ถ๋ฆ
๋๋ค. ํธ์คํธ์ Figma MCP๋ฅผ
๋ฐ๋ก ์ค์ ํ ํ์๊ฐ ์๊ณ , ์ค์ ๋ผ ์์ด๋ devup-mcp๋ ๊ทธ๊ฒ์ ์ฐ์ง ์์ต๋๋ค.
claude mcp add --transport http figma https://mcp.figma.com/mcp
codex mcp add figma --url https://mcp.figma.com/mcp{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"outputs": ["tsx"],
"componentName": "OptionalComponentName",
"rootLayout": "standalone",
"scope": "node",
"outputPaths": { "tsx": "optional/path/Component.tsx" }
}๊ฒฐ๊ณผ์๋ tsx์ ํจ๊ป status, quality, cache, collection, source๊ฐ ํฌํจ๋ฉ๋๋ค. import ๋ชฉ๋ก๊ณผ ์ฌ์ฉ token์ ๋ณ๋ ํค๋ก ๋ณด๋ด์ง ์์ต๋๋ค โ ๊ฐ๊ฐ TSX์ ์ฒซ ์ค๊ณผ ๋ณธ๋ฌธ์ $token์ด ์ด๋ฏธ ๊ฐ์ ๋ด์ฉ์ ๋ด๊ณ ์์ด, ์๋ต์ ๋ ๋ฒ ์ฃ๋ ๋งํผ์ด ๊ทธ๋๋ก ๋ญ๋น์์ต๋๋ค. Auto Layout์ Flex, ์ผ๋ฐ container๋ Box, text๋ Text๋ก ๋ณํํ๊ณ theme binding์ด ์์ผ๋ฉด JSX prop์์ $token์ ์ฐ์ ์ฌ์ฉํฉ๋๋ค. ๋ณ์ token์ ๋น์ด ์์ง ์์ Figma codeSyntax.WEB์ ์ฐ์ ํ๊ณ , ์์ผ๋ฉด ๋ณ์ ๊ฒฝ๋ก์ ๋ง์ง๋ง ์ด๋ฆ์ ์ ๊ทํํฉ๋๋ค. ๋ฐ๋ผ์ TSX์ $token, devup.json key์ source map์ด ๊ฐ์ ์ด๋ฆ์ ์ฌ์ฉํฉ๋๋ค. rootLayout ๊ธฐ๋ณธ๊ฐ์ธ standalone์ ์ ํํ root์ ํฌ๊ธฐยท์์น ์ ์ฝ๊น์ง ํฌํจํ๊ณ Figma instance์ ์ค์ ์์ ์ํ๋ฅผ ํผ์ณ ์ ์๋์ง ์์ component ์ฐธ์กฐ๋ฅผ ๋ง๋ค์ง ์์ต๋๋ค. ์ด๋ฏธ ๋ ์ด์์์ ์์ ํ React ๋ถ๋ชจ ์์ ์ฝ์
ํ ๋๋ rootLayout: "embedded"๋ก root์ ์ธ๋ถ ํฌ๊ธฐยท์์น ์ ์ฝ๋ง ์๋ตํฉ๋๋ค.
๋ํ ํ๋ฉด์ ์ง๋จ details์ verdict/layout ๋ฉํ๋ฐ์ดํฐ๋ metadataDelivery.uri๊ฐ ๊ฐ๋ฆฌํค๋ projection-details.json resource๋ก ์ ๋ฌํ ์ ์์ต๋๋ค. inline์๋ ์ด์ ๊ฐ์ยทIDยทseverity์ ๊ฒํ ์๋ด๋ฅผ ์ ์งํ๊ณ , ๊ฐ fullDetailsResource.jsonPointer ๋๋ metadataPreviewFields์ pointer๋ก ์๋ณธ์ ์ฐพ์ต๋๋ค. preview์ ์๋ต ๊ฐ์ยท์ํ์ ๋ช
์ํ๋ฉฐ, ํ์ ์ฒดํฌ๋ฆฌ์คํธ์ ๋ฐ๋ผ resource๋ฅผ ์ฝ๊ธฐ ์ ์๋ ๊ฒ์ฆ์ ์๋ฃ๋ก ๋ณด๊ณ ํ์ง ๋ง์ญ์์ค. ์ฝ๋ยทthemeยท์์
ํ์ผ๊ณผ resource byte/hash ๊ณ์ฝ์ ๋์ผํฉ๋๋ค.
outputs: ["tsx", "devupJson"]์ devupJsonMode: "used-only"๋ฅผ ํจ๊ป ์ง์ ํ๋ฉด ์์ฑ ์ฝ๋๊ฐ ์ค์ ์ฐธ์กฐํ๋ ํ ํฐ๊ณผ typography ์์กด์ฑ๋ง ๋ฐํํฉ๋๋ค. projectRoot์ ๊ธฐ์กด theme๊ฐ ์์ผ๋ฉด themeDiff๊ฐ ์๋ ์ ์์ ์ด๋ฆ ์ถฉ๋์ ๋ณด๊ณ ํ๊ณ , devupJsonMode: "missing-only"๋ ๊ธฐ์กด ๊ฐ์ ๋ณด์กดํ ์ถ๊ฐ๋ถ๋ง ๋ฐํํฉ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ full์
๋๋ค. ์ฝ์ ์ ์๋ ์คํ์ผ์ skippedStyles์ ์ด๋ฆยท๋
ธ๋ ID๊ฐ ์๋ ๊ฒฝ๊ณ ๋ก ๋ถ๋ฆฌํ๋ฉฐ, strict ๋ชจ๋๋ ๊ฑฐ์ ํฉ๋๋ค. ๋ณ์/๋ฏธ์ง์ fontSize์ ๋ฐฑ๋ถ์จ lineHeight๋ ๋ฌธ์์ด๋ก ๋ณด์กดํฉ๋๋ค.
์ฝ๋ ์ถ๋ ฅ์ ์ ์ ์
๋๋ค. interactiveCandidates, ํ๋กํ ํ์
/์ํ TSX ์ฃผ์, ambiguityQuestions, ํ์ reviewChecklist๋ฅผ ์ค์ ๋ผ์ฐํธ์ ๋์์ ์ฐ๊ฒฐํ๊ณ devup_ui_validate๋ก ๊ฒ์ฆํด์ผ ํฉ๋๋ค. projectRoot๋ ๊ธฐ์กด UI/๋ผ์ฐํธ์ ํ๊ฒฝ ํค ์ด๋ฆ๋ง ๋ณํฉํฉ๋๋ค. devup_project_context์ routes scope์ validator์ renderedHtml href ์ง๊ณ๋ ์ ์ ์ฆ๊ฑฐ์ด๋ฉฐ ํด๋ฆญ ์ฑ๊ณต์ ์ฆ๋ช
ํ์ง ์์ต๋๋ค. ๊ณ ์ navigation ๋ฐ์ค์ ํ์ฑ ์ํ๋ฅผ ๋จ์ ํ์ง ์๊ณ info ๊ฒํ ํ๋ณด๋ก ๋ณด๊ณ ํฉ๋๋ค. responsiveGroups์ breakpointCompletion์ exportํ ํญ๊ณผ ๋จ์ ํญ์ ๊ตฌ๋ถํ๋ฉฐ, ๊ตฌํ/์๊ฐ ๊ฒ์ฆ์ ๋ณ๋์
๋๋ค.
์ค์ฒฉ I44:8533;10:973 ๋
ธ๋ ID๋ URL/assetRequests๋ก ์ง์ ํ ์ ์์ต๋๋ค. SVG native export ์คํจ ์ ์ง์๋๋ ์ค์ subtree geometry๋ง read-only๋ก ๋ณต๊ตฌํ๋ฉฐ, ์ง์๋์ง ์๋ mask/paint/effect๋ ์คํจ ์์ธ์ ๋ณด์กดํฉ๋๋ค. ์คํจํ ์์
์๋ ์์ฑ ๊ฒฝ๋ก๋ฅผ ํ์ํ์ง ์์ต๋๋ค. DEVUP_ASSET_TIMEOUT_MS๋ 1000โ600000 ms ๋ฒ์์ด๋ฉฐ ๊ธฐ๋ณธ๊ฐ์ 90000 ms์
๋๋ค. ์ง๋จ์ ๋จ๊ณ๋ณ ์๊ฐ์ด ํฌํจ๋๋ฉฐ Figma ๋ด๋ถ renderer timeout ์์ฒด๋ฅผ ๋ฐ๊พธ์ง๋ ์์ต๋๋ค. ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ฉํ๋ ค๋ฉด ๊ฐฑ์ ๋ bridge host์ ์ฌ๋น๋ํ plugin์ ํจ๊ป ์ฌ์ฉํ์ญ์์ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"outputs": ["devupJson"],
"scope": "file",
"outputPaths": { "devupJson": "optional/path/devup.json" }
}๊ฒฐ๊ณผ๋ theme.colors, theme.typography, theme.length, theme.shadow๋ฅผ ํฌํจํ๋ ๊ฒฐ์ ์ JSON ๋ฌธ์์ด๊ณผ counts, completeness๋ฅผ ๋ฐํํฉ๋๋ค.
ํ
์คํธ ์คํ์ผ์ ๊ธ์ ํฌ๊ธฐ๊ฐ ๋ณ์์ ๋ฌถ์ฌ ์๊ณ ๊ทธ ๋ณ์์ ๋ชจ๋๊ฐ ๋ธ๋ ์ดํฌํฌ์ธํธ ์ด๋ฆ(MobileยทTabletยทDesktopยทPC, ๋๋ ์ซ์)์ด๋ฉด, ๊ทธ ์คํ์ผ์ ๋ชจ๋๋ง๋ค ํ ์นธ์ธ ๋ฐ์ํ typography ๋ฐฐ์ด์ด ๋ฉ๋๋ค โ Mobile์ ์ฒซ ์นธ, Tablet์ ์
์งธ ์นธ(768px), DesktopยทPC๋ ๋ค์ฏ์งธ ์นธ(1280px)์ด๊ณ , ์นธ๋ง๋ค ๊ทธ ๋ชจ๋์์ ํ๋ฆฐ ํฌ๊ธฐ๋ฅผ ์๋๋ค. ํผ์ผํธ ํ๊ฐ์ ํฌ๊ธฐ๊ฐ ๊ณ ์ ์ด๋ฉด Figma๊ฐ ๊ทธ๋ฆฌ๋ ์ ์ px ํ๊ฐ์ผ๋ก, ํฌ๊ธฐ๊ฐ ๋ณ์์ ๋ฌถ์๊ฑฐ๋ ์์ผ๋ฉด 150%์ฒ๋ผ ํผ์ผํธ ๊ทธ๋๋ก ์๋๋ค(CSS๊ฐ ์ ์ฉ๋๋ ๊ธ์ ํฌ๊ธฐ์ ๋ง์ถฐ ๋์
๋๋ค). ์์ ์๋ ๊ทธ ๊ฒฝ์ฐ ํ
๋ง ์ ์ฒด๋ฅผ DEVUP_THEME_CONFLICT๋ก ๊ฑฐ์ ํ์ต๋๋ค. ๋ชจ๋๊ฐ ๋ธ๋ ์ดํฌํฌ์ธํธ ์ด๋ฆ์ด ์๋๊ฑฐ๋(LightยทDark ๋ฑ), ์คํ์ผ ์ด๋ฆ์ ์ด๋ฏธ ๋ธ๋ ์ดํฌํฌ์ธํธ๊ฐ ๋ค์ด ์๊ฑฐ๋, ํฌ๊ธฐ๊ฐ ๋ชจ๋ ๋ชจ๋์์ ๊ฐ๊ฑฐ๋, ๋ ๋ชจ๋๊ฐ ํ ์นธ์ ๋์ด๊ฑฐ๋, ํ๋ฆฌ์ง ์๋ ๋ชจ๋๊ฐ ์์ผ๋ฉด ํฌ๊ธฐ๋ ์์ ์ฒ๋ผ ๋ณ์์ ํ ํฐ($textTest)์
๋๋ค. ์ซ์ ๋ชจ๋ ์ด๋ฆ์ 0โ5๋ฒ ์นธ์
๋๋ค. ๋ชจ๋๊ฐ ๋ชจ๋ ๋ธ๋ ์ดํฌํฌ์ธํธ ์ด๋ฆ์ธ ์ปฌ๋ ์
์ ๊ธธ์ด ๋ณ์๋ length ํ ํฐ ํ๋๋ฅผ ๋ฐ์ํ ๋ฐฐ์ด๋ก ์จ์ ๋ชจ๋ ํ
๋ง์ ๋ฃ์ต๋๋ค(containerX: ["20px", null, "40px"], ๋ชจ๋๋ง๋ค ๊ฐ์ด ๊ฐ์ผ๋ฉด ๊ฐ ํ๋). ํ๋ฌ๊ทธ์ธ์ ๋ชจ๋ ์ด๋ฆ์ ํ
๋ง ํค(theme.length.mobile)๋ก ์ฐ๋๋ฐ, devup-ui์์ ๊ทธ๊ฒ์ ๊ทธ data-theme์ผ ๋๋ง ๊ฐ์ด ์๋ ํ ํฐ์
๋๋ค. ํ
๋ง์ ๊ฐ์ ์ด๋ฆ์ ํ ํฐ์ด ์ด๋ฏธ ์์ผ๋ฉด ๊ทธ ํ
๋ง์ ๊ฐ์ ๋๊ณ conflicts์ ๋จ๊น๋๋ค. ๋ธ๋ ์ดํฌํฌ์ธํธ ๊ธธ์ด ๋์ด ๊ฐ์ ์ด๋ฆ์ ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๋ฉด ์ ํด์ง ์์๋ก ํ๋๋ฅผ ๊ณ ๋ฅด๊ณ , ๊ทธ ์ถฉ๋์ conflicts์ mode @breakpoints๋ก ๋จ์ต๋๋ค. ์์ devup-ui๊ฐ ๋ฐฐ์ด์ ๋ฐ์ง ์์ ์์ ์ฒ๋ผ ๋ชจ๋ ์ด๋ฆ์ ํ
๋ง ํค๋ก ์๋๋ค. ๋ค๋ฅธ ์ปฌ๋ ์
์ ๋ณ์๋ฅผ ๊ฐ๋ฆฌํค๋ alias๋ ๊ทธ ์ปฌ๋ ์
์ ๋ชจ๋๊ฐ ํ๋๋ฟ์ด๋ฉด(๋ผ์ด๋ธ๋ฌ๋ฆฌ์ primitive ๋ฑ) ๊ทธ ํ๋์ ๊ฐ์ผ๋ก ํ๋๋ค. ํ
๋ง๋ ํ์ผ ์ ์ฒด๋ ๋
ธ๋ ๋ฒ์๋ , ๋
ธ๋๊ฐ ๋ฌถ์ง ์์๋๋ผ๋ ๋ณ์๊ฐ alias๋ก ๊ฐ๋ฆฌํค๋ ๋ณ์๋ฅผ ์ฝ์ด(๊ทธ ๋ณ์๊ฐ ๊ฐ๋ฆฌํค๋ ๋ณ์๊น์ง) ํจ๊ป ๋ฃ์ต๋๋ค. ๋ชจ๋๊ฐ ์ฌ๋ฟ์ด๋ฉด ์ด๋ ๋ชจ๋๋ฅผ ์ธ์ง๋ ์๋น์๊ฐ ์ ํ๋ฏ๋ก unresolvedVariables์ ๋จ๊น๋๋ค.
์์ฑ TSX๋ ๋ณ์์ ๋ฌถ์ธ ๊ธธ์ด(padding, gap, ํ ๊ฐ์ธ ๋ชจ์๋ฆฌ ๋ฐ๊ฒฝ, ๊ทธ๋ฆผ์์ ์คํ์
ยท๋ธ๋ฌยทspread, ๊ธ์ ํฌ๊ธฐ)๋ฅผ ๊ทธ ๋ณ์์ $ํ ํฐ์ผ๋ก ์๋๋ค(px="$containerX", boxShadow="0 $shadowMdY 20px 0 #00000026"). ์กฐ๊ฑด์ ๊ฐ์ ๋ณ์๋ก ๋ง๋ ํ
๋ง์์ ๊ทธ ํ ํฐ์ด, ํ์ด์ง๊ฐ data-theme ์์ด ๋ณด์ฌ ์ฃผ๋ ํ
๋ง์์ ํ๋ฉด์ด ๊ทธ๋ ค์ง ํญ(๋
ธ๋๊ฐ ๋์ธ ํ๋ฉด ํ๋ ์์ ํญ)์ผ ๋ ์ฝ๋์ ์ฐ๋ ๊ฐ๊ณผ ์ ํํ ๊ฐ์ ๊ฒ์
๋๋ค(๋ฐ์ฌ๋ฆผํด์ ๊ฐ์ ๊ฒ์ ๊ฐ์ ๊ฒ์ด ์๋๋๋ค: 20.004px ํ ํฐ์ 20px ์๋ฆฌ์ ๋ค์ด๊ฐ์ง ์์ต๋๋ค). ๋ฐ์ํ ํ ํฐ์ด๋ฉด ๊ทธ ๋ค๋ก ํ๋ฉด ํญ์ ๋ฐ๋ผ ๋์์ธ์ ๋ชจ๋ ๊ฐ์ ๋ฐ๋ผ๊ฐ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์์ ์ฒ๋ผ px๋ฅผ ์๋๋ค(Mobile ๊ฐ์ ํ๋ฉด์ด 800px ํญ์ด๋ฉด ํ ํฐ์ด ๊ฑฐ๊ธฐ์ 40px์ด๋ฏ๋ก 20px). ํ๋ฌ๊ทธ์ธ์ ๊ธธ์ด๋ฅผ ํ ํฐ์ผ๋ก ์ฐ์ง ์์ต๋๋ค. ํญยท๋์ด๋ ์น์ ์ฆ๋ช
์ด px ๊ฐ์ ๊ธฐ๋๋ฏ๋ก ์์ ์ฒ๋ผ px์
๋๋ค.
outputPath๋ฅผ ์๋ตํ๋ฉด ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ MCP ์๋ต์๋ง ์ ์งํฉ๋๋ค. ๋ช
์ํ๋ฉด ์์ฑ๋ TSX ๋๋ devup.json๋ง ํด๋น ๊ฒฝ๋ก์ ๊ธฐ๋กํ๊ณ ์ค์ ์ ๋ ๊ฒฝ๋ก๋ฅผ ์๋ตํฉ๋๋ค. ๊ธฐ๋ณธ ํ์ฉ write root๋ devup-mcp process ์์ ๋น์์ current directory ํ๋์ด๋ฉฐ, ๊ทธ ๋ฐ์ workspace๋ ๋ฐ๋ณต ๊ฐ๋ฅํ --allow-write-root <directory> ์์ ์ธ์๋ก๋ง ์ถ๊ฐํ ์ ์์ต๋๋ค. Tool ์
๋ ฅ์ผ๋ก root ์์ฒด๋ฅผ ๋ํ ์ ์๊ณ .., ๋ค๋ฅธ drive/UNC, alternate data stream, symlink/junction์ ํตํ root ํ์ถ์ ๊ธฐ๋ก ์ ์ ๊ฑฐ์ ๋ฉ๋๋ค.
์ฌ๋ฌ text/asset output์ ๋ชจ๋ ๊ฒ์ฆํ ๋ค ๊ฐ์ directory์ exclusive ์์ ํ์ผ์ stagingํ๊ณ ํ transaction์ผ๋ก ๊ต์ฒดํฉ๋๋ค. ์ ์ runtime ์ค๋ฅ์์๋ ์ด๋ฏธ ๊ต์ฒดํ ํ์ผ์ ์ญ์์ผ๋ก ๋๋๋ฆฌ๊ณ ๊ธฐ์กด ํ์ผ์ ๋ณต๊ตฌํฉ๋๋ค. ๊ฐ๋ณ rename์ atomicํ์ง๋ง ์ฌ๋ฌ directory์ process crash๋ฅผ ๊ฐ๋ก์ง๋ฅด๋ ์์ ํ ์์์ฑ์ ์ผ๋ฐ filesystem ํน์ฑ์ ๋ณด์ฅํ์ง ์์ต๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"outputs": ["tsx"],
"scope": "node",
"strict": true,
"refresh": false,
"delivery": "auto"
}์ outputs๋ ์คํค๋ง ๊ธฐ๋ณธ๊ฐ๊ณผ ๊ฐ์ ๊ถ์ฅ ํธ์ถ์
๋๋ค. ์ฝ์ output๋ง ์์ฒญํ์ธ์ โ ์์ ์๋ต์ ๋ฌด์์ด ๋ค์ด์ค๋๊ฐ ํ๊ฐ ์ ์ฒด ๋ชฉ๋ก ๋ ํผ๋ฐ์ค์ด๊ณ , ๊ทธ ํ๋ฅผ ๊ทธ๋๋ก ํ ๋ฐฐ์ด์ ์ฎ๊ฒจ ์ ์ผ๋ผ๋ ๋ป์ด ์๋๋๋ค. ํนํ rawSnapshot/rawPayload๋ฅผ debug: true ์์ด outputs์ ๋ฃ์ ํธ์ถ์ ํฌ์ ์ ์ -32602๋ก ๊ฑฐ์ ๋ฉ๋๋ค. ์ค์ ๋ก ์ด ์ ์ ์์๊ฐ ํ๋ ์ฌ๋ output์ ์ ๋ถ ๋์ดํ๋ฉด์ debug๋ ๋น ๋จ๋ฆฌ๊ณ ์์๊ณ , ๊ทธ๋๋ก ๋ณต์ฌํ๋ฉด ์คํ๋์ง ์๋ ํธ์ถ์ด์์ต๋๋ค.
devup_figma_export๋ ์์ ์ ํ์ ์ํ ๋๊ตฌ์
๋๋ค.
- ํ ํธ์ถ์ ํ๋ ์ 1~3๊ฐ๋ฅผ ๊ถ์ฅํ๊ณ , ํ๋ ์ 6๊ฐยท(ํ๋ ์ ร output) 12๋จ์๊น์ง๋ง ํ์ฉํฉ๋๋ค.
- ์ํ์ ๋๋ ์ ํ์ ํ๋ฉด ์์ง์ ์์ํ๊ธฐ ์ ์ ๊ฑฐ์ ํ๋ฏ๋ก,
frameIds๋ฅผ ๋ฐฐ์น๋ก ๋๋ ๋ถ๋ฅด์ธ์. - ๊ณํ์ฉ ์ด๋ฆผ๊ฐ์ ํ๋ ์๋น 15~60์ด์ ๋๋ค. ๋ณด์ฅ์ด ์๋๋ผ ์ด๋ฆผ์ด๋ฉฐ, ํ์ด์ง๋ค์ด์ ยท๋ณต์ก๋ยท์ค๋กํ๋ง์ด ๊ฒน์น๋ฉด ๋์ด๊ฐ๋๋ค. ํด๋ผ์ด์ธํธ๋ ๋ณดํต 300์ด์์ ํ์์์ํฉ๋๋ค.
- ํ๋ ์๋ณ ํฌ์์ด ์ผ๋ถ ์คํจํด๋ ์ฑ๊ณตํ ํ๋ ์์ ์ฐ์ถ๋ฌผ์ ์ ์ง๋ฉ๋๋ค.
์ด๋ฏธ ๋
ธ๋ ID๋ฅผ ์๊ณ ์๋ค๋ฉด(๋ธ๋ฆฌํ์ ์ ํ ์๊ฑฐ๋ ์์ ํธ์ถ์ด ์๋ ค์คฌ๋ค๋ฉด) devup_figma_explore๋ฅผ ๊ฑด๋๋ฐ๊ณ frameIds์ ๋ฐ๋ก ๋๊ธฐ์ธ์. ๊ฐ๊ณ ์๋ ID๋ฅผ ๋ค์ ์ฐพ์ผ๋ ค๊ณ ํ์ํ๋ ๊ฒ์ Figma ํธ์ถ ํ๋๋ฅผ ๊ทธ๋ฅ ์ฐ๋ ์ผ์
๋๋ค. ํ์์ Section ๋งํฌ๋ฐ์ ์์ ๋ ์ฐ๋ ๋๊ตฌ์
๋๋ค.
devup_figma_export๋ ๋์ผํ node/resource acquisition์์ ์ฌ๋ฌ projection์ ์์ฑํฉ๋๋ค. ์๋ต์ cache.artifactId๋ฅผ ๋ค์ ์์ฒญ์ artifactId๋ก ๋๊ธฐ๋ฉด Figma๋ฅผ ๋ค์ ํธ์ถํ์ง ์๊ณ ๋ค๋ฅธ output์ ๋ง๋ค ์ ์์ต๋๋ค. artifactId๋ urlยทrefresh์ ๋์์ ์ธ ์ ์๊ณ , ํจ๊ป ๋ณด๋ด๋ฉด DEVUP_FIGMA_HANDOFF_INVALID๋ก ๊ฑฐ์ ๋ฉ๋๋ค. URL ์์ฒญ์ ๊ฐ์ process ์์์ 10๋ถ TTL, ์ต๋ 8๊ฐยท์ ์ฒด 128 MiB์ธ memory-only LRU cache๋ฅผ ์ฌ์ฌ์ฉํ๋ฉฐ, refresh: true๋ ์๋ฃ cache๋ฟ ์๋๋ผ ์งํ ์ค ์์ฒญ ๊ณต์ ๋ ์ฐํํด URL์ ์๋ก ์์งํฉ๋๋ค. ์์ง ํ๋๊ฐ ๊ทธ resource ์ถ๋ ฅ๊ณผ ํจ๊ป 128 MiB๋ฅผ ๋ค ์ธ ์ ์๊ณ , ๊ทธ๋งํผ ์ค๋๋ ํญ๋ชฉ์ ๋ฐ์ด๋
๋๋ค. ์์ ์ ํญ๋ชฉ๋น 32 MiB๋ ํ
์คํธ ํ์ผ ํ๋์ scope: "file" ์์ง(63.6 MB)์ ๊ฑฐ์ ํด export๋ฅผ ์คํจ์์ผฐ์ต๋๋ค. ๋์ผ acquisition์ ์ ํ ์์
์ด ์ทจ์๋๋๋ผ๋ ๋ซํ in-flight ํ์์ ๋ค์ ์์ฒญ์ด ์์์ ์ผ๋ก ์ ๊ฑฐํ๊ณ ๋ค์ ์์งํ๋ฏ๋ก ๊ฐ์ key๊ฐ process ์๋ช
๋์ ์ค์ผ๋์ง ์์ต๋๋ค. cache์๋ reuseKind, ageSeconds, remainingTtlSeconds, avoidedFigmaToolCalls, ์ ์์ง์ originCollection์ด ํฌํจ๋๊ณ , ์๋ต ์ต์์ collection์ ํ์ฌ ์์ฒญ์ด ์ค์ ๋ก ์คํํ ํธ์ถ๋ง ์ง๊ณํฉ๋๋ค. cache.capabilities๋ artifact์ kind(design, theme-only, search, explore, section-index), collectionScope, resourceScope, referencePng ๋ณด์ ์ฌ๋ถ, redacted assetCaptureCount์ sectionSelection๋ง ๊ณต๊ฐํฉ๋๋ค. sectionSelection์ด ๋ง์ง๋ง์ผ๋ก ๊ฒ์ฆ๋ Section ์ ํ(frameIds ๋๋ allScreens)์ ๋ณด์กดํ๋ฏ๋ก, artifact๋ฅผ ์ฌ์ฌ์ฉํ ๋ frameIds๋ฅผ ๋ค์ ๋ณด๋ด์ง ์์๋ ์ ํ์ด ์ ์ง๋ฉ๋๋ค. ์์ ์๋ artifactId๋ง ๋๊ธฐ๋ฉด ์ ํ์ด ์ฌ๋ผ์ ธ ํ๋ณด ๋ชฉ๋ก ์ ์ฒด๊ฐ ๋ค์ ๋์์์ต๋๋ค. ๋ด๋ถ artifact๋ asset IDยทformatยทscale ์ ์ฒด๋ฅผ ๋ณด์กดํ๊ณ ์ธ ๊ฐ์ด ์ ํํ ๊ฐ์ capture๋ง ์ถ๊ฐ Figma ํธ์ถ ์์ด ์ฌ์ฌ์ฉํฉ๋๋ค. ์ฌ์ฌ์ฉ ์์ฒญ์ด ์ด ๋ฒ์๋ฅผ ๋์ผ๋ฉด DEVUP_FIGMA_HANDOFF_INVALID๋ก ํฌ์๊ณผ ํ์ผ ๊ธฐ๋ก ์ ์ ๊ฑฐ์ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด node/used-resource artifact๋ก file ์ ์ฒด devupJson์ ๋ง๋ค๊ฑฐ๋ screenshot์ ์์งํ์ง ์์ artifact๋ก referencePng๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. credential, screenshot๊ณผ asset binary๋ cache key๋ ํต๊ณ์ ํฌํจํ์ง ์๊ณ , process๊ฐ ๋๋๋ฉด cache๋ ์ฌ๋ผ์ง๋๋ค.
delivery๋ auto | inline | resource์
๋๋ค. auto๋ JSON escape, base64์ structured/text ์ด์ค ํํ์ ํฌํจํ ์ค์ MCP wire ํฌ๊ธฐ๋ฅผ ๊ณ์ฐํด ๊ฐ๋ณ 256 KiBยทํฉ๊ณ 1 MiB ์ดํ๋ง inline์ผ๋ก ๋ฐํํ๊ณ , ๊ทธ๋ณด๋ค ํฐ ๊ฒฐ๊ณผ๋ native MCP ResourceLink์ devup://artifact/... URI๋ก ๋ฐ๊ฟ๋๋ค. ๋งํฌ URI๋ JSON manifest๋ฅผ ๊ฐ๋ฆฌํค๋ฏ๋ก link MIME์ application/json์ด๊ณ payload MIMEยท๊ธธ์ดยทSHA-256์ payload* metadata๋ก ๋ถ๋ฆฌํฉ๋๋ค. manifest๋ chunkUris๋ก ๋ด์ฉ ์ฒญํฌ๋ฅผ ์ง์ ๊ฐ๋ฆฌํต๋๋ค โ ๋งํฌ๋ง ๋ฐ๋ผ๊ฐ๋ฉด manifest์์ ๋งํ๊ณ ์ฒญํฌ URI ํ์์ ๋ฐ๋ก ์์๋ด ์์ผ๋ก ์กฐ๋ฆฝํด์ผ ํ๋ ๋ฌธ์ ๊ฐ ์์ด์ก์ต๋๋ค. ๋ URI ํ์์ resources/templates/list์๋ ๊ทธ๋๋ก ๊ฒ์๋ฉ๋๋ค.
devup://artifact/{artifactId}/outputs/{outputId}/manifest
devup://artifact/{artifactId}/outputs/{outputId}/chunks/{index}
``` `resource`๋ ํฌ๊ธฐ์ ๋ฌด๊ดํ๊ฒ TSX/JSON/PNG๋ฅผ bounded chunk resource๋ก ์ ๊ณตํ๋ฉฐ, binary chunk๋ base64 MCP blob์
๋๋ค. asset manifest๋ binary๋ฅผ ๋ด์ฅํ์ง ์๊ณ ๊ฐ asset์ ๋
๋ฆฝ resource URIยทMIMEยท๊ธธ์ดยทSHA-256์ ์ฐธ์กฐํ๋ฏ๋ก `resources/read`๋ก ์๋ณธ bytes๋ฅผ ์ ํํ ์ฌ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๊ฐ์ artifact์ ์ ๊ทํํ projection์ content hash๊ฐ ๊ฐ์ resource๋ฅผ ์ฌ์ฌ์ฉํฉ๋๋ค. ํ์ผ ์ถ๋ ฅ๊ณผ ์ resource publication์ ํจ๊ป ์์ฒญํ๋ฉด resource ์กฐํ๋ฅผ reservation ๋์ ์ฐจ๋จํ ํ๋์ transaction์ผ๋ก ๋ค๋ฃจ๋ฉฐ, ํ์ผ commit์ด ์ ๋ถ ์ฑ๊ณตํ ๋ค์๋ง resource์ LRU ๋ณ๊ฒฝ์ ๊ณต๊ฐํฉ๋๋ค. ์คํจํ๋ฉด ์๋ ํ์ผ์ fingerprint๋ก ๊ฒ์ฆํด ๋ณต์ํ๊ณ ๋ณต์ ๋ถ๋ฅ backup ๊ฒฝ๋ก๋ฅผ ๊ตฌ์กฐํํด ๋ณด๊ณ ํฉ๋๋ค. ํ์ฌ transaction์ด ๋ง๋ temp๋ ์ ์ ์ข
๋ฃยทrollback์์ ์ง์ ์ ๊ฑฐํ์ง๋ง, ์์ ๊ถ์ ์ฆ๋ช
ํ ์ ์๋ pre-existing temp๋ crashยทrollback recovery backup์ ์๋ ์ญ์ ํ์ง ์์ต๋๋ค.
`referencePng`๋ ์ ํํ์ ๋๋ง ์ฝ๊ธฐ๋ฅผ ์ ํํ ํ ๋ฒ ๋ ํฉ๋๋ค. ๋ธ๋ฆฌ์ง๊ฐ ๋งก์ ํ์ผ์ด๋ฉด ํ๋ฌ๊ทธ์ธ์ด ๋
ธ๋๋ฅผ PNG๋ก exportํ๊ณ (์ "๋ธ๋ฆฌ์ง ํ๋ฌ๊ทธ์ธ"), ์๋๋ฉด ๊ณต์ read-only `get_screenshot`์ ๋ถ๋ฆ
๋๋ค. ๋ ๊ฒฝ๋ก์ PNG๋ ํฌ๊ธฐ๋ ๊ฐ์๋ ํฝ์
๊ฐ์ด ์กฐ๊ธ์ฉ ๋ค๋ฆ
๋๋ค. ๋ฐ์คํฌํฑ ์ฑ๊ณผ Figma ์๋ฒ์ ๋ ๋๋ฌ๊ฐ ๋ฌ๋ผ์์
๋๋ค. ๊ฐ์ ํ์ผ์์ `get_screenshot`๊ณผ ๋น๊ตํด ์ฐ ๊ฐ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- **๋ค๋ฅธ ๋ ์ด์ด๊ฐ ๋ฟ์ devup-mcp๊ฐ ๊ทธ๋ฆฐ ๋
ธ๋ 6๊ฐ:** ํฝ์
์ 99.65~99.97%๊ฐ 2/255 ์์ด๊ณ ์ต๋ 15/255์
๋๋ค. 6๊ฐ๋ ๊ทธ๋ผ๋์ธํธ ์, ๋ธ๋ฌยท๊ทธ๋ฆผ์ยท๋ถํฌ๋ช
๋๊ฐ ๊ฑธ๋ฆฐ ์กฐ์ ์๋, ๋ฐฐ๊ฒฝ ๋ธ๋ฌ๋ฅผ ๊ฐ์ง ๋
ธ๋, ํ์ ํ ๋
ธ๋์์ต๋๋ค. ์์ธ๋ ๋ธ๋ฌ๊ฐ ๊ฑธ๋ฆฐ ์กฐ์์ ์น์
์ด ์๋ฅด๋ ๊ฐ์ฅ์๋ฆฌ ํ ์ค๋ก, 84/255์ด๊ณ ๊ทธ ๋
ธ๋ ํฝ์
์ 0.19%์
๋๋ค.
- **ํ๋ค์ค ํ๋ฉด 11๊ฐ(360~1920 ํญ, ๋์ด 7240๊น์ง):** 99.98% ์ด์์ด 2/255 ์์ด๊ณ ์ต๋ 21/255์
๋๋ค. ์ฌ์ง ๊ทธ๋ฆฌ๋๋ง 90.5%, ์ต๋ 37/255(16/255 ์ด๊ณผ 0.07%)์
๋๋ค.
- **์บ๋ฒ์ค ๊ทธ๋๋ก์ธ ๋
ธ๋ 12๊ฐ:** 99.09% ์ด์์ด 2/255 ์์
๋๋ค. ์์ ๋ธ๋ฌ ๊ธ์๊ฐ ์๋ ํ ๋
ธ๋๋ง 94.45%, ์ต๋ 67/255์ธ๋ฐ, ์ด๋ ํ๋ฌ๊ทธ์ธ์ export ์์ฒด๊ฐ ๊ทธ๋ ์ต๋๋ค.
๋ ๋ ํ๋ค์ค(`--channel-tolerance 24`)์ ์ ์๋ reference๋ฅผ ์ด๋ ๊ฒฝ๋ก์์ ๋ฐ์๋ ํ๋ฉด๋ง๋ค 0.02%p ์์์ ๊ฐ์์ต๋๋ค. ๊ทธ๋๋ ํ ๊ธฐ์ค์ ์ reference๋ ํ ๊ฒฝ๋ก์์ ๋ฐ์ผ์ธ์ โ `source.bridgeReads`๊ฐ `collection.figmaToolCalls`์ ๊ฐ์ผ๋ฉด PNG๋ ํ๋ฌ๊ทธ์ธ์ด ๊ทธ๋ฆฐ ๊ฒ์
๋๋ค. ๊ณต์ ๋๊ตฌ๋ ๊ธฐ๋ณธ์ผ๋ก PNG์ URL๊ณผ curl ์๋ด๋ฅผ text๋ก๋ง ๋๋ ค์ฃผ๊ณ ๊ธด ๋ณ์ 1024px๋ก ์ค์ด๋ฏ๋ก, `enableBase64Response: true`์ `maxDimension: 8192`๋ก ํธ์ถํด node ์๋ ํฌ๊ธฐ์ PNG๋ฅผ inline์ผ๋ก ๋ฐ์ต๋๋ค. ๊ฒฐ๊ณผ์ image block์ ์ ํํ ํ๋์ฌ์ผ ํ๋ฉฐ(๊ณ์ text block์ ์ฝ์ง ์์), JSON/text์ ์จ๊ธด image๋ ๋ค์ค image๋ ๊ฑฐ์ ํฉ๋๋ค. 16 MiB compressed, 8192px, 64 MiB decoded ์ํ ์์์ PNG ์ ์ฒด๋ฅผ ์ค์ decodeํ ๋ค byte length์ SHA-256์ ํ์ธํด artifact์ ๋ณด์กดํ๋ฉฐ, ๋จ์ผ ๋งํฌ node์๋ง ์ ์ฉ๋ฉ๋๋ค. ๊ทธ๋์ `referencePng`๋ฅผ `frameIds` ๋๋ `allScreens: true`์ ํจ๊ป ์์ฒญํ๋ฉด ์์ง ์ ์ ๊ฑฐ์ ๋๊ณ , Section์ ์ฌ๋ฌ Frame์ ๋จผ์ ๋ฐํ๋ canonical URL๋ณ๋ก ํ๋์ฉ ์์งํด์ผ ํฉ๋๋ค. PNG bytes๋ logยทํต๊ณยทcache key์ ํฌํจ๋์ง ์์ผ๋ฉฐ `outputPaths.referencePng`๋ฅผ ๋ช
์ํ์ง ์์ผ๋ฉด ๋์คํฌ์ ๊ธฐ๋กํ์ง ์์ต๋๋ค.
๋ชจ๋ ์๋ฃ ์๋ต์๋ ๋ค์์ฒ๋ผ ์์ฒญํ ์ฐ์ถ๋ฌผ๋ณ `quality`๊ฐ ํฌํจ๋ฉ๋๋ค.
```json
{
"status": "complete",
"quality": {
"acquisition": "complete",
"projection": "exact",
"theme": "not-requested",
"assets": "not-requested"
}
}
acquisition์ complete | expected-projection | partial | failed, projection์ exact | approximated | lossy | failed | not-requested, theme์ complete | conflicted | unresolved | not-requested, assets๋ complete | partial | failed | not-requested์
๋๋ค. ๊ฒ์ยทํ์์ ์๋์ ์ธ ์์ graph๋ expected-projection์ผ๋ก ์ ์ ์๋ฃํ์ง๋ง, ํฌํจ๋ field์ ์คํจ๋ truncation์ partial์
๋๋ค. mask/effect fallback์ lossy, absolute layout fallback์ approximated์ด๋ฉฐ includeDiagnostics: false์ฌ๋ ํ์ง ํ์ ์๋ ๋ฐ์๋ฉ๋๋ค. ์ต์์ status๋ complete | partial | failed | selection_required ์ค ํ๋์
๋๋ค. ์์ฒญํ ๋ชจ๋ ์ถ์ด ์ ํยท์์ ํ๊ณ failures[]๊ฐ ๋น์ด ์์ ๋๋ง complete์
๋๋ค. ์ถ ํ๋๋ผ๋ ์ด๊ธ๋๊ฑฐ๋ ์คํจ๊ฐ ํ๋๋ผ๋ ์ง๊ณ๋๋ฉด partial์ด๊ณ , ์์ง์ด๋ ํฌ์ ์์ฒด๊ฐ ์ฃฝ์ผ๋ฉด failed, Section ๋งํฌ์์ ์์ง ํ๋ฉด์ ๊ณ ๋ฅด์ง ์์์ผ๋ฉด selection_required์
๋๋ค.
failures[]์๋ ๋
ธ๋ ๋จ์ ํฌ์ ์คํจ, ์์ฐ export ์คํจ, Section์ ํ๋ ์ ๋จ์ ์คํจ๊ฐ ๋ชจ๋ ํจ๊ป ์ง๊ณ๋ฉ๋๋ค. ์์ ์ฒ๋ผ ์ต์์๊ฐ complete์ธ๋ฐ ์์์ ์์ฐ์ด ์คํจํด ์๋ ์ํ๋ ๋์ค์ง ์์ต๋๋ค.
strict: true๋ ๋ชจ๋ ์์ฒญ ์ถ์ด exact/complete๊ฐ ์๋๋ฉด quality์ completenessReport๋ฅผ ๋ด์ ์ค๋ฅ๋ก ๊ฑฐ์ ํฉ๋๋ค.
๋ชจ๋ ๊ณต๊ฐ TSX generator๋ ๋ฐํ ์ ์ Rust์ ๊ณ ์ ๋ TypeScript+JSX parser๋ฅผ ํต๊ณผํฉ๋๋ค. parser ์ค๋ฅ๋ ๋์์ธ ์๋ฌธ์ ๋
ธ์ถํ์ง ์๊ณ byte range์ ์ค๋ฅ category๋ง ๋ฐํํฉ๋๋ค. ์๋ต์ fidelity๋ ์์ฑ๋ mapping ์๊ฐ ์๋๋ผ ์์งํ source snapshot์์ ๋
๋ฆฝ์ ์ผ๋ก ๊ณ์ฐํ node/text segment/variable/style/asset/layout ๊ธฐ๋ ์งํฉ์ ๋ถ๋ชจ๋ก ์ฌ์ฉํ๊ณ , ๋ด๋ถ validator๊ฐ ๊ฐ ํญ๋ชฉ์ emitted | flattened | ignored ์ค ์ ํํ ํ๋๋ก ๊ฒ์ฆํ๋์ง์ ์ถ๋ณ coverageยทtyped impact count๋ฅผ ๋ด์ต๋๋ค. component set, non-default variant selector์ inline instance๋ ์ต์ข
๋ณํ ํ source identity๋ณ provenance๋ฅผ ๋ค์ ๋ง๋ค๋ฉฐ, ๋ฐ๋ณต๋ ๋์ผ text segment๋ ํ๋์ mapping์ ์ฌ์ฌ์ฉํ์ง ์๊ณ occurrence๋ณ๋ก ์๋นํ๊ณ multilineยท์ค์ฒฉ text์ asset identity๋ฅผ ๊ฒ์ฆํฉ๋๋ค. ์ ์ ์๋ codegen warning/error๋ ๊ฐ๊ฐ ์ต์ approximated/failed๋ก ๋ณด์์ ์ผ๋ก ํ์ ํ๋ฉฐ, strict๋ syntax, source-derived trace coverage, lossy/failed impact๋ฅผ ํจ๊ป ๊ฒ์ฌํฉ๋๋ค.
๋ธ๋ผ์ฐ์ ์๊ฐ ํ๊ท๋ MCP ์๋ฒ๊ฐ ์์ ๋ช
๋ น์ ์คํํ์ง ์๊ณ ์๋น์ repository๊ฐ ์ค์ font/asset/DevupUI ํ๊ฒฝ์ผ๋ก actual.png๋ฅผ ๋ง๋ ๋ค ์์ Rust devup-mcp-visual๋ก ๋น๊ตํฉ๋๋ค.
์์ฑ ์ฝ๋๋ฅผ ํ๋ฌ๊ทธ์ธ์ ๋ต์๊ณผ ์ค ๋จ์๋ก ๋ง์ถฐ๋ณด๋ฉด ๋์ด ์ผ์นํ๋ค๋ ๊ฒ๊น์ง๋ ์ ์ ์์ง๋ง, ๋ ์ค ์ด๋ ์ชฝ๋ Figma๊ฐ ๊ทธ๋ฆฌ๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์์ง๋ ๋งํด์ฃผ์ง ๋ชปํฉ๋๋ค. harness/render๋ ๊ทธ ์ง๋ฌธ์ ๋ตํฉ๋๋ค โ ๊ฐ ํ๋ฉด์ devup-ui๋ก ๋น๋ํด ํ๋ ์ ํฌ๊ธฐ ๊ทธ๋๋ก ์ด๊ณ , Figma๊ฐ ๊ฐ์ ํ๋ ์์ ๋ ๋ํ PNG์ ํฝ์
๋น๊ตํฉ๋๋ค.
cd harness/render && npm install
python scripts/acquire.py # ๋ชจ๋ยทํ
๋งยท์์
ยท๊ธฐ์ค PNG๋ฅผ ์คํ ์ค์ธ devup-mcp์์ ๊ฐ์ ธ์ด
node scripts/render.mjs # ๋น๋ยท์บก์ฒยท๋น๊ต, ํ๋ฉด๋ณ ์๊ณ๊ฐ ์ด๊ณผ ์ exit 1acquire.py๋ Figma ํธ์ถ์ fixtures/local-call-bank์ ์ ๋ฆฝํ๋ฏ๋ก ์ฌ์คํ์ ์ด๋ฏธ ์ง๋ถํ ๋งํผ ๋ฌด๋ฃ์
๋๋ค. ํ๋ฉด๋ง๋ค ์๊ธฐ ํ
๋ง๋ฅผ node scope๋ก ๋ฐ์ต๋๋ค โ ํ์ผ ํ๋์ ์ฌ๋ฌ ๋ธ๋๋ ์ปฌ๋ ์
์ด ์์ด๋ฉด primary ๊ฐ์ ํ ํฐ์ด ์๋ก ๋ฎ์ด์จ์, ๊ณต์ง ํ๋ฉด์ด Figma๊ฐ ํ๋์ผ๋ก ๊ทธ๋ฆฌ๋ ์๋ฆฌ๋ฅผ ๋ณด๋ผ์์ผ๋ก ๊ทธ๋ ธ์ต๋๋ค. devup-ui๋ ํ
๋ง๋ฅผ ๋น๋ ์์ ์ ๊ตฝ๊ธฐ ๋๋ฌธ์ ํ๋ฉด๋ค์ ํ์ํ ํ
๋ง๋ณ๋ก ๋ฌถ์ฌ ๊ทธ๋ฃน๋ง๋ค ํ ๋ฒ์ฉ ๋น๋๋ฉ๋๋ค. ๋ฆฌ์
์ ์์ฑ ์ฝ๋๊ฐ ์ ์ ํ๋ @devup-ui/reset-css ๊ทธ๋๋ก์
๋๋ค.
thresholds.json์ด ํ๋ฉด๋ณ๋ก Figma์ ๋ฒ์ด์ ธ๋ ๋๋ ์ต๋์น๋ฅผ ๋ค๊ณ ์์ต๋๋ค. ์ด๊ณผํ๋ฉด ์คํจํ๊ณ , ๋ฐ๋๋ฉด ๊ทธ๋ ๋ค๊ณ ์๋ ค์ค๋๋ค(= ์์น๋ฅผ ์กฐ์ผ ์ฐจ๋ก). ์ธก์ ๊ฐ:
| ํ๋ฉด | 1920 | 992 / 768 | 360 / 390 |
|---|---|---|---|
| popup | 0.83% | 2.19% | 3.59% |
| popup (ํ๋ฌ๊ทธ์ธ ๋ต์) | 21.06% | 7.14% | 12.02% |
| notice | 2.33% | 4.19% | 8.29% |
| about | 4.54% | 6.94% | 11.26% |
| report 1.87% ยท grid 2.96% ยท keyframes 6.71% |
์ฐจ์ด๊ฐ ์ด๋ ์๋์ง๋ ๋ณด์กฐ ๋๊ตฌ๊ฐ ๋ตํฉ๋๋ค โ bands.mjs(๊ฐ์ฅ ๋ง์ด ์ด๊ธ๋ ๊ตฌ๊ฐ), drift.mjs(๋จ์ ์ด๋์ธ์ง ์ค์ ์ฐจ์ด์ธ์ง), crop.mjs(๊ตฌ๊ฐ์ ๊ธฐ์ค/์บก์ฒ ๋๋ํ), boxes.mjs(DOM ์์๋ฅผ Figma ์ขํ์ ๋์กฐ), elements.mjs(๊ทธ๋ฆผ์ด ์ค์ ๋ก ๋ช ํฝ์
๋ก ๋์๋์ง). ๊ธด ํ๋ฉด์ ํต์งธ๋ก ์ค์ธ ์คํฌ๋ฆฐ์ท์ ์๋ฌด๊ฒ๋ ๋ณด์ฌ์ฃผ์ง ์์ต๋๋ค.
text-check.mjs๋ ํฝ์
์ด ์๋๋ผ ๊ธ์๋ฅผ ๋ด
๋๋ค. ์์ฑ๊ธฐ๋ ํ
์คํธ ๋
ธ๋์ characters๋ฅผ JSX์ ์ฐ๋๋ฐ, JSX๋ ๊ณต๋ฐฑ์ ์๊ธฐ ๊ท์น์ด ์์ต๋๋ค โ ํ ๋ฌธ์ฅ์ด ์์ค ๋ ์ค๋ก ๋๋๋ฉด ์ฌ์ด์ ๊ณต๋ฐฑ ํ๋๊ฐ ๋ค์ด๊ฐ๋๋ค. ๋์์ธ์ ๊ทธ ๊ณต๋ฐฑ์ด ์์ผ๋ฉด ํ๋ฉด์ ๋์์ธ์ ์๋ ๋จ์ด๋ฅผ ์ฐ๊ณ , ๋ฌธ๋จ์ Figma๊ฐ ๋์ง ์๋ ์๋ฆฌ์์ ๊ฐ๊น๋๋ค. JSX๋ฅผ ์ฝ์ด ๋ฌด์์ด ๊ทธ๋ ค์ง์ง ์ถ๋ก ํ๋ ๊ฑด ๊ทธ ๊ท์น์ ๋ค์ ๊ตฌํํ๋ ์ผ์ด๊ณ , ๊ทธ๋ ๊ฒ ๋๊ฒจ์ง์ผ๋ฉด ์๋ ๊ฒฐํจ์ ๋ง๋ค์ด๋
๋๋ค โ ๊ทธ๋์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ค์ ๋ก ์ฐ์ ๊ธ์๋ฅผ characters์ ๋์กฐํฉ๋๋ค. ํ์ฌ 245๊ฐ ํ
์คํธ ์ค 3๊ฐ(๊ฐ์ ๋ฌธ๋จ์ ์ธ ํญ)๊ฐ ๋์์ธ๋๋ก ์ฐํ์ง ์์ต๋๋ค.
์บก์ฒยทํ
๋งยท์์
ยท๋น๋ ์ฐ์ถ๋ฌผ์ ์ปค๋ฐํ์ง ์์ต๋๋ค(harness/render/.gitignore). ์ด ํ๋ค์ค๊ฐ ์ฐพ์๋ธ ๊ฒฐํจ์ ํ
๋ง ์ค์ฝํ, ์ปจํ
์ด๋๊ฐ ์น ํ๋ ๊ทธ๋ฆผ์ ๋งค๋ํ์คํธ ๋๋ฝ, ์๋ฆฐ fill์ crop ํ๋ ฌ, ํ์ผ์์คํ
์ด ๋ชป ๋ฐ๋ ๋ ์ด์ด ์ด๋ฆ, ํญ๋ง๋ค ํฌ๊ธฐ๊ฐ ๋ค๋ฅธ ์ฌ์ง์ ํ์ผ ๊ณต์ , ํฌ๋ช
๋ 0 ๋
ธ๋์ export ๊ฑฐ๋ถ, ๊ทธ๋ฆฌ๊ณ positioned child ๋๋จธ๋ก CSS๊ฐ ๋ชป ๋ฏธ์น๋ ๋์ด์
๋๋ค.
Section ๋งํฌ์์ TSX๋ฅผ ์์ฒญํ๋ฉด ๋จผ์ ๋ด๋ถ screen frame ํ๋ณด์ canonical URL์ selection_required๋ก ๋ฐํํฉ๋๋ค. frameIds๋ก ๊ฒํ ํ frame๋ง ๊ณ ๋ฅด๊ฑฐ๋ allScreens: true๋ก ๋ชจ๋ ํ๋ฉด์ ์๊ฐ ์์๋๋ก batch exportํ ์ ์์ผ๋ฉฐ ๋ ์ต์
์ ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. sourceMap์ nodeIdยท์๋ณธ propertyยทgeneratedPropertyยทresolution์ผ๋ก ํ๋โ์์ฑ ์์ฑ์ ์ค๋ช
ํ๋ sidecar์
๋๋ค. TSX ๋ฌธ์/๋ฐ์ดํธ ์คํ์
์ ์ ๊ณตํ์ง ์์ต๋๋ค. ์์ฑ ์ฝ๋ ๋ฐ์ท๋ ์ง๋จ์ generatedSource๋ฅผ ํ์ธํฉ๋๋ค. devup.json์ JSON pointer๋ฅผ ์ฌ์ฉํฉ๋๋ค. assetManifest๋ image hash/vector/export provenance๋ฅผ ํญ์ ์ด๊ฑฐํ๊ณ , assetRequests๋ก ๋ช
์ํ ํญ๋ชฉ๋ง ๊ถ์ฅ 1โ3๊ฐ, ์ต๋ 6๊ฐยทscale 1~4 ๋ฒ์์์ read-only SVG/PNG exportํฉ๋๋ค. assetRequests๋ฅผ ์ฐ๋ ํธ์ถ์ outputs์ assetManifest๊ฐ ํจ๊ป ์์ด์ผ ํ๋ฉฐ, ๋น ๋จ๋ฆฌ๋ฉด ๊ฑฐ์ ๋ฉ๋๋ค. outputPath๋ฅผ ์ง์ ํ๋ฉด binary๋ฅผ ํด๋น ํ์ผ๋ก ๋์ฝ๋ฉํ๊ณ ์๋ต์ base64๋ฅผ ์ ๊ฑฐํ๋ฉฐ, ์๋ตํ๋ฉด ํ์ ์๋น๋ฅผ ์ํด base64๊ฐ memory-only artifact์ ํด๋น MCP ์๋ต์ ๋จ์ ์ ์์ต๋๋ค.
์์ฐ 6๊ฐ ์ด๊ณผ ์์ฒญ์ ์ธ์ฆยท์์งยทํ์ผ ์ฐ๊ธฐ ์ ์ ๊ฑฐ์ ํ๋ฉฐ recommendedBatchSize, maxAssetCount, recommendedAssetRequests, remainingAssetRequests๋ก ๋ถํ ์ ์๋ดํฉ๋๋ค. ๋๋ฆฐ ์์ฐ ํธ์ถ์ 1์ด ๋๊ธฐ ํ assetJob.jobId, ๋จ๊ณ๋ณ ํธ์ถ ๊ธฐ๋ก, ์์ฐ๋ณ ์์ง/ํ์ผ ์ํ๋ฅผ ๋จผ์ ๋ฐํํฉ๋๋ค. {"jobId":"..."}๋ก ์กฐํํ๊ณ , paused์ด๋ฉด {"jobId":"...","jobAction":"resume"}๋ก ๋ฏธ์๋ฃ ํธ์ถ๋ง ์ฌ๊ฐํฉ๋๋ค. ๋์ผ ์ธ์๋ฅผ ๋ค์ ๋ณด๋ด๋ฉด ์ ์ค๋ ์ต์ด ์๋ต์ ์์
์ ์ฐพ์ต๋๋ค. ํด๋ผ์ด์ธํธ ํ์์์์ ์์
์ ์ทจ์ํ์ง ์์ต๋๋ค. ์ฒดํฌํฌ์ธํธ๋ ๊ฐ์ ์๋ฒ ํ๋ก์ธ์ค์์ ์ต๋ 30๋ถ, ์๋ฃ ๊ฒฐ๊ณผ๋ 5๋ถ ๋ณด์กดํ๋ฉฐ ์๋ฒ ์ฌ์์ ํ์๋ ๋ณต๊ตฌ๋์ง ์์ต๋๋ค. ๊ฐ๋ณ upstream ํธ์ถ์ 90์ด์ ์ผ์์ ์งํฉ๋๋ค. ์์ฐ exported๋ ๊ฒ์ฆ๋ ๋ฐ์ดํธ ์์ง์ด๋ฉฐ, fileState=written์ ์ค์ ํ์ผ ๋ฐ์ดํธ๊น์ง ํ์ธํ ๊ฒฐ๊ณผ์
๋๋ค.
assetManifest๋ ๋ชฉ๋ก์ผ ๋ฟ ํ์ผ์ ์ฐ์ง ์์ต๋๋ค. ํ์ผ์ ์ป์ผ๋ ค๋ฉด assetRequests๋ก ๋ค์ ๋ถ๋ฅด๋, ๊ทธ ํธ์ถ์ artifactId๊ฐ ์๋๋ผ ์๋ url๋ก ํด์ผ ํฉ๋๋ค. ์์ฐ ์บก์ฒ ์์ด ์์ง๋ artifact๋ ์์ฐ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ ์กฐํฉ์ผ๋ก ๋ถ๋ฅด๋ฉด ๋ฌด์์ด ์๋์ง์ ์ด๋ป๊ฒ ๋ณต๊ตฌํ๋์ง๋ฅผ ๋ด์ ๊ฑฐ์ ํฉ๋๋ค:
This artifact was collected without the requested asset captures. Remove artifactId and call again with the original url and assetRequests.
๊ธฐ๋ณธ๊ฐ์์๋ manifest์ path์ TSX์ ์์ฐ ์ฐธ์กฐ๊ฐ ์๋ฆฌํ์์๋ก ๋จ์ต๋๋ค. ์ด๊ฒ์ด ๊ธฐ๋ณธ ๋์์ด๊ณ , assetPublicRoot๋ ์ตํธ์ธ์
๋๋ค.
์ค์ ๊ฒฝ๋ก๋ก ๋ฐ๊พธ๋ ค๋ฉด ๊ฐ์ ํธ์ถ์์ assetPublicRoot์ assetRequests.outputPath๋ฅผ ํจ๊ป ์ฃผ์ธ์. ๊ท์น์ ์ด๋ ์ต๋๋ค.
assetPublicRoot๋ URL/๋ก ์๋น๋๋ ์ด๋ฏธ ์กด์ฌํ๋ ์ ๋ ๋ก์ปฌ ๋๋ ํฐ๋ฆฌ์ฌ์ผ ํฉ๋๋ค. ์๋ ๊ฒฝ๋ก์ด๊ฑฐ๋ ์กด์ฌํ์ง ์์ผ๋ฉด ํธ์ถ์ ์ค๋ฅ์ ๋๋ค.- ๊ฐ์ ํธ์ถ์
assetRequests.outputPath๊ฐ ์ต์ ํ ๊ฐ ์์ด์ผ ํฉ๋๋ค. ์ ์ฅ๋ output ๋งคํ์ artifact์ ๋ณด์กด๋์ง ์์ผ๋ฏ๋กartifactId๋ก ์ฌ์ฌ์ฉํด๋ ์ด์ด์ง์ง ์๊ณ , ์ด ์ง์ ์ ํธ์ถ๋ง๋ค ํด์ผ ํฉ๋๋ค. outputPath๊ฐassetPublicRoot๋ฐ์ด๊ฑฐ๋ ํ์ฉ write root๋ฅผ ๋ฒ์ด๋๋ฉด ๊ฑฐ์ ๋ฉ๋๋ค.
์กฐ๊ฑด์ด ๋ง์ผ๋ฉด ๊ทธ ๋ฃจํธ ์๋์ ์ฐ์ธ ํ์ผ์ด manifest์ ๋ชจ๋ TSX output์์ percent-encoding๋ ์๋ URL๋ก ๋ฐ๋๋๋ค.
๋ด๋ณด๋ธ ๋ฐ์ดํธ๊ฐ ๋์ผํ๋ฉด ํ๋์ canonical path/outputPath๋ฅผ ๊ณต์ ํ๊ณ , ๊ทธ canonical ๊ฒฝ๋ก๋ ์๋ต์ ์ค๋ ค ๋์์ค๋ฏ๋ก ๋ฐํ๋ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋๋ก ํ์ธํด ์ฐ๋ฉด ๋ฉ๋๋ค.
์ค๋ณต ์ ๊ฑฐ์ ํ๋จ ๊ธฐ์ค์ ์ข์ต๋๋ค.
- ๋์ฝ๋ํ export ๋ฐ์ดํธ์ SHA-256์ผ๋ก๋ง ํ๋จํฉ๋๋ค. ๋ ์ด์ด ์ด๋ฆ์ด๋ ๊ฒ์ฆ๋์ง ์์
imageHash๋ก๋ ํฉ์น์ง ์์ต๋๋ค. - ๋จผ์ ๋ฌด๊ฒฐ์ฑ์ ๊ฒ์ฆํฉ๋๋ค. ์์ฐ์ด ์ ๊ณ ํ
byteLengthยทsha256์ด ์ค์ ๋์ฝ๋ ๊ฒฐ๊ณผ์ ๋ค๋ฅด๋ฉด ํฉ์น๊ธฐ ์ ์ ๊ฑฐ์ ํฉ๋๋ค. - ๋ด์ฉ๊ณผ ํฌ๋งท์ด ๋ชจ๋ ๊ฐ์ ๋๋ง ๊ณต์ ํฉ๋๋ค. ํ์ ํค๋ (๋ด์ฉ ํด์, ํ์ฅ์, MIME)์ด๋ผ ๊ฐ์ ๊ทธ๋ฆผ์ SVG์ PNG๋ ๊ฐ๊ฐ ๋จ์ต๋๋ค.
- manifest์ ๋ ธ๋๋ณ ํญ๋ชฉ์ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค. ํฉ์ณ์ง๋ ๊ฒ์ ํ์ผ ๊ฒฝ๋ก์ด์ง ๋ชฉ๋ก์ ์ค์ด ์๋๋ฏ๋ก, ์ด๋ ๋ ธ๋๊ฐ ์ด๋ ์์ฐ์ ์ฐ๋์ง๋ ๊ณ์ ๋ณด์ ๋๋ค.
assetNamesPerNode ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ ํ true์
๋๋ค.
asset์ ํ์ผ ์ด๋ฆ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ์ด์ด ์ด๋ฆ์
๋๋ค โ ํ๋ฌ๊ทธ์ธ์ด ๊ทธ๋ ๊ฒ ์ง๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ๋์ ๋์์ด๋๊ฐ ๊ฐ์ ์ด๋ฆ์ ์ค ๋
ธ๋๋ค์ ํ์ผ ํ๋๋ฅผ ๊ณต์ ํฉ๋๋ค. ๊ฐ์ ๊ทธ๋ฆผ์ด๋ฉด ๋ง์ง๋ง ์๋๋ฉด ์์ค์
๋๋ค. ํ ํ๋ฉด์์ ์ฌ๋ ๋
ธ๋๊ฐ Logo.svg ํ๋๋ฅผ ์ฃผ์ฅํ๋๋ฐ ์ค์ ๋ก๋ ์๋ก ๋ค๋ฅธ ๊ทธ๋ฆผ ๋ค์ฏ ๊ฐ์๊ณ , ํญ๋ง๋ค ๊ทธ๋ ค์ง ์ฌ์ง์ ๋ง์ง๋ง์ผ๋ก export๋ ํญ์ ํ์ผ๋ง ๋จ์ ๋ค๋ฅธ ํญ์์๋ ์์์ ํฌ๊ธฐ๊ฐ ์ด๊ธ๋ ์ฑ ๋์ด๋ฉ๋๋ค(ํ์ผ์ด ์์์ ๊ฐ์ ํฌ๊ธฐ์ด๋ฉด object-fit์ด ๋ฌด์์ด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ผ๋ฏ๋ก, ํ๋ฌ๊ทธ์ธ์์๋ ์ด ๋ฌธ์ ๊ฐ ๋๋ฌ๋์ง ์์ต๋๋ค).
assetNamesPerNode๋ ๊ฐ asset์ ๊ทธ ๋
ธ๋์ ์ด๋ฆ์ผ๋ก ์ง์ด(Logo-422-6921.svg, Frame 269-422-3392.png) ๋์ ํจ๊ป ์์ฑ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ true์
๋๋ค โ ๋ ๋๋งํด ๋ณด๋ฉด ์ด์ชฝ์ด Figma๊ฐ ๊ทธ๋ฆฌ๋ ๊ทธ๋ฆผ์ ๊ฐ๊น๊ณ (๊ณต์ง ํ๋ฉด 992ํญ 6.48% โ 4.19%, about 992ํญ 10.79% โ 6.94%), ํ๋ฌ๊ทธ์ธ golden 268๊ฐ๋ ๊ทธ๋๋ก ํต๊ณผํฉ๋๋ค. golden์ CodegenOptions๋ฅผ ์ง์ ์ฐ๊ณ ๊ทธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ ํ ํ๋ฌ๊ทธ์ธ๊ณผ ๋์ผํ๊ธฐ ๋๋ฌธ์
๋๋ค. ํ๋ฌ๊ทธ์ธ๊ณผ byte ๋จ์๋ก ๊ฐ์ ์ด๋ฆ์ด ํ์ํ๋ฉด assetNamesPerNode: false๋ก ๋์ญ์์ค.
๋ ์ํ์์ ์๋ก ๋ค๋ฅธ ๊ทธ๋ฆผ์ด ํ ํ์ผ์ ๊ณ์ ์ฃผ์ฅํ๋ฉด ์ฒซ ๋ฒ์งธ๋ง ๊ธฐ๋กํ๊ณ ๋๋จธ์ง๋ DEVUP_ASSET_NAME_SHARED diagnostic์ผ๋ก ๋ณด๊ณ ํฉ๋๋ค โ ์กฐ์ฉํ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค.
๋ ์ด์ด ์ด๋ฆ์ด ํ์ผ์์คํ
์ด ๋ฐ์ง ๋ชปํ๋ ์ด๋ฆ์ผ ๋(ic:round-arrow-left์ฒ๋ผ ์ฝ๋ก ์ด ๋ ์ด๋ฆ์ Windows๊ฐ ๋ง๋ค์ง ๋ชปํฉ๋๋ค) ์ ๋ฌ ์์ ์ ์์ฑ ์ฝ๋์ manifest๋ฅผ ํจ๊ป ๊ฐ๋ช
ํด ๋์ด ์ด๊ธ๋์ง ์๊ฒ ํฉ๋๋ค. ์์ฑ๊ธฐ ์์ฒด๋ ํ๋ฌ๊ทธ์ธ์ ์ด๋ฆ์ ๊ทธ๋๋ก ์ฐ๋ฏ๋ก golden parity๋ ์ ์ง๋ฉ๋๋ค.
๊ฐ๋ช
๊ท์น์ ์ด๋ ์ต๋๋ค. ์์ซ์ยท-ยท_๊ฐ ์๋ ๋ฌธ์๋ฅผ -๋ก ๋ฐ๊พธ๊ณ ์๋ค -๋ฅผ ๋ผ๋ฉฐ, Windows ์์ฝ์ด(CON, NUL, COM1โฆ)์ด๊ฑฐ๋ ๋นASCII๊ฐ ์์๊ฑฐ๋ ์ด๋ฆ์ด ๋ฐ๋์๊ฑฐ๋ 120์๋ฅผ ๋์ผ๋ฉด ์๋ ์ด๋ฆ์ SHA-256 ์ 12์๋ฆฌ๋ฅผ ์ ๋ฏธ์ฌ๋ก ๋ถ์ฌ ์๋ก ๋ค๋ฅธ ์ด๋ฆ์ด ํ ํ์ผ๋ก ํฉ์ณ์ง์ง ์๊ฒ ํฉ๋๋ค. ํ์ฅ์๋ ASCII ์์ซ์ 10์๊น์ง๋ง ๋จ๊น๋๋ค.
/icons/ic:round-arrow-left.svg -> /icons/ic-round-arrow-left-b041d24e668d.svg
๊ทธ๋์ ๊ณต๋ฐฑ์ด๋ ํ๊ธ์ด ๋ ๋ ์ด์ด ์ด๋ฆ๋ ์ฝ๋์ manifest ์์ชฝ์์ ๊ฐ์ ASCII ๊ฒฝ๋ก๊ฐ ๋ฉ๋๋ค.
Section ๋งํฌ๋ ์ ์ฒด subtree๋ฅผ ์ง์ ๋ณํํ์ง ์์ต๋๋ค. selection_required.nextAction์ ๋ฐ๋ผ ํ๋ณด๋ฅผ ํ์ธํ ๋ค frameIds ๋๋ allScreens: true๋ก ํ๋ฉด๋ณ export๋ฅผ ๊ณ์ํ๋ฉฐ, ์ผ๋ถ ํ๋ฉด ์์ง์ด ์คํจํ๋ฉด ์ฑ๊ณตํ ํ๋ฉด์ ์ ์งํ๊ณ ์คํจํ node๋ failures์ ๋ณด๊ณ ํฉ๋๋ค. nextAction์ whyยทhowยทdoNot๊ณผ ํจ๊ป ์ฒซ ํ๋ณด๋ฅผ ๊ณ ๋ฅด๋ ๊ทธ๋๋ก ์คํ ๊ฐ๋ฅํ example ํธ์ถ์ ๋ด์ต๋๋ค.
์ฌ๋ฌ ํ๋ฉด์ ํ ๋ฒ์ ๋ฐ์ผ๋ฉด frames[]์ ๊ฐ ํญ๋ชฉ์ด ์๋ก ๊ฐ์ ๊ตฌ์กฐ์ธ์ง ์๋ ค์ค๋๋ค. ์์ฑ ๊ตฌ์กฐ๊ฐ ์์ ํ๋ ์๊ณผ ๊ฐ์ผ๋ฉด ๊ทธ ํ๋ ์์ structurallyIdenticalTo(๊ฐ์ ๊ตฌ์กฐ์ธ ์ฒซ ํ๋ ์์ node ID), differsOnly(์: ["assetReferences"]), comparedOutputs๊ฐ ๋ถ์ต๋๋ค. ๋ ํ๋ฉด์ด ์ ๋ง ๋ค๋ฅธ์ง ํ์ธํ๋ ค๊ณ TSX๋ฅผ ์ง์ ๋์กฐํ ํ์๊ฐ ์์ต๋๋ค.
ํ๋ฉด ํ๋ณด ํ์ ์ explore, export์ selection, allScreens๊ฐ ๊ฐ์ ๊ท์น ํ๋๋ฅผ ์๋๋ค. ์
์ด ์๋ก ๋ค๋ฅธ "ํ๋ฉด" ์ ์๋ฅผ ๊ฐ๋ ๋ฌธ์ ๊ฐ ์ฌ๋ผ์ ธ, allScreens๊ฐ ๋ฐฐ๋ยท์ฃผ์ ํ๋ ์์ ํ๋ฉด์ผ๋ก ๋ง๋ค์ด๋ด์ง ์์ต๋๋ค.
SECTION์ 2๋จ๊ณ์
๋๋ค. 1๋จ๊ณ๋ก status: "selection_required"์ ์ ํ ๋ชฉ๋ก์ ๋ฐ๊ณ , 2๋จ๊ณ๋ก nextAction.example์ ์คํํด ๊ณ ๋ฅธ ํ๋ฉด์ exportํฉ๋๋ค. ํ ๋ฒ์ Section ์ ์ฒด๋ฅผ ์์งํ๋ ค ํ์ง ๋ง์ธ์.
SECTION ๊ธฐ๋ณธ ์๋ต์ ํ๋ฉด ์ํฐํฉํธ๊ฐ ์๋ ์ ํ ๋ชฉ๋ก์
๋๋ค. selection.status์ selection.count๋ก ๋ชฉ๋ก ์กฐํ ์ํ์ ํ๋ณด ์๋ฅผ ์ ์ ์์ผ๋ฉฐ, ์ต์์ status: "selection_required"๋ ์์ง ํ๋ฉด์ ์ ํํด์ผ ํ๋ค๋ ๋ป์
๋๋ค.
๋ชฉ๋ก์ ๋ ๊ฐ๋๋ก ๋๋ฉ๋๋ค.
selection.candidates[]โ ์๋์ผ๋ก ํ๋ฉด์ด๋ผ๊ณ ํ์ ํ ํ๋ณด์ ๋๋ค.node.name,node.nodeType,node.textPreview,canonicalUrl๋ก ์๋ก ๊ตฌ๋ถํฉ๋๋ค.allScreens: true๋ ๋ฉ๋ด์ ๋ชจ๋ ํญ๋ชฉ์ด ์๋๋ผ ๋ฐ๋ก ์ด ์๋ ํ๋ฉด ํ๋ณด๋ฅผ ํ๊บผ๋ฒ์ ๊ณ ๋ฅด๋ ๊ฒ์ ๋๋ค.selection.explicitCandidates[]โ ์๋ ํ์ ์ด ํ๋ฉด์ผ๋ก ๋ณด์ง ์์ ๊ฒ๋ค์ ๋๋ค. ์์ ์ฌ๋ก, ์ฃผ์ยทํ ์คํธ, ๊ทธ๋ฆฌ๊ณ ํ๋ฉด ์น์๋ก ์ธก์ ๋์ง ์๋ ๊ธด ํ์ด์ง ๊ฐ์ ๊ฒ์ด ์ฌ๊ธฐ ๋ค์ด์ต๋๋ค.allScreens๋ ์ด๋ค์ ๊ณ ๋ฅด์ง ์์ผ๋ฏ๋ก, ํ์ํ๋ฉดframeIds๋ ๊ทธcanonicalUrl๋ก ๋ช ์์ ์ผ๋ก ์ ํํ์ธ์.
๊ธด ํ์ด์ง๋ ๋์ดยท๋น์จ ์ด๋ ์ชฝ์ผ๋ก๋ ํ๋ฉด์ผ๋ก ์ธก์ ๋์ง ์์ต๋๋ค. ๊ทธ๋ ๋ค๊ณ ๊ทธ ์์ ๋ฏ์ด ์กฐ๊ฐ๋ค๋ง ํ๋ณด๋ก ๋ด๋์ผ๋ฉด ์ ์ ํ์ด์ง ์์ฒด๋ ๋ชฉ๋ก์ ์๊ฒ ๋๋ฏ๋ก, ํ์ด์ง๋ explicitCandidates์ ํต์งธ๋ก ๋จ๊ธฐ๊ณ ๊ทธ ์์ ์๋ ์๋ ํ๋ฉด ํ๋ณด๋ ํจ๊ป ๋ณด์กดํฉ๋๋ค. ๋ ์ค ๋ฌด์์ ๊ณ ๋ฅผ์ง๋ ํธ์ถ์๊ฐ ์ ํฉ๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๋ณด์ด๋ ํ
์คํธ๋ง ๋ชจ์ ์ต๋ 120์, ์ ์ฒด ์ต๋ 2KB๋ก ์ ํํ๋ฏ๋ก ๋น์ด ์๊ฑฐ๋ ์งง์๋ ์ค์ ํ๋ฉด ๋ด์ฉ์ด ์๋ค๋ ๋ป์ ์๋๋๋ค. nextAction.example์๋ ์ฒซ ํ๋ณด๋ฅผ ์ ํํ๋ devup_figma_export ํธ์ถ ์์๊ฐ ๋ค์ด ์์ต๋๋ค. ์์์ frameIds๋ฅผ ๊ฒํ ํ ํ๋ณด ID๋ก ๋ฐ๊ฟ ํธ์ถํ๋ฉด ์ ํํ ํ๋ฉด๋ง ์์งํฉ๋๋ค.
ํ๋ฌ๊ทธ์ธ ์๋ต์ 19 KiB(์ธก์ ๋ ์ํ 20,480๋ฐ์ดํธ ์๋)๋ฅผ ๋์ ์ ์์ต๋๋ค. ํ๋ณด๊ฐ ๋ง์ Section์ ์ด ํ๊ณ๋ฅผ ๋๋๋ฐ, ์์ ์๋ ๊ฑฐ์ ํ์ต๋๋ค โ ํธ์ถ์๋ ์๋ฌด๊ฒ๋ ๋ฐ์ง ๋ชปํ๊ณ , ํ๊ณ๊ฐ Section ํฌ๊ธฐ์ ์ฑ์ง์ด๋ผ ๊ฐ์ ์์ฒญ์ ๋ค์ ๋ณด๋ด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์์ต๋๋ค.
์ง๊ธ์ ์์๋๋ก ์๋ณดํฉ๋๋ค.
- ํ
์คํธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ๋จผ์ ๋ฒ๋ฆฝ๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ํํธ์ผ ๋ฟ์ด๋ผ ์ ํ ๊ฐ๋ฅํ ํ๋ฉด๊ณผ ๋ฐ๊ฟ ๊ฐ์ด์น๊ฐ ์์ต๋๋ค(
textPreviewState: "budget-exhausted"). - ๊ทธ๋๋ ๋์ผ๋ฉด ๋ค์์๋ถํฐ ํ๋ณด๋ฅผ ์๋ผ๋ด๊ณ
projectionTruncated๋ฅผ ์ธ์๋๋ค. ์ด๋ฏธ traversal ์ํ๊ณผ ํ๋ณด 100๊ฐ ์ํ์ด ์ฐ๋ ๊ทธ ํ๋๊ทธ์ ๋๋ค. - ํ๋ณด ํ๋๋ ๋ค์ด๊ฐ์ง ์์ผ๋ฉด ๊ทธ๋ ๊ฑฐ์ ํ๋ฉฐ,
discoveredCandidates์retainedCandidates๋ฅผ ํจ๊ป ๋ณด๊ณ ํฉ๋๋ค.
์๋ ธ๋ค๊ณ ์กฐ์ฉํ ๋์ด๊ฐ์ง ์์ต๋๋ค. ์๋ฆฐ ์ธ๋ฑ์ค์์๋ allScreens๊ฐ ๊ฑฐ์ ๋๊ณ (DEVUP_FIGMA_RESPONSE_TOO_LARGE), ๋ชฉ๋ก์ ์๋ ID๋ not-found-in-truncated-index๋ก ๋ณด๊ณ ํ๋ฉฐ "์๋ค"๊ณ ๋จ์ ํ์ง ์์ต๋๋ค. ์งง์๋ ์๊ธฐ๊ฐ ์งง๋ค๊ณ ๋งํ๋ ๋ฉ๋ด๊ฐ ๋น ์๋ต๋ณด๋ค ๋ซ๊ณ , ์ ์ด์ ๊ธ์ง๋ ๊ฒ์ ์๋ฆผ์ด ์๋๋ผ ๋ง ์๋ ์๋ฆผ์ด์์ต๋๋ค.
Section ์์ frame์ด mobile / tablet / desktop์ฒ๋ผ breakpoint ์ด๋ฆ์ ๊ฐ์ง๋ฉด, ๊ทธ frame ํ๋๋ฅผ ์์ฒญํด๋ ๊ฐ์ ์ด๋ฆ ๊ท์น์ ํ์ frame์ด ํจ๊ป ์์ง๋ฉ๋๋ค(Section ์์ฒด๋ ์์ง ๋ฒ์ ๋ฐ์ด๋ฉฐ, ๊ทธ ์ด๋ฆ์ ๊ฐ frame์ parentName์ผ๋ก ์ ๋ฌ๋ฉ๋๋ค). ์ด๋ tsx๋ responsiveTsx๋ฅผ ์์ฒญํ๋ฉด ๊ฒฐ๊ณผ์ responsiveTsx๊ฐ ์ถ๊ฐ๋ฉ๋๋ค โ ์ธ ํญ์ ํ๋์ ํธ๋ฆฌ๋ก ์ ๊ณ ํญ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ devup-ui ๋ฐ์ํ ๋ฐฐ์ด [mobile, sm, tablet, lg, pc]๋ก ์ด ๋ชจ๋์
๋๋ค. ๊ฐ ํญ์ด ๋์ด๋ slot์ frame ์ด๋ฆ์ด ์๋๋ผ ํญ์ผ๋ก ์ ํด์ง๋๋ค(โค480 / โค768 / โค992 / โค1280 / ๊ทธ ์ด์). ์ปดํฌ๋ํธ ์ด๋ฆ์ componentName์ด ์ฐ์ ์ด๊ณ , ์์ผ๋ฉด Section ์ด๋ฆ์ PascalCase์ Page๋ฅผ ๋ถ์
๋๋ค(about โ AboutPage).
ํ ํญ์๋ง ์๋ ๋
ธ๋๋ ๋ค๋ฅธ ํญ์์ display: none์ผ๋ก ์จ๊ธด ๋ณต์ฌ๋ณธ๊ณผ ๋ณํฉ๋๋ฉฐ, ์ด๋ ๋ณต์ฌ๋ณธ์ Section ๋ ์ด์ด ์์์ ์ฒซ ํญ์ ๊ฐ์ ๊ฐ์ง๋๋ค โ ๊ทธ๋์ ๋ฐฐ์ด์ ์ฒซ slot์ desktop ๊ฐ์ด ๋์ผ ์ ์์ต๋๋ค. ๊ทธ ๋
ธ๋๋ฅผ ๊ฐ์ง ๋ชจ๋ ํญ์์ ์จ๊ธด ๋ ์ด์ด๋ ์ด๋ ํญ์์๋ ๊ทธ๋ ค์ง์ง ์์ผ๋ฏ๋ก tsx์ฒ๋ผ ๋ชจ๋์์ ๋น ์ง๋๋ค. ํญ๋ง๋ค ์ค๋ฐ๊ฟ ์์น๋ง ๋ค๋ฅธ ํ
์คํธ๋ <Box as="br" display={[...]} />๋ก ์ฐ๊ณ , ์ปดํฌ๋ํธ ์ธ์คํด์ค์ variant prop์ด ํญ๋ง๋ค ๋ค๋ฅด๋ฉด ๋ฐฐ์ด๋ก ์ธ ์ ์์ผ๋ฏ๋ก ๊ฐ์ฅ ๋์ ํญ์ ๊ฐ์ ์ฐ๊ณ responsiveUnrepresented์ ๋ณด๊ณ ํฉ๋๋ค. ํจ๊ป ๋ฐํ๋๋ responsiveSlots, responsiveImports, responsiveComponents๊ฐ slot๊ณผ import ๋ชฉ๋ก์
๋๋ค.
rawPayload๋ rawSnapshot์ด node ํธ๋ฆฌ๋ง ์ฐ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ ์์ง ์ ์ฒด(variables, styles, stats, assets ํฌํจ, referencePng ์ ์ธ)๋ฅผ ์๋๋ค. ์บก์ฒ๋ฅผ fixture๋ก ๋ณด๊ดํด ์คํ๋ผ์ธ์์ ์๋ฒ์ ๊ฐ์ ํ ํฐ ์ด๋ฆ($gray200, typography="h4")์ผ๋ก ๋ณํํ๋ ค๋ฉด ์ด๊ฒ์ด ํ์ํฉ๋๋ค.
quality.projection์ exact๋ ๊ทธ๋ฆฐ ํญ์์ ๋งคํ์ด ์ ํํ๋ค๋ ๋ป์ด์ง, ๋ค๋ฅธ viewport์์๋ ๊ฐ๋ค๋ ๋ป์ด ์๋๋๋ค. absolute ์์์ด ์๋ ๋ฃจํธ๋ ๊ทธ๋ฆฐ ํญ์ px๋ก ์ ์งํ๋ฏ๋ก ๊ธฐ๋ณธ ์ถ๋ ฅ์ ์ด๋ค viewport์์๋ ๊ทธ ํญ์ผ๋ก ๊ทธ๋ ค์ง๋๋ค. ๋ฃจํธ๋ฅผ w="100%"๋ก ๋ํ๋ฉด ๊ฐ ๋
ธ๋๋ ์๊ธฐ constraint๊ฐ ๋ถ๋๋ ๊ฐ์ฅ์๋ฆฌ์ ๋จ์ต๋๋ค โ Figma ๊ธฐ๋ณธ๊ฐ MIN์ด๋ฉด ์ผ์ชฝ์
๋๋ค. ๊ทธ๋์ ์ค๋ฅธ์ชฝ์ ๊ทธ๋ฆฐ ๋ฐฐ์ง์ ๋ฐฐ๊ฒฝ๊ณผ ๊ธ์๊ฐ ๋์ ํ๋ฉด์์ ์๋ก ๋ค๋ฅธ ์๋ฆฌ์ ๋จ๋ ์์ ์ผ์ด ์๊น๋๋ค.
widthBehavior ๋ tsx๋ฅผ ๋ง๋ ์๋ต๋ง๋ค(Section ๋ฐฐ์น๋ componentTsx๋ฅผ ๋ง๋ frames[] ๊ฐ ํญ๋ชฉ์๋) ๋ถ์ต๋๋ค. ์ ์ ํ์ ์
๋๋ค โ constraint, auto-layout sizing, ๊ทธ๋ฆฐ ์ขํ๋ฅผ ์์ฑ๋ prop๊ณผ ๋์กฐํ ๋ฟ ๋ ๋ํ์ง ์์ต๋๋ค(verification.runtime: "not-performed"). ๊ธฐ๋ณธ ์ถ๋ ฅ์ TSX๋ ๋ฐ๋์ง ์์ต๋๋ค.
designWidth,root.generatedWidth/root.fluidโ ๋ฃจํธ๊ฐ px ํญ์ ์ ์งํ๋์งroot.componentSizedโ ๋ฃจํธ๋ฅผ ์ด๋ค ํ๋ฉด๋ณด๋ค ์ข๊ฒ(320px ๋ฏธ๋ง) ๊ทธ๋ ธ๋์ง. ๊ทธ๋ฌ๋ฉด ํ๋ฉด์ด ์๋๋ผ ํธ์คํธ๊ฐ ๋๊ณ ํฌ๊ธฐ๋ฅผ ์ ํ๋ ์ปดํฌ๋ํธ(64px ๋ก๋ฉ ํ์, ์์ด์ฝ)๋ผ์, "๋์ ํ๋ฉด์์ ์ด ๋ถ๋ถ์ ์ด๋๋ก ๊ฐ๋"๋ฅผ ๋ฌป๋consumer-policy-required๋ฐ๊ฒฌ์ ๋ด์ง ์๊ณsummary.componentRootSuppressed๋ก ์ ๋๋ค. ์ค์ 64px ๋ก๋ฉ ํ์์ ๋ถ๋ ๋ฐ๊ฒฌ 5๊ฑด์ด ๊ทธ๋ฐ ์์์ด์์ต๋๋ค. ์์ฑ๊ธฐ๊ฐ ํํํ์ง ๋ชปํ ๊ฒ(generator-approximation)๊ณผ ๋์์ธ์ด ์ ํ ๊ฒ์ ๊ทธ๋๋ก ๋ณด๊ณ ํฉ๋๋คfindings[](์ต๋ 40๊ฐ) โ ๋ ธ๋๋ง๋คkind,status,confidence,evidence(constraint, ์์ชฝ ์ฌ๋ฐฑ, ์์ฑ๋ prop), ํด๋นํ๋ฉดcandidates,drawnInside,carriessummary, ๊ทธ๋ฆฌ๊ณshapeSizeOmittedโ ์์น ์ง์ ๋ ์์ ์๋ ๋ํ์ ํ๋ฌ๊ทธ์ธ์ฒ๋ผh="100%"์ ํญ ์์ด ์ด ๋ ธ๋๋ค. ๊ธฐ๋ณธ ์ถ๋ ฅ์ ๊ทธ๋๋ก ๋๊ณ ์ฌ๊ธฐ์projectionIssues์์ ๋ณด๊ณ ํฉ๋๋ค
| status | ๋๊ฐ ๋ตํ๋ |
|---|---|
generator-approximation |
๋์์ธ์ด ์ ํ ๊ฒ(STRETCHยทSCALEยทCENTER constraint, ์ง์ )์ ๊ธฐ๋ณธ ์ถ๋ ฅ์ด ํํํ์ง ๋ชปํจ. widthPolicy๊ฐ ๊ทธ๋๋ก ์๋๋ค |
consumer-policy-required |
๋์์ธ์ด ๋ตํ์ง ์๋ ์ง๋ฌธ โ ์ค๋ฅธ์ชฝ์ ๊ทธ๋ ธ์ง๋ง ์ผ์ชฝ์ ๊ณ ์ ๋ ๋ฐฐ์ง๊ฐ ๋์ ํ๋ฉด์์ ์ด๋ ์์ด์ผ ํ๋์ง. candidates์์ ๊ณ ๋ฆ
๋๋ค |
design-defined |
๋์์ธ์ด FIXED ํญ์ผ๋ก ์ ํ ๊ฒ. ์๋ฆผ์ผ ๋ฟ์ ๋๋ค |
| kind | ์ํฉ |
|---|---|
right-aligned-but-held-left |
์ค๋ฅธ์ชฝ ๊ฐ์ฅ์๋ฆฌ ๊ฐ๊น์ด ๊ทธ๋ ธ์ง๋ง constraint๊ฐ ์ผ์ชฝ์ ๊ณ ์ . carries๋ ๊ทธ ์์ ๊ทธ๋ ค์ ธ ํจ๊ป ์ฎ๊ฒจ์ง ๋
ธ๋ |
centered-but-held-left |
์์ชฝ ์ฌ๋ฐฑ์ด ๊ฐ๊ฒ ๊ทธ๋ ธ์ง๋ง ์ผ์ชฝ ๊ณ ์ . ํ๋ณด๋ leftยทcenterยทstretch |
group-anchor-mismatch |
๊ทธ๋ ค์ง ์ปจํ ์ด๋์ ๋ค๋ฅธ ๊ฐ์ฅ์๋ฆฌ์ ๊ณ ์ ๋ผ, ํญ์ด ๋ฐ๋๋ฉด ๋์ด ๊ฐ๋ผ์ง |
constraint-not-expressed |
STRETCHยทSCALE constraint๋ฅผ ๊ธฐ๋ณธ ์ถ๋ ฅ์ด px ์์นยทํญ์ผ๋ก ์ |
center-offset-dropped |
CENTER constraint์ธ๋ฐ ์ค์ฌ์์ ๋ฒ์ด๋ ๊ทธ๋ ธ๊ณ , ๊ธฐ๋ณธ ์ถ๋ ฅ์ ์ ํํ ๊ฐ์ด๋ฐ์ ๋ โ ๊ทธ๋ฆฐ ํญ์์๋ ์ฎ๊ฒจ์ง |
fixed-length-line-mask |
์ง์ ์ mask๋ก ๊ทธ๋ ค, ์์๊ฐ ๋์ด๋๋ ์ ์ ๊ทธ๋ฆฐ ๊ธธ์ด์ ๋จธ๋ฌพ |
fixed-width-in-fluid-parent |
๋์์ธ์ด FIXED๋ก ์ ํ ํญ |
widthPolicy ๋ ์ตํธ์ธ์
๋๋ค. ์ฃผ์ง ์์ผ๋ฉด ์ถ๋ ฅ์ ์์ ๊ณผ ๊ฐ์ต๋๋ค.
{ "url": "...", "widthPolicy": { "root": "fluid", "anchors": { "2:4": "stretch", "2:6": "right", "2:12": "center" } } }- ๋ฃจํธ๋ ์ปจํ
์ด๋์ ํญ์ ๋ฐ์ต๋๋ค(
w="100%", ๋์ด๋ ์ ์ง.rootLayout: "embedded"๋ฉด ์๋๋๋ก ์๋ต). - ์์น ์ง์ ๋ ๋
ธ๋์ ๊ฐ์ฅ์๋ฆฌ๋ ์ด ์์๋ก ์ ํฉ๋๋ค:
anchors์ ์ ์ ๊ฒ โ ๊ทธ ๋ ธ๋๊ฐ ๊ทธ๋ ค์ง ์ปจํ ์ด๋๋ฅผ ํธ์ถ์๊ฐrightยทcenter๋ก ๊ณ ์ ํ๋ค๋ฉด ๊ทธ๊ฒ โ ๋ ธ๋ ์์ ์ Figma constraint. ๊ทธ๋์ ๋ฐฐ์ง ๋ฐฐ๊ฒฝ๋งright๋ก ์ฃผ๋ฉด ๊ทธ ์์ ๊ธ์๋ ๋ฐ๋ผ๊ฐ๋๋ค. rightโright,stretchโleft+right(ํญ ์์),scaleโ%ํญ,centerโleft="50%"๋๋calc(50% ยฑ Npx)์translateX(-50%). ๋์ด๋๋ ์ง์ ์ mask๋maskSize="100% 100%", ์์ ์๋ ๋ํ์ ์๊ธฐ px ํฌ๊ธฐ๋ก ์๋๋ค.- ์ด prop๋ค์ด ๊ทธ๋ฆฐ ํญ์์ ์๋ ์์นยทํญ์ ์ ํํ ์ฌํํ๋ค๋ ๊ฒ์ ๊ฒ์ฆํฉ๋๋ค(ABSOLUTE ์ง๋จ์
components.horizontalยทwidth์anchorSource). ๋ค๋ฅธ ํญ์์ ์ด๋ ๋์ด๋์ง๋ ํธ์ถ์์ ์ ์ฑ ์ด์ง ๋์์ธ์ ๋ํ ์ฃผ์ฅ์ด ์๋๋๋ค. - ์บก์ฒ์ ์๋ node id๋ ๊ฑฐ์ ํฉ๋๋ค(
DEVUP_INVALID_INPUT,details.unknownNodeIds) โ ์คํ๊ฐ ์กฐ์ฉํ ์ ์ฉ๋์ง ์๋ ์ต์ปค๊ฐ ๋์ง ์๋๋ก.jobIdํด๋ง์๋ ๋ณด๋ผ ์ ์๊ณ ์๋ ํธ์ถ์ ๋ฃ์ด์ผ ํฉ๋๋ค. - ํ ํญ์ง๋ฆฌ ํ๋ฉด์ฉ์
๋๋ค. ์ฌ๋ฌ ํญ์ ์์งํ
responsiveTsx์๋ ์ ์ฉ๋์ง ์์ต๋๋ค.
verificationScope๋ ์ด ์๋ต์ด ๋ฌด์์ ์ด๋ค ํญ์์ ํ์ธํ๋์ง ๋ฐ๋ก ๋งํฉ๋๋ค โ collectedWidths, ์ ์ ์ผ๋ก ํ์ธํ ๊ฒ(staticallyChecked), ๊ทธ๋ฆฌ๊ณ rendered.state: "not-performed". ๋ค๋ฅธ ํญ์์ ์ค์ ๋ก ์ด๋ป๊ฒ ๊ทธ๋ ค์ง๋์ง๋ devup_runtime_audit๋ก ์๋น์ ํ๋ก์ ํธ์์ ์ฝ๋๋ค.
๋น์ฉ(WQUW-151 ์ค์ ํ๋ฉด 10๊ฐ): widthBehavior๋ 0.82.8 KB, ๊ณ์ฐ 0.020.3 ms(๊ฐ์ ํ๋ฉด์ codegen 3~33 ms). ๊ธฐ๋ณธ ์ถ๋ ฅ์ TSX๋ ๋ณ๊ฒฝ ์ ๊ณผ ๊ฐ์ต๋๋ค โ ํ๋ฌ๊ทธ์ธ golden 268์์ด ํต๊ณผํ๊ณ , ์ค์ ํ๋ฉด 10๊ฐ์ ํฉ์ฑ ํ๋ฉด 1๊ฐ์ TSX SHA-256์ด ๋ณ๊ฒฝ ์ ๋น๋์ ๊ฐ์ต๋๋ค.
codegen์ด ํ๋ฉด ํฌ๊ธฐ์ ์ ๊ณฑ์ผ๋ก ๋๋ ค์ง๋ ๊ฒ์ ๊ณ ์ณค์ต๋๋ค. ์์ฑ๋ ์์ฑ๋ง๋ค ๊ทธ ์์ฑ์ด sourceMap์ ๋งคํ๋๋์ง ํ์ธํ๋ ๊ฐ์ฌ๊ฐ, ํญ๋ชฉ ํ๋๋ฅผ ๋ณผ ๋๋ง๋ค ๊ทธ ์์ฑ์ ์ฃผ์ธ ๋
ธ๋๋ฅผ sourceMap ์ ์ฒด์์ ๋ค์ ์ฐพ์์ต๋๋ค(์์ฑ ์ ร ํญ๋ชฉ ์ยฒ). ์ฃผ์ธ์ ์์ฑ๋ง๋ค ํ ๋ฒ๋ง ์ฐพ๊ฒ ํ๊ณ , ์ถ๋ ฅ์ ๊ฐ์ต๋๋ค โ about ํ๋ฉด ์ธ ํญ์ CodegenOutput ์ ์ฒด(TSX, sourceMap, ์ง๋จ, fidelity)๊ฐ ๋ณ๊ฒฝ ์ ๊ณผ ๊ฐ์ ํด์์
๋๋ค. ์ค์ ํ๋ฉด์์ ํญ ํ๋์ codegen์ด ์ฝ 1 s์์ 70~100 ms๋ก, ๋ธ๋ฆฌ์ง๋ก ๋ฐ์ about(790 node, ์ธ ํญ) export์ ํฌ์์ด 15.3 s์์ 0.58 s๋ก ์ค์์ต๋๋ค.
frame์ After delay ํธ๋ฆฌ๊ฑฐ๋ก ๋ค๋ฅธ frame์ Smart animateํ๋ reaction์ด ์๊ณ , ๊ทธ frame์ด ๋ค์ ๋ค์ frame์ผ๋ก ์ด์ด์ง๋ฉด ํ๋์ ์ฒด์ธ์
๋๋ค(์ฒ์ frame์ผ๋ก ๋์์ค๋ฉด ๋ฃจํ). ์ฒด์ธ์ frame๋ค์ ์์ฒญํ node์ subtree ๋ฐ์ ์๋ ํ์ frame์ด๋ฏ๋ก, ์์ฒญ ๋ฃจํธ๊ฐ ํ๋์ผ ๋ snapshot ์คํฌ๋ฆฝํธ๊ฐ ์ฒด์ธ์ ๋ฐ๋ผ๊ฐ๋ฉฐ ์ถ๊ฐ ๋ฃจํธ๋ก ํจ๊ป ์์งํฉ๋๋ค(๋ค์ค ๋ฃจํธ ์์ฒญ์ ๋ฃจํธ ๋ชฉ๋ก์ ๊ทธ๋๋ก ๋ก๋๋ค).
๋ณํ๊ธฐ๋ ํ๋ฌ๊ทธ์ธ์ getReactionProps ๊ท์น๋๋ก frame ์ฌ์ด์์ ๋ฐ๋๋ ๊ฒ โ ์์น, ํฌ๊ธฐ, opacity, ์ฒซ fill, ํ์ (๋์ delta) โ ์ ์ด๋ฆ์ด ๊ฐ์ ์์์์ ๋จผ์ ์ฐพ์ ์์๋ง๋ค animationName={keyframes({...})} / animationDuration / animationTimingFunction / animationFillMode / animationIterationCount(๋ฃจํ๋ฉด infinite)๋ก ์ฐ๊ณ , ๋ฐ๋๋ ์์์ด ์์ ๋๋ง frame ์์ฒด์ ์๋๋ค. 0%๋ ์์ frame, ๊ฐ ๋จ๊ณ๋ ๋์ฐฉ ์์ ์ ํผ์ผํธ์ ์ง์ keyframe๊ณผ ๋ค๋ฅธ ์์ฑ๋ง, ๋ฃจํ๋ 100%์์ ์์ ๊ฐ์ผ๋ก ๋ซํ๋ฉฐ duration์ ๋๋์๊ฐ๋ ๊ตฌ๊ฐ๊น์ง ์
๋๋ค. 10ms ๋ฏธ๋ง timeout์ delay๋ก ์ฐ์ง ์์ต๋๋ค. keyframes๊ฐ ์ฐ์ด๋ฉด @devup-ui/react์์ import๋ฉ๋๋ค.
snapshot์ ์๋ ๋ชฉ์ ์ง(legacy ๊ฒฝ๋ก, ๋ค์ค ๋ฃจํธ ์์ฒญ)๋ ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๊ณ DEVUP_CODEGEN_ANIMATION_UNREACHABLE diagnostic์ผ๋ก ๋ณด๊ณ ํฉ๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>",
"query": "A : STORY-F-PROOFREAD",
"nodeTypes": ["PAGE", "SECTION", "FRAME", "COMPONENT_SET"],
"match": "normalized",
"limit": 20
}๊ฒ์ ๋ฒ์๋ URL์ด ์ ํฉ๋๋ค. node-id๊ฐ ์์ผ๋ฉด ๊ทธ ๋
ธ๋์ ๊ทธ subtree๋ง, ์์ผ๋ฉด ํ์ผ ์ ์ฒด๋ฅผ ๋ด
๋๋ค. ์๋ต์ scope๊ฐ ์ค์ ๋ก ์ด๋ ์ชฝ์ ๊ฒ์ํ๋์ง ๋ณด๊ณ ํ๋ฏ๋ก, ๊ฒฐ๊ณผ๊ฐ ๊ธฐ๋์ ๋ค๋ฅผ ๋ ๋ฒ์ ๋๋ฌธ์ธ์ง ์ด๋ฆ ๋๋ฌธ์ธ์ง ๊ตฌ๋ถํ ์ ์์ต๋๋ค. limit์ ๋ฐํํ ์ผ์น ๊ฐ์์
๋๋ค.
ํ์ผ ์ ์ฒด ๊ฒ์์ ๋จผ์ read-only Plugin API๋ก ์ค์ figma.root.children page catalog๋ฅผ ์ป๊ณ , page๋ง๋ค ํ ๋ฒ์ฉ ์ ํํ๋ ์์ query projection์ ๋ณ๋ ฌ ์คํํฉ๋๋ค. ์ ์ฒด page snapshot์ ์๋ตํ์ง ์์ผ๋ฏ๋ก ํฐ ํ์ผ์์๋ ๊ณต์ MCP text ์ํ์ ํผํฉ๋๋ค. ๊ฒฐ๊ณผ๋ ์๋ฌธ exact, Unicode NFCยท๊ณต๋ฐฑยท๋์๋ฌธ์๋ฅผ ์ ๊ทํํ exact, prefix, contains ์์ผ๋ก ์ ๋ ฌํ๊ณ match: "fuzzy"์ผ ๋๋ง ์คํ ํ์ฉ ๊ฒ์์ ์ถ๊ฐํ๋ฉฐ, node ID, type, page, ์ ์ฒด breadcrumb์ ํ์ devup_figma_export์ ๊ทธ๋๋ก ์ ๋ฌํ canonical URL์ ํฌํจํฉ๋๋ค.
{
"url": "https://www.figma.com/design/<file-key>/<name>?node-id=1-2",
"limit": 50,
"includeTextPreview": true,
"refresh": false
}์๊ตฌ์ฌํญ ์ ๋ชฉ์ด๋ ์ค๋ช
node ๋งํฌ๊ฐ ์ค์ ๊ตฌํ ํ๋ฉด์ด ์๋ ๋ devup_figma_explore๋ฅผ ๋จผ์ ํธ์ถํฉ๋๋ค. url์๋ node-id๊ฐ ์์ด์ผ ํ๊ณ (์์ผ๋ฉด DEVUP_FIGMA_NODE_NOT_FOUND), limit์ 1~100 ๋ฒ์ ๋ฐ์ด๋ฉด ๊ฑฐ์ ๋ฉ๋๋ค. anchor์ ๊ฐ์ ๊ณต๊ฐ ๋ฌถ์์ frame/component ํ๋ณด๋ฅผ ์๊ฐ ์์์ canonical URL๋ก ๋ฐํํ๋ฉฐ, ๋ค์ ์๊ตฌ์ฌํญ ์ ๋ชฉ์์ ํ์ ๋ฒ์๋ฅผ ๋๋
๋๋ค.
limit์ ๋ฐํํ ํ๋ณด ๊ฐ์์ผ ๋ฟ์ด๊ณ ๊ทธ ์ด์ ์๋ฌด๊ฒ๋ ์๋๋๋ค. ๋์์ธ์ ์ผ๋ง๋ ์ฝ์์ง๋ ๋ฐ๊พธ์ง ์์ผ๋ฏ๋ก(ํฌ์ ์์ฐ์ ํญ์ ๊ณ ์ ์
๋๋ค), limit์ ์ฌ๋ ค์ ํ ์ ์๋ ์ผ์ ๋ต์ ๊ธธ๊ฒ ๋ง๋๋ ๊ฒ๋ฟ์
๋๋ค. ์์ ์๋ limit์ด ํฌ์ ์์ฐ์ผ๋ก 4๋ฐฐ ํ๋๋ผ 30โ33์ผ๋ก ์ฌ๋ ธ๋๋ ํ๋ณด๊ฐ 23โ18๋ก ์ค์ด๋๋ ์ผ์ด ์์์ต๋๋ค.
์๋ฆฐ ์ด์ ๋ ์ด์ ๋๋ก ๋๋ ๋ณด๊ณ ํฉ๋๋ค.
truncation.candidatesโlimit์ด ๋ชฉ๋ก์ ์๋๋ค๋ ๋ป์ ๋๋ค.limit์ ์ฌ๋ฆฌ๋ฉด ๋๋จธ์ง๊ฐ ๋์ต๋๋ค.truncation.projectionโ ์์งํ ์ค๋ ์ท ์์ฒด๊ฐ ๋ถ์์ ํ๋ค๋ ๋ป์ ๋๋ค.limit์ ์๋ฌด๋ฆฌ ์ฌ๋ ค๋ ๊ทธ ํ๋ฉด๋ค์ ๋์์ค์ง ์์ต๋๋ค.
์ต์์ truncated๋ ๋์ OR์
๋๋ค. ๋์ ๊ตฌ๋ถํ์ง ๋ชปํ๋ฉด ๊ณ ์น ์ ์๋ ์ํฉ์์ limit๋ง ์ฌ๋ฆฌ๋ฉฐ ํธ์ถ์ ๋ฐ๋ณตํ๊ฒ ๋ฉ๋๋ค.
includeTextPreview๋ ๋ณ๋ ์์ฐ์ ์๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๊ตฌ์กฐ ํฌ์์ด ์ฐ๊ณ ๋จ๊ธด ๊ณต๊ฐ๋ง ์๋นํ๋ฏ๋ก, ์ผ๊ณ ๋๋ ๊ฒ์ด ํ๋ณด ๊ฐ์ยทIDยทtruncation.projection ์ค ๋ฌด์๋ ๋ฐ๊พธ์ง ์์ต๋๋ค. ๊ฐ์ ํ์ผยท์ต์
์์ ์ด๋ฏธ ์์งํ ๋ ํฐ ํ์ ๊ฒฐ๊ณผ๋ exactยทrelated-nodeยทsuperset ๋ฒ์๋ก ์ฌ์ฌ์ฉ๋๊ณ , ๋์์ ๋ค์ด์จ ํธํ ์์ฒญ๋ ๊ณต์ Figma ํธ์ถ ํ๋๋ฅผ ๊ณต์ ํฉ๋๋ค. refresh: true๋ ๋ชจ๋ ์ฌ์ฌ์ฉ์ ๊ฑด๋๋๋๋ค. ์ํ๋ ํ๋ณด์ canonical URL์ devup_figma_export์ ๋๊ฒจ ์ ํํ ํ๋ฉด๋ง ๋ณํํฉ๋๋ค.
ํ์๊ณผ ๊ฒ์์ ๋ณ์ catalog๋ฅผ ์์งํ์ง ์์ต๋๋ค. ์ ํํ UI ๋ณํ ๋จ๊ณ์์ ์ ํ subtree์ ๋ชจ๋ ๋ณด์กด ํ๋์ ์๋ VARIABLE_ALIAS์ paint/text/effect/grid style ID๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ค์บํ๊ณ , ์ค์ ์ฌ์ฉ๋ ID๋ง ๊ณต์ Figma API๋ก ์กฐํํฉ๋๋ค. outputs: ["devupJson"]์ scope: "file"์ ํจ๊ป ์ค ๊ฒฝ์ฐ์๋ง file ์ ์ฒด ๋ก์ปฌ catalog๋ฅผ ์์งํ๊ณ , ๊ทธ ๋ค ๋
ธ๋๊ฐ ์ฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ณ์ยท์คํ์ผ๊ณผ ๋ณ์๊ฐ alias๋ก ๊ฐ๋ฆฌํค๋ ๋ณ์๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฝ์ด ํฉ์นฉ๋๋ค. ๊ทธ๋์ ๋ฌธ์๋ฅผ ํจ๊ป ์์งํ๋ ํ์ผ ์ ์ฒด export(rawPayload ๋ฑ)๋ ํ
๋ง๋ง ๋ฐ๋ export์ ๊ฐ์ ํ
๋ง๋ฅผ ๋
๋๋ค. Figma๊ฐ ์์ ๊ฐ์ ๋ง์ถฐ ์ ์ํ๋ ๋ณ์(inferredVariables)๋ ๋ฐ์ธ๋ฉ์ด ์๋๋ฏ๋ก ์ฌ์ฉ๋ ๊ฒ์ผ๋ก ์ธ์ง ์์ต๋๋ค.
sourcePolicy ํ๋ผ๋ฏธํฐ๋ auto์ direct ๋ ๋ค ๊ฐ์ ๋์์ด์์ผ๋ฏ๋ก ์ ๊ฑฐํ์ต๋๋ค โ ๋ถ๊ธฐํ์ง ์๋ ์ ํ์ง๋ ํธ์ถ์์๊ฒ ํ๋ฆด ๊ธฐํ๋ง ์ฃผ์์ต๋๋ค. ๊ฒฝ๋ก ์ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ ์๋๋ผ ํ๋ฌ๊ทธ์ธ์ด ๋ถ์ด ์๋์ง๊ฐ ์ ํฉ๋๋ค: ๋ถ์ด ์์ผ๋ฉด ๋ธ๋ฆฌ์ง, ์๋๋ฉด direct์
๋๋ค. direct ๊ฒฝ๋ก๋ ์ฐ๊ฒฐ๊ณผ read-only capability catalog ์กฐํ๋ฅผ ๊ฐ๊ฐ 30์ด, ๊ฐ๋ณ tool ํธ์ถ์ 5๋ถ์ผ๋ก ์ ํํฉ๋๋ค. deadline์ ๋๊ธฐ๋ฉด ํด๋น remote session์ ํ๊ธฐํ๊ณ ๋์์ธ ์๋ฌธ ์์ด retryable timeout ๋จ๊ณ๋ง ๋ฐํํฉ๋๋ค.
์ ํํ node ๋งํฌ์ UI ๋ณํ์ ํ๋ ์ด์์ ๊ณต์ use_figma ํธ์ถ ์์์ subtree์ ์ค์ ์ฌ์ฉ ๋ฆฌ์์ค๋ฅผ ์์งํฉ๋๋ค. ์์ง ์คํฌ๋ฆฝํธ๋ checked-in manifest(devup-ui ๋ณํ๊ธฐ๊ฐ ์ค์ ๋ก ์ฝ๋ ํ๋๋ง)๋ง ํ์ธํ๊ณ โ ํ๋กํ ํ์
์ฒด์ธ ์ ์ฒด๋ฅผ ํ๊ฑฐ๋ ๋ฏธ๋ถ๋ฅ ํ๋๋ฅผ extra์ ๋ด์ง ์์ต๋๋ค โ null/๋น ๋ฐฐ์ด/๋ฏธ๋ฐ์ธ๋ฉ style ID ๊ฐ์ ๊ธฐ๋ณธ๊ฐ์ ๋ดํฌ์์ ์๋ตํฉ๋๋ค. ๊ฒฐ๊ณผ๋ ํญ์ ํ
์คํธ(devupFastSnapshotEnvelope)์ด๋ฉฐ PNG ๊ฐ์ ๋ฐ์ด๋๋ฆฌ transport๋ ์์ต๋๋ค. ํ subtree๊ฐ 15KB ํ
์คํธ ํ๋๋ฅผ ๋์ผ๋ฉด ๊ฐ์ ์คํฌ๋ฆฝํธ๋ฅผ offset์ ์ฎ๊ฒจ ๋ค์ ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก ํ
์คํธ ํ์ด์ง๋ค์ด์
ํฉ๋๋ค โ ๊ฐ ๋ผ์ด๋๋ ๊ทธ ๋ผ์ด๋๊ฐ ๋ณด๋ธ node์์๋ง ๋ฆฌ์์ค๋ฅผ ์ค์บํด ์๊ธฐ ์๊ฒฐ์ ์ด๋ฉฐ, Rust๊ฐ ์ฌ๋ฌ ๋ผ์ด๋์ node์ ๋ฆฌ์์ค๋ฅผ ๋ณํฉํฉ๋๋ค. Rust๋ schemaยท๋์ IDยทnode graphยท๋ฆฌ์์ค ์ฐธ์กฐยท(ํ์ด์ง ์ค์ด ์๋ ๋์) ์์ ์์ ์ฑ์ ๋ชจ๋ ๊ฒ์ฆํ ๋ค์๋ง ๊ฒฐ๊ณผ๋ฅผ ์ฑํํฉ๋๋ค. ํ ํญ๋ชฉ์ด๋ผ๋ ๋ถ์ผ์นํ๋ฉด fast ๊ฒฐ๊ณผ ์ ์ฒด๋ฅผ ๋ฒ๋ฆฌ๊ณ ๊ธฐ์กด cursor ์์ง์ 0๋ถํฐ ์ฌ์์ํฉ๋๋ค. Section multi-root์์๋ ์ฑ๊ณตํ root์ resource๋ ๊ทธ๋๋ก ๋ณด์กดํ๊ณ ์คํจํ๊ฑฐ๋ ์ํ์ ๋์ root๋ง legacy๋ก ๋ค์ ์์งํ ๋ค ์๋ ์๊ฐ ์์๋ก ํฉ์นฉ๋๋ค. direct upstream์ ์ฐ๊ฒฐ๊ณผ read-only tool catalog๋ฅผ ํ session์์ ์ฌ์ฌ์ฉํ๊ณ 30์ด TTL, ์ฐ๊ฒฐ ์ข
๋ฃ ๋๋ transport ์ค๋ฅ ๋๋ง ์ฌ์ฐ๊ฒฐยท์ฌ๊ฒ์ฆํฉ๋๋ค. ๊ฒฐ๊ณผ์ stats์๋ figmaToolCalls, transport(text | text-paginated | legacy-cursor), fallbackUsed, node/variable/style ์์ byte ์๋ง ํฌํจ๋๋ฉฐ ์๋ณธ ๋์์ธ์ด๋ ์ธ์ฆ ์ ๋ณด๋ ํฌํจ๋์ง ์์ต๋๋ค.
์์ ์ฑ ๋ฑ๊ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
full-local-plus-used-remote: ๋ก์ปฌ ์ ์ฒด์ ์ฌ์ฉ๋ ์ธ๋ถ token์ ๋ชจ๋ ํ์ธused-tokens: ํ๋ณดํ token๋ง ๋ณํํ์ผ๋ฉฐ ์ธ๋ถ ์ ์ฒด๋ฅผ ๋ณด์ฅํ์ง ์์resolved-values-only: ์๋ฏธ ์๋ token binding ์์ด ๊ณ์ฐ๊ฐ๋ง ํ๋ณด
scope๋ theme(ํ๋ก์ ํธ devup.json), api(openapi.json), db(Vespertide models/*.json), all์
๋๋ค. ํธ์ถ ์์ ์ ๋์คํฌ์ ์ค์ ๋ก ์๋ ํ์ผ๋ง ์ฝ๊ณ , ์ธ์
๊ฐ ์บ์ํ์ง ์์ผ๋ฉฐ, ์๋ ๊ฒ์ ์ถ์ธกํ์ง ์์ต๋๋ค. ์ค์บ ๊น์ด๋ 4๋จ๊ณ์
๋๋ค.
๋ค์ ๋๋ ํฐ๋ฆฌ๋ ์ค์บํ์ง ์์ต๋๋ค.
- ๋น๋ยท์์กด์ฑ ์ฐ์ถ๋ฌผ:
node_modules,target,dist,build,out,.next,.turbo,.nuxt,.venv,venv,__pycache__,.cache,coverage,.git - ์ค์ฒฉ ์ฒดํฌ์์:
.worktrees,.worktree,.git-worktrees
์ ์ธ๋ ์กฐ์ฉํ ์ผ์ด๋์ง ์์ต๋๋ค. ๋ฌด์ธ๊ฐ๋ฅผ ๊ฑด๋๋ฐ์์ผ๋ฉด excludedPaths[]์ path์ reason(nested-checkout-directory ๋๋ nested-git-checkout)์ผ๋ก ๋ณด๊ณ ํฉ๋๋ค. ํ์ผ์ ํ๋๋ ๋ชป ์ฐพ์๋๋ฐ ์ ์ธํ ๊ฒ์ด ์์ผ๋ฉด ๊ทธ ์ฌ์ค๋ ํจ๊ป ๋ณด๊ณ ํ๋ฏ๋ก, "์์"๊ณผ "์ ์ธํด์ ์ ๋ณด์"์ ๊ตฌ๋ถํ ์ ์์ต๋๋ค. ์์ ์๋ ์คํ
์ผ ๋ธ๋์น์ devup.json์ด ๊ถ์ ์๋ ๊ฒ๊ณผ ์์ฌ 4๊ฐ๊ฐ ๋ฐํ๋๊ณ , ์ด๋ ๊ฒ์ด ๋ง๋์ง ํ์๊ฐ ์์์ต๋๋ค.
๊ฐ์ ์ข
๋ฅ์ ํ์ผ์ด ์ฌ๋ฌ ๊ฐ์ผ ๋๋ ๊ฐ ํญ๋ชฉ์ด authority(project-root | package-local)์ appliesTo(์ ์ฉ ๋๋ ํฐ๋ฆฌ)๋ฅผ ๊ฐ๊ณ , authorityNote๊ฐ ์ด๋ ํ๋๋ ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ์ง๋ฐฐํ์ง ์๋๋ค๋ ์ฌ์ค์ ์๋ ค์ค๋๋ค. ์ฝ๋๋ฅผ ์ฐ๋ ํ์ผ์ด ์ด๋ appliesTo ์์ ์๋์ง๋ก ๊ณจ๋ผ์ผ ํฉ๋๋ค.
์๋ต์ ๋ค์์ ๋ด์ต๋๋ค.
| ํ๋ | ๋ด์ฉ |
|---|---|
ok |
์ฌ๊ฐ๋๋ก ํ์ . error๊ฐ ์์ผ๋ฉด ์คํจ, strict: true๋ฉด warning๋ ์คํจ |
okReason |
clean ยท clean-unverified-tokens ยท info-only ยท warnings-only ยท warnings-and-info ยท strict-warnings ยท error-violations |
violations[] |
rule, severity(info|warning|error), byteRange, message, suggestion, ๊ทธ๋ฆฌ๊ณ ์๋ฐ์ด ๋์ธ JSX ์ฌ๋ ํ๊ทธ์ ๋ฌธ์ ์์ ๋ฒํธ elementIndex(0๋ถํฐ)์ elementยทattribute |
violationCounts |
error / warning / info ๊ฐ์ |
themeNotes[] |
๋น์ด ์๋ ํ ํฐ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์ข ๋ฅ๋ง๋ค ํ ๋ฒ์ฉ๋ง ์์ฝ |
tokens |
referencedByTsx, definedByTheme, unknownTokenCheckRan |
checkedTokens / availableTokenCount |
์ ๋ ๊ฐ๊ณผ ๊ฐ์ ์๋ฅผ ์์ ์ด๋ฆ์ผ๋ก ์ ์ง |
themeAvailable / themeGuardrail |
ํ ๋ง๋ฅผ ์ฐพ์๋์ง, ๋ชป ์ฐพ์์ผ๋ฉด ์ |
layoutRisks[] |
ํญ์ด ๋ฐ๋๋ฉด ๋๋ฌ๋๋ ์ ์ ๋ ์ด์์ ์ํ(anchor-mismatch, right-aligned-but-held-left, centered-but-held-left, fixed-length-line-mask) |
verificationScope |
์ ์ ์ผ๋ก ๊ฒ์ฌํ ๊ฒ(static: ์คํํ ๊ท์น, ํ ํฐ ๊ฒ์ฌ ์ฌ๋ถ, layout ๊ฒ์ฌ์ referenceWidth)๊ณผ ๋ ๋ํ์ง ์์ ๊ฒ(runtime.state: "not-performed") |
sourceMapLink |
sourceMap์ ๋๊ฒผ์ ๋๋ง. linked(linkedViolations, unlinkedViolations) ๋๋ unavailable |
๊ท์น์ ๋ ๊ฐ๋์
๋๋ค. ์์ ์ฌ์ฏ์ tsx ํ๋๋ง ์ค๋ ๋๊ณ , ๋ค์ ๋ค์ฏ์ files ๋ฒ๋ค๋ก ์ค ๋๋ง ๋๋๋ค โ ํ์ผ ๊ฒฝ๋ก์ ํ์ผ ์ฌ์ด์ ๊ด๊ณ๋ฅผ ๋ด์ผ ํ์ ํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
| ๊ฐ๋ | ๊ท์น |
|---|---|
| ํญ์ | invalid-syntax, unknown-token, hardcoded-color, hardcoded-length, unknown-prop, runtime-value |
files ๋ฒ๋ค์์๋ง |
file-placement, one-component-per-file, client-boundary, inline-style, react-query-states |
file-placement๋ ํ๋ ์์ํฌ๊ฐ ๊ฐ์ ํ๋ ํ์ผ์ ๋ฉด์ ํฉ๋๋ค. app/layout.tsx์ default export๊ฐ ์์ผ๋ฉด ๋น๋๊ฐ ๊นจ์ง๋ฏ๋ก, ๊ทธ๊ฑธ ์ง์ ํ๋ ๊ฒ์ ๋ฐ๋ฅผ ์ ์๋ ๊ถ๊ณ ์ด๊ณ warning์ด๋ผ strict: true์์ ๋ฉ์ฉกํ Next.js ์ฑ์ ํ๋ฝ์์ผฐ์ต๋๋ค. ๋ฉด์ ๋์์ App Router์ segment ํ์ผ(page, layout, loading, error, global-error, not-found, template, default)๊ณผ metadataยท์ด๋ฏธ์ง ๊ท์ฝ(sitemap, robots, manifest, icon, apple-icon, opengraph-image, twitter-image), Pages Router์ _appยท_document, ๊ทธ๋ฆฌ๊ณ middleware์
๋๋ค. ๊ทธ ์ด๋ฆ์ด ์์ฝ๋ ๋๋ ํฐ๋ฆฌ ์์์๋ง ๋ฉด์ ๋๋ฏ๋ก src/components/error.tsx๋ ์ฌ์ ํ ์ผ๋ฐ ๋ชจ๋๋ก ํ์ ํฉ๋๋ค.
ํ์ด์ง ์ด๋ฆ ๊ท์น์ ๋ผ์ฐํธ๊ฐ ์ค์ ๋ก ๋ ๋ํ๋ ์ปดํฌ๋ํธ, ์ฆ default export๋ง ๋ด
๋๋ค. ์์ ์๋ ํ์ผ ์์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ๊ฒ์ฌํด์, ์ฌ๋ฐ๋ฅธ export default function NoticePage๋ฅผ ๊ฐ์ง ํ์ผ์ด ๊ทธ ์์ PageContent ํฌํผ ๋๋ฌธ์ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์์ต๋๋ค. page๊ฐ ๋ผ์ฐํธ ์ด๋ฆ์ธ ๊ฒ๋ ๋ผ์ฐํฐ ๋๋ ํฐ๋ฆฌ ์์์๋ฟ์ด๋ผ, src/components/page.tsx๋ ๋ผ์ฐํธ๋ก ํ์ ํ์ง ์์ต๋๋ค.
one-component-per-file๋ ๋ผ์ฐํธ segment ํ์ผ์์๋ ์ ์ฉํ์ง ์์ต๋๋ค. ๊ทธ ํ์ผ์ ์ปดํฌ๋ํธ ๋ชจ๋์ด ์๋๋ผ ํ๋ ์์ํฌ ์ง์
์ ์ด๋ผ ์์ ํฌํผ๋ฅผ ์ด๋ฆ์ผ๋ก importํ ์ ์๋ ๊ณณ์ด ์๊ณ , ๊ทธ๋์ "๊ฐ ์ปดํฌ๋ํธ๋ฅผ ์๊ธฐ ํ์ผ๋ก ์ฎ๊ธฐ๋ผ"๊ฐ ์๋น์์๊ฒ ์ฃผ๋ ๊ฒ์ด ์์ต๋๋ค. ๊ฒ๋ค๊ฐ ๋ฐ๋ก ์ ๊ท์น๊ณผ ์ถฉ๋ํ์ต๋๋ค โ src/app/ ์๋ ํ์ ํ์ผ์ ๊ทธ ์์ฒด๋ก ์๋ฐ์ด๋ฏ๋ก, ํ ๋ผ์ฐํธ๋ง ์ฐ๋ ํฌํผ๋ฅผ ์ฎ๊ธธ ์ ์๋ ๊ณณ์ด src/components/๋ฟ์ด์์ต๋๋ค. ์ผ๋ฐ ์ปดํฌ๋ํธ ํ์ผ์ ๊ทธ๋๋ก์ด๊ณ , ๋น๊ณต๊ฐ ํฌํผ๋ ์ฌ์ ํ ์ก์ต๋๋ค.
tsx๋ files๋ ์ฃผ์ง ์์ ํธ์ถ์ ๊ฑฐ์ ํฉ๋๋ค. ์์ ์๋ ๋น ๋ฌธ์์ด์ ๊ฒ์ฆํด ok: true, okReason: "clean"์ ๋๋ ค์คฌ๋๋ฐ, ๋ณด๋ธ ์ ๋ ์๋ ์ฝ๋๊ฐ ํต๊ณผํ ๊ฒ์ฒ๋ผ ์ฝํ์ต๋๋ค.
clean๊ณผ clean-unverified-tokens๋ ๋ค๋ฆ
๋๋ค. ์์ ๊ฒ์ฌํ๊ณ ๋ฌธ์ ๊ฐ ์์๋ค๋ ๋ป์ด๊ณ , ๋ค๋ ์๋ฐ์ด ์์์ง๋ง devup.json์ ์ฐพ์ง ๋ชปํด ์ด ์ฝ๋๊ฐ ์ด $token์ ์ ์ด์ ๊ฒ์ฌํ์ง ๋ชปํ๋ค๋ ๋ป์
๋๋ค.
ํ๋ก์ ํธ ๋ฃจํธ์ devup.json์ด ์์ผ๋ฉด ๊ทธ๊ฒ์ ์๋๋ค. ์์ผ๋ฉด ํ๋ก์ ํธ ์์ 4๋จ๊ณ๊น์ง ์ฐพ๋๋ฐ, ํ๋ณด๊ฐ ๋ ์ด์์ด๋ฉด ์๋ฌด๊ฒ๋ ๊ณ ๋ฅด์ง ์๊ณ ๊ฑฐ์ ํฉ๋๋ค. ๋ฃจํธ์ ์๋ ์ฌ๋ฌ ํ
๋ง ์ค ๋ฌด์๋ ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ์ง๋ฐฐํ์ง ์์ผ๋ฏ๋ก "๊ทธ" ํ
๋ง๋ผ๋ ๊ฒ์ด ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค.
์์ ์๋ ์ ๋ ฌ ์์์ ์ฒซ ๋ฒ์งธ๋ฅผ ์กฐ์ฉํ ๊ณจ๋๊ณ , ๊ทธ ๊ฒฐ๊ณผ ๋ชจ๋
ธ๋ ํฌ ๋ฃจํธ๋ฅผ ๋๊ธฐ๋ฉด apps/front ์ฝ๋๋ฅผ apps/admin ํ
๋ง๋ก ๊ฒ์ฆํด ์ค์ฌํ๋ ํ ํฐ์ unknown-token error๋ก ๋จ์ ํ๊ณ ๋ค๋ฅธ ์ฑ์ ํ ํฐ์ ๊ณ ์น๋ผ๊ณ ์ ์ํ์ต๋๋ค.
์ง๊ธ์ themeAvailable: false์ ํจ๊ป themeGuardrail.candidateProjectRoots๊ฐ ํ๋ณด๋ง๋ค devupJsonยทprojectRootยทauthorityยทappliesTo๋ฅผ ๋๋ ค์ค๋๋ค. ๊ฑฐ๊ธฐ ์ ํ projectRoot ๊ฐ์ ๊ทธ๋๋ก ๋๊ฒจ ๋ค์ ๋ถ๋ฅด๋ฉด ๋ฉ๋๋ค. ํ๋ณด๊ฐ ํ๋๋ฟ์ด๋ฉด ์์ ์ฒ๋ผ ๊ทธ๋๋ก ํด์ํ๋ฏ๋ก ๋จ์ผ ํจํค์ง ๋ ์ด์์์ ๋์์ ๋ฐ๋์ง ์์ต๋๋ค.
ํ๋์ฝ๋ฉ ๊ฐ์ ํ์ ๊ธฐ์ค์ ์ผ์นํ๋ ํ ํฐ์ด ์ค์ ๋ก ์๋์ง์
๋๋ค. ์์ผ๋ฉด warning์ผ๋ก ์ฌ๋ฆฌ๊ณ ํ ํฐ ์ด๋ฆ์ ์๋ ค์ค๋๋ค. ์์ผ๋ฉด info๋ก ๋ฎ์ถ๊ณ ๊ถ๊ณ ์์ด ์ฌ์ค๋ง ์ ์ผ๋ฉฐ strict ๋ชจ๋์์๋ ์คํจ์ํค์ง ์์ต๋๋ค. ๊ทธ๋์ length ํ ํฐ์ด ํ๋๋ ์๋ ํ
๋ง๊ฐ "ํ ํฐ์ ์ฐ๋ผ"๋ ๊ถ๊ณ ๋ฅผ ๋ฐ๋ ์ผ์ ์๊ณ , ๋์ themeNotes๊ฐ "์ด ํ
๋ง์๋ length ํ ํฐ์ด ์๋ค"๊ณ ํ ๋ฒ ์๋ ค์ค๋๋ค.
checkedTokens์ availableTokenCount๋ ์๋ก ๋ค๋ฅธ ๊ฒ์ ์
๋๋ค โ ์์ ์ด TSX๊ฐ ์ฐธ์กฐํ $token ์, ๋ค๋ devup.json์ด ์ ์ํ ํ ํฐ ์์
๋๋ค. ๋น์จ์ด ์๋๋๋ค. tokens๊ฐ ๊ทธ ์ฌ์ค์ ์ด๋ฆ์ผ๋ก ๋ค์ ๋งํด ์ค๋๋ค.
devup_figma_export๊ฐ ๋๋ ค์ค sourceMap์ ๊ทธ๋๋ก sourceMap์ผ๋ก ๋๊ธฐ๋ฉด, ๊ฐ ์๋ฐ์ ๊ทธ ์์ฑ์ ๋ง๋ Figma ๋
ธ๋์ ํ๋๊ฐ source[](์ต๋ 3๊ฐ: nodeId, property, generatedProperty, resolution)๋ก ๋ถ์ต๋๋ค. ํญ๋ชฉ์ ํ๋ฉด ํ๋๋ฉด tsx, Section ํ๋ ์์ด๋ฉด entries ์๋์ ์๊ณ ๋ ๋ค ๋ฐ์ต๋๋ค. tsx์ componentTsx๋ฅผ ํจ๊ป ์์ฒญํ๋ค๋ฉด ๊ฒ์ฆํ๋ ์ฝ๋์ sourceMap.byOutput.<output>์ {"tsx": [...]}๋ก ๋๊ธฐ์ธ์. ๋ฐ์ดํธ ์คํ์
์์ด elementIndex์ ์์ฑ ์ด๋ฆ์ผ๋ก ์์ต๋๋ค โ sourceMap ํญ๋ชฉ๋ ๊ฐ์ ๋ฒํธ์ elementIndex๋ฅผ ๊ฐ์ต๋๋ค. elementIndex๊ฐ ์๋ ์์ sourceMap์ด๋ฉด sourceMapLink.state๊ฐ unavailable์
๋๋ค. files ๋ฒ๋ค๊ณผ ํจ๊ป ๋๊ฒจ๋ unavailable์
๋๋ค โ ๋ฒ๋ค์ ํ์ผ๋ง๋ค ์์๋ฅผ 0๋ถํฐ ์ธ๋ฏ๋ก, ํ TSX์ sourceMap์ ์ด๋ ํ์ผ์ ์๋ฐ์ ์ด์์ง ์ ํ ์ ์์ต๋๋ค.
์ด์ด์ง์ง ์์ ์๋ฐ์ unlinkedViolations๋ก ์ธ๊ณ ์ด์ ๋ฅผ ๋ถ์
๋๋ค. sourceMap์ด ๊ทธ ์์ฑ์ ๋งคํํ์ง ์์ ๊ฒฝ์ฐ์ด๊ณ , export๋ ๊ทธ๋ฐ ์์ฑ์ projectionIssues(DEVUP_CODEGEN_PROPERTY_UNMAPPED)์ ๊ฐ์ elementIndex๋ก ๋ณด๊ณ ํฉ๋๋ค. WQUW-151 ์ค์ ํ๋ฉด์์๋ 161๊ฑด ์ค 158๊ฑด, 300๊ฑด ์ค 296๊ฑด์ด ์ด์ด์ก๊ณ , ๋๋จธ์ง๋ ์ฌ๋ฌ ์คํ์ผ ๊ตฌ๊ฐ์ ๊ฐ์ง ํ
์คํธ ์์ชฝ <Text>์ color์์ต๋๋ค.
layoutRisks๋ ์์น ์ง์ ๋ ํ์ ๋ค์ด ๊ฐ๊ฐ ์ด๋ ๊ฐ์ฅ์๋ฆฌ์ ๊ณ ์ ๋๋์ง ์ฝ์ด ์ธ ๊ฐ์ง๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
anchor-mismatch: ์น ํด์ง ํ์ ์์ ๊ทธ๋ ค์ก๋๋ฐ ๋ค๋ฅธ ๊ฐ์ฅ์๋ฆฌ์ ๊ณ ์ ๋ ์์fixed-length-line-mask: ๋์ด๋๋ ์์ ์์์ ๊ทธ๋ฆฐ ๊ธธ์ด๋ฅผ ์งํค๋ mask ์ง์right-aligned-but-held-leftยทcentered-but-held-left: ํญ์ด viewport๋ฅผ ๋ฐ๋ผ๊ฐ๋ ์ปจํ ์ด๋ ์์์ ์ผ์ชฝ์ ๊ณ ์ ๋์ง๋ง ์ค๋ฅธ์ชฝ ๊ฐ์ฅ์๋ฆฌ๋ ๊ฐ์ด๋ฐ์ ๊ทธ๋ ค์ง ์์. ์์ผ๋ก ๋ํ ์ค์ ๊ณต์ง ํ๋ฉด์์ Chromium์ด 408px ์ด๊ธ๋จ์ ์ฐ ๋ฐ๋ก ๊ทธ ๊ฒฝ์ฐ์ ๋๋ค. ๋ฐ๋ผ๊ฐ๋ค๊ณ ๋ณด๋ ์ปจํ ์ด๋๋ ๋ณด์์ ์ผ๋ก ๊ณ ๋ฆ ๋๋ค: px ํญ์ด ์๋ ๋ฃจํธ, ๊ทธ๋ฆฌ๊ณ ๊ฐ๋ก ์ฌ๋ฐฑยทpadding ์์ด ๊ทธ ์์ ๊ฝ ์ฑ์ฐ๋ in-flow ์์๋ฟ์ ๋๋ค. ์ค์ ํ๋ฉด 17๊ฐ๋ฅผ export ๊ทธ๋๋ก ๊ฒ์ฌํ์ ๋๋ ํ๋๋ ๋ณด๊ณ ๋์ง ์์์ต๋๋ค.
๋ถ๋ชจ๊ฐ px ํญ์ ๋งํ์ง ์์ผ๋ฉด referenceWidth๋ก ๊ณ์ฐํ๊ณ , ๊ทธ๊ฒ๋ ์์ผ๋ฉด ์ถ์ธกํ์ง ์๊ณ verificationScope.static.groupsWithoutReferenceWidth๋ก ์
๋๋ค.
์ ๊ฒ์ฌ๋ ok, okReason, strict ํ์ ์ ๋ฐ๊พธ์ง ์์ต๋๋ค. ๊ธฐ์กด info๊ฐ error๋ก ๋ฐ๋๋ ์ผ๋ ์์ต๋๋ค โ ๊ฒฐ๊ณผ๋ violations ๋ฐ์ ๋ณ๋ ํค์๋ง ์ค๋ฆฝ๋๋ค.
๋น์ฉ: ์๋ฐ๋ง๋ค elementIndexยทelementยทattribute๊ฐ ๋ถ์ด ๊ธฐ๋ณธ ์๋ต์ violations๊ฐ ์ฝ 19% ์ปค์ง๊ณ (WQUW-151์ 300๊ฑด ํ๋ฉด์์ 88.6 โ 105.5 KB), ๊ฒ์ฆ ์๊ฐ์ 1.12 โ 1.36 ms๊ฐ ๋์ต๋๋ค. sourceMap ์ฐ๊ฒฐ์ ๋๊ธธ ๋๋ง ์ผ์ด๋๋ฉฐ, ๊ฐ์ ํ๋ฉด์์ ์์ฒญ 176 KBยท์๋ต 155 KBยทstdio ์๋ณต 12.6 ms(๋๊ธฐ์ง ์์ผ๋ฉด 5.2 ms)์์ต๋๋ค.
๋ ์ด์ด๋ db-entity, entity-route, route-openapi, openapi-client ๋ท์ด๋ฉฐ ์๋ตํ๋ฉด ์ ๋ถ ์คํํฉ๋๋ค. ์ปดํ์ผ๋ฌ๊ฐ ์๋๋ผ ํ
์คํธ/JSON ํด๋ฆฌ์คํฑ์ด๋ฏ๋ก ๋ชจ๋ ๋ฐ๊ฒฌ์ confidence๋ฅผ ๋ฌ๊ณ ๋์ค๊ณ , ๊ทธ ๊ฐ์ low ๋๋ medium์
๋๋ค โ high๋ ์์ต๋๋ค.
_์ -์ ์ฐจ์ด๋ ๋์กฐํ ๋๋ง ์ ์ต๋๋ค. Vespera๊ฐ openapi.json์ kebab-case๋ฅผ ์ฐ๊ณ ์ฝ๋๋ ์๋ฌธ์ ์ฐ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ณด๊ณ ๋๋ ๋๋ฆฌํํธ๋ ๊ฐ ๋ ์ด์ด๊ฐ ์ค์ ๋ก ์ด ์ฒ ์ ๊ทธ๋๋ก ์ฃ๊ณ , ์ ๊ทํ๋ก ์ผ์น์ํจ ๊ฑด์๋ spellingNormalizedMatches๋ก ๋ฐ๋ก ๊ณต๊ฐํฉ๋๋ค. ๊ฐ์ ๋ผ์ฐํธ๊ฐ ์ธ๋์ค์ฝ์ดํ๊ณผ ํ์ดํํ์ผ๋ก ์์ชฝ์ ์ค๋ณต ์ ๊ณ ๋๋ ๋ฌธ์ ๋ ์ด ๋ฐฉ์์ผ๋ก ์ฌ๋ผ์ง๋๋ค.
actual.png ํ๋์ reference PNG ํ๋๋ฅผ ๋น๊ตํฉ๋๋ค. reference๋ ๊ฒฝ๋ก๋ก ์ฃผ๊ฑฐ๋ artifactId๋ก ์บ์๋ ๊ฒ์ ๊ฐ๋ฆฌํต๋๋ค. ๊ธฐ๋ณธ threshold๋ 0.005(0.5%)์ด๊ณ , ์ํ๋ฉด diff PNG๋ฅผ auto | inline | resource๋ก ๋ฐ์ต๋๋ค.
์ด ๋๊ตฌ๋ ์ค์ค๋ก ๊ทธ๋ฆฌ์ง ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ์ง๋, ๋ช
๋ น์ ์คํํ์ง๋ ์์ต๋๋ค. actual.png๋ ์๋น์ repository๊ฐ ์๊ธฐ fontยทassetยทDevupUI ํ๊ฒฝ์์ ๋ง๋ค์ด ๊ฑด๋ค๋ ๊ฒ์ด๊ณ , ์ฌ๊ธฐ์๋ ์์ Rust๋ก ํฝ์
๋ง ๋น๊ตํฉ๋๋ค. ๊ฒฝ๋ก๋ allowlist ์์ด์ด์ผ ํฉ๋๋ค.
๊ทธ๋์ ํต๊ณผ ์ฌ๋ถ๋ณด๋ค ํ์ ๊ทผ๊ฑฐ๊ฐ ์ค์ํฉ๋๋ค. renderer ํ๊ฒฝ manifest๊ฐ ์๊ฑฐ๋ ๋ถ์์ ํ๊ฑฐ๋ ์ ํจํ์ง ์์ผ๋ฉด, ํฝ์
์ด ์ผ์นํด visual.passed๊ฐ true์ฌ๋ ์ต์ข
ํ์ ์ inconclusive์
๋๋ค โ ๋ฌด์์ผ๋ก ๊ทธ๋ฆฐ ๊ทธ๋ฆผ์ธ์ง ๋ชจ๋ฅด๋ ์ฑ "๊ฐ๋ค"๊ณ ๋งํ๋ ๊ฒ์ ๋ณด์ฆ์ด ์๋๊ธฐ ๋๋ฌธ์
๋๋ค.
์๋ฒ๊ฐ ์ค์ค๋ก ์ฆ๋ช
ํ ์ ์๋ ๊ฒ์ ์๋ฒ๊ฐ ์ฑ์๋๋ค. reference๋ฅผ artifactId๋ก ์ฃผ๊ณ manifest์ referenceResource๋ฅผ ๋น ๋จ๋ฆฌ๋ฉด, ์ด ์๋ฒ๊ฐ Figma์์ ๋ฐ์ ๋ค๊ณ ์๋ ๊ทธ PNG์ ํด์๋ก ์ฑ์ฐ๊ณ environment.filledByServer์ ์ ์ต๋๋ค. ๊ฒฝ๋ก๋ก ์ค reference๋ ์๋น์์ ํ์ผ์ด๋ผ ์ฑ์ฐ์ง ์์ต๋๋ค. ๋๋จธ์ง manifest ํญ๋ชฉ์ ์ฌ์ ํ ์๋น์๊ฐ ๋งํด์ผ ํฉ๋๋ค.
ํ๋ฉด๋ถํฐ ์ปฌ๋ผ๊น์ง ํ ๊ธฐ๋ฅ์ ์ฌ๋ผ์ด์ค๋ฅผ ์ฝ์ด acceptance matrix๋ก ๋๋ ค์ค๋๋ค. ์ถ๋ฐ์ ์ ๋ช
์์ anchor์ฌ์ผ ํฉ๋๋ค โ routePath, figmaNodeId ๋๋ artifactId, operationId ๋๋ apiPath+method, componentPath, tableName.
์๊ตฌ์ฌํญ ์ฐ๋ฌธ์ anchor๊ฐ ์๋๋๋ค. "๋ก๊ทธ์ธ ํ๋ฉด ๋ง๋ค์ด์ค" ๊ฐ์ ๋ฌธ์ฅ๋ง ์ฃผ๋ฉด ์ถ์ธกํด์ ๋ตํ์ง ์๊ณ ๊ฑฐ์ ํฉ๋๋ค. ๊ทผ๊ฑฐ ์์ด ์ด์ด ๋ถ์ธ ์ฌ๋ผ์ด์ค๋ ํ๋ ธ์ ๋ ์ด๋์ ํ๋ ธ๋์ง ์ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ฐ hop์ ๊ทผ๊ฑฐ๊ฐ ์๊ฑฐ๋ UNVERIFIED๋ก ํ์๋๋ฉฐ, ์์ฑ ์ฐ์ถ๋ฌผ์ ์์ ๊ถ(๊ทธ ํ์ผ์ ์์ผ๋ก ๊ณ ์น๋ฉด ์ ๋๋์ง), ์์๊ฐ ๋งค๊ฒจ์ง UI ์ฌ์ฌ์ฉ ํ๋ณด, ๋์์ธ์ ๋ฌธ์์ด๊ณผ request/response ํ๋์ ๋์, ํ์ ์ํ ์ปค๋ฒ๋ฆฌ์ง, ๊ทธ๋ฆฌ๊ณ ์๋ฆผ์ด ์ผ์ด๋ฌ๋ค๋ฉด ๊ทธ ์ํ์ ํจ๊ป ๋ณด๊ณ ํฉ๋๋ค. requirement์ acceptanceCriteria๋ฅผ ๋๊ธฐ๋ฉด ํด์ํ์ง ์๊ณ ๊ทธ๋๋ก ์ค์ด ๋๋ ค์ค๋๋ค.
์ ์ ํ์ฑ์ ๋ฐํ์ ๋์์ ์ฆ๋ช ํ์ง ์์ต๋๋ค. ์ด ๋๊ตฌ๊ฐ "์ฐ๊ฒฐ๋ผ ์๋ค"๊ณ ๋งํ๋ ๊ฒ์ ์ฝ๋๊ฐ ๊ทธ๋ ๊ฒ ์ ํ ์๋ค๋ ๋ป์ด์ง, ์คํํ์ ๋ ๊ทธ๋ ๊ฒ ๋์ํ๋ค๋ ๋ป์ด ์๋๋๋ค.
์์ฑํ ํ๋ฉด์ด ๊ทธ๋ฆฐ ํญ์ด ์๋ ํญ์์ ์ด๋ป๊ฒ ๊ทธ๋ ค์ง๋์ง๋ ๋ ๋ํด ๋ด์ผ ์๋๋ค. ์ด ๋๊ตฌ๋ ๊ทธ ์คํ์ ๊ณํํ๊ณ ๊ฒ์ฆํ๋ฉฐ, ์คํ์ ์๋น์ ํ๋ก์ ํธ๊ฐ ํฉ๋๋ค. ์๋ฒ๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ์ง๋, ๋ช
๋ น์ ์คํํ์ง๋, URL์ ๊ฐ์ ธ์ค์ง๋ ์์ต๋๋ค. Playwright๋ MCP ์๋ฒ์ ์์กด์ฑ์ด ์๋๋ผ ์๋น์๊ฐ ์ค์นํ๋ ์คํ๊ธฐ harness/runtime-audit์ ์์กด์ฑ์
๋๋ค.
planโ viewport, ํ๋ฉด(routePath, ๋๋ role๊ณผ ์ ๊ทผ ๊ฐ๋ฅํ ์ด๋ฆยทtestIdยทํ ์คํธ๋ก ์์๋ฅผ ์ฐพ๋clickยทfill๋จ๊ณ), ๊ธฐํ ๊ฒ์ฌ(no-horizontal-overflow,contained,aligned,spans,visible)๋ฅผ ๋ด์ ์ ์ธํ ๊ณํ์ ๊ฒ์ฆํด ํ์ฉ๋ root ์๋outputPath์ ์๋๋ค. ๋ชจ๋ ๊ฐ์ฒด๊ฐ ๋ชจ๋ฅด๋ ํ๋๋ฅผ ๊ฑฐ์ ํ๋ฏ๋ก ๋ช ๋ น์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ค์ ์๋ฆฌ๊ฐ ์๊ณ , URL์ ์๊ฒฉ์ฆ๋ช ์๋ http(s)์ฌ์ผ ํ๋ฉฐ, ์คํ ์คallowedOrigins๋ฐ์ผ๋ก ๊ฐ๋ ์์ฒญ์ ๋งํ๋๋ค.planId๋ ์ ๊ทํํ ๊ณํ์ SHA-256์ ๋๋ค.- ์คํ โ ์๋น์ ํ๋ก์ ํธ์์
node run.mjs --plan plan.json --out out. viewport๋ง๋ค ํ๋กํยท์ฟ ํคยท์ ์ฅ์ ์๋ ์ ๋ธ๋ผ์ฐ์ context๋ฅผ ์ฐ๊ณreport.json๊ณผ ์คํฌ๋ฆฐ์ท์ ์๋๋ค. ์๊ฐ ์ํ์ ๊ฑธ๋ฆฌ๊ฑฐ๋ ์ค๋จ๋๋ฉด ๋๋ธ ๋งํผ์partialยทaborted๋ก ์ฐ๋ฉฐ, ์ด์ด์ ์คํํ์ง๋ ์์ต๋๋ค. ingestโ ๋ณด๊ณ ์๋ฅผ ๊ทธ๋๋ก ๋ฏฟ์ง ์์ต๋๋ค. ๊ณํ id์ ๊ณํ ํ์ผ ํด์์ ๋ฌถ์ด์ง ์์ ๋ณด๊ณ ์๋ ๋ฐ๋ ์คํฌ๋ฆฐ์ท์rejected(plan-edited,report-for-another-plan,plan-file-differs,artifact-changed)์ด๊ณ , ๋ชจ๋ ๊ฐ์๋ฅผ ํญ๋ชฉ์์ ๋ค์ ์ ๋๋ค. ์๋ ํญ๋ชฉ์not-run์ด์ง ํต๊ณผ๊ฐ ์๋๋ฉฐ, ํ๊ฒฝ ์ค๋ฅ(์ฝ์ยท๋คํธ์ํฌ ์ค๋ฅ, ๋น ์ง ํฐํธ, ๋ค๋ฅธ viewport ํญ)๊ฐ ์์ผ๋ฉด ์คํจ๋inconclusive์ ๋๋ค. ์๋ต์evidence๊ฐ ์๋ฒ๊ฐ ์ง์ ํ์ธํ ๊ฒ๊ณผ ์คํ๊ธฐ๊ฐ ์ ๊ณ ๋ง ํ ๊ฒ์ ๋๋๋๋ค.
์๊ฐ ์๋ณธ์ Figma ํ๋ ์์ ๊ทธ๋ฆฐ ํญ์๋ง ์์ต๋๋ค(figmaReferences[].visualOriginalAt). ๊ทธ ํญ์ ์คํฌ๋ฆฐ์ท์ devup_visual_compare๋ก ๋น๊ตํ๊ณ , ๋๋จธ์ง ํญ์์๋ ๋ ์ด์์ ๊ฒ์ฌ๋ง ์๋ฏธ๊ฐ ์์ต๋๋ค.
ingest๋ ๊ทธ๋ฆฐ ํญ์์ ์ฐํ ๊ฒ์ฆ๋ ์คํฌ๋ฆฐ์ท๋ง๋ค ๋ฐ๋ก ๋ถ๋ฅผ ์ ์๋ devup_visual_compare ํธ์ถ์ visualComparisons[]๋ก ๋๋ ค์ค๋๋ค. audit์ด ์๋ ๊ฒ โ ์คํฌ๋ฆฐ์ท ๊ฒฝ๋ก(actualยทactualPng), viewport, ์คํ๊ธฐ๊ฐ ์ ๊ณ ํ ๋ธ๋ผ์ฐ์ ๋ฒ์ (renderer), OSยทlocaleยทtimezone, ๊ทธ run์ ํ๊ฒฝ ์ค๋ฅ๊ฐ ์์๋์ง(environmentStatus) โ ์ ์ฑ์์ ธ ์๊ณ , ์๋น์๋ง ๋งํ ์ ์๋ ๊ฒ(reference์ artifactId, tsxResource, themePath, assetDirectory, devupUiVersion, fontManifest)์ consumerMustAdd๊ฐ ์ด๋ฆ์ผ๋ก ๋๋๋ค. ๊ทธ๋๋ก ๋ถ๋ฌ๋ inconclusive๊ฐ ๋ ์ฌ์ โ scale 1์ด ์๋ ์บก์ฒ, viewport๋ณด๋ค ๊ธด ํ์ด์ง์ full-page ์บก์ฒ, ํ๊ฒฝ ์ค๋ฅ โ ์ blockers๊ฐ ๋ฏธ๋ฆฌ ๋งํฉ๋๋ค. ์์ ์๋ audit ์คํฌ๋ฆฐ์ท์ ๋น๊ต๊ธฐ์ ๋ฃ์ผ๋ฉด ์ด ํญ๋ชฉ๋ค์ด ๋น์ด ์ธ์ ๋ inconclusive์์ต๋๋ค.
360ยท768ยท1200ยท1440 ํญ ร ํ๋ฉด 2๊ฐ ร ๊ฒ์ฌ 8๊ฐ ๊ณํ์์ plan์ 4.5 ms(structured content 9.2 KB), ์คํฌ๋ฆฐ์ท 8์ฅ์ ํ์ธํ๋ ingest๋ 18.9 ms(12.5 KB)์์ต๋๋ค. ์ค๋จ๋ ์คํ ์ด์ด๊ฐ๊ธฐ(resume), ๋ถ์ํจ๊ณผ๊ฐ ์๋ ๋จ๊ณ, ๋ฐ๋ชจ ๋
นํยทTTSยท์๋ง, ์ธ๊ณ ํจํค์ง๋ ๊ตฌํํ์ง ์์์ต๋๋ค.
"์ด ๋์์ธ์ ๊ตฌํํด์ค"๋ฅผ ๋ฐ์ ์์ด์ ํธ๊ฐ ๊ณง๋ฐ๋ก ํ์ด์ง๋ฅผ ์ฐ๋ฉด, ์ด๋ Figma ํ๋ฉด์ด ์ด๋ URL์ด ๋๋์ง ์ฌ์ฉ์๋ ๋๋ด ๋ชจ๋ฆ ๋๋ค. ๊ทธ๋์ ์์๋ฅผ ๊ณ ์ ํฉ๋๋ค.
draftโ Section/frame ๋งํฌ(๋๋ ๋ธ๋ฆฌ์ง ์ ํ, ๋๋ ์์devup_figma_explore์screens)์projectRoot๋ฅผ ๋ฐ์, ์ด๋ฆ์ด ๊ฐ์ ํ๋ ์์ ๊ทธ๋ฃน์ผ๋ก ๋ชจ์ผ๊ณ (ํ ํ์ด์ง์ธ์ง ์ฌ๋ฌ ํ์ด์ง์ธ์ง๋ ๊ทธ๋ฃน๋ง๋ค ๋ฌป๋, ๊ฐ์ Section ์์ ์ฌ๋ฌ ํญ์ด๋ฉด "One responsive page", ๋ค๋ฅธ Section์ด๋ฉด "Separate pages"๋ฅผ ์ถ์ฒ), ํ๋ฉด๋ง๋คproposedRouteยทrouteEvidenceยทexistingFileยทsharedPartsยทopenDecisions๋ฅผ ๋ด์.devup/screen-plan.json๊ณผ ๊ฐ์ ๋ด์ฉ์.devup/screen-plan.md๋ฅผ ์๋๋ค. ๊ทผ๊ฑฐ ์๋ ๋ผ์ฐํธ๋proposedRoute: null,routeEvidence: "UNVERIFIED"์ด๊ณ ์ง๋ฌธ์ด ๋ฉ๋๋ค. ์๋ต์questions๋ ์ง๋ฌธ ๋๊ตฌ(OpenCodequestion, Claude CodeAskUserQuestion)์ ๊ทธ๋๋ก ๋ฃ๋ ๋ชจ์ โid, 30์ ์ดํheader,question, ์ถ์ฒ์ ๋งจ ์์ ๋๊ณ " (Recommended)"๋ฅผ ๋ถ์ธoptions[{label, description}],multipleโ ์ด๊ณ , ํ ๋ฒ์ ์ต๋ 4๊ฐ์ฉ ๋๋questionRounds์askInstruction์ด ํจ๊ป ์ต๋๋ค. ๋ผ์ด๋๋ ๊ตฌํ ์ ์ ์ฐ๋ฌ์ ๋ชจ๋ ๋ฌป์ต๋๋ค.when์ด ๋ถ์ ์ง๋ฌธ(์: "Separate pages"๋ฅผ ๊ณ ๋ฅธ ๊ทธ๋ฃน์ ํ๋ ์๋ณ ๋ผ์ฐํธ, "Review individually"๋ฅผ ๊ณ ๋ฅธ ์ด๋ฆ ์ถ์ ํญ๋ชฉ)์ ๊ทธ ๋ต์ผ ๋๋ง ๋ฌป์ต๋๋ค. ๋ ์ด์ด ์ด๋ฆ์ผ๋ก ์ถ์ ํ ๋ผ์ฐํธ๋ "Accept all (Recommended)" / "Review individually" ํ ์ง๋ฌธ์ผ๋ก ๋ฌถ์ด ํ์ธํฉ๋๋ค.confirmโ ํด๋นํ๋ ์ง๋ฌธ id๋ณ ๋ต์ ํ ๋ฒ์ ๋ฐ์ต๋๋ค. ํ๋๋ผ๋ ๋น ์ง๋ฉด ๋น ์ง id๋ฅผ ์ด๋ฆ์ผ๋ก ๋๋ฉฐ ๊ฑฐ์ ํ๊ณ , ์๋ฌด๊ฒ๋ ๋ฐ๊พธ์ง ์์ต๋๋ค. ํ์ ๋ค ๊ตฌํ ์ค์๋ ์ฌ์ฉ์์๊ฒ ์๋ฌด๊ฒ๋ ๋ฌป์ง ์์ต๋๋ค. ์๋ก ์๊ธด ๊ฒฐ์ ์ ์ถ์ฒ์์ด๋ ๊ฐ์ฅ ๋ณด์์ ์ธ ์ ํ์ ๋ฐ๋ฅด๊ณassume์ผ๋ก ๊ณํ์assumptions์ ๋จ๊ธฐ๋ฉฐ,status์ ์ต์ข ๋ณด๊ณ ์ ํจ๊ป ๋์ต๋๋ค.statusโ ํ์ ๋ ๊ณํ์devup_project_context scope:"routes"์ ์ค์ ํ์ด์ง์, ์ ํ์ ์ผ๋กdevup_runtime_audit์ plan/report์ ๋์กฐํฉ๋๋ค. URL๋ง๋ค ๊ตฌํ ์ฌ๋ถ์ ํญ๋ณpassยทfail(๊ฐ๋ก ๋์นจ, ํ์ด์ง ์ค๋ฅ ๋ฑ ์ด์ )ยทnot-run์ ๋ด๊ณ , ์์ฝ ํ ์ค(7 URLs: 5 implemented, 3 verified at all widths, /about overflows at 390)๊ณผURL | Figma screen | file | status | widths verified | screenshotsํ๋ฅผ ์ค๋๋ค. audit ํญ๋ชฉ์ด ์๋ ํญ์not-run์ด์งpass๊ฐ ์๋๋๋ค.
devup_figma_export๋ projectRoot๊ฐ ์๊ณ ํ์ด์ง๋ฅผ ์ฐ๋ ํธ์ถ(pageScaffold write, app/ ์๋ outputPaths, outputPaths๊ฐ ์๋ ์ฌ๋ฌ ํ๋ ์ยทallScreens)์ธ๋ฐ ๊ทธ ํ๋ ์์ ๋ฎ๋ ํ์ ๊ณํ์ด ์์ผ๋ฉด ์ฐ์ง ์๊ณ status: "plan_required"์ devup_screen_plan draft๋ก ๊ฐ๋ nextAction์ ๋๋ ค์ค๋๋ค. ์ปดํฌ๋ํธ ํ๋, ์ฐ์ง ์๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๋ง์ง ์์ต๋๋ค. ํ์ ๊ณํ์ด ์์ผ๋ฉด pageScaffold.route๋ ๊ณํ์์ ๊ฐ์ ธ์ค๊ณ , ๋ค๋ฅธ ๋ผ์ฐํธ๋ฅผ ๋๊ธฐ๋ฉด routeMismatch๋ก ๊ฑฐ์ ํฉ๋๋ค. ์ ์ฒด ํ๋ฆ์ devup_skills๋ก ์ค์นํ๋ devup-implementation-plan ์คํฌ์ ์์ต๋๋ค.
๋์์ด๋๋ง๋ค ์ด๋ฆ ์ง๋ ๋ฐฉ์์ด ๋ฌ๋ผ์, ํ๋ก์ ํธ๋ ์ ํ์ ์ผ๋ก .devup/screen-plan.config.json์ modalKeywords(๋ชจ๋ฌ๋ก ๋ณผ ๋ ์ด์ด ์ด๋ฆ ๋จ์ด, ๊ธฐ๋ณธ ๋ชฉ๋ก์ ๋์ฒด), routeAliases(๋ ์ด์ด ์ด๋ฆ โ ๋ผ์ฐํธ), widthGrouping(ํ Section ์์ ์ฌ๋ฌ ํญ: responsive | separate | ask, ๊ธฐ๋ณธ ask), excludeKeywords(๊ตฌํ ๋์์ด ์๋ ์์ญ์ ํ์ํ๋ ๋จ์ด, ๊ธฐ๋ณธ ๋ชฉ๋ก์ ๋์ฒด), includeKeywords(์ด ๋จ์ด๊ฐ ๋ ์ด๋ฆ์ ์ ์ธํ์ง ์์)๋ฅผ ๋ ์ ์์ต๋๋ค. ์๋ ํญ๋ชฉ์ ๊ทผ๊ฑฐ๋ก ์ฐ์ด๊ณ ๊ทธ์ ํด๋นํ๋ ์ง๋ฌธ์ ๋์ ํฉ๋๋ค.
๋ฒ์๋ ๋งํฌ๊ฐ ๊ฐ๋ฆฌํจ ๋
ธ๋ ์๋๋ก๋ง ํ์ ํฉ๋๋ค. ํ์ผ ์ ์ฒด๋ ๋ค๋ฅธ ํ์ด์ง๋ก ๋ํ์ง ์๊ณ (outOfScope์ ๊ธฐ๋ก), ์ด๋ฆ์ด ํด์งํต/trash, ์์นด์ด๋ธ/archive, ๊ตฌ๋ฒ์ /old, ์ฌ์ฉ์ํจ/deprecated, ๋ฐฑ์
/backup, ์์
์ค/draft/WIP, ํ
์คํธ/test, sandbox, playground, ์ฌ๋ณธ/copy์ธ ํ์ด์งยทSectionยทํ๋ ์๊ณผ ์จ๊ฒจ์ง ํ๋ ์์ ์ง์ง ์์ต๋๋ค. ์ ์ธํ ๊ฒ์ excluded์ ์ด์ ์ ํจ๊ป ๋จ๊ธฐ๊ณ .md์ ํ์ธ ์ง๋ฌธ("These N were excluded ... Accept the exclusions (Recommended) / Review individually")์ ๋ณด์ฌ ์ค๋๋ค. ๋งํฌ ์์ฒด๊ฐ ๊ทธ๋ฐ ์์ญ ์์ ๊ฐ๋ฆฌํค๋ฉด ์ ์ธํ์ง ์๊ณ ํ ๋ฒ ๋ฌป์ต๋๋ค.
๊ฐ์ ์ด๋ฆ์ ํ๋ ์์ด ์๋ก ๋ค๋ฅธ Section์ ์์ผ๋ฉด(PC/Mobile์ฒ๋ผ ๊ธฐ๊ธฐ ์ด๋ฆ Section ํฌํจ) ์๋ฒ๊ฐ ์ ํ์ง ์์ต๋๋ค. Section ์ด๋ฆยทํ๋ ์ ์ด๋ฆยทํญยทnodeId์ ๊ด๋ จ ์์ด ๋ณด์ด๋ ์ด์ ๋ฅผ ์ ์ ์ง๋ฌธ์ผ๋ก "Separate pages: the sections are different pages", "One responsive page: the sections only split by device"(๋ชจ๋ Section ์ด๋ฆ์ด ๊ธฐ๊ธฐ ์ด๋ฆ์ผ ๋๋ง ์ถ์ฒ), "The Figma structure is wrong: I will fix it" ์ค์์ ๋ฌป์ต๋๋ค. ํ ํ๋ฉด์ด ์ฌ๋ฌ Section์ ๋๋ ๊ฒฝ์ฐ, Section ๋ฐ์ ํ๋ก ์๋ ํ๋ ์, ํ Section ์์ ๊ฐ์ ์ด๋ฆยท๊ฐ์ ํญ ์ค๋ณต๋ ๊ฐ์ "๊ณ ์น๊ฒ ๋ค" ์ ํ์ง๋ก ๋ฌป์ต๋๋ค. ๊ณ ์น๊ฒ ๋ค๊ณ ํ ํ๋ ์์ ์ง์ง ์๊ณ status์ ์ต์ข
๋ณด๊ณ ์ "Design fixes requested"์ ์ฎ๊ธฐ๊ฑฐ๋ ์ด๋ฆ์ ๋ฐ๊ฟ ํ๋ ์๊ณผ Section์ ์ ํํ ์ ์ต๋๋ค. ์์ด์ ํธ๋ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋๋จธ์ง๋ฅผ ๊ณ์ํฉ๋๋ค. export gate๋ ์ ์ธ๋์๊ฑฐ๋ ๋์์ธ ์์ ๋์์ธ ํ๋ ์์ ํ์ด์ง ์ฐ๊ธฐ๋ฅผ ๊ฐ์ (assume)์ด ์์ด๋ ๊ฑฐ์ ํฉ๋๋ค.
์ฌ์ดํธ ์์ฑ๋: Figma๊ฐ ๊ทธ๋ฆฐ ๊ฒ๋ง์ผ๋ก ๋ง๋ ์ฌ์ดํธ๋ hoverยทfocusยท์ ํยทmetadataยท์์ด์ฝ์ด ์์ด "์ฃฝ์ด" ๋ณด์
๋๋ค. ๊ทธ๋์ ๊ณํ์ ๋๋ก ๋๋๋๋ค. ์์ด์ ํธ๊ฐ ๋ฌป์ง ์๊ณ ์ฑ์ฐ๋ ๊ฒ(defaults์ ๊ธฐ๋ก, ์ต์ข
๋ณด๊ณ ์ ํ์): ๋ชจ๋ ๋งํฌยท๋ฒํผยท์นด๋ยทํญยท์
๋ ฅ์ _hoverยท_focusVisibleยท_activeยท_disabledยทcursor(Figma ์ํ variant ์ฐ์ , ์์ผ๋ฉด ๊ธฐ์กด ํ
๋ง ํ ํฐ์ผ๋ก๋ง ๋ง๋ ์์ ๋์ฒด โ ์ ์์ ๋ง๋ค์ง ์์), ํ ๋ฒ๋ง ์ ์ํ ์ฝ 0.2s transition, _motionReduce, ๋ฃจํธยทํ์ด์ง๋ณ metadata(openGraph ํฌํจ, devfive-frontend ๊ท์น), <html lang>, alt, ์ด๋ฏธ์ง ํฌ๊ธฐ, not-found ํ์ด์ง. ๊ฐ์ ์ฌ์ ์ง๋ฌธ ๋ผ์ด๋์์ ๋ฌป๋ ๊ฒ: ํ๋น์ฝยท๊ณต์ (OG) ์ด๋ฏธ์ง(๊ธฐ์กด ํ์ผ, ๋ฒ์ ์์ Figma ๋ก๊ณ /og ๋
ธ๋, ์ง์ ์ ๊ณต ์ค์์ โ ์ง์ ๊ทธ๋ฆฌ๊ฑฐ๋ ์์ฑํ์ง ์์), ํ๋ก์ ํธ์ ์์ ๋๋ง ์ฌ์ดํธ ์ด๋ฆยท์ด์ URL, ํ์ ์ด ์์ ๋๋ง ๋ถ์/์ธ์ฆ ํ๊ทธ, hover ์ด์์ ๋ชจ์
("None" ์ถ์ฒ). .devup/screen-plan.config.json์ faviconยทogImageยทsiteNameยทsiteUrlยทmotion์ผ๋ก ๋ฏธ๋ฆฌ ๋ตํ ์ ์์ต๋๋ค. status๋ ํ๋น์ฝ, URL๋ณ metadata, OG ์ด๋ฏธ์ง, hover/focus ์ ์ฉ ๋น์จ, reduced-motion์ filled / asked-and-answered / missing์ผ๋ก ๋ณด๊ณ ํ๊ณ , devup_ui_validate๋ ์ํ ์๋ ์ํธ์์ฉ ์์(interactive-states), transition ์๋ _hover(hover-transition), metadata ์๋ page/layout(page-metadata), projectRoot์ ์์ด์ฝ์ด ์๋ ์ฑ(app-icon)์ ์๋ฆฝ๋๋ค.
์ํธ์์ฉ์ ์ญํ ๋ณ ๋ ์ํผ๋ก ์ฑ์๋๋ค(๋ฒํผยท๋ณด์กฐ ๋ฒํผยทํ
์คํธ ๋งํฌยท๋งํฌ ์นด๋ยท๋ด๋น/ํญยท์์ด์ฝ ๋ฒํผยท์
๋ ฅยท์์ฝ๋์ธยท๋ชจ๋ฐ์ผ ๋ฉ๋ด๋ง๋ค hover, pressed, focus ๋ง, ํ์ฌ ํ์ด์ง(aria-current), ํผ์นจ(aria-expanded), disabled, loading). ์ ์ ๊ฐ ๊ท์น์
๋๋ค: Figma ์ํ variant ์ฐ์ , ๊ธฐ์กด ํ ํฐ๋ง, ์ํ๋น ์์ฑ 2๊ฐ ์ดํ, 150โ250ms ํ ๋ฒ ์ ์, bounceยท๋ฌดํ ์ ๋๋ฉ์ด์
๊ธ์ง, ์ด๋ 4pxยทscale 0.97โ1.05 ์ด๋ด, _motionReduce์์ ๋ชจ๋ ๋, ์ํธ์์ฉ ์๋ ์์๋ hover ์์. ํ์ด์ง ์ ํ(View Transitions)์ ํญ์ ์ผญ๋๋ค: ์์กด์ฑ ์
๋ฐ์ดํธ๊ฐ ๋จผ์ ๋์ ํญ์ ์ต์ NextยทReact์ด๋ฏ๋ก ๋ฒ์ ์ ๋ณด์ง ์๊ณ import { ViewTransition } from 'react'๋ฅผ ๊ฐ page.tsx์ ์๋๋ค(์งง์ cross-fade, reduced-motion์์ ๋). ์ค์ ํ์ผ์ viewTransitions: false๋, updateDependencies: false๋ก React 19.3 ๋ฏธ๋ง์ ๋จธ๋ฌธ ๊ฒฝ์ฐ์๋ง ๊ฑด๋๋๋๋ค. ๋์์ ์์ฌํ์ง ์๊ณ ๊ฒ์ฆํฉ๋๋ค: runtime audit์ view-transition ๊ฒ์ฌ๊ฐ ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ document.startViewTransition ํธ์ถ(๋๋ cross-document pagereveal)์ ํ์ธํ๊ณ , ์คํจ๋ ๊ณ ์น ๋ฒ๊ทธ์
๋๋ค. ์ ์ฅ์์ ์ฑ์ด ์ฌ๋ฟ์ด๋ฉด ์ด๋ฆ ์์๊ฐ ์๋๋ผ ์๋ฏธ๋ก ๊ณ ๋ฆ
๋๋ค: ๋ง์ผํ
ํ๋ฉด์ ๊ณต๊ฐ ์ฌ์ดํธ(apps/front), "Admin - ํ์๊ด๋ฆฌ" ๊ฐ์ ํ๋ฉด์ apps/admin, ์์ธ ํ์ผ์ ํ๋ฉด๋ง๋ค ์ฑ์ ์ ํฉ๋๋ค(route ํ์ app ์ด). ๊ธฐ์ค์ "๊ด๋ฆฌ์๋ผ๋ ๋ถ๋ช
ํ ๊ทผ๊ฑฐ๊ฐ ์์ผ๋ฉด ๊ณต๊ฐ ์ฌ์ดํธ"๋ผ์, ๋จ์ ์๋ ํ๋ฉด๋ ๊ณต๊ฐ ์ฌ์ดํธ๋ก ๊ฐ๊ณ ๊ณต๊ฐ ์ฌ์ดํธ๋ก ๋ณด์ด๋ ์ฑ์ด ํ๋๋ ์์ ๋๋ง ๋ฌป์ต๋๋ค. ์์ด์ ํธ ์์ ์ ์ง๋ฌธ์ extraQuestions๋ก ๊ฐ์ ์ฌ์ ๋ผ์ด๋์ ๋ฃ๊ณ , ๋์ ์ ์ถ ์ฒดํฌ๋ฆฌ์คํธ(๋ชจ๋ URL ๊ตฌํ, buildยทlintยทtypecheck ํต๊ณผ, validate ์ค๋ฅ ์์, ์๋ audit์ ์คํจ 0, ์ฌ์ดํธ ์์ฑ๋ ์ฑ์, ์ต์ข
๋ณด๊ณ ์)์
๋๋ค.
๊ท์น์ ์ ์ ๋๋ค: ๋ชจ๋ ํ๋ฉดยท์น์ ยท์์ ์ ๊ทธ๋ ค์ง ๋ชจ๋ ํญ์์ ์๊ฐ์ผ๋ก ๊ฒ์ฆํ๋ค, ๊ธฐ๋ค๋ฆฌ๋๋ผ ๋ฉ์ถ์ง ์๊ณ ์์ ์์๋ฅผ ๋ฐ๊พผ๋ค, ์๋ฃ = ์คํจ 0, ์๋๋ฉด ์ฆ๊ฑฐ์ ํจ๊ป unresolved๋ก ๋จ๊ธด๋ค.
devup_screen_planaction: "auditPlan"(ํ์ ๋ค)์ ํ์ ๋ URL๋ง๋ค runtime audit ๊ณํ์.devup/runtime-audit/<slug>/plan.json์ ์ฐ๊ณ ์คํ๊ธฐ๋ฅผ.devup/runtime-audit/runner/์ ํ ๋ฒ ์๋๋ค.artifacts์ ๊ทธ ๊ณํ ํ๋ ์๋ค์devup_figma_exportartifactId๋ฅผ ๋ชจ๋ ๋๊น๋๋ค. ํญ์ ๊ทธ๋ ค์ง ํญ(๋ทฐํฌํธ ๋์ด = ํ๋ ์ ๋์ด) + 1440/1100/858/390์ ๋๋ค. ๋ชจ๋ ํญ์์ page health(ํ์ด์ง ์ค๋ฅยท์ฝ์ ์ค๋ฅยท"This page couldn't load"/"Application error" ํ ์คํธ ์์), ๊ฐ๋ก ๋์นจ, ์๋ฆฐ ํ ์คํธ, ๋ด๋น ์๋ฆผ์ ๋ณด๊ณ , ๊ทธ๋ ค์ง ํญ์์๋ ํ์ด์ง ์ ์ฒด๋ฅผ referencePng์, ํ๋ ์์ ์ต์์ ์์(์น์ )๊ณผ ์์ ์ ๊ฐ์์ native-node ๋ ๋์ ๋น๊ตํ๊ณ , ์น์ ยท์นด๋ยท์์ ์ ํฌ๊ธฐ์ ์์น(bounds๊ฒ์ฌ; ์นด๋ ์์๊ฐ ํ๋ฆฌ๋ฉด ์คํจ)๋ฅผ ๋ด ๋๋ค. ๋งํฌยท๋ฒํผ ์ ์ฒด์ hover/focus์ ๋ค์ URL๋ก์ view-transition ๊ฒ์ฌ๋ ๋ค์ด๊ฐ๋ฉฐ, view-transition์ ์ฝ๋๊ฐ ๋งจ ๋ค๋ก ๋ณด๋ด๊ณ ์คํ๊ธฐ๊ฐ ๋๋๋ฉด ์๋ URL๋ก ๋์์ต๋๋ค. ๋น ์ง referencePngยท๋ ๋ยทํ๋ ์์missingReferences์ ๋ง๋๋ export ํธ์ถ๊ณผ ํจ๊ป ๋์ต๋๋ค โ ์กฐ์ฉํ ๊ฑด๋๋ฐ์ง ์์ต๋๋ค.- ์น์
ยท์นด๋ยท์์
์
data-figma-node-id๋ก ์ฐพ์ต๋๋ค.projectRoot๊ฐ ์๋ export๋ ํ์ด์ง ๋ฃจํธ, ์น์ , ๊ทธ ์์, ์์ ์ ์ด ์์ฑ์ ์๋๋ค(projectRoot ์๋ export๋ ํ๋ฌ๊ทธ์ธ๊ณผ ๊ฐ์ ์ถ๋ ฅ ๊ทธ๋๋ก). ๋๋ ค๋ฉด ์ค์ figmaNodeIds: false, ํ๋ก๋์ ์์ ๋นผ๋ ค๋ฉด Next์compiler.reactRemoveProperties: { properties: ["^data-figma-node-id$"] }. status์auditPlanPathยทauditReportPath๋ฅผ ์ฃผ๋ฉด ๋ชจ๋ ์คํจ๋ฅผ ๋ถ๋ฅํฉ๋๋ค:runtime-error,overflow,layout-position,layout-size,asset-mismatch(๋ฉํฐ์ปฌ๋ฌ SVG์ mask, ์๋ชป๋ ํ์ผ, crop/objectFit ์์ผ๋ก ์์ธ ์ ์),section-visual,page-visual,interaction,view-transitionโ ๊ฐ๊ฐ Figma ๋ ธ๋, ์ฝ๋ ํ์ผ, ๊ตฌ์ฒด์ ์ธ ์์ ํํธ๋ฅผ ๋ด์ต๋๋ค. ๋ฐํ๋visualComparisonsํธ์ถ(thresholdยทdiffPathํฌํจ)์ ๋๋ฆฌ๊ณ ๊ฒฐ๊ณผ๋ฅผvisualResults๋ก ๋๊น๋๋ค. ์ํฐ์จ๋ฆฌ์ด์ฑ์ ์คํจ๊ฐ ์๋๋๋ค: ๋ฐ๋ ํฝ์ ๋น์จ ํ์ฉ์น๊ฐ ํ์ด์งยท์น์ 3%, ์์ 5%์ด๊ณ , ์ค์ visualThresholds(page,section,asset, ๋ ธ๋๋ณnodes)๋ก ์กฐ์ ํฉ๋๋ค.- ๊ฐ์ finding์ ์ ์คํ๋ง๋ค ํ ๋ฒ๋ง ์๋๋ก ์
๋๋ค.
maxFixAttempts(์ค์ , ๊ธฐ๋ณธ 3)๋ฒ ๊ณ ์น๊ณ ๋ ์คํจํ๋ฉด ์คํฌ๋ฆฐ์ทยทdiff ๊ฒฝ๋ก์ ํจ๊ปunresolved๋ก ๊ธฐ๋กํ๊ณ ์์ ํ์์ ๋บ๋๋ค.workQueue๋ URL๋ง๋ค build โ audit โ fix โ compare ์์ด๊ณ ๋งํ ์ผ์ ๋ค๋ก ๊ฐ๋๋ค. - ํ์ ๋ค ์๊ธด ๊ฒฐ์ ์
action: "defer"(decision: {id, about, question, options, recommended, destructive})๋ก ๋จ๊ธฐ๊ณ ๊ณ์ ์ผํฉ๋๋ค. ๋ง์ง๋ง์assume(about: ๊ฒฐ์ id)์ผ๋ก ์ถ์ฒ์์ ํํ๊ณ , ํ๊ดด์ ์ธ ๊ฒฐ์ ์ ๋ง๋ค์ง ์์ ์ฑ ๋ณด๊ณ ์์ ๋จ์ต๋๋ค. ์คํ๊ธฐ๋ฅผ ์ค์นํ ์ ์์ผ๋ฉดtoolingUnavailable๋ก ๊ทธ URL์ audit๋ฅผ inconclusive๋ก ๋๊ณ ๊ณ์ํฉ๋๋ค. status์finalReport: URL ร ํญ ํ(health, geometry, drift / converter bugs, page, section, asset, interaction, ์คํฌ๋ฆฐ์ท, diff), converter bug์ repro ํ์ผ, unresolved finding๊ณผ ์ฆ๊ฑฐ, ์ฒ๋ฆฌ๋ ๋ณด๋ฅ ๊ฒฐ์ , ๊ฐ์ , ๋์์ธ ์์ ์์ฒญ, ์ ์ธ, ์์กด์ฑ ์ค.
Figma ํ๋ ์์ ์ ์ ์ผ๋ก ๋ณํ๋๋ฏ๋ก, ๊ทธ๋ ค์ง ํญ์์ ํฌ๊ธฐยท์์นยทpaddingยทgap์ "๋์ถฉ ๋ง๋๊ฐ"๊ฐ ์๋๋ผ ๋ง๊ฑฐ๋ ํ๋ฆฌ๊ฑฐ๋์
๋๋ค. ๊ทธ๋์ bounds ๊ฒ์ฌ์๋ ์ค์ ๊ฐ๋ฅํ ํ์ฉ์น๊ฐ ์๊ณ ๋ฐ์ฌ๋ฆผ 0.5px๋ง ํ์ฉํฉ๋๋ค(Chromium์ getBoundingClientRect๋ 1/64px LayoutUnit์ DPR 1์์ ํฝ์
์ ๋ง์ถ์ง ์๊ณ ๋๋ ค์ฃผ๊ณ , Figma์ ์์ px๋ ๋ณํ๊ธฐ๊ฐ ๋ฐ์ฌ๋ฆผํด ์๋๋ค). ๊ณํ๋ ํฐํธ๊ฐ ๋จผ์ ๋ก๋๋๋ฏ๋ก ํ
์คํธ ๋ฐ์ค๋ ์ ํํด์ผ ํ๋ฉฐ, ํฐํธ๊ฐ ์์ผ๋ฉด ๋ ์ด์์ ์คํจ๊ฐ ์๋๋ผ ํ๊ฒฝ ์ค๋ฅ์
๋๋ค. ์ด๋ฏธ์งยทํฝ์
๋น๊ต๋ง ์ํฐ์จ๋ฆฌ์ด์ฑ ์๊ณ๊ฐ(ํ์ด์งยท์น์
3%, ์์
5%)์ ์ ์งํฉ๋๋ค. ๊ทธ๋ ค์ง ํญ ์ฌ์ด์๋ ๋์์ธ์ด ์์ผ๋ฏ๋ก health, ๋์นจ, ํฌํจ, ์๋ฆฐ ํ
์คํธ, ๋ด๋น๋ง ๋ด
๋๋ค.
๋ถ์ผ์น๋ ์น์ธํ์ง ์๊ณ ์์ธ์ผ๋ก ๋ถ๋ฅํฉ๋๋ค. projectRoot๊ฐ ์๋ export๋ ๋
ธ๋๋ง๋ค ์ด ๋ด์ฉ์ .devup/exports/<๋
ธ๋>.json์ ๊ธฐ๋กํ๊ณ , status๊ฐ ์คํจํ ์์์ ์ฝ๋๋ฅผ ๊ทธ ๊ธฐ๋ก๊ณผ ๋น๊ตํฉ๋๋ค.
code-drift: export๊ฐ ์ด ์์ฑ์ด ๋น ์ก๊ฑฐ๋ ๋ฐ๋์๊ฑฐ๋, export๊ฐ ์ฐ์ง ์์ ๋ ์ด์์ ์์ฑ์ด ๋ํด์ก์ต๋๋ค(ํธ๋ค๋ฌยทhover ์คํ์ผยท๋งํฌ ์ถ๊ฐ๋ drift๊ฐ ์๋๋๋ค). ํด๋ฒ์ export ๊ฐ ๋ณต์์ด๋ฉฐ, ๋ ์ด์์์ ์์ผ๋ก ์กฐ์ ํ์ง ์์ต๋๋ค.converter-bug: ์ฝ๋๊ฐ export ๊ทธ๋๋ก์ธ๋ฐ ๋ธ๋ผ์ฐ์ ๋ฐ์ค๊ฐ Figma์ ๋ค๋ฆ ๋๋ค. devup-mcp ๊ฒฐํจ์ด๋ฏ๋ก ์ฌํ ์ ๋ณด(file key, node id, Figma ๋ฐ์ค, DOM ๋ฐ์ค, ์์ฑ๋ props, sourceMap ํญ๋ชฉ)๋ฅผ.devup/converter-bugs/<๋ ธ๋>.json์ ์ฐ๊ณconverterBugs์ ์ต์ข ๋ณด๊ณ ์์ ๋จ๊น๋๋ค. ๊ฒฐ์ ์ ์ธ ๊ฒฐ๊ณผ๋ผ ์ฌ์๋ํ์ง ์์ผ๋ฉฐmaxFixAttempts๋ ์ฐ์ง ์์ต๋๋ค. ์ฌ์ดํธ๋ฅผ ๋ง์น๋ ค๊ณ ๋ก์ปฌ override๋ฅผ ๋ ์๋ ์์ง๋ง repro ํ์ผ์ ๊ฐ๋ฆฌํค๋ ์ฃผ์์ด ์์ด์ผ ํฉ๋๋ค.
ํญ๋ง๋ค ํ๋ ์์ด ๋ฐ๋ก ์๋ ํ์ด์ง๋ฅผ responsiveTsx๋ก ํฉ์น๋ฉด ๊ฐ ์์๊ฐ data-figma-node-id(๊ฐ์ฅ ๋์ ํญ์ ๋
ธ๋)์ data-figma-node-ids="1440:12:34 390:56:78"(๊ทธ๋ ค์ง ํญ๋ง๋ค ํญ:๋
ธ๋, ๊ณต๋ฐฑ ๊ตฌ๋ถ, [data-figma-node-ids~="390:56:78"]๋ก ์ ํ)๋ฅผ ๊ฐ์ง๋๋ค. audit ๊ณํ์ ํญ๋ง๋ค ๊ทธ id๋ก ์น์
ยท์นด๋ยท์์
์ ์ฐพ๊ณ , ์ด๋ค ํญ์์ ๊ทธ๋ฆฌ์ง ์์ ์์๋ ๊ทธ ํญ์์ ์จ๊ฒจ์ ธ ์๋์ง(hidden ๊ฒ์ฌ) ํ์ธํฉ๋๋ค.
๋์ ๋ผ์ฐํธ([slug], [id], catch-all)๋ notAudited๋ก ๋๊ธฐ์ง ์๊ณ ์ค์ URL๋ก ๊ฒ์ฌํฉ๋๋ค: ๋ผ์ฐํธ์ generateStaticParams(๋ฆฌํฐ๋ด, ๋๋ ์ฝ๋ ๋ก์ปฌ ๋ฐ์ดํฐ ํ์ผ) โ ์ด๋ฏธ ๊ฒ์ฌํ ํ์ด์ง์ a[href](์คํ๊ธฐ๊ฐ ํ์ด์ง๋ง๋ค ๋ชจ์ผ๊ณ ๋ค์ auditPlan์ด ์ฌ์ฉ) โ ๋งคํ๋ Figma ์์ธ ํ๋ ์์ ์ ๋ชฉ์ผ๋ก ๋ง๋ ์ํ(๊ฐ์ ์ผ๋ก ๊ธฐ๋ก) ์์์ด๋ฉฐ, 10๊ฐ ์ดํ๋ฉด ์ ๋ถ ๊ฒ์ฌํฉ๋๋ค. ์
๋ค ์์ ๋๋ง ์ด์ ์ ํจ๊ป notAudited์
๋๋ค.
data-figma-node-id(s)๋ ํ๋ก๋์
์ ๋จ์ง ์์ต๋๋ค. vinext์ devup-ui Vite ํ๋ฌ๊ทธ์ธ์๋ ์์ฑ์ ์ง์ฐ๋ ์ต์
์ด ์์ด์, auditPlan์ด ๊ฐ ์ฑ์ vite.config ์์ ์์ Vite ํ๋ฌ๊ทธ์ธ(vite-plugin-strip-figma-node-ids.mjs)์ ๋ก๋๋ค. enforce: 'pre', apply๊ฐ vite build์ผ ๋๋ง์ด๋ฉฐ DEVUP_AUDIT=1์ด๋ฉด ๋จ๊น๋๋ค. Rolldown์ transform ํ
๋ค์ TSX/JSX๋ฅผ ๋ณํํ๋ฏ๋ก ์ด ๋จ๊ณ์์๋ ์์ฑ์ด ๊ทธ๋๋ก JSX ํ
์คํธ์
๋๋ค. plugins: [stripFigmaNodeIds(), vinext()]๋ก ์ฐ๊ฒฐํ๊ณ , audit๋ dev ์๋ฒ๋ DEVUP_AUDIT=1 bun run build๋ก ๋๋ฆฌ๋ฉฐ, ์ ์ถ ์ฒดํฌ๋ฆฌ์คํธ๋ ๋น๋ ์ถ๋ ฅ์์ grep -rl data-figma-node-id dist๊ฐ ์๋ฌด๊ฒ๋ ์ฐพ์ง ์์์ผ ํต๊ณผํฉ๋๋ค. next CLI์์๋ compiler.reactRemoveProperties๋ฅผ ์๋๋ค.
์ต์ ์คํ์ด ๊ธฐ๋ณธ์
๋๋ค: Next App Router๋ฅผ vinext(Vite)๋ก ์คํํ๊ณ , bun workspaces(apps/*), devup-ui, oxlint(eslint-plugin-devup), ์ต์ ๋ฒ์ . vinext ์์กด์ฑยทvinext ์คํฌ๋ฆฝํธยทvinext๋ฅผ importํ๋ vite.config๊ฐ ์์ผ๋ฉด next ์์กด์ฑ์ด ์์ด๋ App Router ์ฑ์ผ๋ก ๋ณด๊ณ , devup_project_context์ ui/routes๊ฐ ์ฑ๋ณ frameworks๋ฅผ ์๋ ค ์ค๋๋ค. ๊ตฌํ ์ ์๋ ๋ฌป์ง ์๊ณ ์ ์ฅ์ ๋ฃจํธ์์ bunx @dependency-check-updates/cli -d -u --rm(-d: ๋ฃจํธ ์๋ ๋ชจ๋ manifest, -u: ๋ณต๊ตฌ ๊ฐ๋ฅํ ์ผ๊ด ์ ์ฉ, --rm: ๊ฐ manifest ์์ lockfileยท์ค์น ๋๋ ํฐ๋ฆฌ ์ญ์ โ Cargo.lockยทtarget/ ํฌํจ) โ bun install โ buildยทlintยทtypecheck๋ฅผ ํ๊ณ , ๋ผ์ด๋ธ๋ฌ๋ฆฌ API๋ ๊ธฐ์ต์ด ์๋๋ผ ํ์ฌ ๋ฌธ์๋ฅผ ๋ด
๋๋ค. ๊ฒฐ๊ณผ๋ assume์ dependencyUpdate๋ก ๋จ๊ธฐ๊ณ status์ dependencies ์ค๋ก ๋์ต๋๋ค. ์ฑ์ด ์์ผ๋ฉด dev-five-git/service-template์์ ์์ํ๊ณ (์ด๋ฆยท๊ตฌ์ฑ๋ง ์ง๋ฌธ), next CLI ํ๋ก์ ํธ์๋ "Migrate to vinext (Recommended) / Keep next"๋ฅผ ํ ๋ฒ ๋ฌป์ต๋๋ค. ์ค์ ํ์ผ์ frameworkยทupdateDependencies: false๋ก ๋ฏธ๋ฆฌ ๋ตํ ์ ์์ต๋๋ค.
๋ช
์์ ์์์ /devup [figma url] [notes]: devup_skills install์ด devup ์คํฌ์ ๋ค๋ฅธ ์คํฌ๊ณผ ํจ๊ป ์ฐ๊ณ (Claude Code๋ ํ๋ก์ ํธ ์คํฌ์ ๊ฐ์ ์ด๋ฆ์ ์ฌ๋์ ๋ช
๋ น์ผ๋ก ์ ๊ณตํ๋ฏ๋ก .claude/skills/devup/SKILL.md๊ฐ ๊ณง /devup), OpenCode์๋ .opencode/command/devup.md๋ ์๋๋ค. ๋ช
๋ น ์์น๊ฐ ๊ฒ์ฆ๋์ง ์์ ๋ค๋ฅธ ๋ฐํ์์ ์ง์ํ์ง ์๋๋ค๊ณ ๋ณด๊ณ ํฉ๋๋ค. devup_skills status์ command๊ฐ ์ค์น ์ฌ๋ถ๋ฅผ ์๋ ค ์ค๋๋ค. /devup ์์ด๋ Figma๋ก ํ์ด์ง๋ ์ฌ์ดํธ๋ฅผ ๋ง๋ค์ด ๋ฌ๋ผ๋ ์์ฒญ์ด๋ฉด ๊ฐ์ ํ๋ฆ์ ์์ํฉ๋๋ค.
์ง๋ฌธ ๋๊ตฌ์ ํธ์ถ๋น ๊ฐ์ ์ ํ์ด ์์ผ๋ฉด(OpenCode question) ํํํ questions ๋ชฉ๋ก์ ํ ๋ฒ์ ๋ฌป๊ณ , ์ ํ์ด ์์ผ๋ฉด(Claude Code AskUserQuestion: 4) maxQuestionsPerRound(๊ธฐ๋ณธ 4)๋ก ๋๋ questionRounds๋ฅผ ์ฐ๋ฌ์ ๋ฌป์ต๋๋ค.
- upstream ํธ์ถ์
get_metadata,get_variable_defs,get_design_context,get_code_connect_map,get_screenshot๊ณผ ๋ด์ฅ๋ read-onlyuse_figmascript๋ก ๋ซํ ์์ต๋๋ค. - ์ฌ์ฉ์ ์
๋ ฅ JavaScript๋ฅผ ๋ฐ์ง ์์ผ๋ฉฐ Figma document mutation API๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค.
figma.io.write๋ asset export(devup_figma_export์assetRequests)์๋ง read-only๋ก ์ฌ์ฉํ๋ฉฐ Figma ํ์ผ์ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. fast snapshot/theme envelope๋ ํญ์ ํ ์คํธ๋ก๋ง ๋ฐํ๋๋ฉฐ ๋ฐ์ด๋๋ฆฌ transport๋ฅผ ์ฐ์ง ์์ต๋๋ค. - stdout์๋ MCP frame๋ง ์ถ๋ ฅํ๊ณ trace๋ stderr๋ก ๋ณด๋ ๋๋ค.
- access token, refresh token, OAuth code, PKCE verifier๋ Debug, trace์ MCP error์ ํฌํจํ์ง ์์ต๋๋ค.
- Figma snapshot๊ณผ screenshot์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์คํฌ์ ์ ์ฅํ์ง ์์ต๋๋ค.
devup_runtime_audit๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ฐ๊ฑฐ๋ ๋ช ๋ น์ ์คํํ์ง ์์ต๋๋ค. ๊ณํ์ ์คํ๋์ง ์๋ ๋ฐ์ดํฐ์ด๊ณ , ์คํ๊ธฐ์ ์คํฌ๋ฆฐ์ท์ ์๋น์์ ๋ณด๊ณ ์ ๋๋ ํฐ๋ฆฌ์๋ง ๋จ์ผ๋ฉฐ ์๋ต์๋ ํด์์ ๊ฒ์ฆ ์ํ๋ง ์ค๋ฆฝ๋๋ค.- screenshot, asset, TSX resource๋ bounded memory artifact์ ๊ฐ์ TTL์ ๊ฐ์ง๋ฉฐ resource manifest์๋ ์ด๋ฆยทMIMEยทํฌ๊ธฐยทhash๋ง ๋ ธ์ถ๋ฉ๋๋ค.
- ํธํ์ฑ fixture๋ ๊ณ ์ ํ JavaScript ํ๋ฌ๊ทธ์ธ์ 268๊ฐ synthetic ์ ๋ ฅ์ ๋๋ค. ๋ณ๋์ WQUW-151 ํ๊ท fixture๋ ๊ณต์ MCP์์ read-only๋ก ์์งํ ๋์์ธ node/ํ ์คํธ/token ์ด๋ฆ๋ง ํฌํจํ๋ฉฐ OAuth token, header, callback parameter, ์ฌ์ฉ์ ๊ณ์ ยทemail์ ํฌํจํ์ง ์์ต๋๋ค.
fixtures/devup-figma-plugin์ dev-five-git/devup-figma-plugin์ ๊ณ ์ commit 243db650f1d635ab5385546a2a297eae4ea93515์์ ์์งํ 54๊ฐ test file๊ณผ 978๊ฐ passing-test inventory๋ฅผ ์ถ์ ํฉ๋๋ค. upstream test 252๊ฐ๊ฐ ๋ง๋ JSON/golden 268์์ Rust serde/codegen ๊ฒฝ๋ก์์ byte parity๋ฅผ ์ ๋ถ ์คํํ๊ณ , 666๊ฐ๋ ๊ฐ์ ๋์ ์์ญ์ ์ค์ Rust assertion์ ์ฐ๊ฒฐํ์ต๋๋ค. ๋๋จธ์ง๋ plugin module/codegen handler/iframe/notify/browser download ์๋ช
์ฃผ๊ธฐ 38๊ฐ์ read-only MCP๊ฐ ์๋์ ์ผ๋ก ์ํํ์ง ์๋ Figma document/style/import write 22๊ฐ์
๋๋ค. not_ported๋ 0๊ฐ์ด๋ฉฐ, ๋น-parity ํญ๋ชฉ๋ ๊ตฌ์ฒด์ ์ธ MCP ๊ฒฝ๊ณ test๋ฅผ ๊ฐ๋ฆฌํต๋๋ค. ์ฆ ์ ํํ ๋ณด์ฅ์ โ268/268 snapshot byte parity, 666๊ฐ ์คํ ๊ฐ๋ฅํ ๋ํ Rust assertion ์ฐ๊ฒฐ, 60๊ฐ ๋ช
์์ runtime/write ๊ฒฝ๊ณ, 978-entry inventoryโ์ด๊ณ JavaScript assertion 978๊ฐ๋ฅผ ๊ฐ๊ฐ ๋ณ๋ fixture๋ก ๋ณต์ ํ๋ค๋ ๋ป์ ์๋๋๋ค. manifest๋ LF๋ก ์ ๊ทํํ fixture์ snapshot 536๊ฐ ํ์ผ์ SHA-256์ ๊ฒ์ฆํ๊ณ , coverage registry๋ ledger๊ฐ ์ค์ Rust test symbol ๋๋ ๊ทผ๊ฑฐ๊ฐ ์๋ ๋น-parity ๋ถ๋ฅ๋ง ์ฐธ์กฐํ๋๋ก ๊ฐ์ ํฉ๋๋ค. ์์ธ ๋ถ๋ฅ์ ์คํ ๋ฐฉ๋ฒ์ fixtures/devup-figma-plugin/README.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
crates/devup-mcp/tests/live_figma_contract.rs๋ ๊ธฐ๋ณธ์ ์ผ๋ก ignore๋ฉ๋๋ค. DEVUP_MCP_LIVE_FIGMA=1์ ์ค์ ํ๊ณ ๊ณต์ MCP์ fast use_figma ๊ฒฐ๊ณผ๋ฅผ stdin์ ํ ์ค๋ก ์ ๋ฌํ๋ฉด ์ค์ payload๋ฅผ ๋์คํฌ์ ์ฐ๊ฑฐ๋ ์ถ๋ ฅํ์ง ์๊ณ envelope ๋ฌด๊ฒฐ์ฑ, serde round-trip, ์์ฒญ context, node/๋ฆฌ์์ค ์์ DevupUI codegen์ ๊ฒ์ฆํ๊ณ ์์ ํ count/hash ์์ฝ๋ง ์ถ๋ ฅํฉ๋๋ค. ๋ณ๋์ ๋น-ignore corruption test๋ ๊นจ์ง fast ์๋ต์ด legacy metadata ์์ง์ผ๋ก ์์์ ์ผ๋ก ํด๋ฐฑํ๋์ง ํ์ธํฉ๋๋ค.
crates/devup-mcp-figma/tests/explore_script_behavior.mjs๋ compile-in explore.js ์์ฒด๋ฅผ mock Figma scene graph์์ ์คํํฉ๋๋ค. ๋ ๋จ๊ณ ์ด์ ์ค์ฒฉ๋ ํ๋ฉด์ parent chain, ํ๋ฉด์ด ์๋ 1,000-node Section์ projectionLimit * 8 ๋ฐฉ๋ฌธ ์ํ, ํ์ node๋ง ๋จ๊ธฐ๋ 14,000์ ์ดํ fallback์ ๊ฒ์ฆํ๋ฉฐ CI์ Node ๋ด์ฅ test runner๋ก ์คํ๋ฉ๋๋ค. ์ ํ binary์ ๊ธฐ๋ณธ Cargo test์๋ JavaScript runtime ์์กด์ฑ์ด ์ถ๊ฐ๋์ง ์์ต๋๋ค.
legacy ๊ฒฝ๋ก์์ ์ค์ ํ์ธ๋ ๊ณต์ metadata๋ XML text content envelope์ด๋ฉฐ, local ๋ณ์/style์ catalog ํ resource ๋จ์๋ก ์์งํฉ๋๋ค. style์ consumers์ฒ๋ผ ๋จ์ผ field๊ฐ ๊ณต์ MCP์ text ์ํ(์ค์ธก 20,480 UTF-8 ๋ฐ์ดํธ, ๋๋ ๋งํผ ์๋ฆฌ๊ณ // truncated to 20kb๊ฐ ๋ถ์)์ ๋์ ์ ์์ผ๋ฏ๋ก, base field์ 320๊ฐ ๋จ์์ compact consumer relation์ ๋ถ๋ฆฌํด ์ฝ๊ณ Rust์์ ์๋ exhaustive JSON shape๋ก ์ฌ์กฐ๋ฆฝํฉ๋๋ค. legacy node snapshot๋ byte budget๊ณผ cursor๋ฅผ ์ฌ์ฉํด ๊ฐ์ ์ํ ์๋์์ ์๋ ์ฌ๊ฐํฉ๋๋ค. range์ ๋๋ฝยท์ค๋ณต์ด๋ ์์ง ์ค ๋ชฉ๋ก ๋ณ๊ฒฝ์ ์ฑ๊ณต์ผ๋ก ์จ๊ธฐ์ง ์๊ณ ์ค๋ฅ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
server/mod.rs๋ MCP tool router, service construction, handoff ์ฐ๊ฒฐ๊ณผ ServerHandler๋ง ์์ ํฉ๋๋ค. projection.rs๋ TSX/theme/source-map/asset/reference output ์์ฑ๊ณผ delivery transaction์, validation.rs๋ output/schema/artifact capability ์
๋ ฅ ๊ฒ์ฆ์ ๋ด๋นํฉ๋๋ค. delivery.rs, artifacts.rs, output.rs, resources.rs, quality.rs๋ ๊ฐ๊ฐ ํฌ๊ธฐ ๊ฒฐ์ , memory artifact, allowlisted filesystem transaction, MCP resource protocol, typed ํ์ง ์ง๊ณ๋ฅผ ๋ด๋นํ๋ฉฐ source-level boundary test๊ฐ generator์ filesystem ๊ตฌํ์ด router๋ก ๋๋์์ค๋ ๊ฒ์ ๋ง์ต๋๋ค.
2026-09-01 ์ค์ ํ์ผ ๊ฒ์ฆ์์๋ 13๊ฐ page ์ ์ฒด ๊ฒ์์ผ๋ก [FR-026] ๋ณธ์ฐ์ฒด Section (4217:7743)์ ์ฐพ๊ณ , ๊ทธ ์์ 360ร740 ํ๋ฉด 10๊ฐ๋ฅผ ์๊ฐ ์์๋๋ก ์ธ๋ฑ์ฑํด A : STORY-F-PROOFREAD (3879:35518)๋ฅผ ์ ํํ ๋์์ผ๋ก ์ ํํ์ต๋๋ค. Section ์ ์ฒด fast envelope๋ 8 MiB ์์ ์ํ์ ๋์ด์๋ฏ๋ก ์ฑ๊ณต์ผ๋ก ์ค์ธํ์ง ์๊ณ , ๊ฐ ํ๋ฉด์ ๊ณต์ read-only MCP๋ก ๊ฐ๋ณ ์์งํ์ต๋๋ค. ์ด ํ๋ฉด์ ๊ฐ๊ฐ 15210๊ฐ node๋ฅผ ๊ฐ์ง๋ฉฐ ๋ชจ๋ child, styled text segment, ๋ณ์ 325๊ฐ์ text style 2~13๊ฐ์ ์ฐธ์กฐ ์์ ์ฑ์ ์ค์ JSON fixture์ DevupUI TSX snapshot์ผ๋ก ๊ฒ์ฆํฉ๋๋ค. ๋ํ proofread ํ๋ฉด์ ๊ณต์ read-only MCP 1ํ, 3๊ฐ PNG envelope ์ฒญํฌ์์ 144๊ฐ node, ๋ณ์ 20๊ฐ์ text style 11๊ฐ๋ฅผ ์์งํ๊ณ ํด๋ฐฑ์ ์์์ต๋๋ค. instance children, concrete boolean property, mixed typography, nested [1. ์ด๋ฆ], token binding๊ณผ ๊ฐ๋ณ footer stroke๋ Rust snapshot/live contract๋ก ๊ฒ์ฆํ์ต๋๋ค. ๊ฐ์ ํ์ผ์ ์ ์ฒด theme export๋ legacy ๊ณต์ read-only ํธ์ถ 89๊ฐ๋ฅผ ํตํด collection 1๊ฐ, variable 49๊ฐ, style 37๊ฐ, mode 2๊ฐ๋ฅผ ์์งํด 42,794์ devup.json์ ์์ฑํ์ผ๋ฉฐ diagnostics๋ 0๊ฐ์์ต๋๋ค. ํ์ฌ full-theme fast collector๋ ๊ฐ์ collection/variable/style ์ ์ฒด๋ฅผ ๋จ์ผ read-only use_figma ํธ์ถ๋ก ์์งํ๊ณ , envelope ๊ฒ์ฆ ์คํจ ์์๋ง ์ด legacy ๊ฒฝ๋ก๋ฅผ 0๋ถํฐ ๋ค์ ์์ํ๋๋ก contract test๋ก ๊ณ ์ ํ์ต๋๋ค.
Figma Remote MCP์์๋ JSON_REST_V1 export๊ฐ ํ์ฉ๋์ง ์์ผ๋ฏ๋ก host object๋ฅผ ๊ทธ๋๋ก REST JSON์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค. ๋์ checked-in property manifest์ runtime prototype/enumerable ํ์์ ํจ๊ป ์ฌ์ฉํด ๋ชจ๋ ๋ฐ๊ฒฌํ data field์ key์ ์ฝ๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์กดํฉ๋๋ค. ํจ์, ์ํ node object๋ ์ ์ธํ๊ฑฐ๋ id๋ก ๋ฐ๊พธ๊ณ , binary asset์ bytes ๋์ metadata๋ก ๋ํ๋ด๋ฉฐ, ํ plugin private data์ ์ค๋ฅ๋ฅผ ๋ด๋ getter๋ ์ฝ์ ์ ์์ต๋๋ค. ๋จ์ผ ๊ฐ์ด byte budget์ ๋์ผ๋ฉด key๋ฅผ ์์ ์ง ์๊ณ { "$truncated": ..., "byteLength": ... }์ DEVUP_FIELD_VALUE_TRUNCATED๋ฅผ ๋จ๊ธฐ๋ฉฐ, characters, styled segment, resource binding์ฒ๋ผ UI ๋ณํ์ ํ์ํ ๊ฐ์ ์ฐ์ ๋ณด์กดํฉ๋๋ค.
ํ์ฌ private MVP์ ๋จ์ ํ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๊ณต์
get_metadata์ file-level page ๋ชฉ๋ก์ ์ค์ page ์ ์ฒด๋ณด๋ค ์ ๊ฒ ๋ฐํ๋ ์ ์์ต๋๋ค. ์ด๋ฆ ๊ฒ์์ Plugin API page catalog์ per-page projection์ผ๋ก ์ฐํํ๋ฉฐ ์ค์ 13๊ฐ page ํ์ผ์์ ๊ฒ์ฆํ์ต๋๋ค. - ๋งค์ฐ ํฐ computed field(์: vector
fillGeometry)๋ ํ์ฌ ๊ฐ ์ ์ฒด ๋์ ๋ช ์์ ์ธ byte-length marker๋ก ๋ณด์กด๋ฉ๋๋ค. ๋ชจ๋ ๋์ฉ๋ field ๊ฐ์ losslessํ๊ฒ exportํ๋ ๊ธฐ๋ฅ์ ํ์ wire-format ๊ฐ์ ๋์์ ๋๋ค. - exact-node fast envelope๊ฐ 8 MiB ์์ ์ํ์ ๋๊ฑฐ๋ ๊ณต์ MCP๊ฐ image transport๋ฅผ ๋ฐ๊พธ๋ฉด ์๋ legacy fallback์ด ์ฌ๋ฌ cursor call์ ์ฌ์ฉํ๋ฏ๋ก subtree ํฌ๊ธฐ์ ๋ฐ๋ผ ์๊ฐ์ด ๋์ด๋ ์ ์์ต๋๋ค.
- direct OAuth registration์ Figma MCP Catalog ์น์ธ์ด ์๋
client_name์ผ๋ก๋ ๊ฑฐ์ ๋ฉ๋๋ค. ์น์ธ๋ ์ด๋ฆ(๊ธฐ๋ณธ๊ฐCodex)์ผ๋ก๋ง ๋ฑ๋ก์ด ์ฑ๋ฆฝํ๋ฉฐ, ๊ทธ ๋ฑ๋ก์ Figma์๊ฒ ํด๋น ์ ํ์ผ๋ก ๊ธฐ๋ก๋ฉ๋๋ค. - ์ฌ์ฉ๋์ง ์์ ์ธ๋ถ Figma library ๋ณ์ ์ ์ฒด๋ Remote MCP๊ฐ ์ ๊ณตํ์ง ์์ ์ ์์ต๋๋ค.
- node/page theme scope๋ ๋ก์ปฌ ๋ณ์ API์ file-wide ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ ์ธ๋ฐํ ์ฌ์ฉ ๋ฒ์ ํํฐ๋ ํ์ ๋ณด๊ฐ ๋์์ ๋๋ค.
- vector, mask, image, absolute layout๊ณผ ์ผ๋ถ effect๋ diagnostics๋ฅผ ํฌํจํ ์ ํ์ fallback์ ๋๋ค.
- Figma Remote MCP์
use_figmatool contract๊ฐ ๋ฐ๋๋ฉด live smoke test์ adapter ๊ฐฑ์ ์ด ํ์ํฉ๋๋ค.
absolute ์์์ด ์๋ ํ๋ ์์ ์์ฑ ์ฝ๋๊ฐ containing block์ ๋ง๋ญ๋๋ค. standalone์์๋ PAGE/SECTION ์๋์ ๋ฃจํธ๋ FIXED ์ถ์ ์๋ณธ ํฌ๊ธฐ๋ฅผ ๋ณด์กดํฉ๋๋ค. ์๋ฅผ ๋ค์ด WQUW-120์ 360ร740 ์์ง ํ๋ ์์ VStack pos="relative" w="360px" h="740px"๊ฐ ๋์ด ๋ชจ๋ฌ์ left="50%", w="100%"๊ฐ ์ด ๋ฃจํธ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ณ์ฐ๋ฉ๋๋ค. absolute ์์์ด ์๋ ํ๋ฉด์ ๊ธฐ์กด ์ ๋ ํฌ๊ธฐ ์ ์ฑ
์ ์ ์ง๋ฉ๋๋ค.
placementContracts๋ includeDiagnostics ์์ด๋ ๋ฐํํ๋ฉฐ SECTION ์๋ต์๋ ํ๋ ์๋ณ ๋ชฉ๋ก๋ ์์ต๋๋ค. ๊ฐ ๊ณ์ฝ์ details.output, generatedRoot, sourceSize, containingBlock, parentCollected, parentIncludedInOutput, hostRequirements๋ฅผ ํจ๊ป ํ์ธํ์ธ์. ์บก์ฒ ๋ฐ ๋ถ๋ชจ๊ฐ ์์ผ๋ฉด ๊ทธ ์ฌ์ค์ ๋ช
์ํ๋ฉฐ, ์ผ๋ฐ ๋ฃจํธ๋ ์ฑ์ normal flow์ ์ฝ์
๋ฉ๋๋ค. Figma canvas์ x/y๊ฐ ์ฑ ์์ ์์น๋ฅผ ๋ปํ์ง ์์ต๋๋ค.
embedded์์๋ absolute ์์์ ๊ธฐ์ค ์์๋ ์ ์งํ์ง๋ง ๋ฃจํธ ํฌ๊ธฐ๋ ํธ์คํธ/๋ด์ฉ์ ์์กดํฉ๋๋ค. ์ด ์์กด์ด๋ absolute ๋ฃจํธ์ ์ธ๋ถ ๋ถ๋ชจ ์์กด์ hostRequirements์ projectionIssues์ ๊ทผ์ฌ๋ก ๊ธฐ๋กํฉ๋๋ค. ์ด๋ฅผ ์ถฉ์กฑํ๊ฑฐ๋ containing parent๋ฅผ standalone์ผ๋ก exportํ ํ ๋ฐฐ์น๋ฅผ ์์ฉํ์ธ์. ์ด ๊ณ์ฝ์ CSS ์์ฑ ๊ทผ๊ฑฐ์ด๋ฉฐ ๋ธ๋ผ์ฐ์ ํฝ์
๋น๊ต๋ ๋ฐ์ํ ๋์ผ์ฑ ๋ณด์ฆ์ด ์๋๋๋ค.
projectionIssues๋ includeDiagnostics ์์ด๋ ๊ทผ์ฌยท์์ค์ ๋
ธ๋, ํ๋, ์ฌ์ ์ ์๋ณธ/์ ์ฉ ๊ทผ๊ฑฐ๋ฅผ ๋ฐํํฉ๋๋ค. ๋ถ๋ฅ ๊ทผ๊ฑฐ ์๋ uncoveredLayout์ lossy์ด๋ฉฐ exact๋ ์ต์ข
์ฐ์ถ๋ฌผ๋ก ํ์ํ์ง ์์ต๋๋ค. ์จ๊น ์์ฐ ์ฐธ์กฐ๋ฅผ ์ ๊ฑฐํ๊ณ , ์ ์ธ ์์ฐ์ด ์ฌ์ ํ ํ์ํ ์ถ๋ ฅ์ ์คํจ ์ฌ์ ์ ํจ๊ป ๋ณด๋ฅํฉ๋๋ค.
quality.assets๋ ์์ฐ ๋ฐ์ดํธ ์์ง ํ์ง์ด๋ฉฐ manifest ์์ฑ ์ฑ๊ณต์ ๋ปํ์ง ์์ต๋๋ค. assetSummary.description๊ณผ excludedCount๊ฐ ๋ฏธ์์งยท๋ถ๋ถ ์์งยท์จ๊น ์ ์ธ๋ฅผ ์ค๋ช
ํฉ๋๋ค. ๋ฐ์ดํธ ์์ง์ ์์ฒญํ์ง ์์๋ค๋ฉด not-collected ์์ฝ๊ณผ quality.assets: not-requested๊ฐ ํจ๊ป ์ฌ ์ ์์ต๋๋ค.
๋ฐฐ์น ์๋ต์ recommendedBatchSize๋ ์ต๋ 3, maxFrameCount๋ 6, maxFrameOutputUnits๋ 12์
๋๋ค.
sourceMap.version=2๋ ๊ณต๊ฐ ์คํ์
์ ์ ๊ฑฐํ ๊ณ์ฝ์
๋๋ค. exact๋ ์๋ณธ ํ๋์ ๋์ํ๋ ์์ฑ ์์ฑ/ํ๊ทธ/ํ
์คํธ ๋งคํ์ ๊ฒ์ฆํ๋ค๋ ๋ป์
๋๋ค. ์ค ์์น, ๋ธ๋ผ์ฐ์ ํฝ์
์ผ์น, ๋ฐ์ํ ๋๋ฑ์ฑ ๋๋ ํ๋ฉด ์ ์ฒด ์์ฑ๋๋ฅผ ๋ณด์ฆํ์ง ์์ต๋๋ค. generatedProperty๋ h="740px", flex="1", aspectRatio="320 / 48"์ฒ๋ผ ์ถ๋ ฅ์ ์๋ ์์ฑ์ ๋ด์ต๋๋ค. characters๋ children, ์๋ฌต์ cross-axis stretch๋ implicit:align-self:stretch๋ก ํ์ํฉ๋๋ค. grow๋ ์ค์ flex ์์ฑ๊ณผ accounted-for-implicit-flex-grow๋ฅผ ํจ๊ป ์ฝ์ต๋๋ค. ๊ธฐ์กด sizing ๊ฒ์ฆ๊ณผ ์ง๋จ์ ์ ์ง๋ฉ๋๋ค. ๋ด๋ถ renderer/validator์ ์์น ์ ๋ณด๋ ๊ณต๊ฐ sourceMap์ ์ง๋ ฌํํ์ง ์์ต๋๋ค.
overflowDirection์ ์บก์ฒ manifest์ ํฌํจ๋ฉ๋๋ค. NONE์ ๋ช
์์ ๋น์คํฌ๋กค, JSON null์ ์์ง ์ ์๋ณธ ์์ฑ์ด ์์, ํค ๋ถ์ฌ๋ ์ด์ ์์ง๊ธฐ์ ๋ฏธ์์ง, fieldErrors.overflowDirection์ ์ฝ๊ธฐ ์คํจ์
๋๋ค. ์ธ๋ก/๊ฐ๋ก/์๋ฐฉํฅ ์คํฌ๋กค์ ๊ฐ๊ฐ overflowY="auto"/overflowX="auto"/overflow="auto"๋ก ์์ฑํฉ๋๋ค. clipsContent=true๋ ์คํฌ๋กค์ ์ทจ์ํ์ง ์์ผ๋ฉฐ, ํ ์ถ ์คํฌ๋กค์์๋ ๋ค๋ฅธ ์ถ์ clipํฉ๋๋ค. ABSOLUTE FIXED ๋์ด๋ ํ์ padding์ด ์์ด๋ ๋ช
์์ ๋์ด๋ก ๋ณด์กดํฉ๋๋ค. FILL/HUG๋ฅผ px๋ก ๊ณ ์ ํ์ง ์์ต๋๋ค.
์ผ๋ฐ ํ๋ฉด export๋ ์์ง์ด ๊ธธ์ด์ง๋ฉด ์ฝ 1์ด์ ์ด๊ธฐ ๋๊ธฐ ํ exportJob์ ๋ฐํํฉ๋๋ค(assetJob์ exportJob์ ๊ฐ๋ฆฌํค๋ ํธํ ์ฐธ์กฐ์ด๋ฉฐ ๋ณธ๋ฌธ์ ๋ฐ๋ณตํ์ง ์์ต๋๋ค). jobId๋ก ์ํ๋ฅผ ์กฐํํ๊ณ (์์ฐ ํ์ assetIdยทstatusยทbyteLengthยทsha256ยทfileState ์์ฃผ๋ก ๊ฐ๊ฒฐํ๊ฒ ๋ฐํ๋๋ฉฐ, ์ ์ฒด ํ์ ์กฐํ์ responseFields:["exportJob.assets"]๋ฅผ ๋ถ์ฌ ์ ํํฉ๋๋ค) paused ์ํ๋ jobAction:"resume"์ผ๋ก ์ฌ๊ฐํฉ๋๋ค. calls์ frame/root IDยทpaginationยทelapsedMs์ projection ์๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค. ์์ฐ์ frame-output unit๋น 5โ20์ด์ ๊ณํ์ฉ ์ถ์ ์ด๋ฉฐ ๋ณด์ฅ์ด ์๋๋๋ค. ์์ฒญ ํ๋ 6 frames/12 units์ ๋ณ๊ฐ๋ก upstream ์ง์ฐ์ job์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ง์ฐ ํ๋ ์์ ๋ถ๋ฆฌํ๋ ค๋ฉด ํ ํ๋ ์์ฉ ํธ์ถํ์ญ์์ค. ์์
์ ์๋ฒ ํ๋ก์ธ์ค ์์์ 30๋ถ, ์๋ฃ ์๋ต์ 5๋ถ ๋ณด์กด๋๋ฉฐ ์ฌ์์์ ๋๊ฒจ ๋ณด์กด๋์ง ์์ต๋๋ค.
artifact์ artifactState๋ expired(ํ์ธ๋ TTL ๋ง๋ฃ), evicted(ํ์ธ๋ ์บ์ ์ ๊ฑฐ), issued-by-another-process(๋ค๋ฅธ devup-mcp ํ๋ก์ธ์ค๊ฐ ๋ฐ๊ธํ id โ ์ฌ์์ ์ ์ ์๋ฒ๋ ๋ค๋ฅธ ์ธ์
์ ์๋ฒ), unknown(ํ์ฌ ์๋ฒ์์ ์์ธ ํ๋จ ๋ถ๊ฐ)์ ๊ตฌ๋ถํฉ๋๋ค. artifactId์ ์ 6๋ฐ์ดํธ๊ฐ ๋ฐ๊ธํ ํ๋ก์ธ์ค์ ํ์์ด๋ผ ๋์คํฌ์ ์๋ฌด๊ฒ๋ ์ฐ์ง ์๊ณ ๊ตฌ๋ถํ๋ฉฐ, id๋ ๊ทธ๋๋ก 43์์
๋๋ค. ์ต๊ทผ ์ ๊ฑฐ 64๊ฐ ์ด๋ด์ ๋ณต๊ตฌ metadata๊ฐ ์์ผ๋ฉด canonical URL๊ณผ ์ ํ์ nextAction.arguments๋ก ์ ๊ณตํฉ๋๋ค. URL ์๋ฌธ์ ํ์ผ ์ ๋ชฉ์ ์ ์ฅํ์ง ์์๋ ๊ฐ์ ๋์์ ๊ฐ๋ฆฌํค๋ canonical URL์ ๊ตฌ์ฑํฉ๋๋ค. metadata๊ฐ ์์ผ๋ฉด recoveryState:"unrecoverable"๋ก ๋ช
์ํ๋ฉฐ, ์๋ฒ ์ฌ์์์ด๋ผ๊ณ ๋จ์ ํ์ง ์์ต๋๋ค.
์ค๋ฅ์ details.recovery๋ mode(recollect | reproject | reread-manifest | fix-uri), cause, reprojectable, requiresOriginalUrl์ ์ค๋๋ค. resource ์ฝ๊ธฐ ์คํจ๋ ๊ณ์ resource not found์ด์ง๋ง data์ ๊ฐ์ recovery๊ฐ ์ค๋ฆฝ๋๋ค โ artifact๊ฐ ์ด์ ์๋๋ฐ output์ด ์์ผ๋ฉด reproject, ์ฒญํฌ ๋ฒํธ๊ฐ ๋ฒ์ ๋ฐ์ด๋ฉด chunkCountยทmanifestUri์ ํจ๊ป reread-manifest์
๋๋ค. artifact์ capability๊ฐ ์์ฒญํ output์ ๋ฎ์ง ๋ชปํด ๊ฑฐ์ ํ ๋๋ recovery.missing์ด ๋น ์ง ๊ฒ(referencePng, asset-captures ๋ฑ)์, nextAction์ด artifactId ๋์ ์๋ url๋ก ๋ค์ ๋ถ๋ฅด๋ ์ธ์๋ฅผ ๋ด์ต๋๋ค. ์ฑ๊ณต ์๋ต์ cache.reuse๋ ์ด artifactId๋ก Figma ํธ์ถ ์์ด ๋ ํฌ์ํ ์ ์๋ output(withArtifactId)๊ณผ ์๋ url์ด ํ์ํ ๊ฒ(needsUrl)์ ๋ฏธ๋ฆฌ ๋์ดํฉ๋๋ค.
responseLimit/responseOffset์ ์ด๋ฏธ ์์ง๋ ๊ฒฐ๊ณผ๋ฅผ ์๋ฅด๋ ๋ฐํ ํ๋์ ๋๋ค(compact.rs๊ฐ ์์ง๋ ๋ ธ๋ ๋ชฉ๋ก์skip/take). Figma๋ฅผ ์ผ๋ง๋ ์ฝ๋์ง๋ ๋ฐ๊พธ์ง ์์ผ๋ฏ๋ก ์์ง ๋น์ฉ์ ์ํ์ด ์๋๋๋ค. ๋งค์ฐ ํฐ ๋ ธ๋(outputs:["outline"]์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ฒฝ์ฐ)๋ ๊ฐ์ ์กฐ์ ํ์ง ๋ง๊ณdevup_figma_explore๋ก ๋ด๋ถ ํ๋ ์์ ์ฐพ์ ๊ทธ ํ๋ ์๋ง exportํ๊ฑฐ๋, ์น์๋ง ํ์ํ๋ฉดdevup_figma_measure๋ฅผ ์ฐ์ธ์. ์ค๋ ๊ฑธ๋ฆฌ๋ ์์ ์jobAction:"cancel"๋ก ์ทจ์ํ ์ ์์ต๋๋ค.- ์งง์ ์ํ ์กฐํ: ํด๋ง์
responseFields๋ฅผ ๋ถ์ด๋ฉด ํ์ํ ๋ถ๋ถ๋ง ๋ฐ์ต๋๋ค. ์:{"jobId":"<id>","responseFields":["exportJob.state","exportJob.elapsedMs","exportJob.completedCalls","exportJob.nextAction"]}. ํ๋ ์ด๋ฆ์ ์ค์ ์๋ต์ ํค๋ฅผ ๋ฐ๋ฅด๋ฏ๋ก ๋จผ์ ํ ๋ฒ ์ ์ฒด ์๋ต์ผ๋ก ํ์ธํ์ธ์.devup_figma_auth์status๋ ์ต์์summaryํ ์ค์ด ์ง๊ธ ์ฐ๋ ๊ฒฝ๋ก(๋ธ๋ฆฌ์ง/metered direct)์ ๋น์ฉ์ ๋จผ์ ๋งํฉ๋๋ค. - resource ์๋น:
delivery:"resource"(๋๋ ์๋ ์ ํ)์ ๊ฒฐ๊ณผ๋devup://artifact/{artifactId}/outputs/{outputId}/manifest๋ฅผ ๋จผ์ ์ฝ๊ณ , manifest์chunkUris๋ฅผ ์์๋๋ก ์ฝ์ด ์ด์ด ๋ถ์ ๋๋ค. ์ฒญํฌ ๋ฒํธ๊ฐ ๋ฒ์ ๋ฐ์ด๋ฉด ์ค๋ฅ์recovery๊ฐ manifest๋ฅผ ๋ค์ ์ฝ์ผ๋ผ๊ณ ์๋ดํฉ๋๋ค. - ๋ฌธ์์ด/๊ฐ์ฒด ๋ฐํ ์ฐจ์ด: ๋๊ตฌ ๊ฒฐ๊ณผ๋
content์ JSON ํ ์คํธ์structuredContent๋ก ๊ฐ์ ๋ด์ฉ์ด ํจ๊ป ์ฌ ์ ์๊ณ ,read_mcp_resource์ ๋ฐํํ์ ํธ์คํธ ์ด๋ํฐ๋ง๋คcontents[0].text(๋ฌธ์์ด)์ด๊ฑฐ๋ ์ด๋ฏธ ํ์ฑ๋ ๊ฐ์ฒด์ผ ์ ์์ต๋๋ค.typeof raw === "string" ? JSON.parse(raw) : raw์ฒ๋ผ ์ ๊ทํํด์ ์ฝ์ผ์ธ์. ์ด ์ฐจ์ด๋ ์๋ฒ๊ฐ ์๋๋ผ ํธ์คํธ ์ด๋ํฐ ๋ชซ์ผ ์ ์์ผ๋ฉฐ, ์๋ฒ ๋ฒ๊ทธ๋ก ํ์ ๋ ์ฌ๋ก๋ ์์ต๋๋ค. - ์ฐ๊ฒฐ ์ํ ์ฝ๊ธฐ:
activePath:"direct"์ด๋ฉด์paths.bridge.available:false๋ ์๋ฒ ์ ์ ์คํจ๊ฐ ์๋๋ผ "ํ๋ฌ๊ทธ์ธ์ด ์ฐ๊ฒฐ๋์ง ์์ metered direct๋ก ์ฝ๋ ์ค"์ด๋ผ๋ ๋ป์ ๋๋ค.summary์paths.bridge.reason์ ๋ณด์ธ์.
TSX ํญ๋ชฉ์ ๊ธฐ๋ณธ ํ๋๋ nodeId, property, generatedProperty, resolution์
๋๋ค. ์ ํ์ variableId๋ ์๋ณธ ๋ณ์ ํ ํฐ ์ฐธ์กฐ, styleId๋ typography/style ํ ํฐ ์ฐธ์กฐ, assetId๋ ์ด๋ฏธ์งยท๋ฒกํฐ ์์ฐ ์ฐธ์กฐ๋ฅผ ์๋ณํ ๋ ๋ถ์ต๋๋ค. ํ ํญ๋ชฉ์ ์ฌ๋ฌ ์๋ณ์๊ฐ ํจ๊ป ์์ ์ ์์ผ๋ฉฐ ํด๋น ์ฐธ์กฐ๊ฐ ์์ผ๋ฉด ์๋ตํฉ๋๋ค. elementIndex๋ ๊ทธ ํญ๋ชฉ์ด ๋งคํํ JSX ์ฌ๋ ํ๊ทธ์ ๋ฌธ์ ์์ ๋ฒํธ(0๋ถํฐ)์ด๊ณ , devup_ui_validate๊ฐ ์๋ฐ์ ๋ถ์ด๋ ๋ฒํธ์ ๊ฐ์ต๋๋ค โ ์คํ์
์์ด ๋์ ์๋ ํค์
๋๋ค. devup.json ๋งคํ์ jsonPointer๋ก ํ
๋ง ์์น๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ TSX ๊ธฐ๋ณธ ํ๋๊ฐ ๋ชจ๋ ์๋ ๊ฒ์ ์๋๋๋ค.
| resolution | ์๋ฏธ์ ๊ฒ์ฆ ๋ฒ์ |
|---|---|
exact |
์๋ณธ ํ๋์ ์์ฑ ํ๊ทธยทํ ์คํธ์ ์๋ฏธ ๋งคํ. ํ๋ฉด ์ ์ฒด์ ํฝ์ /๋ฐ์ํ ๋๋ฑ์ฑ ๋ณด์ฆ์ ์๋. |
raw-fallback |
ํ ํฐ ๋๋ ์ ์ฉ ๋งคํ ๋ผ๋ฒจ์ด ์๋ ์ผ๋ฐ ์๋ณธ ๊ฐยท์์ฑ ์ ์ฑ
๋งคํ ๊ฒฝ๋ก. raw ๊ฐ์ ๋ฌด๋ณํ ๋ณต์ฌ๋ ๋ฎ์ ์ ๋ขฐ๋๋ฅผ ๋ปํ์ง ์์ผ๋ฉฐ, ๋ณ๋ ABSOLUTE component๊ฐ verified์ฌ๋ ์ด ๋ผ๋ฒจ์ ์ ์ง๋ฉ๋๋ค. |
verified-explicit-dimension |
์ฝ๊ธฐ ์ค๋ฅ ์๋ ์๋ณธ width/height ์์น์ ์์ฑ w/h/boxSize์ px ๊ฐ์ด ์ ํํ ๊ฐ์์ ํ์ธ. ๋ฐ์ํ ๋ฐฐ์น๊น์ง ๊ฒ์ฆํ ๊ฒ์ ์๋. |
accounted-for-content-sizing |
textAutoResize์ ๋ฐ๋ฅธ ๊ณ ์ ํฌ๊ธฐ ์๋ต์ ์๋ฏธ ๋งคํ. ํฐํธ ๋ฉํธ๋ฆญ๊ณผ ๋ธ๋ผ์ฐ์ ํฝ์ ์ ๋ฏธ์ธก์ . |
verified-layout-sizing |
์๋ณธ FIXED/FILL/layoutGrow ์๋์ ์์ฑ h/boxSize/flex ๊ด๊ณ๋ฅผ sizing ๊ฒ์ฆ๊ธฐ๋ก ํ์ธ. |
accounted-for-implicit-flex-stretch |
์ค์ ์์ฑ ๋ถ๋ชจ์ cross-axis stretch์ ํฌ๊ธฐ ๊ธฐ์ค์ผ๋ก ์๋ต๋ ํฌ๊ธฐ๋ฅผ ์ค๋ช . |
accounted-for-implicit-flex-grow |
์ค์ ์์ฑ ๋ถ๋ชจ์ main-axis flex-grow์ ๋จ์ ๊ณต๊ฐ์ผ๋ก ํฌ๊ธฐ๋ฅผ ์ค๋ช . |
restored-hug-after-mask-child-folding |
์ ํ mask ์์์ ์๋ณธ ํฌ๊ธฐ์ ๋
๋ฆฝ์ ์ธ ํฌ๊ธฐ ๊ธฐ์ค์ผ๋ก HUG/aspectRatio ๋ณต์. -from-absoluteBoundingBox ์ ๋ฏธ์ฌ๋ bounding box์์ ํฌ๊ธฐ๋ฅผ ์ป์ ๊ฒฝ์ฐ. |
variable-token / style-token |
์๋ณธ ๋ณ์/์คํ์ผ ID์ ์์ฑ ํ ํฐ ์ฐธ์กฐ์ ๋งคํ. |
asset |
์๋ณธ ์์ฐ ID์ ์์ฑ ์์ฐ ์์ฑ์ ๋งคํ. ๋ฐ์ด๋๋ฆฌ ์์ง ์ฑ๊ณต ์ฌ๋ถ๋ assetSummary์์ ๋ณ๋ ํ์ธ. |
variant-selector |
์๋ณธ variant ์ ํ์ ์์ฑ selector ์์ฑ๊ณผ ์ฐ๊ฒฐ. |
unverified-property-mapping |
์๋ณธ์ ๋์ํ๋ ์์ฑ ์์ฑ์ ํ์ธํ์ง ๋ชปํจ. ์ถ๊ฐ ๊ฒ์ฆ ํ์. |
variable / alias / style |
devup.json์ ์ง์ ๋ณ์ ๊ฐ / ํด์๋ ๋ณ์ alias / ์คํ์ผ์์ ๋์จ ํ ๋ง ๊ฐ๊ณผ JSON pointer. |
node๋ ๋ด๋ถ ๋
ธ๋ ๋ฒ์์ฉ์ด๋ฉฐ ๊ณต๊ฐ v2 property entries์๋ ํฌํจ๋์ง ์์ต๋๋ค.
R16์ sourceMap.resolutionSemantics๋ ์ด ๋ผ๋ฒจ ์ฌ์ ๊ณผ axis="mapping-method"๋ฅผ ์๋ต์ ํฌํจํฉ๋๋ค. Section frame์ dictionary="/resolutionSemantics"๋ก ์์ ์๋ต์ ๊ณตํต ์ฌ์ ์ ์ฐธ์กฐํ๋ฉฐ, ์ด ์ฌ์ ์ resource delivery์๋ ๋จ์ต๋๋ค. diagnostics.details.components.*.state๋ ๋ณ๋์ ์ ํ๋ ๊ฒ์ฆ ์ถ์
๋๋ค. ๊ฐ์ screen/output ์์์ nodeId์ ์๋ณธ property(width/height/x/y โ width/height/horizontal/vertical)๋ก ์ฐ๊ฒฐํฉ๋๋ค. ์๋ฅผ ๋ค์ด w="100%"์ ๋งคํ์ raw-fallback์ด์ง๋ง, ํ์ ๋ ๋์ผ FIXED ๋ถ๋ชจ ํญ์์ ํด์ํ ๊ฐ์ด ์๋ณธ ํญ๊ณผ ๊ฐ์ผ๋ฉด ABSOLUTE width๋ verified์ผ ์ ์์ต๋๋ค. ์ด ๋ ๋ผ๋ฒจ ๋ชจ๋ ํ๋ฉด ์ ์ฒด์ ํฝ์
ยท๋ฐ์ํ ๋ฑ๊ฐ์ฑ ์ธก์ ์ ์๋๋๋ค.
R16์ ์คํจํ ์น์ ์ฆ๋ช
์ blockedBy๋ฅผ ์ถ๊ฐํฉ๋๋ค. ๋ถ๋ชจ ํญ ๋ถ๋ช
(parent-width-unknown), ๋ถ๋ชจ ํญ ๋ถ์ผ์น(parent-width-unequal), ์ฝ๊ธฐ ์ค๋ฅ(read-error), ๋นFIXED sizing(non-fixed-sizing), dimension ์ถฉ๋(conflicting-dimension-props)์ ๊ตฌ๋ถํฉ๋๋ค. ์ฑ๊ณต ์ null์ด๋ฉฐ widthPreservation์๋ ๊ฐ์ ๊ฐ์ด ๋ค์ด๊ฐ๋๋ค. ์ฒซ ์ฐจ๋จ ์ด์ ๋ง ๋ณด๊ณ ํ๋ฏ๋ก ๋๋จธ์ง ์กฐ๊ฑด์ ํต๊ณผ๋ ๋ค๋ฅธ ์คํจ ๋ถ๊ธฐ์ ์คํ์ ๋ปํ์ง ์์ต๋๋ค. ์์ฐ์ ๋ถ๋ชจ percentage ์ฆ๋ช
๋์ ์ค์ ์ ํ๋ render-boundary ์ฆ๋ช
์ ์คํจ ์ด์ ๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
์ต์ข
์๋ต๊ณผ ๊ฐ frame์ verdictScope๋ status/projection์ ๊ทธ๋๋ก ํ์ํ๊ณ statusCauses์ projectionCauses๋ก ์์ธ์ ์์ฝํฉ๋๋ค. projection ์์ธ์ nodeId/screenId/output/code/property์ ๋ฏธํด๊ฒฐ component๋ฅผ ๊ฐ๋ฆฌํค๋ฏ๋ก, width/height๊ฐ verified์ฌ๋ horizontal/vertical์ด approximated์ธ ํ๋ฉด์ ์ ์ฒด ํ์ ์ ๋ฐ๋ก ์ค๋ช
ํฉ๋๋ค. diagnosticIndex๋ ๊ฐ์ ๊ฐ์ฒด์ projectionIssues ์ธ๋ฑ์ค์
๋๋ค. includeDiagnostics=false ๋ฐ resource delivery์๋ ์์ฝ์ด ์ ์ง๋ฉ๋๋ค.
ABSOLUTE ์ง๋จ์ components๋ height/width/horizontal/vertical๋ณ stateยทfidelityImpactยท์๋ณธ ๊ฐยท์์ฑ ๊ฐยท๊ฒ์ฆ ์ด์ ๋ฅผ ์ ๊ณตํฉ๋๋ค. resolutionConditions์๋ ๋จ์ ๊ทผ์ฌ ํญ๋ชฉ์ ํด์ ์กฐ๊ฑด๋ง ๋ค์ด๊ฐ๋๋ค. CENTER๋ ์๋ณธ ์ค์ฌ ์คํ์
, left/top 50%, translate ๋ฐ ์ค์ ์์ฑ ๋ถ๋ชจ ์ขํ ๊ธฐ์ค๊น์ง ํ์ธํด์ผ ๊ฒ์ฆ๋ฉ๋๋ค. MIN์ ์๋ณธ ์คํ์
๊ณผ ์์ฑ px๋ฅผ ๋น๊ตํฉ๋๋ค. MAX๋ ํฌ๊ธฐ ๊ฒ์ฆ์ ์ ์ ๋ก parentSize-offset-size์ right/bottom ์ฌ๋ฐฑ์ ๋น๊ตํฉ๋๋ค. ์ ์ฝ ํ๋ ์ ์ฒด๊ฐ ์๋ ์ด์ ์บก์ฒ๋ constraintDeclared=false๋ก ํ์ํ๋ฉฐ ์์ฑ๋ ๋ก์ปฌ ์คํ์
๋ง ๋น๊ตํ๊ณ ๋ฐ์ํ ์ ์ฝ์ ์ถ์ ํ์ง ์์ต๋๋ค. ์ฆ๋ช
๋์ง ์์ MAX/STRETCH/SCALE, ๋๋ฝ geometry ๋๋ ํ๋ ์ค๋ฅ๋ ๊ทผ์ฌ๋ก ๋จ์ต๋๋ค. ๋ช
์์ FIXED ๋์ด ๋ณด์กด์ percentage ๋๋น์ ๋๋ฑ์ฑ์ ์ฆ๋ช
ํ์ง ์์ต๋๋ค.
R14๋ ABSOLUTE ์์์ FIXED ํญ๊ณผ ์์ฑ๋ ์ง๊ณ containing block์ ํ์ px ํญ์ด ๊ฐ์ ๊ฒฝ์ฐ w="100%"์ ๋์์ ๊ฒ์ฆํฉ๋๋ค. ํน์ ํญ์ ํ์ ํ์ง ์์ผ๋ฉฐ, ์์ฑ ์ฝ๋๋ ๋ฐ๊พธ์ง ์์ต๋๋ค. ํ์ฌ ์ฆ๋ช
๋ฒ์๋ ์ฝ๊ธฐ ์ค๋ฅ๊ฐ ์๋ ๋์ผ ํฌ๊ธฐ์ FIXED ๋ถ๋ชจ, ๋ช
์์ positioning, ๋ถ๋ชจ padding/border ๋ฐ ํฌ๊ธฐ override๊ฐ ์๋ ๊ฒฝ์ฐ์
๋๋ค. ๋ถ๋ชจ ํญ์ด ์ ๋์ ์ด๊ฑฐ๋ ๊ฐ์ด ๋ค๋ฅด๋ฉด ๊ทผ์ฌ๋ก ๋จ์ต๋๋ค. appliedValue.widthPreservation์ components.width์ ๊ฐ์ ๊ทผ๊ฑฐ, ๋ถ๋ชจ ์์ฑ ํญ, resolvedPixels, sourceFields, ๊ณ์ฐ์์ด ๋ค์ด๊ฐ๋๋ค. componentSummary.verified/unresolved๋ ๋ค ํญ๋ชฉ ์ค ๊ฒ์ฆ๋ ๊ฒ๊ณผ ๋จ์ ๊ฒ์ ๋๋๋๋ค.
ABSOLUTE ์์ฐ์ components๋ boundary(์ ํํ export ๊ฒฝ๊ณยท์๋ณธ bounding box์์ ์ฐจ์ดยทsourceFieldsยท๊ณ์ฐ์), rounding(์
๋ ฅยท์์ฑ๊ฐยท์ค์ฐจ), constraintInterpretation(์ง์ ์ ์ฝยท์ฒซ ์์ ์์ยท๊ธฐ๋ณธ๊ฐ)์ ๋ถ๋ฆฌํฉ๋๋ค. ๋ฐ์ฌ๋ฆผ์ round(value*100)/100์ ์์ฑ๊ฐ์ ์ผ์น ๋ฐ ์ต๋ 0.005px ์ค์ฐจ๋ฅผ ํ์ธํ๋ฉฐ ๋ถ๋์์์ ๋น๊ต ์ฌ์ ๋ 1e-12px์
๋๋ค. ๊ฒฝ๊ณ ์ฐจ์ด๋ฅผ ๋ฐ์ฌ๋ฆผ ์ค์ฐจ๋ก ํก์ํ์ง ์์ต๋๋ค. ์์ฐ ์น์์ verified๋ ์์ง๋ render bounds ํฌ์์ ๊ฒ์ฆ์ด๋ฉฐ ์๋ณธ layout box์์ ๋์ผ์ฑ์ด๋ SVG/CSS ํฉ์ฑ ์ธก์ ์ ์๋๋๋ค. GROUP์ null/๋๋ฝ ์ ์ฝ์ ์ฒซ ์์์์ ๊ฐ์ ธ์ค๊ฑฐ๋ MIN์ผ๋ก ๊ธฐ๋ณธ ์ฒ๋ฆฌํ ๊ฒฝ์ฐ ๊ทธ ์ ์ฑ
์ assumed๋ก ํ์ํฉ๋๋ค. ์์น ๊ณ์ฐ๊ณผ ๋ฐ์ฌ๋ฆผ์ด ๋ง์๋ GROUP์ ๋ฐฐ์น ์๋์ ๊ฐ๋ค๋ ์ฆ๋ช
์ด ์์ผ๋ฉด ํด๋น ์์น ์ถ์ approximated๋ก ์ ์งํฉ๋๋ค.
๋น๋ ๋ ์ง๋จ์ ์ค๋ฅ ์์ด ์ฝ์ visible=false ๋๋ ๋ช
์์ absoluteRenderBounds=null์ accounted-for-non-rendering / fidelityImpact=none์ผ๋ก ๊ธฐ๋กํฉ๋๋ค. verification์ fieldยทfieldPresentยทvalueยทreadError๊ฐ ๊ทผ๊ฑฐ์
๋๋ค. ํ๋ ๋ถ์ฌ๋ ์ฝ๊ธฐ ์คํจ๋ unverified-non-rendering / approximated๋ก ์ ์งํ๋ฉฐ ์ฌ์์ง ์กฐ๊ฑด์ ์๋ดํฉ๋๋ค.
HUG ๊ฒ์ฆ์ ์๋ณธ๊ณผ ์ผ์นํ๋ ์์ฑ auto-layout์์ ํฌ๊ธฐ override ์์ด intrinsic sizing ์๋๋ฅผ ํํํ๋์ง ํ์ธํฉ๋๋ค. FIXED percentage ํฌ๊ธฐ๋ ์ผ์นํ๋ auto-layout๊ณผ ๋ช ์์ ์ผ๋ก ๊ฐ์ ํฌ๊ธฐ์ธ FIXED ๋ถ๋ชจ, ํ ๋๋ฆฌยทpaddingยทmin/max override ๋ถ์ฌ๊ฐ ํ์ธ๋ ์ ํ๋ ๊ฒฝ์ฐ๋ง ๊ฒ์ฆํฉ๋๋ค. CENTER ๊ฒ์ฆ์ ์๋ณธ์ ์ค์ฌ ์คํ์ 0๊ณผ ์์ฑ CSS์ ์ค์ฌ ๊ด๊ณ๋ฅผ ๋ปํฉ๋๋ค. ๋ถ๋ชจ๊ฐ ์ปค์ง ๋ ์๋ x๋ฅผ ๊ณ ์ ํ๋ค๋ ๋ป์ด ์๋๋ฉฐ, ๋ถ๋ชจ์ ๋ช ์์ px ๊ฐ์ด ๋ฐ๋๋ฉด ๋ถ๋ชจ ์์ ์ dimension coverage ์ฌ๊ฒ์ฆ์ด ์คํจํฉ๋๋ค. ๊ฒ์ฆ๋ ๋ช ์์ ํฌ๊ธฐ ๋งคํ์ canvas/derived-padding์ ์ผ๋ฐ ์๋ต ๊ท์น์ผ๋ก ์ฌ๊ฒ์ฆ ์๋ฌด๋ฅผ ๋ฉด์ ํ์ง ์์ต๋๋ค.
projectionEvidence๋ ํ์ธ๋ ๋น๋ ๋์ ๊ฒ์ฆ ์๋ฃ ABSOLUTE ํญ๋ชฉ์ ๊ทผ๊ฑฐ๋ฅผ ๋ด์ผ๋ฉฐ, includeDiagnostics=false์ฌ๋ ์ต์์ ๋ฐ ํ๋ ์ ์๋ต์ ์ ๊ณตํฉ๋๋ค. ๋ฏธํด๊ฒฐ ๊ทผ์ฌ๋ projectionIssues์ ๋จ์ผ๋ฏ๋ก ๋ ๋ฐฐ์ด์ ๊ตฌ๋ถํด ์ฝ์ต๋๋ค.
์ต์ข
TSX์ ๋ชจ๋ JSX ์์ฑ(ํํ์ยทbooleanยทspread ํฌํจ)์ ํ์๋ก ๊ฒ์ฌํฉ๋๋ค. ๊ธฐ์กด sourceMap์ ์๋ ์์ฑ์ ์์ฑ ๋จ๊ณ์ ์๋ณธ ํ๋์ ๊ณ์ฐ์ผ๋ก ๋์กฐํ๋ฉฐ, ํ์ธ๋ ํญ๋ชฉ์ DEVUP_CODEGEN_PROPERTY_EVIDENCE๋ก projectionEvidence์ ๋จ๊น๋๋ค. sourceFields, originalValue, calculation, stage, generatedProperty, elementIndex, assetId ๋ฐ details.output์ ํจ๊ป ์ฝ์ต๋๋ค. ์์ฐ ๊ฒฝ๊ณ ๋ณด์ ์ render bounds์ bounding box์ ์ฐจ์ด, ํจ๊ณผ๋ ์๋ณธ effects๋ฅผ ๊ทผ๊ฑฐ๋ก ๋จ๊น๋๋ค. ์ด ๊ทผ๊ฑฐ๋ ์์ฑ ๊ณ์ฐ์ ๋์์ด๋ฉฐ SVG/CSS ํจ๊ณผ์ ๋ธ๋ผ์ฐ์ ํฉ์ฑ ์ค์ธก์ด ์๋๋๋ค.
์ค๋ช
ํ ์ ์๋ ์์ฑ์ DEVUP_CODEGEN_PROPERTY_UNMAPPED, mappingComplete=false๋ก ํญ์ ๋ณด๊ณ ํฉ๋๋ค. ๊ฐ์ ์ ์ง๋๋ฏ๋ก ์ด ์ง๋จ์ fidelityImpact๋ none์
๋๋ค. ๋ค๋ฅธ ์์คยท๊ทผ์ฌ๊ฐ ์๋ ๊ฒฝ์ฐ quality.projection=mapping-incomplete๊ฐ ๋๋ฉฐ exact์ ์ต์ข
์๋ฃ ํ์ ์ ํ์ฉํ์ง ์์ต๋๋ค. ๊ธฐ์กด lossyยทapproximated ํ์ ์ ์ ์งํฉ๋๋ค. ๋ฐ์ํ ๋ณํฉ์ ๊ฐ ํญ์ slot์์ ๋ณํฉ ๋ชจ๋์ ์ฝ์ด(๋ฐฐ์ด์ devup-ui๊ฐ ์ฝ๋ ๋๋ก, ๊ทธ ํญ์์ ์จ๊ธด ์์๋ ๋นผ๊ณ ) ๊ทธ ํญ๋ง ๋ฐ๋ก ๋ณํํ tsx์ ๋์กฐํฉ๋๋ค. ๊ฐ์ ์์, ๊ฐ์ ๊ฐ(๊ทธ ํญ์ ๊ณ์ฝ์ด ๊ฒ์ฆํ ๊ฐ), ๊ฐ์ ๊ธ์ด๊ณ ๊ทธ ํญ์ ๋จ๋ ์์๊ฐ ์์ ๋๋ง mergedMappingVerified๊ฐ true์ด๊ณ , ์๋๋ฉด mergeGaps๊ฐ ์ด๋ ํญ์ ์ด๋ ๋
ธ๋ยท์์ฑ์ธ์ง ๋๋ฉฐ ๊ฐ์ ์ง๋จ์ ์ ๊ณตํฉ๋๋ค. ์ปดํฌ๋ํธ ์ฐธ์กฐ๋ ์ด๋ฆ๊ณผ ๊ทธ ํญ์ ์ธ์คํด์ค๊ฐ ๊ณ ๋ฅธ variant๊น์ง ๋์กฐํ์ง๋ง, ๊ทธ๋ฆฌ๋ ๊ฒ์ ์ด ๋ชจ๋์ ์๋ ์ปดํฌ๋ํธ ํ์ผ์ด๊ณ ์ธ์คํด์ค๋ ๊ทธ ๊ธยทํฌ๊ธฐ๋ฅผ ๋ฎ์ด์ธ ์ ์์ผ๋ฏ๋ก, ์ฐธ์กฐ๋ฅผ ๋ณด์ฌ ์ฃผ๋ ๋ชจ๋์ ๊ฒ์ฆ๋์ง ์์ต๋๋ค(component-body-unverified). ์ฝ๋๋ฅผ ์ฝ๋ ๋์กฐ์ด์ง ๋ ๋๋ง์ด ์๋๋๋ค. strict๋ ๋งคํ ๋๋ฝ๋ ๊ฑฐ์ ํฉ๋๋ค. tsx์ componentTsx๋ฅผ ํจ๊ป ์์ฒญํ ๊ฒฝ์ฐ sourceMap.byOutput์ด ์ถ๋ ฅ๋ณ map์ ๊ตฌ๋ถํ๋ฉฐ ๊ธฐ์กด ๋จ์ผ map ํ๋๋ ํธํ์ฑ์ ์ํด ์ ์งํฉ๋๋ค.
outputPaths์ ํ๋ ์ ์ถ๋ ฅ ํค๋ frame:<nodeId>:<output>์
๋๋ค. ์: {"frame:3997:46715:tsx":"C:/allowed/Screen.tsx","frame:3997:46715:sourceMap":"C:/allowed/Screen.map.json"}. outputPathResults.supportedKeys๋ ์ด๋ฒ ํฌ์์์ ์ค์ ์ธ ์ ์๋ ํค๋ฅผ ์ด๊ฑฐํฉ๋๋ค. ํ๋ ์ ์๋ต์ ์ผ๋ฐ tsx/sourceMap ํค๋ฅผ ์ฐ๊ฑฐ๋ ๋ฏธ์ง์ยท๋ฏธ์์ฑ ์ถ๋ ฅ ํค๋ฅผ ์ฐ๋ฉด outputPathResults.diagnostics์ ๋ช
์ํ๋ฉฐ ์กฐ์ฉํ ๋ฌด์ํ์ง ์์ต๋๋ค. ์ต์์ ๋จ์ผ ์ถ๋ ฅ์ ๊ธฐ์กด ์ผ๋ฐ ํค๋ฅผ ์ฌ์ฉํฉ๋๋ค. outputPaths ์๋ต์ ์ฑ๊ณต์ ์ผ๋ก ์ปค๋ฐํ ํ์ผ๋ง ๋ํ๋
๋๋ค. ์์ฐ binary๋ ๊ณ์ assetRequests[].outputPath๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ช
์์ resource์ ์๋ resource ์ ํ ๋ชจ๋ nextAction.tool/arguments๋ก ๋์ผ artifact์ ์์ ๋ณธ๋ฌธ ๋์กฐ ์์๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ผ๋ฐ ํ๋ฉด์ ๋จ์ผ frameยท๋จ์ผ ์ถ๋ ฅ์ด๋ฉฐ ํ์ผ์ ๋ค์ ์ฐ์ง ์์ต๋๋ค. sizeEstimate.outputBytes๋ ๊ธฐ์กด ์ ํ ์ถ๋ ฅ์ UTF-8 ๋ฐ์ดํธ ์(PNG๋ binary ๋ฐ์ดํธ ์)์ด๊ณ minimumWireBytes๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ์ธํ JSON ์ค๋ณต ์ ์ก ํํ์
๋๋ค. ์ฌํฌ์ ์๋ต์ ์ ์ฒด ํฌ๊ธฐ๋ ์ค์ธกํ์ง ์์์ผ๋ฏ๋ก ํ๋ ๋ฏธ๋ง์ ๊ฒฝ์ฐ์๋ inlineFit=unknown์
๋๋ค. ํ์คํ ํ๋๋ฅผ ๋๋ ๊ฒฝ์ฐ resource๋ฅผ ์๋ดํ๋ฉฐ, inline ํฌ๊ธฐ ์ด๊ณผ ์ ๊ธฐ์กด R12 ๊ต์ ์ธ์๋ฅผ ์ ์งํฉ๋๋ค. ์์ฐ ์์ฒญยท์ถ๋ ฅ ๊ฒฝ๋ก๊ฐ ์ฝ๋ URL์ ๊ฒฐ์ ํ๋ ๊ฒฝ์ฐ์๋ ์๋ ๊ฒฐํฉ๋ resource ์ธ์๋ฅผ ์ ์งํ์ฌ ์๋ชป๋ ๋ณธ๋ฌธ ๋์กฐ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
/devup is the entry point for new projects, existing features, bug fixes,
Figma page implementation and refactors. Figma screen planning is a branch
of the confirmed project plan; complete this section before the screen workflow below.
Read sources before asking: devup_project_context for every supported scope,
Atlassian MCP getJiraIssue / searchJiraIssuesUsingJql for issues, epic children
and dependencies, referenced Confluence/spec documents, and Figma exploration
(screen names, field labels, forms, tables and detail screens). Pass each read as
evidence: [{source, facts}] to devup_project_plan. Facts use goal, parts,
figma (links), screens ([{name, fields}]), and <featureId>.screens, .states,
.permissions, .forms, .notifications. Backend decisions use erd, tenancy,
auth, lifecycle, indexes, storage; delivery uses jiraPolicy, branchPolicy,
prPolicy. A sourced fact is a default with its provenance, not another question.
Sources are read by the runtime's connectors, never by treating a URL as its contents.
devup_project_plan intakewith projectRoot: always ask the four initial questions with the runtime question tool (recommended option first): work type (refactor may be a custom answer), optional Figma/Jira/spec sources, one-sentence goal, and parts. Existingapis/recommends front + admin + API;apps/adminrecommends front + admin. Retain planId on every later call.- Read newly named sources.
draftwith all initial answers, source-labelled evidence andfeatures: [{id,scope,screens,acceptance}]orissues: [{key,scope,dependencies,acceptance}](epic children are issues too). Each unresolved feature gets concrete screen/role, state, permission, validation, notification/integration rounds. Put all remaining unknowns into extraQuestions. No implementation starts while a question remains unanswered. - API in scope: inspect existing
vespertide.jsonandapis/*/models/*.json. Draft completeentitiesas vespertide model objects andrelationswith from/to, cardinality oneToMany|manyToMany, column/joinTable and onDelete. Signup/post Figma evidence seeds user/post entities and a user FK, but the agent must expand every actual domain from the source evidence. Review the ERD round, ownership/tenancy, auth with integer roles (0,10,50,100), status enums, soft delete, audit timestamps, nullable fields, unique/composite keys, filter/sort indexes, file/image storage and cascade/restrict/set_null actions. Read https://github.com/dev-five-git/vespertide/blob/main/SKILL.md and schemas/. Use snake_case,$schemaon every model, inline PK/FK/unique/index constraints, and table constraints only for CHECK. A manyToMany relation generates its join table. modelsDir is relative to projectRoot; set it explicitly for multiple APIs. Re-draft structured entities for requested corrections before confirming. - When Figma is present, run the existing screen-plan draft/rounds/confirm workflow (routes, groups, exclusions, site facts) before project confirm.
- Ask all delivery questions now: Jira none/comment/transition, branch, PR.
devup_project_plan confirmrequires every applicable answer and writes source models plus confirmed state in one transaction. Then in modelsWorkingDirectory run the returned commands, in order:vespertide diff,vespertide sql,vespertide revision -m "confirmed project plan",vespertide export --orm seaorm. The tool returns commands; the runtime executes and checks them. Never hand-write migrations/ or src/models/. Build vespera CRUD and feature routes, openapi.json, and the devup-api client;devup_stack_diffmust show zero drift before done. - Latest-first updates, vinext, exact layout, all interaction/site defaults, runtime/visual audits and the existing never-wait rules below still apply. After confirm, use project-plan defer with id/reason/recommended/destructive; continue independent work. At the end assume with no decisions resolves all pending recommendations; destructive decisions remain unbuilt. Status includes ERD Mermaid, decisions and the unit table; retain unresolved evidence in reports.
devup_project_plan split splits work, not files. Jira input produces one unit
per issue/sub-task with its explicit dependencies (reject cycles/unknown IDs).
Without Jira, it produces shared layout/theme first, then each feature's
models -> API -> client -> front chain; front-only features depend on shared.
Review cross-feature dependencies before dispatch; the supervisor sequences
shared database work to avoid concurrent schema edits. Each unit has acceptance
criteria and build/lint/typecheck/tests/validate/runtime/visual/stack-diff checks.
.devup/units/<id>.md contains scope, decisions, ERD and screen context, and checklist.
Default unitQuestions: "supervisor" means workers never ask the user: questions
were settled across all units during intake, and supervisor ownership avoids
repeated questions and keeps decisions consistent. unitQuestions: "worker"
is an explicit alternative, still subject to the confirmed never-wait policy.
Load orca-cli and orchestration skills to create one worktree per unit,
dispatch the DAG in parallel where independent, collect worker_done, and rerun
each unit's checks yourself before merging. New decisions use orchestration
ask/reply to the supervisor: answer from recorded decisions, or defer with a
recommended option while the worker continues other work. Send failed checks
back to the same worker session. Update unit states with status unitUpdates
(pending -> running -> verifying -> merged, or unresolved); merged needs recorded
supervisor verification. Without Orca, execute the same units sequentially in one
session. Only under the recorded Jira/PR policy, comment results and PR link and
transition issues. Final report includes the unit table, DAG, ERD and unresolved
items; never claim completion from split or command generation alone.
Source organization: Rust source under crates/ is limited to 1000 lines per
file, including tests. The existing size-contract test checks this alongside
all embedded JSON text assets. Source sections use include! inside the
original module namespace to retain narrow privacy and existing test names.
Long tool text is in crates/devup-mcp/src/server/text/; other crates use
src/text/. include_str! keeps these assets inside the binary.
App selection keyword overrides in .devup/screen-plan.config.json:
{"appSelectionKeywords":{"publicApps":["storefront"],"admin":["controlroom"],"publicScreens":["catalogue"],"adminRoutes":["control"]}}Each supplied category replaces its defaults; omitted categories retain the vendored defaults. An empty category explicitly disables its keyword matches.
Connected URLs: run links-resolve at every width. Each same-origin anchor contributes source URL, accessible label, href, resolved pathname and width to linkTable (also Markdown in finalReport). GET each distinct target once, including concrete dynamic hrefs, and reject HTTP failures, error pages and unplanned-target URLs absent from the confirmed plan and existing routes. Any failing link row blocks done.
Header navigation wider than a narrow viewport emits a navigation-fit risk and a validation warning. Exploration carries measured navigation widths into the screen plan; without a mobile-menu frame, draft proposes a drawer behind a menu button below the navigation content-fit breakpoint.