"use strict";
/**
 * Shared utilities for detecting multiple @doquflow/cli installations across
 * different npm global prefixes (nvm, hermes, fnm, homebrew, etc.).
 *
 * Used by:
 *  - prefix-check.ts  (startup warning, DEF-4)
 *  - commands/init.ts (repair cross-prefix MCP configs, DEF-12)
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveServerBinForPrefix = resolveServerBinForPrefix;
exports.findInstallsSync = findInstallsSync;
exports.getMcpEntryPrefix = getMcpEntryPrefix;
exports.getInstalledCliVersion = getInstalledCliVersion;
exports.semverGt = semverGt;
exports.semverCompare = semverCompare;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const node_os_1 = __importDefault(require("node:os"));
/**
 * Resolve the @doquflow/studio MCP entry for a given install prefix.
 * Tries the bundled location (inside cli's node_modules) then the hoisted location.
 */
function resolveServerBinForPrefix(prefix) {
    const bundled = node_path_1.default.join(prefix, "lib", "node_modules", "@doquflow", "cli", "node_modules", "@doquflow", "studio", "dist", "mcp", "index.js");
    if (node_fs_1.default.existsSync(bundled))
        return bundled;
    const hoisted = node_path_1.default.join(prefix, "lib", "node_modules", "@doquflow", "studio", "dist", "mcp", "index.js");
    if (node_fs_1.default.existsSync(hoisted))
        return hoisted;
    return null;
}
/**
 * Candidate prefix paths to scan on macOS / Linux.
 * Accepts an optional extra list (useful for tests via DOCUFLOW_EXTRA_PREFIXES).
 */
function candidatePrefixes(extras = []) {
    const home = node_os_1.default.homedir();
    const candidates = [...extras];
    // nvm
    const nvmDir = node_path_1.default.join(home, ".nvm", "versions", "node");
    if (node_fs_1.default.existsSync(nvmDir)) {
        try {
            for (const ver of node_fs_1.default.readdirSync(nvmDir)) {
                candidates.push(node_path_1.default.join(nvmDir, ver));
            }
        }
        catch { /* ignore */ }
    }
    // hermes (Waymark / custom node manager)
    candidates.push(node_path_1.default.join(home, ".hermes", "node"));
    // fnm
    const fnmDir = node_path_1.default.join(home, ".fnm", "node-versions");
    if (node_fs_1.default.existsSync(fnmDir)) {
        try {
            for (const ver of node_fs_1.default.readdirSync(fnmDir)) {
                candidates.push(node_path_1.default.join(fnmDir, ver, "installation"));
            }
        }
        catch { /* ignore */ }
    }
    // volta
    candidates.push(node_path_1.default.join(home, ".volta", "tools", "image", "node"));
    // homebrew / system
    candidates.push("/opt/homebrew", "/usr/local", "/usr");
    // npm-global (manually configured)
    candidates.push(node_path_1.default.join(home, ".npm-global"));
    return candidates;
}
/**
 * Synchronously scan all known npm prefix locations and return every prefix
 * that has @doquflow/cli installed, sorted newest-first.
 */
function findInstallsSync(extras = []) {
    const results = [];
    const seen = new Set();
    for (const prefix of candidatePrefixes(extras)) {
        const resolved = node_path_1.default.resolve(prefix);
        if (seen.has(resolved))
            continue;
        seen.add(resolved);
        const pkgJson = node_path_1.default.join(resolved, "lib", "node_modules", "@doquflow", "cli", "package.json");
        if (!node_fs_1.default.existsSync(pkgJson))
            continue;
        try {
            const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgJson, "utf8"));
            if (!pkg.version)
                continue;
            const nodeBin = node_path_1.default.join(resolved, "bin", "node");
            results.push({
                prefix: resolved,
                version: pkg.version,
                nodeBin: node_fs_1.default.existsSync(nodeBin) ? nodeBin : process.execPath,
                serverBin: resolveServerBinForPrefix(resolved),
            });
        }
        catch { /* corrupted install — skip */ }
    }
    results.sort((a, b) => semverCompare(b.version, a.version));
    return results;
}
/** Extract the npm prefix from an MCP entry path. */
function getMcpEntryPrefix(entryPath) {
    const m = entryPath.match(/^(.*?)\/lib\/node_modules\/@doquflow\//);
    return m ? node_path_1.default.resolve(m[1]) : null;
}
/** Read the @doquflow/cli version from an MCP entry path (traverses up to find package.json). */
function getInstalledCliVersion(mcpEntryPath) {
    const prefix = getMcpEntryPrefix(mcpEntryPath);
    if (!prefix)
        return null;
    const pkgJson = node_path_1.default.join(prefix, "lib", "node_modules", "@doquflow", "cli", "package.json");
    try {
        const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgJson, "utf8"));
        return pkg.version ?? null;
    }
    catch {
        return null;
    }
}
/** Returns true when version string a > b (semver numeric compare). */
function semverGt(a, b) {
    return semverCompare(a, b) > 0;
}
/** 3-part numeric semver comparison. Returns >0 if a>b, <0 if a<b, 0 if equal. */
function semverCompare(a, b) {
    const pa = a.split(".").map(Number);
    const pb = b.split(".").map(Number);
    for (let i = 0; i < 3; i++) {
        const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
        if (diff !== 0)
            return diff;
    }
    return 0;
}
