const STRUCTURED_PATH_KEYS = new Set([
    "destination",
    "dest",
    "file",
    "filename",
    "filepath",
    "file_path",
    "path",
    "target",
    "target_path",
]);
const STRUCTURED_PATH_ARRAY_KEYS = new Set([
    "destinations",
    "files",
    "filepaths",
    "file_paths",
    "paths",
    "targets",
    "target_paths",
]);
const READ_ONLY_COMMANDS = new Set([
    "awk",
    "cat",
    "echo",
    "false",
    "head",
    "less",
    "ls",
    "pwd",
    "printf",
    "rg",
    "sed",
    "tail",
    "test",
    "true",
    "wc",
]);
const READ_ONLY_GIT_SUBCOMMANDS = new Set([
    "blame",
    "branch",
    "diff",
    "grep",
    "log",
    "ls-files",
    "rev-parse",
    "show",
    "status",
]);
export function extractStructuredToolPaths(args, access = "unknown") {
    const raw = recordValue(args);
    const paths = [];
    for (const [key, value] of Object.entries(raw)) {
        const normalizedKey = key.toLowerCase();
        if (STRUCTURED_PATH_KEYS.has(normalizedKey)) {
            const path = normalizedPath(value);
            if (path)
                paths.push({ path, access, source: `args.${key}` });
        }
        if (STRUCTURED_PATH_ARRAY_KEYS.has(normalizedKey)) {
            for (const path of normalizedPathArray(value)) {
                paths.push({ path, access, source: `args.${key}` });
            }
        }
    }
    return dedupePaths(paths);
}
export function extractWriteToolPaths(toolName, args) {
    const normalized = toolName.trim().toLowerCase();
    if (normalized === "apply_patch" || normalized === "patch") {
        const patch = extractPatchText(args);
        const patchPaths = patch ? extractApplyPatchPaths(patch) : [];
        if (patchPaths.length > 0)
            return patchPaths;
    }
    return extractStructuredToolPaths(args, "write");
}
export function extractCommandFromArgs(args) {
    if (typeof args === "string" && args.trim())
        return args.trim();
    const raw = recordValue(args);
    for (const key of ["command", "cmd", "script", "input"]) {
        const value = raw[key];
        if (typeof value === "string" && value.trim())
            return value.trim();
    }
    return undefined;
}
export function analyzeShellCommand(command) {
    if (!command?.trim()) {
        return { file_effect: "unknown", paths: [], reason: "Shell tool has no command string to inspect." };
    }
    const writePaths = extractShellWritePaths(command);
    if (writePaths.length > 0) {
        return {
            file_effect: strongestWriteEffect(writePaths),
            paths: writePaths,
            reason: "Shell command exposes concrete write targets through redirection or tee.",
        };
    }
    if (isReadOnlyShellCommand(command)) {
        return { file_effect: "none", paths: [], reason: "Shell command matches the conservative read-only command set." };
    }
    return { file_effect: "unknown", paths: [], reason: "Shell command may have side effects but exposes no concrete write target." };
}
export function extractWorkspaceModePaths(args) {
    const raw = recordValue(args);
    const mode = stringValue(raw.mode);
    const access = mode === "read" || mode === "write" || mode === "append" ? mode : "unknown";
    return extractStructuredToolPaths(args, access);
}
export function extractWorkspaceToolPaths(toolName, args) {
    const normalized = toolName.trim().toLowerCase();
    const raw = recordValue(args);
    if (normalized === "seed_workspace_diff_record") {
        const paths = normalizedPathArray(raw.paths);
        return dedupePaths(paths.map((path) => ({ path, access: "write", source: "args.paths" })));
    }
    if (normalized === "seed_workspace_worktree_merge_record") {
        const paths = normalizedPathArray(raw.target_paths);
        return dedupePaths(paths.map((path) => ({ path, access: "write", source: "args.target_paths" })));
    }
    return extractWorkspaceModePaths(args);
}
function extractShellWritePaths(command) {
    const paths = [];
    const redirectPattern = /(?:^|\s)(?:\d?>>?|\&>>?)\s*(?:"([^"]+)"|'([^']+)'|([^\s;&|<>]+))/g;
    for (const match of command.matchAll(redirectPattern)) {
        const rawPath = match[1] ?? match[2] ?? match[3];
        const path = normalizedPath(rawPath);
        if (!path || path === "/dev/null" || path === "&1" || path === "&2")
            continue;
        const operator = match[0];
        paths.push({ path, access: operator.includes(">>") ? "append" : "write", source: "shell.redirect" });
    }
    const teePattern = /\btee\s+((?:-[A-Za-z]+\s+)*)(?:"([^"]+)"|'([^']+)'|([^\s;&|<>]+))/g;
    for (const match of command.matchAll(teePattern)) {
        const flags = match[1] ?? "";
        const rawPath = match[2] ?? match[3] ?? match[4];
        const path = normalizedPath(rawPath);
        if (!path || path === "/dev/null")
            continue;
        paths.push({ path, access: flags.includes("a") ? "append" : "write", source: "shell.tee" });
    }
    return dedupePaths(paths);
}
function extractPatchText(args) {
    if (typeof args === "string" && args.trim())
        return args;
    const raw = recordValue(args);
    for (const key of ["patch", "input", "content", "text"]) {
        const value = raw[key];
        if (typeof value === "string" && value.trim())
            return value;
    }
    return undefined;
}
function extractApplyPatchPaths(patch) {
    const paths = [];
    const headerPattern = /^\*\*\* (?:Add File|Update File|Delete File|Move to):\s*(.+?)\s*$/gm;
    for (const match of patch.matchAll(headerPattern)) {
        const path = normalizedPath(match[1]);
        if (path)
            paths.push({ path, access: "write", source: "patch.header" });
    }
    return dedupePaths(paths);
}
function isReadOnlyShellCommand(command) {
    if (/[;&]|&&|\|\|/.test(command))
        return false;
    const pipeline = command.split("|").map((part) => part.trim()).filter(Boolean);
    if (pipeline.length === 0)
        return false;
    return pipeline.every(isReadOnlyCommandSegment);
}
function isReadOnlyCommandSegment(segment) {
    const tokens = tokenizeShellSegment(segment);
    const commandIndex = tokens.findIndex((token) => !/^[A-Za-z_][A-Za-z0-9_]*=/.test(token));
    if (commandIndex < 0)
        return true;
    const executable = basename(tokens[commandIndex] ?? "").toLowerCase();
    const args = tokens.slice(commandIndex + 1);
    if (executable === "git") {
        const subcommand = args.find((arg) => !arg.startsWith("-"))?.toLowerCase();
        return subcommand ? READ_ONLY_GIT_SUBCOMMANDS.has(subcommand) : false;
    }
    if (executable === "grep" || executable === "find") {
        return !args.some((arg) => arg === "-delete" || arg === "-exec" || arg === "-execdir" || arg === "-ok");
    }
    if (executable === "sed") {
        return !args.some((arg) => arg === "-i" || arg.startsWith("-i"));
    }
    return READ_ONLY_COMMANDS.has(executable);
}
function tokenizeShellSegment(segment) {
    const tokens = [];
    const tokenPattern = /"([^"]*)"|'([^']*)'|(\S+)/g;
    for (const match of segment.matchAll(tokenPattern)) {
        tokens.push(match[1] ?? match[2] ?? match[3] ?? "");
    }
    return tokens.filter(Boolean);
}
function strongestWriteEffect(paths) {
    if (paths.some((path) => path.access === "write"))
        return "write";
    if (paths.some((path) => path.access === "append"))
        return "append";
    return "unknown";
}
function dedupePaths(paths) {
    const seen = new Set();
    const deduped = [];
    for (const entry of paths) {
        const key = `${entry.path}:${entry.access}:${entry.source}`;
        if (seen.has(key))
            continue;
        seen.add(key);
        deduped.push(entry);
    }
    return deduped;
}
function normalizedPath(value) {
    if (typeof value !== "string")
        return undefined;
    const path = value.trim().replaceAll("\\", "/").replace(/\/+/g, "/").replace(/\/$/, "");
    if (!path || path.startsWith("-") || /^https?:\/\//i.test(path))
        return undefined;
    return path;
}
function normalizedPathArray(value) {
    if (!Array.isArray(value))
        return [];
    return value.map(normalizedPath).filter((path) => Boolean(path));
}
function basename(value) {
    return value.replaceAll("\\", "/").split("/").at(-1) ?? value;
}
function recordValue(input) {
    return typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
}
function stringValue(input) {
    return typeof input === "string" && input.trim().length > 0 ? input.trim() : undefined;
}
//# sourceMappingURL=path-extractor.js.map