coderio 1.0.1 → 1.0.2
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 +18 -48
- package/dist/cli.js +27 -12
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,62 +79,34 @@ 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
|
-
|
|
110
|
-
|
|
111
|
-
figma:
|
|
112
|
-
token: your-figma-token-here
|
|
113
|
-
|
|
114
|
-
debug:
|
|
115
|
-
enabled: false
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
<details>
|
|
119
|
-
<summary><strong>macOS / Linux One-click Command</strong></summary>
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
mkdir -p ~/.coderio
|
|
123
|
-
cat > ~/.coderio/config.yaml << 'EOF'
|
|
124
|
-
model:
|
|
125
|
-
provider: openai # anthropic | openai | google
|
|
126
|
-
model: gemini-3-pro-preview
|
|
127
|
-
baseUrl: https://api.anthropic.com
|
|
128
|
-
apiKey: your-api-key-here
|
|
99
|
+
provider: openai # anthropic | openai | google
|
|
100
|
+
model: gemini-3-pro-preview
|
|
101
|
+
baseUrl: https://api.anthropic.com
|
|
102
|
+
apiKey: your-api-key-here
|
|
129
103
|
|
|
130
104
|
figma:
|
|
131
|
-
|
|
105
|
+
token: your-figma-token-here
|
|
132
106
|
|
|
133
107
|
debug:
|
|
134
|
-
|
|
135
|
-
EOF
|
|
108
|
+
enabled: false # set 'true', if you want to save model and request information
|
|
136
109
|
```
|
|
137
|
-
</details>
|
|
138
110
|
|
|
139
111
|
#### 4. Usage
|
|
140
112
|
|
|
@@ -163,10 +135,7 @@ pnpm dev
|
|
|
163
135
|
|
|
164
136
|
#### 6. View Validation Report
|
|
165
137
|
|
|
166
|
-
|
|
167
|
-
# Open validation report in browser
|
|
168
|
-
open coderio/<design-name_node-id>/process/validation/index.html
|
|
169
|
-
```
|
|
138
|
+
report path: coderio/<design-name_node-id>/process/validation/index.html
|
|
170
139
|
|
|
171
140
|
#### 📖 All Commands
|
|
172
141
|
|
|
@@ -179,21 +148,22 @@ open coderio/<design-name_node-id>/process/validation/index.html
|
|
|
179
148
|
| `images` | - | Download and process Figma assets |
|
|
180
149
|
|
|
181
150
|
### Option 2: Skill (Portable Embedded Workflow)
|
|
151
|
+
|
|
182
152
|
Best for control and precision using AI Agents.
|
|
183
153
|
|
|
184
154
|
**Prerequisites**:
|
|
185
155
|
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
|
-
```
|
|
156
|
+
|
|
157
|
+
Copy `skills\design-to-code` folder to `~\.cursor\skills` (Windows: `%USERPROFILE%\.cursor\skills`)
|
|
190
158
|
|
|
191
159
|
**Using in Cursor**:
|
|
192
|
-
|
|
160
|
+
|
|
161
|
+
1. Open Cursor Chat.
|
|
193
162
|
2. Type: **"Use design-to-code skill to convert this design: [Your Figma URL]"**
|
|
194
163
|
3. The Agent will guide you step-by-step through protocol extraction and code generation.
|
|
195
164
|
|
|
196
165
|
**Using in Claude Code**:
|
|
166
|
+
|
|
197
167
|
1. Start Claude Code.
|
|
198
168
|
2. Type: **"Read docs/skills/SKILL.md and perform design conversion: [Your Figma URL]"**
|
|
199
169
|
|
package/dist/cli.js
CHANGED
|
@@ -594,12 +594,17 @@ 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 exclude - Optional list of file/directory names to exclude from deletion
|
|
597
599
|
*/
|
|
598
|
-
deleteWorkspace(workspace) {
|
|
600
|
+
deleteWorkspace(workspace, exclude = []) {
|
|
599
601
|
try {
|
|
600
602
|
if (fs2.existsSync(workspace.root)) {
|
|
601
603
|
const entries = fs2.readdirSync(workspace.root);
|
|
602
604
|
for (const entry of entries) {
|
|
605
|
+
if (exclude.includes(entry)) {
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
603
608
|
const fullPath = path2.join(workspace.root, entry);
|
|
604
609
|
fs2.rmSync(fullPath, { recursive: true, force: true });
|
|
605
610
|
}
|
|
@@ -653,7 +658,7 @@ function saveDebugLog(requestInfo, responseInfo) {
|
|
|
653
658
|
"------------response------------",
|
|
654
659
|
JSON.stringify(responseInfo, null, 2)
|
|
655
660
|
].join("\n");
|
|
656
|
-
writeFile(workspaceManager.path?.debug ?? "", `fetch_${(/* @__PURE__ */ new Date()).toISOString()}.md`, debugContent);
|
|
661
|
+
writeFile(workspaceManager.path?.debug ?? "", `fetch_${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}.md`, debugContent);
|
|
657
662
|
}
|
|
658
663
|
async function get(url, config) {
|
|
659
664
|
const response = await axios.get(url, config);
|
|
@@ -1418,10 +1423,13 @@ var FigmaTool = class {
|
|
|
1418
1423
|
}
|
|
1419
1424
|
const document2 = await fetchFigmaNode(fileId, nodeId, token);
|
|
1420
1425
|
if (!document2 || !document2?.children?.length) {
|
|
1421
|
-
|
|
1426
|
+
throw new Error("Failed to fetch Figma document");
|
|
1422
1427
|
}
|
|
1423
1428
|
const images = await fetchFigmaImages(fileId, nodeId, token);
|
|
1424
1429
|
const thumbnail = images?.[nodeId] || "";
|
|
1430
|
+
if (!thumbnail) {
|
|
1431
|
+
throw new Error("Failed to fetch Figma document thumbnail");
|
|
1432
|
+
}
|
|
1425
1433
|
document2.thumbnailUrl = thumbnail;
|
|
1426
1434
|
const cleanedDocument = cleanFigma(document2);
|
|
1427
1435
|
return cleanedDocument;
|
|
@@ -1553,7 +1561,7 @@ async function callModel(options) {
|
|
|
1553
1561
|
"------------response------------",
|
|
1554
1562
|
JSON.stringify(message.text, null, 2)
|
|
1555
1563
|
].join("\n");
|
|
1556
|
-
writeFile(workspaceManager.path?.debug ?? "", `model_${(/* @__PURE__ */ new Date()).toISOString()}.md`, debugContent);
|
|
1564
|
+
writeFile(workspaceManager.path?.debug ?? "", `model_${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}.md`, debugContent);
|
|
1557
1565
|
}
|
|
1558
1566
|
return message.text;
|
|
1559
1567
|
} catch (error) {
|
|
@@ -2012,7 +2020,7 @@ var parseFigmaUrl = (url) => {
|
|
|
2012
2020
|
if (!fileId || !nodeId) {
|
|
2013
2021
|
throw new Error("Invalid Figma URL");
|
|
2014
2022
|
}
|
|
2015
|
-
return { fileId, name, nodeId, projectName: `${name}_${nodeId}` };
|
|
2023
|
+
return { fileId, name, nodeId, projectName: `${name}_${nodeId.replace(/:/g, "_")}` };
|
|
2016
2024
|
};
|
|
2017
2025
|
|
|
2018
2026
|
// src/cli/d2p.ts
|
|
@@ -6333,6 +6341,14 @@ async function checkpointExists(checkpointer, threadId) {
|
|
|
6333
6341
|
return false;
|
|
6334
6342
|
}
|
|
6335
6343
|
}
|
|
6344
|
+
async function clearCheckpoint(checkpointer, threadId) {
|
|
6345
|
+
try {
|
|
6346
|
+
await checkpointer.deleteThread(threadId);
|
|
6347
|
+
} catch (error) {
|
|
6348
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6349
|
+
logger.printWarnLog(`Failed to clear checkpoint: ${errorMessage}`);
|
|
6350
|
+
}
|
|
6351
|
+
}
|
|
6336
6352
|
async function promptCheckpointChoice(checkpointer, threadId) {
|
|
6337
6353
|
const hasCheckpoint = await checkpointExists(checkpointer, threadId);
|
|
6338
6354
|
if (!hasCheckpoint) {
|
|
@@ -6341,6 +6357,9 @@ async function promptCheckpointChoice(checkpointer, threadId) {
|
|
|
6341
6357
|
const choice = await promptUserChoice();
|
|
6342
6358
|
return choice === "resume";
|
|
6343
6359
|
}
|
|
6360
|
+
async function clearThreadCheckpoint(checkpointer, threadId) {
|
|
6361
|
+
await clearCheckpoint(checkpointer, threadId);
|
|
6362
|
+
}
|
|
6344
6363
|
function initializeSqliteSaver(dbPath) {
|
|
6345
6364
|
const dbDir = path14.dirname(dbPath);
|
|
6346
6365
|
if (!fs11.existsSync(dbDir)) {
|
|
@@ -6356,20 +6375,16 @@ async function design2code(url, mode) {
|
|
|
6356
6375
|
const urlInfo = parseFigmaUrl(url);
|
|
6357
6376
|
const threadId = urlInfo.projectName;
|
|
6358
6377
|
const workspace = workspaceManager.initWorkspace(threadId);
|
|
6359
|
-
|
|
6378
|
+
const checkpointer = initializeSqliteSaver(workspace.db);
|
|
6360
6379
|
const resume = await promptCheckpointChoice(checkpointer, threadId);
|
|
6361
6380
|
logger.printInfoLog(`Starting design-to-code process for: ${urlInfo.projectName}`);
|
|
6362
6381
|
if (resume !== true) {
|
|
6363
|
-
workspaceManager.deleteWorkspace(workspace);
|
|
6382
|
+
workspaceManager.deleteWorkspace(workspace, ["checkpoint"]);
|
|
6364
6383
|
logger.printInfoLog("Starting fresh...");
|
|
6365
|
-
checkpointer
|
|
6384
|
+
await clearThreadCheckpoint(checkpointer, threadId);
|
|
6366
6385
|
} else {
|
|
6367
6386
|
logger.printInfoLog("Resuming from cache...");
|
|
6368
6387
|
}
|
|
6369
|
-
await callModel({
|
|
6370
|
-
question: "\u8BF7\u4ECB\u7ECD\u4F60\u81EA\u5DF1\uFF0C\u4F60\u662F\u4EC0\u4E48\u6A21\u578B",
|
|
6371
|
-
streaming: false
|
|
6372
|
-
});
|
|
6373
6388
|
const graph = new StateGraph(GraphStateAnnotation).addNode("initial" /* INITIAL */, initialProject).addNode("process" /* PROCESS */, generateProtocol).addNode("code" /* CODE */, generateCode).addNode("validation" /* VALIDATION */, runValidation).addEdge(START, "initial" /* INITIAL */).addEdge("initial" /* INITIAL */, "process" /* PROCESS */).addEdge("process" /* PROCESS */, "code" /* CODE */).addEdge("code" /* CODE */, "validation" /* VALIDATION */).addEdge("validation" /* VALIDATION */, END).compile({ checkpointer });
|
|
6374
6389
|
const config = { configurable: { thread_id: threadId } };
|
|
6375
6390
|
const validationMode = mode ?? "full" /* Full */;
|