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
132 changes: 66 additions & 66 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
{
"name": "@donnes/syncode",
"version": "1.1.7",
"description": "Sync AI code agent configs (Claude Code, Cursor, Windsurf, OpenCode) across machines and projects.",
"private": false,
"type": "module",
"bin": {
"syncode": "./dist/index.js"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsup",
"dev": "tsx src/index.ts",
"test": "tsx scripts/execute-tests.ts",
"prepublishOnly": "npm run build",
"check:lint": "biome check . --diagnostic-level=error",
"check:unsafe": "biome check . --write --unsafe --diagnostic-level=error",
"check:types": "bunx tsc --noEmit"
},
"keywords": [
"ai-agents",
"claude-code",
"cursor",
"windsurf",
"opencode",
"vscode",
"ai-coding",
"code-agent",
"skill-conversion",
"syncode",
"dotfiles",
"configuration-management",
"developer-tools",
"ai-assistant",
"coding-assistant"
],
"engines": {
"node": ">=20.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/donnes/syncode.git"
},
"bugs": {
"url": "https://github.com/donnes/syncode/issues"
},
"homepage": "https://github.com/donnes/syncode#readme",
"author": "Donald Silveira",
"license": "MIT",
"dependencies": {
"@clack/prompts": "^0.9.1"
},
"devDependencies": {
"@biomejs/biome": "^2.3.11",
"@opencode-ai/sdk": "^1.1.41",
"@types/bun": "latest",
"@types/node": "^20.0.0",
"tsup": "^8.5.1",
"tsx": "^4.21.0",
"typescript": "^5.7.3"
}
"name": "@donnes/syncode",
"version": "1.1.7",
"description": "Sync AI code agent configs (Claude Code, Cursor, Windsurf, OpenCode) across machines and projects.",
"private": false,
"type": "module",
"bin": {
"syncode": "./dist/index.js"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsup",
"dev": "tsx src/index.ts",
"test": "tsx scripts/execute-tests.ts",
"prepublishOnly": "npm run build",
"check:lint": "biome check . --diagnostic-level=error",
"check:unsafe": "biome check . --write --unsafe --diagnostic-level=error",
"check:types": "bunx tsc --noEmit"
},
"keywords": [
"ai-agents",
"claude-code",
"cursor",
"windsurf",
"opencode",
"vscode",
"ai-coding",
"code-agent",
"skill-conversion",
"syncode",
"dotfiles",
"configuration-management",
"developer-tools",
"ai-assistant",
"coding-assistant"
],
"engines": {
"node": ">=20.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/donnes/syncode.git"
},
"bugs": {
"url": "https://github.com/donnes/syncode/issues"
},
"homepage": "https://github.com/donnes/syncode#readme",
"author": "Donald Silveira",
"license": "MIT",
"dependencies": {
"@clack/prompts": "^0.9.1"
},
"devDependencies": {
"@biomejs/biome": "^2.3.11",
"@opencode-ai/sdk": "^1.1.41",
"@types/bun": "latest",
"@types/node": "^20.0.0",
"tsup": "^8.5.1",
"tsx": "^4.21.0",
"typescript": "^5.7.3"
}
}
2 changes: 2 additions & 0 deletions scripts/release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pkg.version = newVersion;
await writeFile("package.json", `${JSON.stringify(pkg, null, 2)}\n`);
console.log("Updated package.json");

await $`bun check:unsafe`;

// 5. Git operations
const tag = `v${newVersion}`;
let output = `version=${newVersion}\ntag=${tag}\n`;
Expand Down
31 changes: 30 additions & 1 deletion src/adapters/amp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
createSymlink,
ensureDir,
exists,
getSymlinkTarget,
isSymlink,
removeDir,
} from "../utils/fs";
Expand Down Expand Up @@ -52,7 +53,10 @@ export class AmpAdapter implements AgentAdapter {
}

isLinked(systemPath: string, repoPath: string): boolean {
return exists(systemPath) && exists(repoPath) && isSymlink(systemPath);
if (!exists(systemPath) || !exists(repoPath) || !isSymlink(systemPath)) {
return false;
}
return getSymlinkTarget(systemPath) === repoPath;
}

async import(systemPath: string, repoPath: string): Promise<ImportResult> {
Expand All @@ -63,6 +67,20 @@ export class AmpAdapter implements AgentAdapter {
};
}

if (isSymlink(systemPath)) {
return {
success: true,
message: "Already linked to repo - no import needed",
};
}

if (exists(repoPath)) {
return {
success: true,
message: "Configs already in repo - no import needed",
};
}

ensureDir(repoPath);
copyDir(systemPath, repoPath);

Expand All @@ -80,6 +98,17 @@ export class AmpAdapter implements AgentAdapter {
};
}

if (isSymlink(systemPath)) {
const target = getSymlinkTarget(systemPath);
if (target === repoPath) {
return {
success: true,
message: "Already linked to repo - no export needed",
linkedTo: repoPath,
};
}
}

