Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "coderio",
"version": "1.0.2",
"version": "1.0.3",
"description": "A modern CLI development tool built with TypeScript",
"type": "module",
"bin": {
Expand Down Expand Up @@ -69,7 +69,7 @@
"better-sqlite3": "^11.10.0",
"chalk": "^5.4.1",
"commander": "^12.1.0",
"evoltagent": "^1.1.2",
"evoltagent": "1.1.5",
"js-yaml": "^4.1.1",
"pixelmatch": "^7.1.0",
"prompts": "^2.4.2"
Expand Down
39 changes: 5 additions & 34 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions src/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ export async function design2code(url: string, mode?: ValidationMode): Promise<v

// If not resuming, delete workspace and reinitialize checkpointer
if (resume !== true) {
// Exclude checkpoint directory to avoid EBUSY error on Windows (SQLite lock)
workspaceManager.deleteWorkspace(workspace, ['checkpoint']);
// Preserve only the database file to avoid EBUSY error on Windows (SQLite lock)
workspaceManager.deleteWorkspace(workspace, [
'checkpoint/coderio-cli.db',
'checkpoint/coderio-cli.db-shm',
'checkpoint/coderio-cli.db-wal',
]);
logger.printInfoLog('Starting fresh...');

// Clear existing checkpoints for this thread instead of deleting the file
Expand Down
34 changes: 29 additions & 5 deletions src/nodes/code/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,45 @@ const FILE_NAMING_CONVENTION = `

const OUTPUT_FORMAT = `
<output_format>
If only one file (TSX) is needed:
**CRITICAL - Output Format Requirements:**

**CASE 1: Single File (TSX only)**
- Return code wrapped in triple backticks with language identifier
- NO file name header needed
- Example:
\`\`\`tsx
// code...
export default function Component() {
return <div>...</div>;
}
\`\`\`

If multiple files are needed (e.g., TSX + Styles):
**CASE 2: Multiple Files (TSX + Styles)**
- **REQUIRED**: Each file MUST start with EXACTLY \`## \` (two hash symbols + one space) followed by filename
- **REQUIRED**: Filename must be complete with extension (e.g., \`index.tsx\`, \`index.module.css\`)
- **FORBIDDEN**: Do NOT use single \`#\`, do NOT omit filename, do NOT use other markers
- Follow this exact structure:

## index.tsx
\`\`\`tsx
// code...
export default function Component() {
return <div>...</div>;
}
\`\`\`

## index.module.[css|less|scss]
\`\`\`[css|less|scss]
// styles...
.container {
/* styles */
}
\`\`\`

**VALIDATION CHECKLIST (for multiple files):**
✓ Each file section starts with \`## \` (two hashes + space)
✓ Filename includes full extension
✓ Code wrapped in triple backticks with language
✗ DO NOT use \`# filename\` (single hash)
✗ DO NOT omit file headers
✗ DO NOT use other separators
</output_format>`;

// ============================================
Expand Down
44 changes: 33 additions & 11 deletions src/utils/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,45 @@ class Workspace {
/**
* Delete all files and directories inside the workspace
* @param workspace - The workspace structure
* @param exclude - Optional list of file/directory names to exclude from deletion
* @param preserve - Optional list of relative paths (from workspace root) to preserve from deletion
*/
deleteWorkspace(workspace: WorkspaceStructure, exclude: string[] = []): void {
deleteWorkspace(workspace: WorkspaceStructure, preserve: string[] = []): void {
try {
if (fs.existsSync(workspace.root)) {
// Read all entries in the workspace root
const entries = fs.readdirSync(workspace.root);
if (!fs.existsSync(workspace.root)) return;

// Delete each entry
// Build set of normalized relative paths to preserve
const preserveFiles = new Set(preserve.map(p => path.normalize(p)));

// Collect ancestor directories of preserved files
const preserveDirs = new Set<string>();
for (const p of preserveFiles) {
let dir = path.dirname(p);
while (dir !== '.') {
preserveDirs.add(dir);
dir = path.dirname(dir);
}
}

const deleteRecursive = (dirPath: string, relativeTo: string = '') => {
const entries = fs.readdirSync(dirPath);
for (const entry of entries) {
if (exclude.includes(entry)) {
continue;
const fullPath = path.join(dirPath, entry);
const relPath = relativeTo ? path.join(relativeTo, entry) : entry;

if (preserveFiles.has(relPath)) {
continue; // This file is preserved
}

if (preserveDirs.has(relPath)) {
// Directory contains preserved files, recurse into it
deleteRecursive(fullPath, relPath);
} else {
fs.rmSync(fullPath, { recursive: true, force: true });
}
const fullPath = path.join(workspace.root, entry);
fs.rmSync(fullPath, { recursive: true, force: true });
}
}
};

deleteRecursive(workspace.root);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.printWarnLog(`Failed to delete workspace: ${errorMessage}`);
Expand Down
Loading