// shadowing check — when a harness's own launcher shadows our shim on PATH, adopt
// it (symlink-only, reversible) so version management wins regardless of PATH order.
// A REAL native binary is never moved — it's surfaced as needsAttention so the
// interactive layer can inform the user once. POSIX-only (the launcher convention
// and PATH-order problem are POSIX; Windows resolves via the registry PATH).
import { resultOf } from '../types.js';
import { AGENTS } from '../../agents.js';
import { getPathShadowingExecutable, adoptShadowingLauncher, listAgentsWithNonIsolatedInstalledVersions, } from '../../installations/shims.js';
import { getGlobalDefault } from '../../installations/versions.js';
export const shadowingCheck = {
    id: 'shadowing',
    title: 'Launcher shadowing the version-managed shim',
    platforms: ['darwin', 'linux'],
    cadence: 'frequent',
    async run(ctx) {
        const fixed = [];
        const needsAttention = [];
        // Isolated-only agents are skipped outright. Adoption repoints the user's OWN
        // launcher (e.g. the npm symlink ~/.npm-global/bin/codex) at our shim — the most
        // invasive thing self-heal does, and the exact opposite of what `--isolated`
        // promises. The `getGlobalDefault` guard below already blocked this in practice,
        // since an isolated install never sets a default; but that made the boundary
        // depend on an invariant enforced elsewhere. Any path that pins a default from
        // an isolated copy would silently re-arm the adoption. Gate on the installs
        // themselves so it cannot happen regardless of how a default got recorded.
        for (const agent of listAgentsWithNonIsolatedInstalledVersions()) {
            if (!getGlobalDefault(agent))
                continue; // only default agents, like the interactive flow
            const cmd = AGENTS[agent].cliCommand;
            const shadowedBy = getPathShadowingExecutable(agent);
            if (!shadowedBy)
                continue;
            if (ctx.dryRun) {
                // Classify without mutating: adoption only ever touches a symlink.
                let isSymlink = false;
                try {
                    const fs = await import('node:fs');
                    isSymlink = fs.lstatSync(shadowedBy).isSymbolicLink();
                }
                catch { /* treat as real binary */ }
                if (isSymlink)
                    fixed.push(`${cmd} launcher (${shadowedBy})`);
                else
                    needsAttention.push(`${cmd}: real binary shadows the shim (${shadowedBy})`);
                continue;
            }
            const res = adoptShadowingLauncher(agent);
            if (res.adopted)
                fixed.push(`adopted ${cmd} launcher (${res.launcher})`);
            else if (res.reason === 'not-a-symlink') {
                needsAttention.push(`${cmd}: real binary shadows the shim (${shadowedBy})`);
            }
        }
        return resultOf(fixed, needsAttention);
    },
};
