/**
 * Tool Guard — 安全规则引擎
 *
 * 可扩展的规则数组，每条规则定义：
 *   name:  规则名称
 *   tools: 适用的工具列表（'*' = 所有工具）
 *   check: (toolName, input, context) => { result: 'allow'|'deny'|'uncertain', reason? }
 */

import path from 'path';
import { readFileSync, statSync, existsSync } from 'fs';

// ─── 脚本内容审查模式（供 script-execution-guard 和 write-content-guard 复用）───

/** 危险命令模式（合并自规则 4 & 5 的核心模式） */
const DANGEROUS_SCRIPT_PATTERNS = [
  // 提权
  { pattern: /\bsudo\b/, reason: '使用 sudo' },
  { pattern: /\bsu\s+\w/, reason: '切换用户' },
  { pattern: /\bdoas\b/, reason: '使用 doas' },
  // 关机/重启
  { pattern: /\b(shutdown|reboot|halt|poweroff)\b/, reason: '关机/重启系统' },
  { pattern: /\binit\s+[06]\b/, reason: '关机/重启系统' },
  // 杀进程
  { pattern: /\bkill\s+(-\d+\s+)?1\b/, reason: '杀 init 进程' },
  { pattern: /\bkillall\b/, reason: '使用 killall' },
  { pattern: /\bpkill\b/, reason: '使用 pkill' },
  // 破坏性删除
  { pattern: /\brm\s+[^|]*-[^\s]*r[^\s]*\s+\/(\s|$)/, reason: '递归删除根目录' },
  { pattern: /\brm\s+[^|]*-[^\s]*r[^\s]*\s+\/(etc|usr|var|bin|sbin|lib|boot|sys|proc|dev)\b/, reason: '删除系统目录' },
  // 磁盘操作
  { pattern: /\bdd\s+.*\bof=\/dev\//, reason: '直接写入磁盘设备' },
  { pattern: /\bmkfs\b/, reason: '格式化磁盘' },
  { pattern: /\bfdisk\b/, reason: '操作磁盘分区' },
  // 网络/防火墙
  { pattern: /\b(iptables|nftables|ufw)\b/, reason: '修改防火墙规则' },
  // 定时任务
  { pattern: /\bcrontab\s+(-e|-r)\b/, reason: '编辑/删除 crontab' },
  // 用户/组管理
  { pattern: /\b(useradd|userdel|usermod|groupadd|groupdel)\b/, reason: '管理系统用户/组' },
  { pattern: /\bpasswd\b/, reason: '修改密码' },
  { pattern: /\bvisudo\b/, reason: '编辑 sudoers' },
  // 内核模块
  { pattern: /\b(insmod|rmmod|modprobe)\b/, reason: '操作内核模块' },
  // 服务管理
  { pattern: /\b(systemctl|service)\s+(start|stop|restart|enable|disable|reload)\b/, reason: '管理系统服务' },
  { pattern: /\blaunchctl\s+(load|unload|start|stop|bootstrap|bootout)\b/, reason: '管理 macOS 服务' },
  // 容器/云平台
  { pattern: /\bdocker\s+(rm|rmi|stop|kill|restart|network|volume|system\s+prune)\b/, reason: '管理 Docker' },
  { pattern: /\bkubectl\b/, reason: '操作 Kubernetes' },
  // Web 服务器
  { pattern: /\bnginx\s+(-s\s+)?(reload|stop|start|restart|quit)\b/, reason: '管理 nginx' },
  { pattern: /\bapachectl\b/, reason: '管理 Apache' },
  // 系统配置写入
  { pattern: />\s*\/etc\//, reason: '写入 /etc/' },
  { pattern: /\btee\s+(-a\s+)?\/etc\//, reason: '写入 /etc/' },
  { pattern: /\bsed\s+-i[^\s]*\s+\/etc\//, reason: '修改 /etc/ 文件' },
];

/**
 * 检查文本内容中的系统端口查询操作
 */
function checkSystemPortsInContent(content) {
  for (const envVar of ['PORT', 'VITE_PORT']) {
    const port = process.env[envVar];
    if (port && /^\d+$/.test(port)) {
      if (new RegExp(`\\blsof\\b[^\\n]*:${port}\\b`).test(content) ||
          new RegExp(`\\bfuser\\b[^\\n]*\\b${port}\\b`).test(content)) {
        return { denied: true, reason: `包含对系统端口 ${port} 的查询操作` };
      }
    }
  }
  return { denied: false };
}

/**
 * 检查文本内容中的绝对路径是否越界（复用白名单逻辑）
 */
function checkPathsInContent(content, context) {
  // 去除注释行（# 开头的行），避免示例路径被误判
  const nonCommentContent = content
    .split('\n')
    .filter(line => !/^\s*#/.test(line))
    .join('\n');

  const pathPattern = /(?:^|\s|=|"|')(\/[^\s"'`;|&><){}$]+)/gm;
  let match;
  while ((match = pathPattern.exec(nonCommentContent)) !== null) {
    const bad = checkResolvedPath(path.resolve(match[1]), context);
    if (bad) return { denied: true, reason: `访问项目目录之外的路径: ${bad}` };
  }
  return { denied: false };
}

// ─── 工具函数 ──────────────────────────────────────────────

/**
 * 检查路径是否在允许的前缀列表内
 */
function isPathAllowed(resolvedPath, context) {
  // 在用户的允许目录内
  for (const prefix of context.allowedPrefixes) {
    if (resolvedPath.startsWith(prefix + '/') || resolvedPath === prefix) {
      return true;
    }
  }
  // 在 cwd 内（cwd 应当已在 user-projects/{uuid}/ 下）
  if (context.cwd && (resolvedPath.startsWith(context.cwd + '/') || resolvedPath === context.cwd)) {
    return true;
  }
  return false;
}

/**
 * 检查路径是否属于其他用户
 */
function isCrossUserPath(resolvedPath, context) {
  const crossUserPattern = /\/(user-data|user-projects)\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\//i;
  const match = resolvedPath.match(crossUserPattern);
  if (match) {
    const pathUuid = match[2].toLowerCase();
    if (pathUuid !== context.userUuid.toLowerCase()) {
      return true;
    }
  }
  return false;
}

/**
 * 检查路径是否在临时目录中
 */
function isInTempDir(resolvedPath, context) {
  return context.tempDirs.some(tmpDir => resolvedPath.startsWith(tmpDir + '/') || resolvedPath === tmpDir);
}

/**
 * 检查临时目录路径是否包含用户 UUID 子目录
 */
function hasTempUserSubdir(resolvedPath, context) {
  return resolvedPath.includes('/' + context.userUuid + '/') || resolvedPath.includes('/' + context.userUuid);
}

/**
 * 对已解析的绝对路径执行统一白名单检查（供内容扫描和 Bash 命令扫描复用）
 * @returns {string|null} null = 通过；字符串 = 越界的路径
 */
function checkResolvedPath(resolvedPath, context) {
  if (SAFE_SPECIAL_PATHS.includes(resolvedPath)) return null;
  if (SAFE_COMMAND_PATHS.some(prefix => resolvedPath.startsWith(prefix))) return null;
  if (isPathAllowed(resolvedPath, context)) return null;
  if (isInTempDir(resolvedPath, context)) return null;
  if (PLACEHOLDER_PATH_PREFIXES.some(prefix => resolvedPath.startsWith(prefix))) return null;
  if (!existsSync(resolvedPath)) return null;
  return resolvedPath;
}

/** 安全命令路径前缀（用于 Bash 路径提取时排除） */
const SAFE_COMMAND_PATHS = ['/usr/bin/', '/usr/local/bin/', '/bin/', '/sbin/', '/usr/sbin/', '/opt/homebrew/bin/'];

/** 安全的特殊路径 */
const SAFE_SPECIAL_PATHS = ['/dev/null', '/dev/stdin', '/dev/stdout', '/dev/stderr', '/dev/zero', '/dev/urandom', '/dev/random'];

/** 常见占位符路径前缀（示例/文档用途，不应被视为真实访问路径） */
const PLACEHOLDER_PATH_PREFIXES = ['/path/to/', '/your/', '/example/', '/placeholder/'];


/**
 * 检查单个文件路径的安全性
 * @returns {{ result: 'allow'|'deny'|'uncertain', reason?: string }}
 */
function checkFilePath(filePath, context, toolName) {
  if (!filePath || typeof filePath !== 'string') {
    return { result: 'allow' };
  }

  const resolvedPath = path.isAbsolute(filePath)
    ? path.resolve(filePath)
    : context.cwd
      ? path.resolve(context.cwd, filePath)
      : null;

  if (!resolvedPath) {
    return { result: 'uncertain', reason: `无法解析路径: ${filePath}` };
  }

  // 在允许的目录内 → ALLOW
  if (isPathAllowed(resolvedPath, context)) {
    return { result: 'allow' };
  }

  // 在临时目录内 → 检查用户子目录
  if (isInTempDir(resolvedPath, context)) {
    if (hasTempUserSubdir(resolvedPath, context)) {
      return { result: 'allow' };
    }
    return {
      result: 'deny',
      reason: `请在临时目录中使用以用户 ID 命名的子文件夹。正确用法: /tmp/${context.userUuid}/your-file`
    };
  }

  // 访问其他用户的目录 → DENY（提供更具体的错误信息）
  if (isCrossUserPath(resolvedPath, context)) {
    return { result: 'deny', reason: '不允许访问其他用户的文件' };
  }

  // 不在白名单中（非用户目录、非临时目录）→ DENY
  return { result: 'deny', reason: `不允许访问项目目录之外的路径: ${resolvedPath}` };
}

// ─── 规则定义 ──────────────────────────────────────────────

const rules = [
  // ── 规则 1: 文件路径隔离 ──
  {
    name: 'file-path-isolation',
    tools: ['Read', 'Write', 'Edit'],
    check: (_toolName, input, context) => {
      return checkFilePath(input?.file_path, context, _toolName);
    }
  },

  // ── 规则 2: 搜索路径隔离 ──
  {
    name: 'search-path-isolation',
    tools: ['Glob', 'Grep'],
    check: (_toolName, input, context) => {
      // Glob/Grep 的 path 参数为搜索根目录，可选
      if (!input?.path) {
        // 未指定 path 时，SDK 默认使用 cwd，视为安全
        return { result: 'allow' };
      }
      return checkFilePath(input.path, context, _toolName);
    }
  },

  // ── 规则 9: 写入内容安全审查 ──
  {
    name: 'write-content-guard',
    tools: ['Write', 'Edit'],
    check: (toolName, input, context) => {
      const content = toolName === 'Write' ? input?.content : input?.new_string;
      if (!content || typeof content !== 'string') return { result: 'allow' };

      // 仅审查脚本文件（扩展名）或含 shebang 的文件
      const filePath = input?.file_path || '';
      const isShellScript = /\.(sh|bash|zsh|fish|ksh|csh)$/i.test(filePath);
      const hasShebang = /^#!\s*\//.test(content.trimStart());

      if (!isShellScript && !hasShebang) return { result: 'allow' };

      // 检查危险命令模式
      for (const { pattern, reason } of DANGEROUS_SCRIPT_PATTERNS) {
        if (pattern.test(content)) {
          return { result: 'deny', reason: `不允许写入包含危险操作的脚本: ${reason}` };
        }
      }

      // 检查系统端口查询
      const portCheck = checkSystemPortsInContent(content);
      if (portCheck.denied) {
        return { result: 'deny', reason: `不允许写入${portCheck.reason}的脚本` };
      }

      // 检查路径越界
      const pathCheck = checkPathsInContent(content, context);
      if (pathCheck.denied) {
        return { result: 'deny', reason: `不允许写入${pathCheck.reason}的脚本` };
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 3: 临时目录隔离（Bash 命令中的临时路径） ──
  {
    name: 'temp-dir-isolation',
    tools: ['Bash'],
    check: (_toolName, input, context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      // 提取命令中涉及的临时目录路径
      const tempPathPattern = /(\/tmp\/[^\s"'`;|&><)]+|\/var\/tmp\/[^\s"'`;|&><)]+|\/private\/tmp\/[^\s"'`;|&><)]+)/g;
      const tempPaths = command.match(tempPathPattern);

      if (!tempPaths || tempPaths.length === 0) {
        return { result: 'allow' };
      }

      for (const tmpPath of tempPaths) {
        if (!hasTempUserSubdir(tmpPath, context)) {
          return {
            result: 'deny',
            reason: `请在临时目录中使用以用户 ID 命名的子文件夹。正确用法: /tmp/${context.userUuid}/your-dir/`
          };
        }
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 4: 危险命令拦截 ──
  {
    name: 'dangerous-commands',
    tools: ['Bash'],
    check: (_toolName, input, _context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      const DANGEROUS_PATTERNS = [
        // 提权
        { pattern: /\bsudo\b/, reason: '不允许使用 sudo' },
        { pattern: /\bsu\s+\w/, reason: '不允许切换用户' },
        { pattern: /\bdoas\b/, reason: '不允许使用 doas' },

        // 关机/重启
        { pattern: /\b(shutdown|reboot|halt|poweroff)\b/, reason: '不允许关机/重启系统' },
        { pattern: /\binit\s+[06]\b/, reason: '不允许关机/重启系统' },

        // 杀进程（危险）
        { pattern: /\bkill\s+(-\d+\s+)?1\b/, reason: '不允许杀 init 进程' },
        { pattern: /\bkillall\b/, reason: '不允许使用 killall（可能影响系统服务，请使用 kill <PID> 终止特定进程）' },
        { pattern: /\bpkill\b/, reason: '不允许使用 pkill（可能影响系统服务，请使用 kill <PID> 终止特定进程）' },

        // 破坏性删除
        { pattern: /\brm\s+[^|]*-[^\s]*r[^\s]*\s+\/(\s|$)/, reason: '不允许递归删除根目录' },
        { pattern: /\brm\s+[^|]*-[^\s]*r[^\s]*\s+\/(etc|usr|var|bin|sbin|lib|boot|sys|proc|dev)\b/,
          reason: '不允许删除系统目录' },

        // 磁盘操作
        { pattern: /\bdd\s+.*\bof=\/dev\//, reason: '不允许直接写入磁盘设备' },
        { pattern: /\bmkfs\b/, reason: '不允许格式化磁盘' },
        { pattern: /\bfdisk\b/, reason: '不允许操作磁盘分区' },

        // 网络/防火墙
        { pattern: /\b(iptables|nftables|ufw)\b/, reason: '不允许修改防火墙规则' },

        // 定时任务
        { pattern: /\bcrontab\s+(-e|-r)\b/, reason: '不允许编辑/删除 crontab' },

        // 用户/组管理
        { pattern: /\b(useradd|userdel|usermod|groupadd|groupdel)\b/, reason: '不允许管理系统用户/组' },
        { pattern: /\bpasswd\b/, reason: '不允许修改密码' },
        { pattern: /\bvisudo\b/, reason: '不允许编辑 sudoers' },

        // 内核模块
        { pattern: /\b(insmod|rmmod|modprobe)\b/, reason: '不允许操作内核模块' },
      ];

      for (const { pattern, reason } of DANGEROUS_PATTERNS) {
        if (pattern.test(command)) {
          return { result: 'deny', reason };
        }
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 5: 系统环境保护 ──
  {
    name: 'no-system-modification',
    tools: ['Bash'],
    check: (_toolName, input, _context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      const SYSTEM_MOD_PATTERNS = [
        // 服务管理
        { pattern: /\b(systemctl|service)\s+(start|stop|restart|enable|disable|reload)\b/,
          reason: '不允许管理系统服务' },
        { pattern: /\blaunchctl\s+(load|unload|start|stop|bootstrap|bootout)\b/,
          reason: '不允许管理 macOS 服务' },

        // 容器/云平台
        { pattern: /\bdocker\s+(rm|rmi|stop|kill|restart|network|volume|system\s+prune)\b/,
          reason: '不允许管理 Docker 容器和资源' },
        { pattern: /\bkubectl\b/, reason: '不允许操作 Kubernetes' },
        { pattern: /\bgcloud\b/, reason: '不允许操作 Google Cloud' },
        { pattern: /\baws\s+(?!configure\s+list\b)/, reason: '不允许操作 AWS' },
        { pattern: /\bterraform\s+(apply|destroy|import)\b/, reason: '不允许执行 Terraform 变更' },

        // Web 服务器
        { pattern: /\bnginx\s+(-s\s+)?(reload|stop|start|restart|quit)\b/,
          reason: '不允许管理 nginx' },
        { pattern: /\bapachectl\b/, reason: '不允许管理 Apache' },
        { pattern: /\bcaddy\s+(stop|start|reload|reverse-proxy)\b/, reason: '不允许管理 Caddy' },

        // 系统配置写入
        { pattern: />\s*\/etc\//, reason: '不允许写入 /etc/' },
        { pattern: /\btee\s+(-a\s+)?\/etc\//, reason: '不允许写入 /etc/' },
        { pattern: /\bsed\s+-i[^\s]*\s+\/etc\//, reason: '不允许修改 /etc/ 下的文件' },
        { pattern: /\bcp\s+.*\s+\/etc\//, reason: '不允许复制文件到 /etc/' },
        { pattern: /\bmv\s+.*\s+\/etc\//, reason: '不允许移动文件到 /etc/' },

        // SSH
        { pattern: /\/etc\/ssh\/sshd_config/, reason: '不允许修改 SSH 配置' },

        // 权限变更（系统目录）
        { pattern: /\bchmod\b.*\/(etc|usr|var|bin|sbin|lib|boot)\b/, reason: '不允许修改系统目录权限' },
        { pattern: /\bchown\b.*\/(etc|usr|var|bin|sbin|lib|boot)\b/, reason: '不允许修改系统目录所有者' },
      ];

      for (const { pattern, reason } of SYSTEM_MOD_PATTERNS) {
        if (pattern.test(command)) {
          return { result: 'deny', reason };
        }
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 6: 全局安装拦截 ──
  {
    name: 'no-global-install',
    tools: ['Bash'],
    check: (_toolName, input, _context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      const GLOBAL_INSTALL_PATTERNS = [
        { pattern: /\bnpm\s+(install|i|add)\s+[^|]*(-g|--global)\b/,
          reason: '不允许全局安装 npm 包，请使用本地安装' },
        { pattern: /\bnpm\s+(-g|--global)\s+(install|i|add)\b/,
          reason: '不允许全局安装 npm 包，请使用本地安装' },
        { pattern: /\byarn\s+global\s+add\b/,
          reason: '不允许全局安装 yarn 包' },
        { pattern: /\bgem\s+install\b/,
          reason: '不允许全局安装 Ruby gem' },
        { pattern: /\bcargo\s+install\b/,
          reason: '不允许全局安装 Rust 包' },
      ];

      for (const { pattern, reason } of GLOBAL_INSTALL_PATTERNS) {
        if (pattern.test(command)) {
          return { result: 'deny', reason };
        }
      }

      // pip install 特殊处理：venv 内使用放行，否则 UNCERTAIN
      if (/\bpip3?\s+install\b/.test(command)) {
        // 如果命令中包含 venv 相关路径，视为虚拟环境内安装
        if (/venv\/bin\/pip|\.venv\/bin\/pip|virtualenv/.test(command)) {
          return { result: 'allow' };
        }
        // --user 仍然写入服务器宿主机 ~/.local/，多用户平台下污染共享环境
        if (/--user\b/.test(command)) {
          return { result: 'deny', reason: '不允许使用 pip install --user（会写入服务器共享的 ~/.local/），请在虚拟环境内安装' };
        }
        // 其他情况交给 LLM 判断
        return { result: 'uncertain', reason: 'pip install 可能在虚拟环境外执行，需要 LLM 审查' };
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 8: 系统端口保护 ──
  {
    name: 'system-port-protection',
    tools: ['Bash'],
    check: (_toolName, input, _context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      // 从环境变量收集系统端口
      const systemPorts = [];
      for (const envVar of ['PORT', 'VITE_PORT']) {
        const port = process.env[envVar];
        if (port && /^\d+$/.test(port)) systemPorts.push(port);
      }

      if (systemPorts.length === 0) return { result: 'allow' };

      for (const port of systemPorts) {
        // lsof -ti :PORT, lsof -i :PORT
        if (new RegExp(`\\blsof\\b[^|]*:${port}\\b`).test(command)) {
          return { result: 'deny', reason: `不允许查询系统端口 ${port} 的进程信息（该端口为平台服务端口）` };
        }
        // fuser PORT/tcp, fuser :PORT
        if (new RegExp(`\\bfuser\\b[^|]*\\b${port}\\b`).test(command)) {
          return { result: 'deny', reason: `不允许查询系统端口 ${port} 的进程信息（该端口为平台服务端口）` };
        }
        // ss -tlnp | grep PORT, netstat ... PORT
        if (new RegExp(`\\b(ss|netstat)\\b[^|]*\\b${port}\\b`).test(command)) {
          return { result: 'deny', reason: `不允许查询系统端口 ${port} 的连接信息（该端口为平台服务端口）` };
        }
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 10: 脚本执行内容审查 ──
  {
    name: 'script-execution-guard',
    tools: ['Bash'],
    check: (_toolName, input, context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      // 检测脚本文件执行：bash/sh/python/node/ruby/perl 后跟文件路径
      const interpreterMatch = command.match(
        /\b(?:bash|sh|zsh|dash|source)\s+(?:-\S+\s+)*([^\s;|&><"'`-][^\s;|&><"'`]*)/
      );
      const langMatch = command.match(
        /\b(?:python3?|node|ruby|perl|php)\s+(?:-\S+\s+)*([^\s;|&><"'`-][^\s;|&><"'`]*)/
      );
      const directMatch = command.match(/\.\/([^\s;|&><"'`]+)/);

      const scriptFile = interpreterMatch?.[1] || langMatch?.[1] || directMatch?.[1];
      if (!scriptFile) return { result: 'allow' };

      // 编程语言脚本（python/node/ruby 等）的字符串字面量（URL 路径、os.sep 等）
      // 会被路径正则误判为文件系统路径，路径越界检查仅对 shell 脚本有意义
      const isShellScript = !!interpreterMatch || (!langMatch && !!directMatch);

      // 解析脚本路径
      const resolvedScript = path.isAbsolute(scriptFile)
        ? path.resolve(scriptFile)
        : context.cwd
          ? path.resolve(context.cwd, scriptFile)
          : null;

      if (!resolvedScript) return { result: 'allow' };

      try {
        // 限制文件大小，防止读取巨大文件阻塞
        const stat = statSync(resolvedScript);
        if (stat.size > 1024 * 1024) {
          return { result: 'uncertain', reason: '脚本文件过大，需要 LLM 审查其安全性' };
        }

        const content = readFileSync(resolvedScript, 'utf8');

        // 检查危险命令模式
        for (const { pattern, reason } of DANGEROUS_SCRIPT_PATTERNS) {
          if (pattern.test(content)) {
            return { result: 'deny', reason: `脚本文件包含危险操作: ${reason}` };
          }
        }

        // 检查系统端口查询
        const portCheck = checkSystemPortsInContent(content);
        if (portCheck.denied) {
          return { result: 'deny', reason: `脚本文件${portCheck.reason}` };
        }

        // 检查路径越界（仅 shell 脚本，编程语言脚本的字符串字面量会误判为文件路径）
        if (isShellScript) {
          const pathCheck = checkPathsInContent(content, context);
          if (pathCheck.denied) {
            return { result: 'deny', reason: `脚本文件${pathCheck.reason}` };
          }
        }
      } catch {
        // 文件不存在或无法读取 — 交由其他规则处理
      }

      return { result: 'allow' };
    }
  },

  // ── 规则 7: Bash 路径隔离 ──
  {
    name: 'bash-path-isolation',
    tools: ['Bash'],
    check: (_toolName, input, context) => {
      const command = input?.command;
      if (!command || typeof command !== 'string') return { result: 'allow' };

      // 检测 ~ 和 $HOME 引用 — 指向服务器主目录，不在用户允许范围内
      if (/(?:^|\s|=|"|')~\//.test(command) || /(?:^|\s|=|"|')~(?:\s|$|;|&&|\|)/.test(command)) {
        return { result: 'deny', reason: '不允许访问服务器主目录（~），请仅在项目目录内操作' };
      }
      if (/\$HOME\b/.test(command)) {
        return { result: 'deny', reason: '不允许访问服务器主目录（$HOME），请仅在项目目录内操作' };
      }

      // 提取命令中的绝对路径（以 / 开头）
      const pathPattern = /(?:^|\s|=|"|')(\/[^\s"'`;|&><){}$]+)/g;
      let match;
      const extractedPaths = [];
      while ((match = pathPattern.exec(command)) !== null) {
        extractedPaths.push(match[1]);
      }

      if (extractedPaths.length === 0) {
        return { result: 'allow' };
      }

      for (const rawPath of extractedPaths) {
        const bad = checkResolvedPath(path.resolve(rawPath), context);
        if (bad) return { result: 'deny', reason: `不允许访问项目目录之外的路径: ${bad}` };
      }

      // 检查命令复杂度：包含变量替换、子 shell 等 → UNCERTAIN
      if (/\$\(|\$\{|`/.test(command)) {
        return { result: 'uncertain', reason: '命令包含变量替换或子 shell，需要 LLM 审查路径安全性' };
      }

      return { result: 'allow' };
    }
  },
];

// ─── 规则引擎 ──────────────────────────────────────────────

/**
 * 执行所有适用规则
 * @returns {{ denied: boolean, uncertain: boolean, denyReasons: string[], uncertainReasons: string[] }}
 */
export function evaluateRules(toolName, input, context) {
  const denyReasons = [];
  const uncertainReasons = [];

  for (const rule of rules) {
    // 检查规则是否适用于当前工具
    if (!rule.tools.includes('*') && !rule.tools.includes(toolName)) {
      continue;
    }

    const result = rule.check(toolName, input, context);

    if (result.result === 'deny') {
      denyReasons.push(result.reason || rule.name);
    } else if (result.result === 'uncertain') {
      uncertainReasons.push(result.reason || rule.name);
    }
    // 'allow' → 继续检查下一条规则
  }

  return {
    denied: denyReasons.length > 0,
    uncertain: uncertainReasons.length > 0,
    denyReasons,
    uncertainReasons,
  };
}