// Remove existing (symlink or directory)
if (exists(systemPath)) {
if (isSymlink(systemPath)) {
Expand Down
31 changes: 30 additions & 1 deletion src/adapters/antigravity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
createSymlink,
ensureDir,
exists,
getSymlinkTarget,
isSymlink,
removeDir,
} from "../utils/fs";
Expand Down Expand Up @@ -54,7 +55,10 @@ export class AntigravityAdapter implements AgentAdapter {
}

isLinked(systemPath: string, repoPath: string): boolean {
return exists(systemPath) && exists(repoPath) && isSymlink(systemPath);
if (!exists(systemPath) || !exists(repoPath) || !isSymlink(systemPath)) {
return false;
}
return getSymlinkTarget(systemPath) === repoPath;
}

async import(systemPath: string, repoPath: string): Promise<ImportResult> {
Expand All @@ -65,6 +69,20 @@ export class AntigravityAdapter implements AgentAdapter {
};
}

if (isSymlink(systemPath)) {
return {
success: true,
message: "Already linked to repo - no import needed",
};
}

if (exists(repoPath)) {
return {
success: true,
message: "Configs already in repo - no import needed",
};
}

ensureDir(repoPath);
copyDir(systemPath, repoPath);

Expand All @@ -82,6 +100,17 @@ export class AntigravityAdapter implements AgentAdapter {
};
}

if (isSymlink(systemPath)) {
const target = getSymlinkTarget(systemPath);
if (target === repoPath) {
return {
success: true,
message: "Already linked to repo - no export needed",
linkedTo: repoPath,
};
}
}

// Remove existing (symlink or directory)
if (exists(systemPath)) {
if (isSymlink(systemPath)) {
Expand Down
17 changes: 7 additions & 10 deletions src/adapters/claude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
* Claude Code adapter
*/

import { copyFileSync, existsSync, statSync, unlinkSync } from "node:fs";
import { copyFileSync, existsSync, statSync } from "node:fs";
import { dirname, join } from "node:path";
import {
copyDir,
ensureDir,
exists,
isDirectory,
removeDir,
isSymlink,
} from "../utils/fs";
import { contractHome } from "../utils/paths";
import type {
Expand Down Expand Up @@ -89,6 +89,10 @@ export class ClaudeAdapter implements AgentAdapter {

if (!existsSync(srcPath)) continue;

if (isSymlink(srcPath)) continue;

if (existsSync(destPath)) continue;

if (statSync(srcPath).isDirectory()) {
copyDir(srcPath, destPath);
filesImported.push(`${pattern}/`);
Expand Down Expand Up @@ -134,14 +138,7 @@ export class ClaudeAdapter implements AgentAdapter {

if (!existsSync(srcPath)) continue;

// Remove existing and copy fresh
if (existsSync(destPath)) {
if (statSync(destPath).isDirectory()) {
removeDir(destPath);
} else {
unlinkSync(destPath);
}
}
if (existsSync(destPath)) continue;

if (statSync(srcPath).isDirectory()) {
copyDir(srcPath, destPath);
Expand Down
31 changes: 30 additions & 1 deletion src/adapters/clawdbot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
createSymlink,
ensureDir,
exists,
getSymlinkTarget,
isSymlink,
removeDir,
} from "../utils/fs";
Expand Down Expand Up @@ -62,7 +63,10 @@ export class ClawdbotAdapter implements AgentAdapter {
}

isLinked(systemPath: string, repoPath: string): boolean {
return exists(systemPath) && exists(repoPath) && isSymlink(systemPath);
if (!exists(systemPath) || !exists(repoPath) || !isSymlink(systemPath)) {
return false;
}
return getSymlinkTarget(systemPath) === repoPath;
}

async import(systemPath: string, repoPath: string): Promise<ImportResult> {
Expand All @@ -73,6 +77,20 @@ export class ClawdbotAdapter implements AgentAdapter {
};
}

if (isSymlink(systemPath)) {
return {
success: true,
message: "Already linked to repo - no import needed",
};
}

if (exists(repoPath)) {
return {
success: true,
message: "Configs already in repo - no import needed",
};
}

ensureDir(repoPath);
copyDir(systemPath, repoPath);

Expand Down Expand Up @@ -110,6 +128,17 @@ export class ClawdbotAdapter implements AgentAdapter {
repoPath: string,
systemPath: string,
): Promise<ExportResult> {
if (isSymlink(systemPath)) {
const target = getSymlinkTarget(systemPath);
if (target === repoPath) {
return {
success: true,
message: "Already linked to repo - no export needed",
linkedTo: repoPath,
};
}
}

if (exists(systemPath) && !isSymlink(systemPath)) {
const backupPath = `${systemPath}.backup`;
if (exists(backupPath)) {
Expand Down
Loading
Loading