diff --git a/biome.json b/biome.json index 5d497bc..c516fed 100644 --- a/biome.json +++ b/biome.json @@ -20,7 +20,8 @@ "rules": { "recommended": true, "style": { - "noNonNullAssertion": "off" + "noNonNullAssertion": "off", + "noCommonJs": "error" } } }, diff --git a/src/adapters/agents.ts b/src/adapters/agents.ts index 7b048a9..db069bd 100644 --- a/src/adapters/agents.ts +++ b/src/adapters/agents.ts @@ -2,7 +2,7 @@ * Shared Agents adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -127,7 +127,7 @@ export class AgentsAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/amp.ts b/src/adapters/amp.ts index 8d67d15..35e883c 100644 --- a/src/adapters/amp.ts +++ b/src/adapters/amp.ts @@ -2,7 +2,7 @@ * Amp adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -132,7 +132,7 @@ export class AmpAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/antigravity.ts b/src/adapters/antigravity.ts index 3018f0d..ee5eacd 100644 --- a/src/adapters/antigravity.ts +++ b/src/adapters/antigravity.ts @@ -2,7 +2,7 @@ * Antigravity adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -125,7 +125,7 @@ export class AntigravityAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/clawdbot.ts b/src/adapters/clawdbot.ts index 07ca67f..dcc9cbc 100644 --- a/src/adapters/clawdbot.ts +++ b/src/adapters/clawdbot.ts @@ -2,7 +2,7 @@ * Clawdbot adapter */ -import { existsSync } from "node:fs"; +import { existsSync, renameSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -144,7 +144,7 @@ export class ClawdbotAdapter implements AgentAdapter { if (exists(backupPath)) { removeDir(backupPath); } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } createSymlink(repoPath, systemPath); diff --git a/src/adapters/codex.ts b/src/adapters/codex.ts index e4159d5..9b80b65 100644 --- a/src/adapters/codex.ts +++ b/src/adapters/codex.ts @@ -2,7 +2,7 @@ * Codex adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -26,6 +26,24 @@ import type { Platform, } from "./types"; +// ~/.codex is symlinked into the repo, so Codex's runtime data (sqlite logs, +// sessions, worktrees, plugin binaries, auth.json) lands in the repo too. +// Track only real config. +const CODEX_GITIGNORE = `# Managed by syncode: only sync Codex config, not runtime data +/* +!/.gitignore +!/AGENTS.md +!/config.toml +!/prompts/ +!/rules/ +!/skills +/skills/.system/ +`; + +function writeCodexGitignore(repoPath: string): void { + writeFileSync(join(repoPath, ".gitignore"), CODEX_GITIGNORE); +} + export class CodexAdapter implements AgentAdapter { readonly id = "codex"; readonly name = "Codex"; @@ -92,6 +110,7 @@ export class CodexAdapter implements AgentAdapter { ensureDir(repoPath); copyDir(systemPath, repoPath); + writeCodexGitignore(repoPath); return { success: true, @@ -107,6 +126,8 @@ export class CodexAdapter implements AgentAdapter { }; } + writeCodexGitignore(repoPath); + if (isSymlink(systemPath)) { const target = getSymlinkTarget(systemPath); if (target === repoPath) { @@ -132,7 +153,7 @@ export class CodexAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/devin.ts b/src/adapters/devin.ts index 3db7898..c1c5721 100644 --- a/src/adapters/devin.ts +++ b/src/adapters/devin.ts @@ -2,7 +2,7 @@ * Devin adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -145,7 +145,7 @@ export class DevinAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/droid.ts b/src/adapters/droid.ts index 83e5463..07b3afe 100644 --- a/src/adapters/droid.ts +++ b/src/adapters/droid.ts @@ -2,7 +2,7 @@ * Droid adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -132,7 +132,7 @@ export class DroidAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/gemini-cli.ts b/src/adapters/gemini-cli.ts index ef85aad..69039ef 100644 --- a/src/adapters/gemini-cli.ts +++ b/src/adapters/gemini-cli.ts @@ -2,7 +2,7 @@ * Gemini CLI adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -132,7 +132,7 @@ export class GeminiCliAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/github-copilot.ts b/src/adapters/github-copilot.ts index 2553780..dc98f3f 100644 --- a/src/adapters/github-copilot.ts +++ b/src/adapters/github-copilot.ts @@ -2,7 +2,7 @@ * GitHub Copilot adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -134,7 +134,7 @@ export class GithubCopilotAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/goose.ts b/src/adapters/goose.ts index 1033a9c..b28ed91 100644 --- a/src/adapters/goose.ts +++ b/src/adapters/goose.ts @@ -2,7 +2,7 @@ * Goose adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -123,7 +123,7 @@ export class GooseAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/kilo.ts b/src/adapters/kilo.ts index f2fd214..5b072b2 100644 --- a/src/adapters/kilo.ts +++ b/src/adapters/kilo.ts @@ -2,7 +2,7 @@ * Kilo Code adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -123,7 +123,7 @@ export class KiloAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/kimi-cli.ts b/src/adapters/kimi-cli.ts index 1d69b36..e5051d9 100644 --- a/src/adapters/kimi-cli.ts +++ b/src/adapters/kimi-cli.ts @@ -2,7 +2,7 @@ * Kimi CLI adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -145,7 +145,7 @@ export class KimiCliAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/kiro-cli.ts b/src/adapters/kiro-cli.ts index 36b19a0..9924131 100644 --- a/src/adapters/kiro-cli.ts +++ b/src/adapters/kiro-cli.ts @@ -2,7 +2,7 @@ * Kiro CLI adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -123,7 +123,7 @@ export class KiroCliAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/roo.ts b/src/adapters/roo.ts index 3069ae9..1b5c026 100644 --- a/src/adapters/roo.ts +++ b/src/adapters/roo.ts @@ -2,7 +2,7 @@ * Roo Code adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -123,7 +123,7 @@ export class RooAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/adapters/trae.ts b/src/adapters/trae.ts index d9c4061..53c7b2d 100644 --- a/src/adapters/trae.ts +++ b/src/adapters/trae.ts @@ -2,7 +2,7 @@ * Trae adapter */ -import { unlinkSync } from "node:fs"; +import { renameSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import { copyDir, @@ -123,7 +123,7 @@ export class TraeAdapter implements AgentAdapter { removeDir(backupPath); } } - require("node:fs").renameSync(systemPath, backupPath); + renameSync(systemPath, backupPath); } } diff --git a/src/commands/init.ts b/src/commands/init.ts index 36d72f6..41d26b1 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -14,6 +14,7 @@ import { import { configExists, initConfig } from "../config/manager"; import { SUPPORTED_AGENTS } from "../config/types"; import { contractHome, expandHome } from "../utils/paths"; +import { getErrorLogFile, logError } from "../utils/trace"; export async function initCommand() { p.intro("Initialize from Existing Repo"); @@ -82,7 +83,6 @@ export async function initCommand() { try { mkdirSync(dirname(repoPath), { recursive: true }); } catch (error) { - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(error); p.cancel( `Failed to create directory: ${error}\n${getErrorLogFile(logFile)}`, @@ -218,7 +218,6 @@ Next steps: • Configs in ${contractHome(repoPath)}/configs will apply to this machine`, ); } catch (error) { - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(error); p.cancel( `Failed to create configuration: ${error}\n${getErrorLogFile(logFile)}`, diff --git a/src/commands/machine/status.ts b/src/commands/machine/status.ts index 4491f53..8229319 100644 --- a/src/commands/machine/status.ts +++ b/src/commands/machine/status.ts @@ -5,6 +5,7 @@ import { getConfig } from "../../config/manager"; import { contractHome, expandHome, getConfigsDir } from "../../utils/paths"; import { getPackageManager, getPlatformName } from "../../utils/platform"; import { exec } from "../../utils/shell"; +import { getErrorLogFile, logError } from "../../utils/trace"; export async function machineStatusCommand(options?: { skipIntro?: boolean }) { if (!options?.skipIntro) { @@ -69,7 +70,6 @@ export async function machineStatusCommand(options?: { skipIntro?: boolean }) { p.outro("Done"); } catch (error) { - const { logError, getErrorLogFile } = require("../../utils/trace"); const logFile = logError(error); p.cancel(`Error: ${error}\n${getErrorLogFile(logFile)}`); } diff --git a/src/commands/new.ts b/src/commands/new.ts index f773a55..9cefe82 100644 --- a/src/commands/new.ts +++ b/src/commands/new.ts @@ -15,6 +15,7 @@ import { configExists, getConfig, initConfig } from "../config/manager"; import { SUPPORTED_AGENTS } from "../config/types"; import { INSTALL_SH_TEMPLATE } from "../templates"; import { contractHome, expandHome } from "../utils/paths"; +import { getErrorLogFile, logError } from "../utils/trace"; export async function newCommand() { p.intro("Initialize Agent Config Repository"); @@ -74,7 +75,6 @@ export async function newCommand() { try { mkdirSync(repoPath, { recursive: true }); } catch (error) { - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(error); p.cancel( `Failed to create directory: ${error}\n${getErrorLogFile(logFile)}`, @@ -331,7 +331,6 @@ syncode push s.stop("Repository structure created"); } catch (error) { s.stop("Failed to create repository structure"); - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(error); p.cancel(`Error: ${error}\n${getErrorLogFile(logFile)}`); return; @@ -369,7 +368,6 @@ Next steps: • Run 'syncode push' to commit and push changes`, ); } catch (error) { - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(error); p.cancel( `Failed to create configuration: ${error}\n${getErrorLogFile(logFile)}`, diff --git a/src/commands/pull.ts b/src/commands/pull.ts index ae565e8..9122f2c 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -15,6 +15,7 @@ import { pull, } from "../utils/git"; import { expandHome } from "../utils/paths"; +import { getErrorLogFile, logError } from "../utils/trace"; export async function pullCommand() { p.intro("Pull from Remote"); @@ -102,7 +103,6 @@ export async function pullCommand() { p.outro("Successfully pulled from remote"); } else { spinner.stop("Pull failed"); - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(new Error(result.message), "pull"); p.log.error(result.message); p.cancel(`Failed to pull from remote\n${getErrorLogFile(logFile)}`); diff --git a/src/commands/push.ts b/src/commands/push.ts index 664567a..76c142b 100644 --- a/src/commands/push.ts +++ b/src/commands/push.ts @@ -15,6 +15,7 @@ import { stageAll, } from "../utils/git"; import { expandHome } from "../utils/paths"; +import { getErrorLogFile, logError } from "../utils/trace"; export async function pushCommand() { p.intro("Push to Remote"); @@ -132,7 +133,6 @@ export async function pushCommand() { p.outro("Successfully pushed to remote"); } else { spinner.stop("Push failed"); - const { logError, getErrorLogFile } = require("../utils/trace"); const logFile = logError(new Error(result.message), "push"); p.log.error(result.message); p.cancel(`Failed to push to remote\n${getErrorLogFile(logFile)}`); diff --git a/src/commands/sync.ts b/src/commands/sync.ts index af9cd18..aca766b 100644 --- a/src/commands/sync.ts +++ b/src/commands/sync.ts @@ -13,6 +13,7 @@ import { import { getConfig } from "../config/manager"; import { checkAndMigrateConfig } from "../config/migrations"; import type { GlobalConfig } from "../config/types"; +import { logError } from "../utils/trace"; export async function syncCommand() { p.intro("Sync Agent Configs"); @@ -181,7 +182,6 @@ export async function syncCommand() { const errorMsg = error instanceof Error ? error.message : String(error); const errorObj = error instanceof Error ? error : new Error(String(error)); - const { logError } = require("../utils/trace"); logError(errorObj, "sync"); s.message(`✗ ${adapter.name}: ${errorMsg}`); errors.push({ agent: adapter.name, error: errorMsg }); diff --git a/src/commands/unsync.ts b/src/commands/unsync.ts index e11b8bf..39bf6bc 100644 --- a/src/commands/unsync.ts +++ b/src/commands/unsync.ts @@ -15,6 +15,7 @@ import { removeDir, } from "../utils/fs"; import { expandHome } from "../utils/paths"; +import { logError } from "../utils/trace"; function copyDirReplacingSymlinks(src: string, dest: string): void { ensureDir(dest); @@ -145,7 +146,6 @@ export async function unsyncCommand() { } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); - const { logError } = require("../utils/trace"); logError(errorObj, "unsync"); s.message(`✗ Error unsyncing ${adapter.name}: ${error}`); failCount++; diff --git a/src/index.ts b/src/index.ts index ecfb23c..303ec7f 100755 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import { pushCommand } from "./commands/push"; import { statusCommand } from "./commands/status"; import { syncCommand } from "./commands/sync"; import { unsyncCommand } from "./commands/unsync"; +import { getErrorLogFile, logError } from "./utils/trace"; import { checkForUpdates } from "./utils/update-check"; // Read version from package.json @@ -181,8 +182,6 @@ Quick Start: } main().catch((error) => { - const { logError, getErrorLogFile } = require("./utils/trace"); - const logFile = logError(error); console.error("Error:", error.message); console.error(getErrorLogFile(logFile)); diff --git a/src/utils/fs.ts b/src/utils/fs.ts index 96d1c8a..226f732 100644 --- a/src/utils/fs.ts +++ b/src/utils/fs.ts @@ -13,7 +13,7 @@ import { unlinkSync, } from "node:fs"; import { dirname, join } from "node:path"; -import { REPO_ROOT } from "./paths"; +import { REPO_ROOT, systemPaths } from "./paths"; export function exists(path: string): boolean { return existsSync(path); @@ -231,8 +231,6 @@ export function getAllSymlinksToRepo(): Array<{ }; // Check common config locations - const { systemPaths } = require("./paths"); - checkPath(systemPaths.zshrc); checkPath(systemPaths.bashrc); checkPath(systemPaths.ssh); diff --git a/src/utils/paths.ts b/src/utils/paths.ts index da33355..e8fea67 100644 --- a/src/utils/paths.ts +++ b/src/utils/paths.ts @@ -1,6 +1,7 @@ import { homedir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; +import { tryGetRepoRoot } from "../config/manager"; import { isMacOS } from "./platform"; // Home directory @@ -16,15 +17,9 @@ const LEGACY_REPO_ROOT = resolve(dirname(dirname(__dirname))); * Tries to read from config, falls back to legacy path for backward compatibility */ export function getRepoRoot(): string { - // Import here to avoid circular dependency - try { - const { tryGetRepoRoot } = require("../config/manager"); - const configPath = tryGetRepoRoot(); - if (configPath) { - return configPath; - } - } catch { - // Config module not available or error reading config + const configPath = tryGetRepoRoot(); + if (configPath) { + return configPath; } // Fall back to legacy path diff --git a/src/utils/trace.ts b/src/utils/trace.ts index 0c8b61a..5f0f943 100644 --- a/src/utils/trace.ts +++ b/src/utils/trace.ts @@ -1,5 +1,6 @@ -import { existsSync, mkdirSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; import { getRepoRoot } from "./paths"; export interface TraceData { @@ -17,10 +18,11 @@ export interface TraceData { } export function logError( - error: Error, + thrown: unknown, command?: string, args?: string[], ): string { + const error = thrown instanceof Error ? thrown : new Error(String(thrown)); const repoRoot = getRepoRoot(); const timestamp = Date.now(); const logDir = join(repoRoot, ".syncode-logs"); @@ -58,9 +60,6 @@ export function getErrorLogFile(logFile: string): string { function getVersion(): string { try { - const { readFileSync } = require("node:fs"); - const { join, dirname } = require("node:path"); - const { fileURLToPath } = require("node:url"); const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packageJson = JSON.parse(