// The single filesystem boundary for the workspace layer (ADR-0005 D1). Every other module
// depends on the `WorkspaceFs` port, never on `node:fs` directly, so discovery/detection are
// testable with an in-memory fake and all real IO is auditable in one place. Synchronous, to
// mirror the existing `loadConfigFromFile`/`readFileSync` usage in the gateway.
import { lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
import { open } from "node:fs/promises";
function isSymlink(absolutePath) {
    return lstatSync(absolutePath, { throwIfNoEntry: false })?.isSymbolicLink() ?? false;
}
export const nodeWorkspaceFs = {
    readFileUtf8: (absolutePath) => readFileSync(absolutePath, "utf8"),
    stat: (absolutePath) => {
        const stats = statSync(absolutePath, { throwIfNoEntry: true });
        return {
            size: stats.size,
            isFile: stats.isFile(),
            isDirectory: stats.isDirectory(),
            isSymbolicLink: isSymlink(absolutePath),
            hardLinkCount: stats.nlink,
        };
    },
    readDir: (absolutePath) => readdirSync(absolutePath, { withFileTypes: true }).map((entry) => ({
        name: entry.name,
        isDirectory: entry.isDirectory(),
        isFile: entry.isFile(),
        isSymbolicLink: entry.isSymbolicLink(),
    })),
    realPath: (absolutePath) => realpathSync(absolutePath),
    exists: (absolutePath) => {
        try {
            return statSync(absolutePath, { throwIfNoEntry: false }) !== undefined;
        }
        catch {
            return false;
        }
    },
    readFileBytes: async (absolutePath, maxBytes) => {
        const handle = await open(absolutePath, "r");
        try {
            const cap = Math.max(0, Math.floor(maxBytes));
            const buffer = new Uint8Array(cap);
            if (cap === 0) {
                return buffer;
            }
            const { bytesRead } = await handle.read(buffer, 0, cap, 0);
            return buffer.subarray(0, bytesRead);
        }
        finally {
            await handle.close();
        }
    },
};
