specweave 0.23.18 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +93 -49
- package/CLAUDE.md +137 -4
- package/dist/src/cli/helpers/ado-area-path-mapper.d.ts +89 -0
- package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -0
- package/dist/src/cli/helpers/ado-area-path-mapper.js +213 -0
- package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts +29 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +109 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +2 -0
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/smart-filter.d.ts +83 -0
- package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -0
- package/dist/src/cli/helpers/smart-filter.js +265 -0
- package/dist/src/cli/helpers/smart-filter.js.map +1 -0
- package/dist/src/core/qa/quality-gate-decider.d.ts +1 -1
- package/dist/src/core/qa/quality-gate-decider.js +2 -2
- package/dist/src/core/qa/quality-gate-decider.js.map +1 -1
- package/dist/src/core/qa/risk-calculator.d.ts +2 -2
- package/dist/src/core/qa/risk-calculator.js +2 -2
- package/dist/src/core/validators/ac-presence-validator.d.ts +56 -0
- package/dist/src/core/validators/ac-presence-validator.d.ts.map +1 -0
- package/dist/src/core/validators/ac-presence-validator.js +149 -0
- package/dist/src/core/validators/ac-presence-validator.js.map +1 -0
- package/dist/src/integrations/ado/area-path-mapper.d.ts +137 -0
- package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -0
- package/dist/src/integrations/ado/area-path-mapper.js +267 -0
- package/dist/src/integrations/ado/area-path-mapper.js.map +1 -0
- package/dist/src/integrations/jira/filter-processor.d.ts +126 -0
- package/dist/src/integrations/jira/filter-processor.d.ts.map +1 -0
- package/dist/src/integrations/jira/filter-processor.js +207 -0
- package/dist/src/integrations/jira/filter-processor.js.map +1 -0
- package/dist/src/integrations/jira/jira-client.d.ts +13 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +33 -0
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/utils/ac-embedder.d.ts +63 -0
- package/dist/src/utils/ac-embedder.d.ts.map +1 -0
- package/dist/src/utils/ac-embedder.js +217 -0
- package/dist/src/utils/ac-embedder.js.map +1 -0
- package/dist/src/utils/env-manager.d.ts +86 -0
- package/dist/src/utils/env-manager.d.ts.map +1 -0
- package/dist/src/utils/env-manager.js +188 -0
- package/dist/src/utils/env-manager.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave/agents/AGENTS-INDEX.md +1 -1
- package/plugins/specweave/agents/increment-quality-judge-v2/AGENT.md +9 -9
- package/plugins/specweave/commands/specweave-do.md +37 -0
- package/plugins/specweave/commands/specweave-done.md +159 -0
- package/plugins/specweave/commands/specweave-embed-acs.md +446 -0
- package/plugins/specweave/commands/specweave-next.md +148 -3
- package/plugins/specweave/commands/specweave-qa.md +2 -2
- package/plugins/specweave/hooks/pre-increment-start.sh +168 -0
- package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
- package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +331 -0
- package/plugins/specweave-alternatives/.claude-plugin/plugin.json +10 -0
- package/plugins/specweave-alternatives/commands/alternatives-analyze.md +336 -0
- package/plugins/specweave-alternatives/skills/architecture-alternatives/SKILL.md +651 -0
- package/plugins/specweave-alternatives/skills/bmad-method/SKILL.md +420 -0
- package/plugins/specweave-alternatives/skills/spec-kit-expert/SKILL.md +487 -0
- package/plugins/specweave-backend/commands/api-scaffold.md +80 -0
- package/plugins/specweave-backend/commands/crud-generate.md +109 -0
- package/plugins/specweave-backend/commands/migration-generate.md +139 -0
- package/plugins/specweave-confluent/commands/connector-deploy.md +154 -0
- package/plugins/specweave-confluent/commands/ksqldb-query.md +179 -0
- package/plugins/specweave-confluent/commands/schema-register.md +123 -0
- package/plugins/specweave-core/.claude-plugin/plugin.json +21 -0
- package/plugins/specweave-core/commands/architecture-review.md +288 -0
- package/plugins/specweave-core/commands/code-review.md +213 -0
- package/plugins/specweave-core/commands/refactor-plan.md +249 -0
- package/plugins/specweave-core/skills/code-quality/SKILL.md +157 -0
- package/plugins/specweave-core/skills/design-patterns/SKILL.md +244 -0
- package/plugins/specweave-core/skills/software-architecture/SKILL.md +83 -0
- package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +22 -0
- package/plugins/specweave-cost-optimizer/commands/cost-analyze.md +360 -0
- package/plugins/specweave-cost-optimizer/commands/cost-optimize.md +480 -0
- package/plugins/specweave-cost-optimizer/skills/aws-cost-expert/SKILL.md +416 -0
- package/plugins/specweave-cost-optimizer/skills/cloud-pricing/SKILL.md +325 -0
- package/plugins/specweave-cost-optimizer/skills/cost-optimization/SKILL.md +337 -0
- package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-diagrams/commands/diagrams-generate.md +168 -0
- package/plugins/specweave-docs/.claude-plugin/plugin.json +10 -0
- package/plugins/specweave-docs/commands/docs-generate.md +441 -0
- package/plugins/specweave-docs/commands/docs-init.md +334 -0
- package/plugins/specweave-docs/skills/docusaurus/SKILL.md +581 -0
- package/plugins/specweave-docs/skills/spec-driven-brainstorming/SKILL.md +689 -0
- package/plugins/specweave-docs/skills/technical-writing/SKILL.md +1039 -0
- package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-figma/.claude-plugin/plugin.json +23 -0
- package/plugins/specweave-figma/commands/figma-import.md +690 -0
- package/plugins/specweave-figma/commands/figma-to-react.md +834 -0
- package/plugins/specweave-figma/commands/figma-tokens.md +815 -0
- package/plugins/specweave-frontend/.claude-plugin/plugin.json +21 -0
- package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +387 -0
- package/plugins/specweave-frontend/agents/frontend-architect/README.md +385 -0
- package/plugins/specweave-frontend/agents/frontend-architect/examples.md +590 -0
- package/plugins/specweave-frontend/agents/frontend-architect/templates/component-template.tsx +152 -0
- package/plugins/specweave-frontend/agents/frontend-architect/templates/hook-template.ts +311 -0
- package/plugins/specweave-frontend/agents/frontend-architect/templates/page-template.tsx +228 -0
- package/plugins/specweave-frontend/commands/component-generate.md +510 -0
- package/plugins/specweave-frontend/commands/design-system-init.md +494 -0
- package/plugins/specweave-frontend/commands/frontend-scaffold.md +207 -0
- package/plugins/specweave-frontend/commands/nextjs-setup.md +396 -0
- package/plugins/specweave-frontend/skills/design-system-architect/SKILL.md +278 -0
- package/plugins/specweave-frontend/skills/frontend/SKILL.md +420 -0
- package/plugins/specweave-frontend/skills/nextjs/SKILL.md +546 -0
- package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +194 -0
- package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-jira/commands/import-projects.js +183 -0
- package/plugins/specweave-jira/commands/import-projects.md +97 -0
- package/plugins/specweave-jira/commands/import-projects.ts +288 -0
- package/plugins/specweave-jira/commands/specweave-jira-import-projects.md +298 -0
- package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-kubernetes/commands/cluster-setup.md +262 -0
- package/plugins/specweave-kubernetes/commands/deployment-generate.md +242 -0
- package/plugins/specweave-kubernetes/commands/helm-scaffold.md +333 -0
- package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-mobile/commands/app-scaffold.md +233 -0
- package/plugins/specweave-mobile/commands/build-config.md +256 -0
- package/plugins/specweave-mobile/commands/screen-generate.md +289 -0
- package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-plugin-dev/.claude-plugin/plugin.json +13 -12
- package/plugins/specweave-plugin-dev/commands/plugin-create.md +333 -0
- package/plugins/specweave-plugin-dev/commands/plugin-publish.md +339 -0
- package/plugins/specweave-plugin-dev/commands/plugin-test.md +293 -0
- package/plugins/specweave-plugin-dev/skills/claude-sdk/SKILL.md +162 -0
- package/plugins/specweave-plugin-dev/skills/marketplace-publishing/SKILL.md +263 -0
- package/plugins/specweave-plugin-dev/skills/plugin-development/SKILL.md +316 -0
- package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-release/commands/specweave-release-npm.md +110 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +168 -0
- package/plugins/specweave-testing/.claude-plugin/plugin.json +21 -0
- package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +797 -0
- package/plugins/specweave-testing/agents/qa-engineer/README.md +443 -0
- package/plugins/specweave-testing/agents/qa-engineer/templates/playwright-e2e-test.ts +470 -0
- package/plugins/specweave-testing/agents/qa-engineer/templates/test-data-factory.ts +507 -0
- package/plugins/specweave-testing/agents/qa-engineer/templates/vitest-unit-test.ts +400 -0
- package/plugins/specweave-testing/agents/qa-engineer/test-strategies.md +726 -0
- package/plugins/specweave-testing/commands/e2e-setup.md +1081 -0
- package/plugins/specweave-testing/commands/test-coverage.md +979 -0
- package/plugins/specweave-testing/commands/test-generate.md +1156 -0
- package/plugins/specweave-testing/commands/test-init.md +409 -0
- package/plugins/specweave-testing/skills/e2e-playwright/SKILL.md +769 -0
- package/plugins/specweave-testing/skills/tdd-expert/SKILL.md +934 -0
- package/plugins/specweave-testing/skills/unit-testing-expert/SKILL.md +1011 -0
- package/plugins/specweave-tooling/.claude-plugin/plugin.json +22 -0
- package/plugins/specweave-tooling/commands/specweave-tooling-skill-create.md +691 -0
- package/plugins/specweave-tooling/commands/specweave-tooling-skill-package.md +751 -0
- package/plugins/specweave-tooling/commands/specweave-tooling-skill-validate.md +858 -0
- package/plugins/specweave-ui/.claude-plugin/plugin.json +10 -0
- package/plugins/specweave-ui/commands/ui-automate.md +199 -0
- package/plugins/specweave-ui/commands/ui-inspect.md +70 -0
- package/plugins/specweave-ui/skills/browser-automation/SKILL.md +314 -0
- package/plugins/specweave-ui/skills/ui-testing/SKILL.md +716 -0
- package/plugins/specweave-ui/skills/visual-regression/SKILL.md +728 -0
- package/plugins/specweave/commands/check-hooks.md +0 -257
- package/plugins/specweave/commands/specweave-archive-increments.md +0 -82
- package/plugins/specweave-plugin-dev/skills/plugin-expert/SKILL.md +0 -1231
- /package/plugins/specweave/{agents/code-reviewer.md → skills/code-reviewer/SKILL.md} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave-docs-preview",
|
|
3
3
|
"description": "Interactive documentation preview with Docusaurus. Launch local dev server to view living documentation in beautiful UI with hot reload, auto-generated sidebar, and Mermaid diagrams. Build static sites for deployment.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.24.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SpecWeave Team",
|
|
7
7
|
"url": "https://spec-weave.com"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "specweave-figma",
|
|
3
|
+
"description": "Comprehensive Figma design-to-code automation. Import Figma designs via API/MCP, convert components to React/Vue/Angular, extract design tokens, generate responsive layouts, and sync design systems. Focus on accelerating frontend development from Figma designs.",
|
|
4
|
+
"version": "0.24.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Anton Abyzov",
|
|
7
|
+
"email": "anton.abyzov@gmail.com"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://spec-weave.com",
|
|
10
|
+
"repository": "https://github.com/anton-abyzov/specweave",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"figma",
|
|
14
|
+
"design-to-code",
|
|
15
|
+
"figma-api",
|
|
16
|
+
"design-tokens",
|
|
17
|
+
"react-components",
|
|
18
|
+
"vue-components",
|
|
19
|
+
"design-systems",
|
|
20
|
+
"figma-plugin",
|
|
21
|
+
"specweave"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
# /specweave-figma:import
|
|
2
|
+
|
|
3
|
+
Import Figma designs into your project using Figma REST API or MCP server integration.
|
|
4
|
+
|
|
5
|
+
You are a Figma integration expert who automates design imports with comprehensive metadata extraction.
|
|
6
|
+
|
|
7
|
+
## Your Task
|
|
8
|
+
|
|
9
|
+
Import Figma designs (files, frames, components, styles) into your project with full metadata, assets, and specifications.
|
|
10
|
+
|
|
11
|
+
### 1. Figma API Overview
|
|
12
|
+
|
|
13
|
+
**REST API Capabilities**:
|
|
14
|
+
- Fetch files, frames, components, and styles
|
|
15
|
+
- Export images (PNG, JPG, SVG, PDF)
|
|
16
|
+
- Access design tokens (colors, typography, spacing)
|
|
17
|
+
- Read component metadata and descriptions
|
|
18
|
+
- Retrieve version history
|
|
19
|
+
|
|
20
|
+
**API Endpoints**:
|
|
21
|
+
```
|
|
22
|
+
GET /v1/files/:file_key # Get file metadata
|
|
23
|
+
GET /v1/files/:file_key/nodes # Get specific nodes
|
|
24
|
+
GET /v1/images/:file_key # Export images
|
|
25
|
+
GET /v1/files/:file_key/components # Get components
|
|
26
|
+
GET /v1/files/:file_key/styles # Get styles
|
|
27
|
+
GET /v1/teams/:team_id/projects # List projects
|
|
28
|
+
GET /v1/files/:file_key/versions # Version history
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Authentication**:
|
|
32
|
+
```bash
|
|
33
|
+
# Personal Access Token (recommended for server-side)
|
|
34
|
+
curl -H "X-Figma-Token: YOUR_TOKEN" https://api.figma.com/v1/files/:file_key
|
|
35
|
+
|
|
36
|
+
# OAuth 2.0 (recommended for user-facing apps)
|
|
37
|
+
# Authorization: Bearer YOUR_OAUTH_TOKEN
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Setup Configuration
|
|
41
|
+
|
|
42
|
+
**Environment Variables (.env)**:
|
|
43
|
+
```bash
|
|
44
|
+
# Required
|
|
45
|
+
FIGMA_ACCESS_TOKEN=figd_XXXXXXXXXXXXXXXXXXXX
|
|
46
|
+
|
|
47
|
+
# Optional (MCP server)
|
|
48
|
+
FIGMA_MCP_ENABLED=true
|
|
49
|
+
FIGMA_MCP_SERVER_PATH=/path/to/figma-mcp-server
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Configuration File (figma.config.json)**:
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"fileKey": "ABC123XYZ456",
|
|
56
|
+
"fileUrl": "https://www.figma.com/file/ABC123XYZ456/ProjectName",
|
|
57
|
+
"importSettings": {
|
|
58
|
+
"components": true,
|
|
59
|
+
"styles": true,
|
|
60
|
+
"assets": true,
|
|
61
|
+
"exportFormats": ["svg", "png@2x"],
|
|
62
|
+
"skipHidden": true,
|
|
63
|
+
"includeMetadata": true
|
|
64
|
+
},
|
|
65
|
+
"exportPaths": {
|
|
66
|
+
"components": "./src/components/figma",
|
|
67
|
+
"assets": "./public/assets/figma",
|
|
68
|
+
"tokens": "./src/design-tokens",
|
|
69
|
+
"metadata": "./.figma/metadata.json"
|
|
70
|
+
},
|
|
71
|
+
"naming": {
|
|
72
|
+
"componentPrefix": "Figma",
|
|
73
|
+
"useKebabCase": true,
|
|
74
|
+
"preserveFigmaNames": false
|
|
75
|
+
},
|
|
76
|
+
"mcp": {
|
|
77
|
+
"enabled": false,
|
|
78
|
+
"serverPath": null,
|
|
79
|
+
"cacheDir": "./.figma/cache"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Figma REST API Integration
|
|
85
|
+
|
|
86
|
+
**TypeScript/JavaScript Implementation**:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import axios from 'axios';
|
|
90
|
+
import fs from 'fs/promises';
|
|
91
|
+
import path from 'path';
|
|
92
|
+
|
|
93
|
+
interface FigmaConfig {
|
|
94
|
+
accessToken: string;
|
|
95
|
+
fileKey: string;
|
|
96
|
+
exportFormats?: string[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
class FigmaImporter {
|
|
100
|
+
private baseUrl = 'https://api.figma.com/v1';
|
|
101
|
+
private headers: Record<string, string>;
|
|
102
|
+
private fileKey: string;
|
|
103
|
+
|
|
104
|
+
constructor(config: FigmaConfig) {
|
|
105
|
+
this.headers = {
|
|
106
|
+
'X-Figma-Token': config.accessToken,
|
|
107
|
+
};
|
|
108
|
+
this.fileKey = config.fileKey;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Fetch file metadata and structure
|
|
113
|
+
*/
|
|
114
|
+
async fetchFile() {
|
|
115
|
+
const response = await axios.get(
|
|
116
|
+
`${this.baseUrl}/files/${this.fileKey}`,
|
|
117
|
+
{ headers: this.headers }
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return response.data;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Fetch specific nodes by ID
|
|
125
|
+
*/
|
|
126
|
+
async fetchNodes(nodeIds: string[]) {
|
|
127
|
+
const ids = nodeIds.join(',');
|
|
128
|
+
const response = await axios.get(
|
|
129
|
+
`${this.baseUrl}/files/${this.fileKey}/nodes?ids=${ids}`,
|
|
130
|
+
{ headers: this.headers }
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
return response.data.nodes;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Export images for nodes
|
|
138
|
+
*/
|
|
139
|
+
async exportImages(
|
|
140
|
+
nodeIds: string[],
|
|
141
|
+
options: {
|
|
142
|
+
format?: 'png' | 'jpg' | 'svg' | 'pdf';
|
|
143
|
+
scale?: number;
|
|
144
|
+
useAbsoluteBounds?: boolean;
|
|
145
|
+
} = {}
|
|
146
|
+
) {
|
|
147
|
+
const { format = 'png', scale = 2, useAbsoluteBounds = false } = options;
|
|
148
|
+
const ids = nodeIds.join(',');
|
|
149
|
+
|
|
150
|
+
const response = await axios.get(
|
|
151
|
+
`${this.baseUrl}/images/${this.fileKey}?ids=${ids}&format=${format}&scale=${scale}&use_absolute_bounds=${useAbsoluteBounds}`,
|
|
152
|
+
{ headers: this.headers }
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return response.data.images;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Fetch all components in file
|
|
160
|
+
*/
|
|
161
|
+
async fetchComponents() {
|
|
162
|
+
const response = await axios.get(
|
|
163
|
+
`${this.baseUrl}/files/${this.fileKey}/components`,
|
|
164
|
+
{ headers: this.headers }
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return response.data.meta.components;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Fetch all styles (colors, text, effects, grids)
|
|
172
|
+
*/
|
|
173
|
+
async fetchStyles() {
|
|
174
|
+
const response = await axios.get(
|
|
175
|
+
`${this.baseUrl}/files/${this.fileKey}/styles`,
|
|
176
|
+
{ headers: this.headers }
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
return response.data.meta.styles;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Download image from URL
|
|
184
|
+
*/
|
|
185
|
+
async downloadImage(imageUrl: string, outputPath: string) {
|
|
186
|
+
const response = await axios.get(imageUrl, {
|
|
187
|
+
responseType: 'arraybuffer',
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
191
|
+
await fs.writeFile(outputPath, response.data);
|
|
192
|
+
|
|
193
|
+
return outputPath;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Traverse Figma node tree recursively
|
|
198
|
+
*/
|
|
199
|
+
traverseNodes(node: any, callback: (node: any) => void) {
|
|
200
|
+
callback(node);
|
|
201
|
+
|
|
202
|
+
if (node.children) {
|
|
203
|
+
node.children.forEach((child: any) => {
|
|
204
|
+
this.traverseNodes(child, callback);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Extract design tokens from file
|
|
211
|
+
*/
|
|
212
|
+
async extractDesignTokens() {
|
|
213
|
+
const file = await this.fetchFile();
|
|
214
|
+
const styles = await this.fetchStyles();
|
|
215
|
+
|
|
216
|
+
const tokens = {
|
|
217
|
+
colors: {},
|
|
218
|
+
typography: {},
|
|
219
|
+
spacing: {},
|
|
220
|
+
effects: {},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Extract color tokens
|
|
224
|
+
styles.forEach((style: any) => {
|
|
225
|
+
if (style.style_type === 'FILL') {
|
|
226
|
+
const node = this.findNodeById(file.document, style.node_id);
|
|
227
|
+
if (node?.fills?.[0]) {
|
|
228
|
+
const color = node.fills[0];
|
|
229
|
+
if (color.type === 'SOLID') {
|
|
230
|
+
tokens.colors[style.name] = this.rgbaToHex(color.color);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Extract text styles
|
|
236
|
+
if (style.style_type === 'TEXT') {
|
|
237
|
+
const node = this.findNodeById(file.document, style.node_id);
|
|
238
|
+
if (node?.style) {
|
|
239
|
+
tokens.typography[style.name] = {
|
|
240
|
+
fontFamily: node.style.fontFamily,
|
|
241
|
+
fontSize: node.style.fontSize,
|
|
242
|
+
fontWeight: node.style.fontWeight,
|
|
243
|
+
lineHeight: node.style.lineHeightPx,
|
|
244
|
+
letterSpacing: node.style.letterSpacing,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Extract effect styles (shadows, blurs)
|
|
250
|
+
if (style.style_type === 'EFFECT') {
|
|
251
|
+
const node = this.findNodeById(file.document, style.node_id);
|
|
252
|
+
if (node?.effects) {
|
|
253
|
+
tokens.effects[style.name] = node.effects;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
return tokens;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Find node by ID in tree
|
|
263
|
+
*/
|
|
264
|
+
private findNodeById(node: any, id: string): any {
|
|
265
|
+
if (node.id === id) return node;
|
|
266
|
+
|
|
267
|
+
if (node.children) {
|
|
268
|
+
for (const child of node.children) {
|
|
269
|
+
const found = this.findNodeById(child, id);
|
|
270
|
+
if (found) return found;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Convert RGBA to HEX
|
|
279
|
+
*/
|
|
280
|
+
private rgbaToHex(color: { r: number; g: number; b: number; a?: number }): string {
|
|
281
|
+
const r = Math.round(color.r * 255);
|
|
282
|
+
const g = Math.round(color.g * 255);
|
|
283
|
+
const b = Math.round(color.b * 255);
|
|
284
|
+
|
|
285
|
+
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Usage
|
|
290
|
+
async function importFigmaDesigns() {
|
|
291
|
+
const importer = new FigmaImporter({
|
|
292
|
+
accessToken: process.env.FIGMA_ACCESS_TOKEN!,
|
|
293
|
+
fileKey: 'ABC123XYZ456',
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Fetch file structure
|
|
297
|
+
const file = await importer.fetchFile();
|
|
298
|
+
console.log('File:', file.name);
|
|
299
|
+
|
|
300
|
+
// Fetch components
|
|
301
|
+
const components = await importer.fetchComponents();
|
|
302
|
+
console.log(`Found ${components.length} components`);
|
|
303
|
+
|
|
304
|
+
// Export component images
|
|
305
|
+
const componentIds = components.map((c: any) => c.node_id);
|
|
306
|
+
const images = await importer.exportImages(componentIds, {
|
|
307
|
+
format: 'svg',
|
|
308
|
+
scale: 1,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Download images
|
|
312
|
+
for (const [nodeId, imageUrl] of Object.entries(images)) {
|
|
313
|
+
const component = components.find((c: any) => c.node_id === nodeId);
|
|
314
|
+
const outputPath = `./assets/${component.name}.svg`;
|
|
315
|
+
await importer.downloadImage(imageUrl as string, outputPath);
|
|
316
|
+
console.log(`Exported: ${outputPath}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Extract design tokens
|
|
320
|
+
const tokens = await importer.extractDesignTokens();
|
|
321
|
+
await fs.writeFile(
|
|
322
|
+
'./src/design-tokens/figma-tokens.json',
|
|
323
|
+
JSON.stringify(tokens, null, 2)
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
importFigmaDesigns().catch(console.error);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 4. MCP Server Integration
|
|
331
|
+
|
|
332
|
+
**MCP Server for Figma** (Recommended for Claude Code):
|
|
333
|
+
|
|
334
|
+
MCP (Model Context Protocol) servers provide structured access to Figma via Claude Code.
|
|
335
|
+
|
|
336
|
+
**Available MCP Servers**:
|
|
337
|
+
1. **@modelcontextprotocol/server-figma** (Official)
|
|
338
|
+
2. **figma-mcp-server** (Community)
|
|
339
|
+
3. **claude-figma-bridge** (Custom)
|
|
340
|
+
|
|
341
|
+
**Setup MCP Server**:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# Install MCP server
|
|
345
|
+
npm install -g @modelcontextprotocol/server-figma
|
|
346
|
+
|
|
347
|
+
# Configure in Claude Code settings
|
|
348
|
+
# ~/.claude/config.json
|
|
349
|
+
{
|
|
350
|
+
"mcpServers": {
|
|
351
|
+
"figma": {
|
|
352
|
+
"command": "mcp-server-figma",
|
|
353
|
+
"args": [],
|
|
354
|
+
"env": {
|
|
355
|
+
"FIGMA_ACCESS_TOKEN": "figd_XXXXXXXXXXXXXXXXXXXX"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Using MCP in Claude Code**:
|
|
363
|
+
|
|
364
|
+
Once MCP server is configured, Claude Code can directly access Figma:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// Claude Code will use MCP tools automatically
|
|
368
|
+
// Example: mcp__figma__getFile, mcp__figma__exportImages
|
|
369
|
+
|
|
370
|
+
// In your prompt:
|
|
371
|
+
// "Import all components from Figma file ABC123XYZ456 and export as SVG"
|
|
372
|
+
|
|
373
|
+
// Claude Code will invoke:
|
|
374
|
+
// - mcp__figma__getFile({ fileKey: "ABC123XYZ456" })
|
|
375
|
+
// - mcp__figma__exportImages({ nodeIds: [...], format: "svg" })
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**MCP Server Benefits**:
|
|
379
|
+
- No need to manage API tokens in code
|
|
380
|
+
- Automatic rate limiting
|
|
381
|
+
- Built-in caching
|
|
382
|
+
- Structured tool interface
|
|
383
|
+
- Better error handling
|
|
384
|
+
|
|
385
|
+
### 5. Import Workflow
|
|
386
|
+
|
|
387
|
+
**Step 1: Analyze Figma File**
|
|
388
|
+
```typescript
|
|
389
|
+
// Discover structure
|
|
390
|
+
const file = await importer.fetchFile();
|
|
391
|
+
|
|
392
|
+
// Find components, frames, pages
|
|
393
|
+
const components = [];
|
|
394
|
+
const frames = [];
|
|
395
|
+
|
|
396
|
+
importer.traverseNodes(file.document, (node) => {
|
|
397
|
+
if (node.type === 'COMPONENT') {
|
|
398
|
+
components.push({
|
|
399
|
+
id: node.id,
|
|
400
|
+
name: node.name,
|
|
401
|
+
description: node.description,
|
|
402
|
+
componentPropertyDefinitions: node.componentPropertyDefinitions,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (node.type === 'FRAME') {
|
|
407
|
+
frames.push({
|
|
408
|
+
id: node.id,
|
|
409
|
+
name: node.name,
|
|
410
|
+
width: node.absoluteBoundingBox.width,
|
|
411
|
+
height: node.absoluteBoundingBox.height,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
console.log(`Components: ${components.length}, Frames: ${frames.length}`);
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Step 2: Export Assets**
|
|
420
|
+
```typescript
|
|
421
|
+
// Export all components as SVG
|
|
422
|
+
const componentIds = components.map(c => c.id);
|
|
423
|
+
const svgImages = await importer.exportImages(componentIds, {
|
|
424
|
+
format: 'svg',
|
|
425
|
+
scale: 1,
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// Export all frames as PNG@2x
|
|
429
|
+
const frameIds = frames.map(f => f.id);
|
|
430
|
+
const pngImages = await importer.exportImages(frameIds, {
|
|
431
|
+
format: 'png',
|
|
432
|
+
scale: 2,
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Step 3: Save Metadata**
|
|
437
|
+
```typescript
|
|
438
|
+
const metadata = {
|
|
439
|
+
fileKey: importer.fileKey,
|
|
440
|
+
fileName: file.name,
|
|
441
|
+
version: file.version,
|
|
442
|
+
lastModified: file.lastModified,
|
|
443
|
+
components: components.map(c => ({
|
|
444
|
+
id: c.id,
|
|
445
|
+
name: c.name,
|
|
446
|
+
description: c.description,
|
|
447
|
+
exportedAs: `./assets/components/${c.name}.svg`,
|
|
448
|
+
})),
|
|
449
|
+
frames: frames.map(f => ({
|
|
450
|
+
id: f.id,
|
|
451
|
+
name: f.name,
|
|
452
|
+
dimensions: { width: f.width, height: f.height },
|
|
453
|
+
exportedAs: `./assets/frames/${f.name}@2x.png`,
|
|
454
|
+
})),
|
|
455
|
+
importedAt: new Date().toISOString(),
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
await fs.writeFile(
|
|
459
|
+
'./.figma/metadata.json',
|
|
460
|
+
JSON.stringify(metadata, null, 2)
|
|
461
|
+
);
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### 6. CLI Command
|
|
465
|
+
|
|
466
|
+
**NPM Script (package.json)**:
|
|
467
|
+
```json
|
|
468
|
+
{
|
|
469
|
+
"scripts": {
|
|
470
|
+
"figma:import": "tsx scripts/figma-import.ts",
|
|
471
|
+
"figma:import:watch": "tsx scripts/figma-import.ts --watch",
|
|
472
|
+
"figma:sync": "tsx scripts/figma-sync.ts"
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**CLI with Arguments**:
|
|
478
|
+
```typescript
|
|
479
|
+
// scripts/figma-import.ts
|
|
480
|
+
import yargs from 'yargs';
|
|
481
|
+
|
|
482
|
+
const argv = yargs(process.argv.slice(2))
|
|
483
|
+
.option('file-key', {
|
|
484
|
+
type: 'string',
|
|
485
|
+
description: 'Figma file key',
|
|
486
|
+
required: true,
|
|
487
|
+
})
|
|
488
|
+
.option('components', {
|
|
489
|
+
type: 'boolean',
|
|
490
|
+
description: 'Import components',
|
|
491
|
+
default: true,
|
|
492
|
+
})
|
|
493
|
+
.option('assets', {
|
|
494
|
+
type: 'boolean',
|
|
495
|
+
description: 'Export assets',
|
|
496
|
+
default: true,
|
|
497
|
+
})
|
|
498
|
+
.option('tokens', {
|
|
499
|
+
type: 'boolean',
|
|
500
|
+
description: 'Extract design tokens',
|
|
501
|
+
default: true,
|
|
502
|
+
})
|
|
503
|
+
.option('format', {
|
|
504
|
+
type: 'string',
|
|
505
|
+
description: 'Export format (svg, png, jpg)',
|
|
506
|
+
default: 'svg',
|
|
507
|
+
})
|
|
508
|
+
.parseSync();
|
|
509
|
+
|
|
510
|
+
const importer = new FigmaImporter({
|
|
511
|
+
accessToken: process.env.FIGMA_ACCESS_TOKEN!,
|
|
512
|
+
fileKey: argv.fileKey,
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
if (argv.components) {
|
|
516
|
+
const components = await importer.fetchComponents();
|
|
517
|
+
console.log(`Importing ${components.length} components...`);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (argv.assets) {
|
|
521
|
+
// Export logic
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (argv.tokens) {
|
|
525
|
+
const tokens = await importer.extractDesignTokens();
|
|
526
|
+
// Save tokens
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
**Usage**:
|
|
531
|
+
```bash
|
|
532
|
+
# Import everything
|
|
533
|
+
npm run figma:import -- --file-key ABC123XYZ456
|
|
534
|
+
|
|
535
|
+
# Import only components
|
|
536
|
+
npm run figma:import -- --file-key ABC123XYZ456 --no-assets --no-tokens
|
|
537
|
+
|
|
538
|
+
# Export as PNG
|
|
539
|
+
npm run figma:import -- --file-key ABC123XYZ456 --format png
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### 7. Rate Limiting and Caching
|
|
543
|
+
|
|
544
|
+
**Rate Limits** (Figma API):
|
|
545
|
+
- 30 requests per minute per IP
|
|
546
|
+
- 1000 requests per hour per token
|
|
547
|
+
|
|
548
|
+
**Implement Caching**:
|
|
549
|
+
```typescript
|
|
550
|
+
import NodeCache from 'node-cache';
|
|
551
|
+
|
|
552
|
+
class CachedFigmaImporter extends FigmaImporter {
|
|
553
|
+
private cache: NodeCache;
|
|
554
|
+
|
|
555
|
+
constructor(config: FigmaConfig) {
|
|
556
|
+
super(config);
|
|
557
|
+
this.cache = new NodeCache({ stdTTL: 3600 }); // 1 hour TTL
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async fetchFile() {
|
|
561
|
+
const cacheKey = `file:${this.fileKey}`;
|
|
562
|
+
const cached = this.cache.get(cacheKey);
|
|
563
|
+
|
|
564
|
+
if (cached) {
|
|
565
|
+
console.log('Using cached file data');
|
|
566
|
+
return cached;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const file = await super.fetchFile();
|
|
570
|
+
this.cache.set(cacheKey, file);
|
|
571
|
+
return file;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**Rate Limiting**:
|
|
577
|
+
```typescript
|
|
578
|
+
import Bottleneck from 'bottleneck';
|
|
579
|
+
|
|
580
|
+
class RateLimitedFigmaImporter extends FigmaImporter {
|
|
581
|
+
private limiter: Bottleneck;
|
|
582
|
+
|
|
583
|
+
constructor(config: FigmaConfig) {
|
|
584
|
+
super(config);
|
|
585
|
+
|
|
586
|
+
// 30 requests per minute
|
|
587
|
+
this.limiter = new Bottleneck({
|
|
588
|
+
minTime: 2000, // 2s between requests
|
|
589
|
+
maxConcurrent: 1,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async fetchFile() {
|
|
594
|
+
return this.limiter.schedule(() => super.fetchFile());
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async exportImages(...args: any[]) {
|
|
598
|
+
return this.limiter.schedule(() => super.exportImages(...args));
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### 8. Error Handling
|
|
604
|
+
|
|
605
|
+
**Common API Errors**:
|
|
606
|
+
- 401 Unauthorized: Invalid access token
|
|
607
|
+
- 403 Forbidden: No permission to access file
|
|
608
|
+
- 404 Not Found: File or node doesn't exist
|
|
609
|
+
- 429 Too Many Requests: Rate limit exceeded
|
|
610
|
+
- 500 Server Error: Figma API issue
|
|
611
|
+
|
|
612
|
+
**Error Handling Pattern**:
|
|
613
|
+
```typescript
|
|
614
|
+
async function importWithRetry(fileKey: string, retries = 3) {
|
|
615
|
+
for (let i = 0; i < retries; i++) {
|
|
616
|
+
try {
|
|
617
|
+
const importer = new FigmaImporter({
|
|
618
|
+
accessToken: process.env.FIGMA_ACCESS_TOKEN!,
|
|
619
|
+
fileKey,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
return await importer.fetchFile();
|
|
623
|
+
} catch (error) {
|
|
624
|
+
if (axios.isAxiosError(error)) {
|
|
625
|
+
const status = error.response?.status;
|
|
626
|
+
|
|
627
|
+
if (status === 401) {
|
|
628
|
+
throw new Error('Invalid Figma access token');
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (status === 403) {
|
|
632
|
+
throw new Error('No permission to access this file');
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (status === 429) {
|
|
636
|
+
const retryAfter = error.response?.headers['retry-after'] || 60;
|
|
637
|
+
console.log(`Rate limited. Retrying after ${retryAfter}s...`);
|
|
638
|
+
await sleep(retryAfter * 1000);
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (status === 500 && i < retries - 1) {
|
|
643
|
+
console.log(`Server error. Retrying (${i + 1}/${retries})...`);
|
|
644
|
+
await sleep(2000);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
throw error;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
throw new Error('Max retries exceeded');
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
## Workflow
|
|
658
|
+
|
|
659
|
+
1. Ask about Figma file URL and access requirements
|
|
660
|
+
2. Extract file key from URL
|
|
661
|
+
3. Verify Figma access token (from .env or prompt)
|
|
662
|
+
4. Fetch file metadata and analyze structure
|
|
663
|
+
5. Ask about import preferences (components, assets, tokens)
|
|
664
|
+
6. Set up directory structure for exports
|
|
665
|
+
7. Export assets with specified formats and scales
|
|
666
|
+
8. Extract design tokens and metadata
|
|
667
|
+
9. Save all data to configured paths
|
|
668
|
+
10. Generate import report with statistics
|
|
669
|
+
|
|
670
|
+
## When to Use
|
|
671
|
+
|
|
672
|
+
- Starting new projects with Figma designs
|
|
673
|
+
- Syncing design systems with code
|
|
674
|
+
- Automating asset exports from Figma
|
|
675
|
+
- Extracting design tokens for theme configuration
|
|
676
|
+
- Migrating from manual Figma exports to automated workflow
|
|
677
|
+
- Setting up CI/CD for design-to-code pipeline
|
|
678
|
+
|
|
679
|
+
## Best Practices
|
|
680
|
+
|
|
681
|
+
1. **Security**: Store access tokens in .env (never commit)
|
|
682
|
+
2. **Caching**: Cache file data to reduce API calls
|
|
683
|
+
3. **Rate Limiting**: Respect Figma API limits (30 req/min)
|
|
684
|
+
4. **Versioning**: Track Figma file versions in metadata
|
|
685
|
+
5. **Organization**: Structure exports by component type
|
|
686
|
+
6. **Documentation**: Include component descriptions from Figma
|
|
687
|
+
7. **Automation**: Use watch mode for continuous sync
|
|
688
|
+
8. **Testing**: Validate exports before committing
|
|
689
|
+
|
|
690
|
+
Import Figma designs with production-ready automation!
|