/**
 * ============================================================
 *  src/tools/bash/semantics.ts —— 命令退出码语义解释
 * ------------------------------------------------------------
 *  许多命令用 exit code 传递"信息"而不是"成功/失败"。
 *  最典型的是 grep：没匹配返回 1，但这不算错误。
 *
 *  这里对一小撮"退出码语义特殊"的命令做白名单化处理，
 *  让 Bash 工具能正确地把它们的"信息性退出码"识别成非错误，
 *  避免模型看到 ok=false 后无意义重试。
 *
 *  纯函数模块，无 I/O，便于单测。
 * ============================================================
 */
const DEFAULT_SEMANTIC = (exitCode) => ({
    isError: exitCode !== 0,
    message: exitCode !== 0 ? `Command failed with exit code ${exitCode}` : undefined,
});
export const COMMAND_SEMANTICS = new Map([
    // grep: 0=找到匹配, 1=无匹配（非错误）, 2+=真错误
    ['grep', (exitCode) => ({
            isError: exitCode >= 2,
            message: exitCode === 1 ? 'No matches found' : undefined,
        })],
    // ripgrep 与 grep 同义
    ['rg', (exitCode) => ({
            isError: exitCode >= 2,
            message: exitCode === 1 ? 'No matches found' : undefined,
        })],
    // find: 1=部分目录不可达（仍有结果，非致命）, 2+=错误
    ['find', (exitCode) => ({
            isError: exitCode >= 2,
            message: exitCode === 1 ? 'Some directories were inaccessible' : undefined,
        })],
    // diff: 0=相同, 1=有差异（非错误）, 2+=错误
    ['diff', (exitCode) => ({
            isError: exitCode >= 2,
            message: exitCode === 1 ? 'Files differ' : undefined,
        })],
    // test: 0=真, 1=假（非错误）, 2+=错误
    ['test', (exitCode) => ({
            isError: exitCode >= 2,
            message: exitCode === 1 ? 'Condition is false' : undefined,
        })],
    // [ 是 test 的别名
    ['[', (exitCode) => ({
            isError: exitCode >= 2,
            message: exitCode === 1 ? 'Condition is false' : undefined,
        })],
]);
/**
 * 从复合命令串里启发式抽出"最终决定 exit code 的那个命令"。
 *
 * 规则（够用即可，不追求严谨 shell 解析）：
 *  1. 去掉前缀 `bash -c "..."` / `sh -c '...'`
 *  2. 按 ` | `、`&&`、`||`、`;` 分段，取最后一段（决定退出码的是最后一个命令）
 *  3. 去掉前置 `env VAR=val` / `VAR=val` 形态的环境变量赋值
 *  4. 取第一个 token 作为命令名
 *
 * 不依赖 shell-quote，避免引新依赖。
 */
function extractPrimaryCommand(command) {
    let cmd = command.trim();
    // 剥 bash -c "..." / sh -c '...' 外壳
    const wrapMatch = cmd.match(/^(?:bash|sh|zsh|dash)\s+-c\s+(['"])(.+)\1\s*$/s);
    if (wrapMatch)
        cmd = wrapMatch[2].trim();
    // 按 shell 控制操作符切，取最后一段
    const segments = cmd.split(/\s*(?:\|\||&&|;|\|)\s*/).filter((s) => s.length > 0);
    let last = segments[segments.length - 1] ?? cmd;
    last = last.trim();
    // 去掉前置环境变量赋值：`FOO=bar BAZ=qux cmd ...` 或 `env FOO=bar cmd ...`
    const tokens = last.split(/\s+/);
    let i = 0;
    if (tokens[i] === 'env')
        i++;
    while (i < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[i]))
        i++;
    return tokens[i] ?? '';
}
export function interpretCommandResult(command, exitCode, stdout, stderr) {
    const base = extractPrimaryCommand(command);
    const fn = COMMAND_SEMANTICS.get(base) ?? DEFAULT_SEMANTIC;
    return fn(exitCode, stdout, stderr);
}
