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 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**: This tool requires an LLM with **multimodal (vision) capabilities** to analyze design screenshots.
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`) with:
95
+ Create config file at `~/.coderio/config.yaml` (Windows: `%USERPROFILE%\.coderio\config.yaml`):
103
96
 
104
97
  ```yaml
105
98
  model:
106
- provider: openai # anthropic | openai | google
107
- model: gemini-3-pro-preview
108
- baseUrl: https://api.anthropic.com
109
- apiKey: your-api-key-here
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
- token: your-figma-token-here
105
+ token: your-figma-token-here
132
106
 
133
107
  debug:
134
- enabled: false
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
- ```bash
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
- ```bash
187
- mkdir -p ~/.cursor/skills/design-to-code
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
- 1. Open Cursor Chat (`Cmd` + `L`).
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
- return void 0;
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
- let checkpointer = initializeSqliteSaver(workspace.db);
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 = initializeSqliteSaver(workspace.db);
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 */;