"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CAPABILITY_REVIEW_ALLOWED_COMMANDS = void 0;
exports.createCapabilityReviewBashTool = createCapabilityReviewBashTool;
const errors_1 = require("./errors");
exports.CAPABILITY_REVIEW_ALLOWED_COMMANDS = [
    "alpaca catalog topics list",
    "alpaca capability list",
    "alpaca capability search",
    "alpaca skill catalog list --include-system",
    "alpaca skill list",
    "alpaca skill search",
    "alpaca mcp catalog list --include-system",
    "alpaca mcp list",
    "alpaca mcp search",
    "alpaca mcp verify",
];
function createCapabilityReviewBashTool(input) {
    if (input.createBashToolDefinition === undefined ||
        input.createLocalBashOperations === undefined) {
        throw new errors_1.WorkerUnavailableError("Pi capability review requires bash tool factory exports.");
    }
    const localOperations = input.createLocalBashOperations();
    return input.createBashToolDefinition(input.workspacePath, {
        operations: {
            exec(command, cwd, options) {
                const normalizedCommand = normalizeCapabilityReviewCommand(command);
                return localOperations.exec(normalizedCommand, cwd, options);
            },
        },
    });
}
const CAPABILITY_REVIEW_SIMPLE_COMMANDS = new Set([
    "alpaca catalog topics list",
    "alpaca skill catalog list --include-system",
    "alpaca mcp catalog list --include-system",
]);
const CAPABILITY_REVIEW_COMMAND_SPECS = [
    {
        group: "capability",
        action: "list",
        mode: "read-only",
        booleanFlags: ["--include-excluded"],
        valueFlags: ["--for"],
    },
    {
        group: "capability",
        action: "search",
        mode: "search",
        booleanFlags: [
            "--include-excluded",
            "--installed-only",
            "--installable-only",
        ],
        valueFlags: ["--for"],
    },
    {
        group: "skill",
        action: "list",
        mode: "read-only",
        booleanFlags: ["--include-excluded"],
        valueFlags: ["--for"],
    },
    {
        group: "skill",
        action: "search",
        mode: "search",
        booleanFlags: [
            "--include-excluded",
            "--installed-only",
            "--installable-only",
        ],
        valueFlags: ["--for"],
    },
    {
        group: "mcp",
        action: "list",
        mode: "read-only",
        booleanFlags: ["--include-excluded"],
        valueFlags: ["--for"],
    },
    {
        group: "mcp",
        action: "search",
        mode: "search",
        booleanFlags: [
            "--include-excluded",
            "--installed-only",
            "--installable-only",
        ],
        valueFlags: ["--for"],
    },
    {
        group: "mcp",
        action: "verify",
        mode: "read-only",
        booleanFlags: [],
        valueFlags: ["--for", "--ref"],
    },
];
function normalizeCapabilityReviewCommand(command) {
    assertNoUnquotedShellControl(command);
    const tokens = parseCapabilityReviewCommandTokens(command);
    if (tokens[0] !== "alpaca") {
        throw new Error("Capability review bash allows only AlpacaLoop read-only commands.");
    }
    const exactCommand = tokens.join(" ");
    if (CAPABILITY_REVIEW_SIMPLE_COMMANDS.has(exactCommand)) {
        return renderShellCommand(tokens);
    }
    const spec = findCapabilityReviewCommandSpec(tokens[1], tokens[2]);
    if (spec === undefined) {
        throw new Error(`Unsupported capability review command: ${command}`);
    }
    const args = tokens.slice(3);
    const flags = {
        booleanFlags: new Set(spec.booleanFlags),
        valueFlags: new Set(spec.valueFlags),
    };
    if (spec.mode === "search") {
        validateSearchOptions(args, flags);
        return renderShellCommand(tokens);
    }
    validateReadOnlyOptions(args, flags);
    return renderShellCommand(tokens);
}
function assertNoUnquotedShellControl(command) {
    let quote = null;
    for (const char of command) {
        if (quote !== null) {
            if (char === quote) {
                quote = null;
            }
            continue;
        }
        if (char === "'" || char === '"') {
            quote = char;
            continue;
        }
        if (/[;&|<>`$\\\n\r]/u.test(char)) {
            throw new Error("Capability review bash allows only single AlpacaLoop read-only commands.");
        }
    }
}
function findCapabilityReviewCommandSpec(group, action) {
    if (group === undefined || action === undefined) {
        return undefined;
    }
    return CAPABILITY_REVIEW_COMMAND_SPECS.find((spec) => spec.group === group && spec.action === action);
}
function parseCapabilityReviewCommandTokens(command) {
    const tokens = [];
    let current = "";
    let quote = null;
    for (const char of command.trim()) {
        if (quote !== null) {
            if (char === quote) {
                quote = null;
            }
            else {
                current += char;
            }
            continue;
        }
        if (char === "'" || char === '"') {
            quote = char;
            continue;
        }
        if (/\s/u.test(char)) {
            if (current.length > 0) {
                tokens.push(current);
                current = "";
            }
            continue;
        }
        current += char;
    }
    if (quote !== null) {
        throw new Error("Capability review command has an unterminated quote.");
    }
    if (current.length > 0) {
        tokens.push(current);
    }
    if (tokens.length === 0) {
        throw new Error("Capability review command is empty.");
    }
    return tokens;
}
function validateSearchOptions(args, flags) {
    let foundQuery = false;
    let installedOnly = false;
    let installableOnly = false;
    for (let index = 0; index < args.length; index += 1) {
        const token = args[index];
        if (token === undefined) {
            throw new Error("Capability review command contains an empty argument.");
        }
        if (token.startsWith("--")) {
            if (token === "--installed-only") {
                installedOnly = true;
            }
            if (token === "--installable-only") {
                installableOnly = true;
            }
            if (installedOnly && installableOnly) {
                throw new Error("Capability review search commands cannot combine --installed-only and --installable-only.");
            }
            index = validateFlag(args, index, flags);
            continue;
        }
        if (foundQuery) {
            throw new Error(`Unexpected capability review argument: ${token}`);
        }
        foundQuery = true;
    }
    if (!foundQuery) {
        throw new Error("Capability review search commands require a query.");
    }
}
function validateReadOnlyOptions(args, flags) {
    for (let index = 0; index < args.length; index += 1) {
        index = validateFlag(args, index, flags);
    }
}
function validateFlag(args, index, flags) {
    const token = args[index];
    if (token === undefined) {
        throw new Error("Capability review command contains an empty argument.");
    }
    if (flags.booleanFlags.has(token)) {
        return index;
    }
    if (!flags.valueFlags.has(token)) {
        throw new Error(`Unsupported capability review option: ${token}`);
    }
    const value = args[index + 1];
    if (value === undefined || value.startsWith("--")) {
        throw new Error(`Missing value for capability review option: ${token}`);
    }
    return index + 1;
}
function renderShellCommand(tokens) {
    return tokens.map(renderShellArgument).join(" ");
}
function renderShellArgument(token) {
    if (/^[A-Za-z0-9_./:@%+=,-]+$/u.test(token)) {
        return token;
    }
    return `'${token.replaceAll("'", `'"'"'`)}'`;
}
