import { existsSync, readFileSync, renameSync, rmSync } from "node:fs" import { join, dirname, basename } from "node:path" import { log } from "./logger" import { getSidecarPath } from "./migration/migrations-sidecar" import { CONFIG_BASENAME, LEGACY_CONFIG_BASENAME } from "./plugin-identity" import { writeFileAtomically } from "./write-file-atomically" function buildCanonicalPath(legacyPath: string): string { const dir = dirname(legacyPath) const ext = basename(legacyPath).includes(".jsonc") ? ".jsonc" : ".json" return join(dir, `${CONFIG_BASENAME}${ext}`) } function archiveLegacyConfigFile(legacyPath: string): boolean { const backupPath = `${legacyPath}.bak` try { renameSync(legacyPath, backupPath) log("[migrateLegacyConfigFile] Legacy config was migrated and renamed to backup. Update the canonical file only.", { legacyPath, backupPath, }) return true } catch (renameError) { try { rmSync(legacyPath) log("[migrateLegacyConfigFile] Legacy config was migrated and removed after backup rename failed. Update the canonical file only.", { legacyPath, backupPath, renameError, }) return true } catch (removeError) { log("[migrateLegacyConfigFile] WARNING: canonical config was written but the legacy file still exists and will be ignored. Remove or rename it manually.", { legacyPath, backupPath, renameError, removeError, }) return false } } } function migrateLegacySidecarFile(legacyPath: string, canonicalPath: string): boolean { const legacySidecarPath = getSidecarPath(legacyPath) if (!existsSync(legacySidecarPath)) return true const canonicalSidecarPath = getSidecarPath(canonicalPath) if (existsSync(canonicalSidecarPath)) return true try { const content = readFileSync(legacySidecarPath, "utf-8") writeFileAtomically(canonicalSidecarPath, content) log("[migrateLegacyConfigFile] Migrated legacy migration sidecar to canonical path", { from: legacySidecarPath, to: canonicalSidecarPath, }) return true } catch (error) { log("[migrateLegacyConfigFile] Failed to migrate legacy migration sidecar", { legacySidecarPath, canonicalSidecarPath, error, }) return false } } export function migrateLegacyConfigFile(legacyPath: string): boolean { if (!existsSync(legacyPath)) return false if (!basename(legacyPath).startsWith(LEGACY_CONFIG_BASENAME)) return false const canonicalPath = buildCanonicalPath(legacyPath) if (existsSync(canonicalPath)) return false try { const content = readFileSync(legacyPath, "utf-8") writeFileAtomically(canonicalPath, content) const migratedSidecar = migrateLegacySidecarFile(legacyPath, canonicalPath) const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath) log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", { from: legacyPath, to: canonicalPath, migratedSidecar, archivedLegacyConfig, }) return true } catch (error) { log("[migrateLegacyConfigFile] Failed to migrate legacy config file", { legacyPath, error }) return false } }