coderio 1.0.1 → 1.0.3-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -41
- package/dist/cli.js +78 -19
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +62 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -54,12 +54,12 @@ https://github.com/user-attachments/assets/bd0c3f18-e98a-4050-bf22-46b198fadac2
|
|
|
54
54
|
|
|
55
55
|
CodeRio can be seamlessly integrated into Cursor as a Skill. Simply input a prompt like **"Create a React project and restore this design with high fidelity,"** along with your output directory, Figma URL([Design Link](https://www.figma.com/design/c0UBII8lURfxZIY8W6tSDR/Top-16-Websites-of-2024---Awwwards--Community-?node-id=30-8264&t=FB3Hohq2nsH7ZFts-4)), and Token. The Agent will guide you step-by-step through the page generation process. For Landing Pages, it achieves **high-fidelity restoration**, accurately reproducing images and styles. It also automatically encapsulates reusable components (such as cards) and strictly adheres to **frontend development best practices**.
|
|
56
56
|
|
|
57
|
-
|
|
58
57
|
https://github.com/user-attachments/assets/43817e97-ffd2-40e3-9d33-78ee55b2ec2d
|
|
59
58
|
|
|
60
59
|
## 🚀 Quick Start
|
|
61
60
|
|
|
62
61
|
### Option 1: CLI (Recommended 👍🏻)
|
|
62
|
+
|
|
63
63
|
Best for one-click generation.
|
|
64
64
|
|
|
65
65
|
#### 1. Prerequisites
|
|
@@ -79,48 +79,104 @@ npm install -g coderio
|
|
|
79
79
|
pnpm add -g coderio
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
> **Note for pnpm v9+ users**: If you see a warning about "Ignored build scripts", run:
|
|
83
|
-
>
|
|
84
|
-
> ```bash
|
|
85
|
-
> pnpm approve-builds
|
|
86
|
-
> ```
|
|
87
|
-
>
|
|
88
|
-
> This allows native dependencies (better-sqlite3) to compile properly.
|
|
82
|
+
> **Note for pnpm v9+ users**: If you see a warning about "Ignored build scripts", run: `pnpm approve-builds` to allow native dependencies (better-sqlite3) to compile properly.
|
|
89
83
|
>
|
|
90
84
|
> **Note**: Validation features (e.g., `d2c --mode full`) require optional dependencies `playwright` and `sharp`. They are not bundled with coderio by default to keep installation lightweight. Please install them globally beforehand for smoother execution:
|
|
91
85
|
>
|
|
92
86
|
> ```bash
|
|
93
87
|
> npm install -g playwright sharp
|
|
94
88
|
> npx playwright install chromium
|
|
95
|
-
> ```
|
|
89
|
+
> ```
|
|
96
90
|
|
|
97
91
|
#### 3. Configuration
|
|
98
92
|
|
|
99
|
-
> **Important**:
|
|
100
|
-
> We highly recommend using **`gemini-3-pro-preview`** for the best balance of performance and cost.
|
|
93
|
+
> **Important**: Requires a **multimodal (vision)** model (Recommended: `gemini-3-pro-preview`).
|
|
101
94
|
|
|
102
|
-
Create `~/.coderio/config.yaml` (Windows: `%USERPROFILE%\.coderio\config.yaml`)
|
|
95
|
+
Create config file at `~/.coderio/config.yaml` (Windows: `%USERPROFILE%\.coderio\config.yaml`):
|
|
103
96
|
|
|
104
97
|
```yaml
|
|
105
98
|
model:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
provider: openai # anthropic | openai | google
|
|
100
|
+
model: gemini-3-pro-preview
|
|
101
|
+
baseUrl: https://api.anthropic.com
|
|
102
|
+
apiKey: your-api-key-here
|
|
110
103
|
|
|
111
104
|
figma:
|
|
112
|
-
|
|
105
|
+
token: your-figma-token-here
|
|
113
106
|
|
|
114
107
|
debug:
|
|
115
|
-
|
|
108
|
+
enabled: false # set 'true', if you want to save model and request information
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### 4. Usage
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Convert Figma design to code (default mode: code only)
|
|
115
|
+
coderio d2c -s 'https://www.figma.com/design/your-file-id/...'
|
|
116
|
+
|
|
117
|
+
# Full mode: Generate code + visual validation + auto-refinement
|
|
118
|
+
coderio d2c -s 'https://www.figma.com/design/your-file-id/...' -m full
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### 5. Run Your Project
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Navigate to generated project
|
|
125
|
+
cd coderio/<design-name_node-id>/my-app
|
|
126
|
+
|
|
127
|
+
# Install dependencies
|
|
128
|
+
pnpm install
|
|
129
|
+
|
|
130
|
+
# Start dev server
|
|
131
|
+
pnpm dev
|
|
132
|
+
|
|
133
|
+
# 🎉 Open http://localhost:5173
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### 6. View Validation Report
|
|
137
|
+
|
|
138
|
+
report path: coderio/<design-name_node-id>/process/validation/index.html
|
|
139
|
+
|
|
140
|
+
#### 📖 All Commands
|
|
141
|
+
|
|
142
|
+
| Command | Alias | Description |
|
|
143
|
+
| ----------------- | ----- | --------------------------------------------------- |
|
|
144
|
+
| `design2code` | `d2c` | Full pipeline: Figma → Protocol → Code → Validation |
|
|
145
|
+
| `design2protocol` | `d2p` | Extract design protocol only |
|
|
146
|
+
| `protocol2code` | `p2c` | Generate code from existing protocol |
|
|
147
|
+
| `validate` | `val` | Run validation on generated code |
|
|
148
|
+
| `images` | - | Download and process Figma assets |
|
|
149
|
+
|
|
150
|
+
### Option 2: Docker
|
|
151
|
+
|
|
152
|
+
Best for portable environments without Node.js installation.
|
|
153
|
+
|
|
154
|
+
#### 1. Prerequisites
|
|
155
|
+
|
|
156
|
+
- [Docker](https://docs.docker.com/get-docker/)
|
|
157
|
+
- [Figma Personal Access Token](https://www.figma.com/developers/api#access-tokens)
|
|
158
|
+
- LLM API Key ([Anthropic](https://console.anthropic.com/) | [OpenAI](https://platform.openai.com/) | [Google](https://aistudio.google.com/))
|
|
159
|
+
|
|
160
|
+
> **For Windows Users:** The commands below use bash syntax (heredoc, `${PWD}`, `--network=host`, etc.) which are not compatible with CMD or PowerShell. Please use **WSL2** to run them:
|
|
161
|
+
>
|
|
162
|
+
> 1. Install [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) and a Linux distribution (e.g. Ubuntu)
|
|
163
|
+
> 2. Install [Docker Desktop](https://docs.docker.com/desktop/install/windows-install/) and enable **WSL2 integration** in Settings → Resources → WSL Integration
|
|
164
|
+
> 3. Open a WSL2 terminal (run `wsl` in CMD/PowerShell, or open Ubuntu from the Start menu)
|
|
165
|
+
> 4. Run all the following commands inside the WSL2 terminal
|
|
166
|
+
|
|
167
|
+
#### 2. Installation
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
docker pull crpi-p4hwwrt00km3axuk.cn-shanghai.personal.cr.aliyuncs.com/coderio/coderio
|
|
116
171
|
```
|
|
117
172
|
|
|
118
|
-
|
|
119
|
-
|
|
173
|
+
#### 3. Configuration
|
|
174
|
+
|
|
175
|
+
Create a working directory and `config.yaml`:
|
|
120
176
|
|
|
121
177
|
```bash
|
|
122
|
-
mkdir -p
|
|
123
|
-
cat >
|
|
178
|
+
mkdir -p ./coderio-app && cd ./coderio-app
|
|
179
|
+
cat > config.yaml << 'EOF'
|
|
124
180
|
model:
|
|
125
181
|
provider: openai # anthropic | openai | google
|
|
126
182
|
model: gemini-3-pro-preview
|
|
@@ -134,10 +190,19 @@ debug:
|
|
|
134
190
|
enabled: false
|
|
135
191
|
EOF
|
|
136
192
|
```
|
|
137
|
-
</details>
|
|
138
193
|
|
|
139
194
|
#### 4. Usage
|
|
140
195
|
|
|
196
|
+
```bash
|
|
197
|
+
docker run -ti --rm \
|
|
198
|
+
--network=host \
|
|
199
|
+
-v ${PWD}:/app \
|
|
200
|
+
-v ./config.yaml:/root/.coderio/config.yaml \
|
|
201
|
+
crpi-p4hwwrt00km3axuk.cn-shanghai.personal.cr.aliyuncs.com/coderio/coderio bash
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Once inside the container, use CodeRio commands:
|
|
205
|
+
|
|
141
206
|
```bash
|
|
142
207
|
# Convert Figma design to code (default mode: code only)
|
|
143
208
|
coderio d2c -s 'https://www.figma.com/design/your-file-id/...'
|
|
@@ -163,37 +228,29 @@ pnpm dev
|
|
|
163
228
|
|
|
164
229
|
#### 6. View Validation Report
|
|
165
230
|
|
|
166
|
-
|
|
167
|
-
# Open validation report in browser
|
|
168
|
-
open coderio/<design-name_node-id>/process/validation/index.html
|
|
169
|
-
```
|
|
231
|
+
Generated files are mounted to your host machine. Open the validation report in your browser:
|
|
170
232
|
|
|
171
|
-
|
|
233
|
+
```
|
|
234
|
+
./coderio/<design-name_node-id>/process/validation/index.html
|
|
235
|
+
```
|
|
172
236
|
|
|
173
|
-
|
|
174
|
-
| ----------------- | ----- | --------------------------------------------------- |
|
|
175
|
-
| `design2code` | `d2c` | Full pipeline: Figma → Protocol → Code → Validation |
|
|
176
|
-
| `design2protocol` | `d2p` | Extract design protocol only |
|
|
177
|
-
| `protocol2code` | `p2c` | Generate code from existing protocol |
|
|
178
|
-
| `validate` | `val` | Run validation on generated code |
|
|
179
|
-
| `images` | - | Download and process Figma assets |
|
|
237
|
+
### Option 3: Skill (Portable Embedded Workflow)
|
|
180
238
|
|
|
181
|
-
### Option 2: Skill (Portable Embedded Workflow)
|
|
182
239
|
Best for control and precision using AI Agents.
|
|
183
240
|
|
|
184
241
|
**Prerequisites**:
|
|
185
242
|
Copy the Skill file to your Cursor configuration directory:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
cp docs/skills/SKILL.md ~/.cursor/skills/design-to-code/SKILL.md
|
|
189
|
-
```
|
|
243
|
+
|
|
244
|
+
Copy `skills\design-to-code` folder to `~\.cursor\skills` (Windows: `%USERPROFILE%\.cursor\skills`)
|
|
190
245
|
|
|
191
246
|
**Using in Cursor**:
|
|
192
|
-
|
|
247
|
+
|
|
248
|
+
1. Open Cursor Chat.
|
|
193
249
|
2. Type: **"Use design-to-code skill to convert this design: [Your Figma URL]"**
|
|
194
250
|
3. The Agent will guide you step-by-step through protocol extraction and code generation.
|
|
195
251
|
|
|
196
252
|
**Using in Claude Code**:
|
|
253
|
+
|
|
197
254
|
1. Start Claude Code.
|
|
198
255
|
2. Type: **"Read docs/skills/SKILL.md and perform design conversion: [Your Figma URL]"**
|
|
199
256
|
|
package/dist/cli.js
CHANGED
|
@@ -475,7 +475,7 @@ var AGENT_CONTEXT_WINDOW_TOKENS = 128e3;
|
|
|
475
475
|
|
|
476
476
|
// src/cli/init.ts
|
|
477
477
|
function registerCommands(program) {
|
|
478
|
-
const version = false ? "0.0.1" : "1.0.1";
|
|
478
|
+
const version = false ? "0.0.1" : "1.0.3-alpha.1";
|
|
479
479
|
program.name(CLI_NAME).description(`${CLI_NAME} - Convert Figma designs to code`).version(version, "-v, -V, --version", "Output the version number").showHelpAfterError();
|
|
480
480
|
}
|
|
481
481
|
|
|
@@ -594,16 +594,37 @@ var Workspace = class {
|
|
|
594
594
|
}
|
|
595
595
|
/**
|
|
596
596
|
* Delete all files and directories inside the workspace
|
|
597
|
+
* @param workspace - The workspace structure
|
|
598
|
+
* @param preserve - Optional list of relative paths (from workspace root) to preserve from deletion
|
|
597
599
|
*/
|
|
598
|
-
deleteWorkspace(workspace) {
|
|
600
|
+
deleteWorkspace(workspace, preserve = []) {
|
|
599
601
|
try {
|
|
600
|
-
if (fs2.existsSync(workspace.root))
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
602
|
+
if (!fs2.existsSync(workspace.root)) return;
|
|
603
|
+
const preserveFiles = new Set(preserve.map((p) => path2.normalize(p)));
|
|
604
|
+
const preserveDirs = /* @__PURE__ */ new Set();
|
|
605
|
+
for (const p of preserveFiles) {
|
|
606
|
+
let dir = path2.dirname(p);
|
|
607
|
+
while (dir !== ".") {
|
|
608
|
+
preserveDirs.add(dir);
|
|
609
|
+
dir = path2.dirname(dir);
|
|
605
610
|
}
|
|
606
611
|
}
|
|
612
|
+
const deleteRecursive = (dirPath, relativeTo = "") => {
|
|
613
|
+
const entries = fs2.readdirSync(dirPath);
|
|
614
|
+
for (const entry of entries) {
|
|
615
|
+
const fullPath = path2.join(dirPath, entry);
|
|
616
|
+
const relPath = relativeTo ? path2.join(relativeTo, entry) : entry;
|
|
617
|
+
if (preserveFiles.has(relPath)) {
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (preserveDirs.has(relPath)) {
|
|
621
|
+
deleteRecursive(fullPath, relPath);
|
|
622
|
+
} else {
|
|
623
|
+
fs2.rmSync(fullPath, { recursive: true, force: true });
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
deleteRecursive(workspace.root);
|
|
607
628
|
} catch (error) {
|
|
608
629
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
609
630
|
logger.printWarnLog(`Failed to delete workspace: ${errorMessage}`);
|
|
@@ -653,7 +674,7 @@ function saveDebugLog(requestInfo, responseInfo) {
|
|
|
653
674
|
"------------response------------",
|
|
654
675
|
JSON.stringify(responseInfo, null, 2)
|
|
655
676
|
].join("\n");
|
|
656
|
-
writeFile(workspaceManager.path?.debug ?? "", `fetch_${(/* @__PURE__ */ new Date()).toISOString()}.md`, debugContent);
|
|
677
|
+
writeFile(workspaceManager.path?.debug ?? "", `fetch_${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}.md`, debugContent);
|
|
657
678
|
}
|
|
658
679
|
async function get(url, config) {
|
|
659
680
|
const response = await axios.get(url, config);
|
|
@@ -1418,10 +1439,13 @@ var FigmaTool = class {
|
|
|
1418
1439
|
}
|
|
1419
1440
|
const document2 = await fetchFigmaNode(fileId, nodeId, token);
|
|
1420
1441
|
if (!document2 || !document2?.children?.length) {
|
|
1421
|
-
|
|
1442
|
+
throw new Error("Failed to fetch Figma document");
|
|
1422
1443
|
}
|
|
1423
1444
|
const images = await fetchFigmaImages(fileId, nodeId, token);
|
|
1424
1445
|
const thumbnail = images?.[nodeId] || "";
|
|
1446
|
+
if (!thumbnail) {
|
|
1447
|
+
throw new Error("Failed to fetch Figma document thumbnail");
|
|
1448
|
+
}
|
|
1425
1449
|
document2.thumbnailUrl = thumbnail;
|
|
1426
1450
|
const cleanedDocument = cleanFigma(document2);
|
|
1427
1451
|
return cleanedDocument;
|
|
@@ -1553,7 +1577,7 @@ async function callModel(options) {
|
|
|
1553
1577
|
"------------response------------",
|
|
1554
1578
|
JSON.stringify(message.text, null, 2)
|
|
1555
1579
|
].join("\n");
|
|
1556
|
-
writeFile(workspaceManager.path?.debug ?? "", `model_${(/* @__PURE__ */ new Date()).toISOString()}.md`, debugContent);
|
|
1580
|
+
writeFile(workspaceManager.path?.debug ?? "", `model_${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}.md`, debugContent);
|
|
1557
1581
|
}
|
|
1558
1582
|
return message.text;
|
|
1559
1583
|
} catch (error) {
|
|
@@ -2012,7 +2036,7 @@ var parseFigmaUrl = (url) => {
|
|
|
2012
2036
|
if (!fileId || !nodeId) {
|
|
2013
2037
|
throw new Error("Invalid Figma URL");
|
|
2014
2038
|
}
|
|
2015
|
-
return { fileId, name, nodeId, projectName: `${name}_${nodeId}` };
|
|
2039
|
+
return { fileId, name, nodeId, projectName: `${name}_${nodeId.replace(/:/g, "_")}` };
|
|
2016
2040
|
};
|
|
2017
2041
|
|
|
2018
2042
|
// src/cli/d2p.ts
|
|
@@ -5706,21 +5730,45 @@ var FILE_NAMING_CONVENTION = `
|
|
|
5706
5730
|
- NEVER use PascalCase or other names for filenames (e.g., DO NOT use \`MainFrame.tsx\` or \`Button.tsx\`).`;
|
|
5707
5731
|
var OUTPUT_FORMAT = `
|
|
5708
5732
|
<output_format>
|
|
5709
|
-
|
|
5733
|
+
**CRITICAL - Output Format Requirements:**
|
|
5734
|
+
|
|
5735
|
+
**CASE 1: Single File (TSX only)**
|
|
5736
|
+
- Return code wrapped in triple backticks with language identifier
|
|
5737
|
+
- NO file name header needed
|
|
5738
|
+
- Example:
|
|
5710
5739
|
\`\`\`tsx
|
|
5711
|
-
|
|
5740
|
+
export default function Component() {
|
|
5741
|
+
return <div>...</div>;
|
|
5742
|
+
}
|
|
5712
5743
|
\`\`\`
|
|
5713
5744
|
|
|
5714
|
-
|
|
5745
|
+
**CASE 2: Multiple Files (TSX + Styles)**
|
|
5746
|
+
- **REQUIRED**: Each file MUST start with EXACTLY \`## \` (two hash symbols + one space) followed by filename
|
|
5747
|
+
- **REQUIRED**: Filename must be complete with extension (e.g., \`index.tsx\`, \`index.module.css\`)
|
|
5748
|
+
- **FORBIDDEN**: Do NOT use single \`#\`, do NOT omit filename, do NOT use other markers
|
|
5749
|
+
- Follow this exact structure:
|
|
5750
|
+
|
|
5715
5751
|
## index.tsx
|
|
5716
5752
|
\`\`\`tsx
|
|
5717
|
-
|
|
5753
|
+
export default function Component() {
|
|
5754
|
+
return <div>...</div>;
|
|
5755
|
+
}
|
|
5718
5756
|
\`\`\`
|
|
5719
5757
|
|
|
5720
5758
|
## index.module.[css|less|scss]
|
|
5721
5759
|
\`\`\`[css|less|scss]
|
|
5722
|
-
|
|
5760
|
+
.container {
|
|
5761
|
+
/* styles */
|
|
5762
|
+
}
|
|
5723
5763
|
\`\`\`
|
|
5764
|
+
|
|
5765
|
+
**VALIDATION CHECKLIST (for multiple files):**
|
|
5766
|
+
\u2713 Each file section starts with \`## \` (two hashes + space)
|
|
5767
|
+
\u2713 Filename includes full extension
|
|
5768
|
+
\u2713 Code wrapped in triple backticks with language
|
|
5769
|
+
\u2717 DO NOT use \`# filename\` (single hash)
|
|
5770
|
+
\u2717 DO NOT omit file headers
|
|
5771
|
+
\u2717 DO NOT use other separators
|
|
5724
5772
|
</output_format>`;
|
|
5725
5773
|
function generateChildrenPropsInstructions(modes) {
|
|
5726
5774
|
const instructions = [];
|
|
@@ -6333,6 +6381,14 @@ async function checkpointExists(checkpointer, threadId) {
|
|
|
6333
6381
|
return false;
|
|
6334
6382
|
}
|
|
6335
6383
|
}
|
|
6384
|
+
async function clearCheckpoint(checkpointer, threadId) {
|
|
6385
|
+
try {
|
|
6386
|
+
await checkpointer.deleteThread(threadId);
|
|
6387
|
+
} catch (error) {
|
|
6388
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6389
|
+
logger.printWarnLog(`Failed to clear checkpoint: ${errorMessage}`);
|
|
6390
|
+
}
|
|
6391
|
+
}
|
|
6336
6392
|
async function promptCheckpointChoice(checkpointer, threadId) {
|
|
6337
6393
|
const hasCheckpoint = await checkpointExists(checkpointer, threadId);
|
|
6338
6394
|
if (!hasCheckpoint) {
|
|
@@ -6341,6 +6397,9 @@ async function promptCheckpointChoice(checkpointer, threadId) {
|
|
|
6341
6397
|
const choice = await promptUserChoice();
|
|
6342
6398
|
return choice === "resume";
|
|
6343
6399
|
}
|
|
6400
|
+
async function clearThreadCheckpoint(checkpointer, threadId) {
|
|
6401
|
+
await clearCheckpoint(checkpointer, threadId);
|
|
6402
|
+
}
|
|
6344
6403
|
function initializeSqliteSaver(dbPath) {
|
|
6345
6404
|
const dbDir = path14.dirname(dbPath);
|
|
6346
6405
|
if (!fs11.existsSync(dbDir)) {
|
|
@@ -6356,13 +6415,13 @@ async function design2code(url, mode) {
|
|
|
6356
6415
|
const urlInfo = parseFigmaUrl(url);
|
|
6357
6416
|
const threadId = urlInfo.projectName;
|
|
6358
6417
|
const workspace = workspaceManager.initWorkspace(threadId);
|
|
6359
|
-
|
|
6418
|
+
const checkpointer = initializeSqliteSaver(workspace.db);
|
|
6360
6419
|
const resume = await promptCheckpointChoice(checkpointer, threadId);
|
|
6361
6420
|
logger.printInfoLog(`Starting design-to-code process for: ${urlInfo.projectName}`);
|
|
6362
6421
|
if (resume !== true) {
|
|
6363
|
-
workspaceManager.deleteWorkspace(workspace);
|
|
6422
|
+
workspaceManager.deleteWorkspace(workspace, ["checkpoint/coderio-cli.db"]);
|
|
6364
6423
|
logger.printInfoLog("Starting fresh...");
|
|
6365
|
-
checkpointer
|
|
6424
|
+
await clearThreadCheckpoint(checkpointer, threadId);
|
|
6366
6425
|
} else {
|
|
6367
6426
|
logger.printInfoLog("Resuming from cache...");
|
|
6368
6427
|
}
|