/**
 * Shared helper — resolve the FileSystemSurface for the current session.
 *
 * Priority:
 * 1. If `targetPath` is absolute and outside the current project boundary,
 *    find or create a surface scoped to contain that path.
 * 2. Look for an existing surface with the conventional ID `fs-{sessionId}`
 *    that is running (the auto-created surface for the session).
 * 3. Look for *any* running filesystem surface belonging to the session
 *    (e.g. one started via `surfaces.start` with a custom project root).
 * 4. If nothing exists, auto-start one with `context.projectRoot`.
 *
 * This ensures that when the user asks to read/edit files anywhere on their
 * local filesystem, the agent can access them without "escapes project
 * boundary" errors — while still maintaining PathGuard isolation per surface.
 */
import { resolve, isAbsolute, dirname } from "node:path";
import { stat } from "node:fs/promises";
import { FileSystemSurface } from "../../surfaces/filesystem.js";
/**
 * Given a `targetPath`, determine the correct project root.
 * If the path is a directory, use it directly.
 * If the path is a file, use its parent directory.
 * Falls back to the path itself if stat fails (e.g. doesn't exist yet).
 */
async function deriveProjectRoot(targetPath) {
    const abs = resolve(targetPath);
    try {
        const info = await stat(abs);
        return info.isDirectory() ? abs : dirname(abs);
    }
    catch {
        // Path doesn't exist yet — use the parent directory
        return dirname(abs);
    }
}
/**
 * Check if `surface` can serve `targetPath` (i.e. the path is within
 * the surface's project boundary).
 */
function surfaceCovers(surface, targetPath) {
    return surface.isPathAllowed(targetPath);
}
/**
 * Among multiple surfaces that cover a path, prefer the most specific one
 * (deepest project root).
 */
function pickMostSpecific(surfaces, targetPath) {
    let best = null;
    let bestLen = -1;
    for (const s of surfaces) {
        if (!surfaceCovers(s, targetPath))
            continue;
        const root = s.snapshot().metadata?.projectRoot;
        const len = root?.length ?? 0;
        if (len > bestLen) {
            best = s;
            bestLen = len;
        }
    }
    return best;
}
export async function getFs(registry, context, targetPath) {
    const absTarget = targetPath ? resolve(context.projectRoot, targetPath) : undefined;
    // ── If target is absolute and we already have a surface that covers it, use it ──
    if (absTarget) {
        // Collect all running FS surfaces for this session
        const candidates = [];
        const fsId = `fs-${context.sessionId}`;
        const conventional = registry.getSurface(fsId);
        if (conventional?.state === "running")
            candidates.push(conventional);
        for (const s of registry.getBySession(context.sessionId)) {
            if (s instanceof FileSystemSurface && s.state === "running" && s !== conventional) {
                candidates.push(s);
            }
        }
        // Pick the most specific surface that covers this path
        const best = pickMostSpecific(candidates, absTarget);
        if (best)
            return best;
        // No existing surface covers this path — create one scoped to the target
        if (isAbsolute(targetPath)) {
            const newRoot = await deriveProjectRoot(absTarget);
            const safeName = newRoot.replace(/[:\\\/]/g, "_").replace(/_+$/, "").toLowerCase();
            const surfaceId = `fs-${context.sessionId}-${safeName}`;
            const existing = registry.getSurface(surfaceId);
            if (existing?.state === "running")
                return existing;
            const started = await registry.startSurface("filesystem", surfaceId, {
                sessionId: context.sessionId,
                projectRoot: newRoot,
            });
            return started;
        }
    }
    // ── Default: find or create the conventional session surface ──
    // 1. Conventional per-session ID
    const fsId = `fs-${context.sessionId}`;
    const conventional = registry.getSurface(fsId);
    if (conventional && conventional.state === "running")
        return conventional;
    // 2. Any running filesystem surface for this session
    const sessionSurfaces = registry.getBySession(context.sessionId);
    for (const s of sessionSurfaces) {
        if (s instanceof FileSystemSurface &&
            s.state === "running") {
            return s;
        }
    }
    // 3. Nothing found — auto-start one
    const started = await registry.startSurface("filesystem", fsId, {
        sessionId: context.sessionId,
        projectRoot: context.projectRoot,
    });
    return started;
}
/**
 * Resolve the effective project root for a session.
 *
 * Prefers the most specific (deepest) project root among all running
 * filesystem surfaces for this session — avoids returning a broad drive root
 * when a more specific project surface exists.
 * Falls back to `process.cwd()`.
 */
export function resolveProjectRoot(registry, sessionId, 
/** Optional fallback from session record before falling back to process.cwd() */
sessionProjectPath) {
    let best = null;
    let bestLen = -1;
    for (const s of registry.getBySession(sessionId)) {
        if (s instanceof FileSystemSurface && s.state === "running") {
            const root = s.snapshot().metadata
                ?.projectRoot;
            if (root && root.length > bestLen) {
                best = root;
                bestLen = root.length;
            }
        }
    }
    return best ?? sessionProjectPath?.trim() ?? process.cwd();
}
//# sourceMappingURL=get-fs.js.map