From afbbb1fbb0f59adfefd8b95daf96f8a85dadb734 Mon Sep 17 00:00:00 2001 From: zackeryyy wang Date: Sat, 12 Jul 2025 22:44:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E7=8E=B0?= =?UTF-8?q?=E4=BB=A3=E5=8C=96=E5=91=BD=E4=BB=A4=E7=AE=A1=E7=90=86=E4=B8=BA?= =?UTF-8?q?=E5=9F=BA=E4=BA=8E=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎯 解决问题: - 避免推荐用户系统中不存在的工具 - 防止因缺失工具导致的命令执行失败 - 提供更安全、更灵活的现代化命令管理 🔧 主要改进: - 新增 ai_shell/modern_commands.toml 配置文件 - 智能检测系统中已安装的现代化工具 - 只推荐实际可用的工具,安全回退到原始命令 - 完整的工具描述、分类和安装提示 📦 配置文件特性: - 28 个命令映射配置 - 20 个工具描述说明 - 8 个工具分类组织 - 6 个详细安装提示 🛠️ 新增管理工具: - scripts/manage_modern_commands.py 配置管理脚本 - 支持验证、列表、安装建议等功能 - 完整的配置状态检查和报告 🔍 用户体验优化: - ai --config 显示详细的工具状态 - 区分已启用、保持原样、未安装的工具 - 提供具体的安装命令和说明 - 支持环境变量和配置文件自定义 🛡️ 安全保障: - 绝不推荐不存在的工具 - 优雅降级到原始命令 - 保持完全向后兼容性 📋 技术实现: - 添加 tomli 依赖支持 TOML 解析 - 重构配置加载逻辑 - 智能工具检测和状态管理 - 完善的错误处理和回退机制 --- ai_shell/config.py | 163 ++++++++++--------- ai_shell/main.py | 35 +++-- ai_shell/modern_commands.toml | 98 ++++++++++++ pyproject.toml | 1 + scripts/manage_modern_commands.py | 200 +++++++++++++++++++++++ uv.lock | 3 +- 基于配置文件的现代化命令管理完成总结.md | 201 ++++++++++++++++++++++++ 7 files changed, 614 insertions(+), 87 deletions(-) create mode 100644 ai_shell/modern_commands.toml create mode 100755 scripts/manage_modern_commands.py create mode 100644 基于配置文件的现代化命令管理完成总结.md diff --git a/ai_shell/config.py b/ai_shell/config.py index 7e1da91..e9d16c2 100644 --- a/ai_shell/config.py +++ b/ai_shell/config.py @@ -3,13 +3,23 @@ Configuration module for AI Shell """ import os +import shutil from pathlib import Path +from typing import Dict, List, Optional try: from dotenv import load_dotenv except ImportError: load_dotenv = None +try: + import tomllib # Python 3.11+ +except ImportError: + try: + import tomli as tomllib # fallback for older Python + except ImportError: + tomllib = None + # Load .env file if it exists def load_env_file() -> None: """Load environment variables from .env file""" @@ -61,57 +71,30 @@ def get_max_retries() -> int: """Get max retries from environment""" return int(os.getenv("AI_SHELL_MAX_RETRIES", "3")) -def get_modern_commands() -> dict: - """Get modern command alternatives configuration""" - # Default modern command alternatives - default_alternatives = { - "ls": "eza", # Modern ls replacement - "cat": "bat", # Syntax highlighting cat - "find": "fd", # Fast and user-friendly find - "grep": "rg", # Ripgrep - faster grep - "du": "ncdu", # Interactive disk usage - "df": "duf", # Modern df with better output - "ps": "procs", # Modern ps replacement - "top": "htop", # Interactive process viewer - "ping": "gping", # Ping with graph - "curl": "httpie", # User-friendly HTTP client - "wget": "aria2c", # Multi-connection downloader - "diff": "delta", # Better diff with syntax highlighting - "tree": "tree", # Keep tree as is (already modern) - "sed": "sd", # Simpler sed alternative - "awk": "choose", # Human-friendly awk alternative - "cut": "choose", # Alternative to cut - "sort": "sort", # Keep sort as is - "uniq": "uniq", # Keep uniq as is - "head": "head", # Keep head as is - "tail": "tail", # Keep tail as is - "less": "bat", # Use bat for paging too - "more": "bat", # Use bat for paging - "vim": "nvim", # Modern vim - "nano": "micro", # Modern nano alternative - "cd": "zoxide", # Smart cd with frecency - "cp": "cp", # Keep cp as is (or could use rsync) - "mv": "mv", # Keep mv as is - "rm": "trash", # Safer deletion (trash-cli) - "mkdir": "mkdir", # Keep mkdir as is - "rmdir": "rmdir", # Keep rmdir as is - "chmod": "chmod", # Keep chmod as is - "chown": "chown", # Keep chown as is - "tar": "ouch", # Universal archive tool - "zip": "ouch", # Universal archive tool - "unzip": "ouch", # Universal archive tool - "ssh": "ssh", # Keep ssh as is - "scp": "rsync", # More efficient file transfer - "rsync": "rsync", # Keep rsync as is - "git": "git", # Keep git as is - "docker": "docker", # Keep docker as is - "python": "python", # Keep python as is - "node": "node", # Keep node as is - "npm": "pnpm", # Faster npm alternative - "yarn": "pnpm", # Faster yarn alternative - } +def load_modern_commands_config() -> Dict[str, any]: + """Load modern commands configuration from TOML file""" + config_file = Path(__file__).parent / "modern_commands.toml" - # Try to load custom alternatives from environment or config file + if not config_file.exists(): + return {"commands": {}, "descriptions": {}, "categories": {}, "installation_hints": {}} + + if tomllib is None: + # Fallback to basic parsing if tomllib not available + return {"commands": {}, "descriptions": {}, "categories": {}, "installation_hints": {}} + + try: + with open(config_file, "rb") as f: + return tomllib.load(f) + except Exception: + return {"commands": {}, "descriptions": {}, "categories": {}, "installation_hints": {}} + +def get_modern_commands() -> Dict[str, str]: + """Get modern command alternatives configuration""" + # Load from TOML config file + config = load_modern_commands_config() + default_alternatives = config.get("commands", {}) + + # Try to load custom alternatives from environment custom_alternatives_str = os.getenv("AI_SHELL_MODERN_COMMANDS", "") custom_alternatives = {} @@ -132,10 +115,8 @@ def get_modern_commands() -> dict: return alternatives -def get_available_modern_commands() -> dict: +def get_available_modern_commands() -> Dict[str, str]: """Get only the modern commands that are actually installed on the system""" - import shutil - all_alternatives = get_modern_commands() available_alternatives = {} @@ -143,17 +124,45 @@ def get_available_modern_commands() -> dict: # Check if the modern command is actually available if shutil.which(new_cmd): available_alternatives[old_cmd] = new_cmd - # If modern command not available, keep the original + # If modern command not available, keep the original (if it exists) elif shutil.which(old_cmd): available_alternatives[old_cmd] = old_cmd return available_alternatives +def get_missing_modern_commands() -> Dict[str, str]: + """Get modern commands that are configured but not installed""" + all_alternatives = get_modern_commands() + missing_commands = {} + + for old_cmd, new_cmd in all_alternatives.items(): + # If modern command is not available but old command exists + if not shutil.which(new_cmd) and shutil.which(old_cmd) and old_cmd != new_cmd: + missing_commands[old_cmd] = new_cmd + + return missing_commands + +def get_installation_hint(command: str) -> Optional[str]: + """Get installation hint for a modern command""" + config = load_modern_commands_config() + installation_hints = config.get("installation_hints", {}) + return installation_hints.get(command) + +def get_command_description(command: str) -> Optional[str]: + """Get description for a modern command""" + config = load_modern_commands_config() + descriptions = config.get("descriptions", {}) + return descriptions.get(command) + def generate_modern_commands_prompt() -> str: """Generate prompt text about available modern command alternatives""" available_commands = get_available_modern_commands() + config = load_modern_commands_config() - if not available_commands: + # Only include commands that have modern alternatives available + active_alternatives = {k: v for k, v in available_commands.items() if k != v} + + if not active_alternatives: return "" prompt_parts = [ @@ -162,42 +171,44 @@ def generate_modern_commands_prompt() -> str: "" ] - # Group by categories for better readability - categories = { - "文件操作": ["ls", "cat", "find", "tree", "cp", "mv", "rm"], - "文本处理": ["grep", "sed", "awk", "cut", "sort", "uniq", "head", "tail", "less", "more", "diff"], - "系统监控": ["ps", "top", "du", "df"], - "网络工具": ["ping", "curl", "wget"], - "编辑器": ["vim", "nano"], - "导航": ["cd"], - "压缩工具": ["tar", "zip", "unzip"], - "包管理": ["npm", "yarn"], - "其他": [] - } + # Use categories from config file + categories = config.get("categories", {}) + descriptions = config.get("descriptions", {}) - for category, commands in categories.items(): + for category_name, commands in categories.items(): category_commands = [] for cmd in commands: - if cmd in available_commands and available_commands[cmd] != cmd: - category_commands.append(f" - Use `{available_commands[cmd]}` instead of `{cmd}`") + if cmd in active_alternatives: + new_cmd = active_alternatives[cmd] + desc = descriptions.get(new_cmd, "") + if desc: + category_commands.append(f" - Use `{new_cmd}` instead of `{cmd}` ({desc})") + else: + category_commands.append(f" - Use `{new_cmd}` instead of `{cmd}`") if category_commands: - prompt_parts.append(f"**{category}:**") + # Convert category name to display format + display_name = category_name.replace("_", " ").title() + prompt_parts.append(f"**{display_name}:**") prompt_parts.extend(category_commands) prompt_parts.append("") # Add remaining commands not in categories - other_commands = [] categorized_commands = set() for commands in categories.values(): categorized_commands.update(commands) - for old_cmd, new_cmd in available_commands.items(): - if old_cmd not in categorized_commands and new_cmd != old_cmd: - other_commands.append(f" - Use `{new_cmd}` instead of `{old_cmd}`") + other_commands = [] + for old_cmd, new_cmd in active_alternatives.items(): + if old_cmd not in categorized_commands: + desc = descriptions.get(new_cmd, "") + if desc: + other_commands.append(f" - Use `{new_cmd}` instead of `{old_cmd}` ({desc})") + else: + other_commands.append(f" - Use `{new_cmd}` instead of `{old_cmd}`") if other_commands: - prompt_parts.append("**其他工具:**") + prompt_parts.append("**Other Tools:**") prompt_parts.extend(other_commands) prompt_parts.append("") diff --git a/ai_shell/main.py b/ai_shell/main.py index 59db8cb..d3ec39c 100644 --- a/ai_shell/main.py +++ b/ai_shell/main.py @@ -81,7 +81,8 @@ def create_parser() -> argparse.ArgumentParser: def show_config() -> None: """Show current configuration""" from .config import (get_api_key, get_base_url, get_model, get_timeout, - get_max_retries, validate_config, get_available_modern_commands) + get_max_retries, validate_config, get_available_modern_commands, + get_missing_modern_commands, get_installation_hint) print("AI Shell Configuration:") print(f" Model: {get_model()}") @@ -115,26 +116,40 @@ def show_config() -> None: # Show modern commands configuration modern_commands = get_available_modern_commands() - if modern_commands: - print(f"\n现代化命令替代 ({len(modern_commands)} 个可用):") + missing_commands = get_missing_modern_commands() + print(f"\n现代化命令替代:") + + if modern_commands: # Group commands for better display active_alternatives = {k: v for k, v in modern_commands.items() if k != v} unchanged_commands = {k: v for k, v in modern_commands.items() if k == v} if active_alternatives: - print(" 已启用的替代:") + print(f" ✅ 已启用的替代 ({len(active_alternatives)} 个):") for old_cmd, new_cmd in sorted(active_alternatives.items()): print(f" {old_cmd} → {new_cmd}") if unchanged_commands: - print(f" 保持原样: {', '.join(sorted(unchanged_commands.keys()))}") + print(f" ➡️ 保持原样: {', '.join(sorted(unchanged_commands.keys()))}") - print("\n 自定义配置格式:") - print(" export AI_SHELL_MODERN_COMMANDS=\"old1:new1,old2:new2\"") - print(" 例如: export AI_SHELL_MODERN_COMMANDS=\"ls:exa,cat:bat,find:fd\"") - else: - print("\n现代化命令替代: 未检测到可用的现代化工具") + if missing_commands: + print(f"\n ⚠️ 可配置但未安装的工具 ({len(missing_commands)} 个):") + for old_cmd, new_cmd in sorted(missing_commands.items()): + hint = get_installation_hint(new_cmd) + if hint: + print(f" {old_cmd} → {new_cmd}") + print(f" 安装: {hint.split('#')[0].strip()}") + else: + print(f" {old_cmd} → {new_cmd}") + + if not modern_commands and not missing_commands: + print(" 未检测到可用的现代化工具配置") + + print("\n 配置方法:") + print(" 1. 编辑配置文件: ai_shell/modern_commands.toml") + print(" 2. 环境变量: export AI_SHELL_MODERN_COMMANDS=\"ls:eza,cat:bat\"") + print(" 3. .env 文件: AI_SHELL_MODERN_COMMANDS=\"ls:eza,cat:bat\"") def main() -> None: """Main entry point""" diff --git a/ai_shell/modern_commands.toml b/ai_shell/modern_commands.toml new file mode 100644 index 0000000..a7145e1 --- /dev/null +++ b/ai_shell/modern_commands.toml @@ -0,0 +1,98 @@ +# AI Shell 现代化命令替代配置文件 +# 只有在系统中实际安装了对应工具时,才会启用替代 + +[commands] +# 文件操作 +ls = "eza" # 现代化的 ls,支持图标和颜色 +cat = "bat" # 带语法高亮的 cat +find = "fd" # 更快更友好的 find +tree = "tree" # 保持原样(已经很现代) + +# 文本处理 +grep = "rg" # ripgrep - 更快的文本搜索 +sed = "sd" # 更简单的 sed 替代 +awk = "choose" # 人性化的 awk 替代 +cut = "choose" # cut 的替代 +diff = "delta" # 带语法高亮的 diff +less = "bat" # 用 bat 进行分页显示 +more = "bat" # 用 bat 进行分页显示 + +# 系统监控 +ps = "procs" # 现代化的进程查看器 +top = "htop" # 交互式进程监控 +du = "ncdu" # 交互式磁盘使用分析 +df = "duf" # 更好的磁盘空间显示 + +# 网络工具 +ping = "gping" # 带图形的 ping +curl = "httpie" # 更友好的 HTTP 客户端 +wget = "aria2c" # 多连接下载器 + +# 编辑器 +vim = "nvim" # 现代化的 vim +nano = "micro" # 现代化的 nano 替代 + +# 导航和文件管理 +cd = "zoxide" # 智能目录跳转(需要初始化) +rm = "trash" # 安全删除(移到回收站) + +# 压缩工具 +tar = "ouch" # 通用压缩工具 +zip = "ouch" # 通用压缩工具 +unzip = "ouch" # 通用压缩工具 + +# 开发工具 +npm = "pnpm" # 更快的 npm 替代 +yarn = "pnpm" # 更快的 yarn 替代 +scp = "rsync" # 更高效的文件传输 + +# 保持原样的命令(不需要替代) +# git = "git" +# docker = "docker" +# python = "python" +# node = "node" +# ssh = "ssh" +# rsync = "rsync" + +[descriptions] +# 工具描述,用于生成更好的 AI 提示 +eza = "现代化的 ls 替代,支持图标、颜色和更好的格式化" +bat = "带语法高亮和行号的 cat 替代" +fd = "更快、更用户友好的 find 替代" +rg = "极快的文本搜索工具,比 grep 更快" +sd = "更简单直观的 sed 替代" +choose = "人性化的字段选择工具,可替代 awk 和 cut" +delta = "带语法高亮的 git diff 查看器" +procs = "现代化的进程查看器,比 ps 更直观" +htop = "交互式的系统监控工具" +ncdu = "交互式的磁盘使用分析工具" +duf = "更美观的磁盘空间显示工具" +gping = "带图形显示的 ping 工具" +httpie = "更友好的 HTTP 客户端" +aria2c = "支持多连接的下载工具" +nvim = "现代化的 vim 编辑器" +micro = "现代化的终端文本编辑器" +zoxide = "智能的目录跳转工具" +trash = "安全的文件删除工具(移到回收站)" +ouch = "通用的压缩/解压工具" +pnpm = "更快、更高效的 Node.js 包管理器" + +[categories] +# 工具分类,用于更好的组织和显示 +file_operations = ["ls", "cat", "find", "tree", "rm"] +text_processing = ["grep", "sed", "awk", "cut", "diff", "less", "more"] +system_monitoring = ["ps", "top", "du", "df"] +network_tools = ["ping", "curl", "wget"] +editors = ["vim", "nano"] +navigation = ["cd"] +compression = ["tar", "zip", "unzip"] +development = ["npm", "yarn", "scp"] + +[installation_hints] +# 安装提示,当工具不存在时可以提供安装建议 +eza = "brew install eza # macOS\nsudo apt install eza # Ubuntu\ncargo install eza # Rust" +bat = "brew install bat # macOS\nsudo apt install bat # Ubuntu\ncargo install bat # Rust" +fd = "brew install fd # macOS\nsudo apt install fd-find # Ubuntu\ncargo install fd-find # Rust" +rg = "brew install ripgrep # macOS\nsudo apt install ripgrep # Ubuntu\ncargo install ripgrep # Rust" +ncdu = "brew install ncdu # macOS\nsudo apt install ncdu # Ubuntu" +htop = "brew install htop # macOS\nsudo apt install htop # Ubuntu" diff --git a/pyproject.toml b/pyproject.toml index fe9a9a6..b052a7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ dependencies = [ "openai", "requests>=2.32.4", "python-dotenv>=1.0.0", + "tomli>=1.2.0; python_version<'3.11'", ] [project.scripts] diff --git a/scripts/manage_modern_commands.py b/scripts/manage_modern_commands.py new file mode 100755 index 0000000..9a0acab --- /dev/null +++ b/scripts/manage_modern_commands.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +""" +现代化命令配置管理工具 +""" + +import sys +import os +import shutil +import argparse +from pathlib import Path + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +from ai_shell.config import ( + load_modern_commands_config, + get_modern_commands, + get_available_modern_commands, + get_missing_modern_commands, + get_installation_hint, + get_command_description +) + +def list_commands(): + """列出所有配置的现代化命令""" + print("🔧 现代化命令配置状态\n") + + available = get_available_modern_commands() + missing = get_missing_modern_commands() + + # 已启用的替代 + active_alternatives = {k: v for k, v in available.items() if k != v} + if active_alternatives: + print(f"✅ 已启用的替代 ({len(active_alternatives)} 个):") + for old_cmd, new_cmd in sorted(active_alternatives.items()): + desc = get_command_description(new_cmd) + if desc: + print(f" {old_cmd:8} → {new_cmd:12} ({desc})") + else: + print(f" {old_cmd:8} → {new_cmd}") + print() + + # 保持原样的命令 + unchanged = {k: v for k, v in available.items() if k == v} + if unchanged: + print(f"➡️ 保持原样的命令: {', '.join(sorted(unchanged.keys()))}\n") + + # 未安装的工具 + if missing: + print(f"⚠️ 可配置但未安装的工具 ({len(missing)} 个):") + for old_cmd, new_cmd in sorted(missing.items()): + desc = get_command_description(new_cmd) + hint = get_installation_hint(new_cmd) + + if desc: + print(f" {old_cmd:8} → {new_cmd:12} ({desc})") + else: + print(f" {old_cmd:8} → {new_cmd}") + + if hint: + print(f" 安装: {hint.split('#')[0].strip()}") + print() + +def check_command(command): + """检查特定命令的状态""" + config = load_modern_commands_config() + commands = config.get("commands", {}) + + if command not in commands: + print(f"❌ 命令 '{command}' 未在配置中找到") + return + + modern_cmd = commands[command] + desc = get_command_description(modern_cmd) + hint = get_installation_hint(modern_cmd) + + print(f"🔍 命令 '{command}' 的配置:") + print(f" 替代工具: {modern_cmd}") + + if desc: + print(f" 描述: {desc}") + + # 检查是否安装 + if shutil.which(modern_cmd): + print(f" 状态: ✅ 已安装") + print(f" 路径: {shutil.which(modern_cmd)}") + else: + print(f" 状态: ❌ 未安装") + if hint: + print(f" 安装方法: {hint}") + +def install_suggestions(): + """显示安装建议""" + missing = get_missing_modern_commands() + + if not missing: + print("✅ 所有配置的现代化工具都已安装!") + return + + print("📦 安装建议\n") + + # 按类别分组显示 + config = load_modern_commands_config() + categories = config.get("categories", {}) + + for category_name, commands in categories.items(): + category_missing = [] + for cmd in commands: + if cmd in missing: + category_missing.append((cmd, missing[cmd])) + + if category_missing: + display_name = category_name.replace("_", " ").title() + print(f"**{display_name}:**") + + for old_cmd, new_cmd in category_missing: + hint = get_installation_hint(new_cmd) + desc = get_command_description(new_cmd) + + print(f" {new_cmd}:") + if desc: + print(f" 功能: {desc}") + if hint: + print(f" 安装: {hint}") + print() + +def validate_config(): + """验证配置文件""" + config_file = Path(__file__).parent.parent / "ai_shell" / "modern_commands.toml" + + print(f"🔍 验证配置文件: {config_file}") + + if not config_file.exists(): + print("❌ 配置文件不存在") + return False + + try: + config = load_modern_commands_config() + + # 检查必需的部分 + required_sections = ["commands", "descriptions", "categories", "installation_hints"] + for section in required_sections: + if section not in config: + print(f"⚠️ 缺少配置部分: {section}") + else: + print(f"✅ 配置部分 '{section}': {len(config[section])} 项") + + # 检查命令一致性 + commands = config.get("commands", {}) + descriptions = config.get("descriptions", {}) + installation_hints = config.get("installation_hints", {}) + + print(f"\n📊 配置统计:") + print(f" 配置的命令: {len(commands)}") + print(f" 有描述的工具: {len(descriptions)}") + print(f" 有安装提示的工具: {len(installation_hints)}") + + # 检查缺少描述的工具 + modern_tools = set(commands.values()) + missing_descriptions = modern_tools - set(descriptions.keys()) + if missing_descriptions: + print(f" ⚠️ 缺少描述的工具: {', '.join(sorted(missing_descriptions))}") + + return True + + except Exception as e: + print(f"❌ 配置文件解析错误: {e}") + return False + +def main(): + parser = argparse.ArgumentParser(description="现代化命令配置管理工具") + subparsers = parser.add_subparsers(dest="command", help="可用命令") + + # list 命令 + subparsers.add_parser("list", help="列出所有配置的现代化命令") + + # check 命令 + check_parser = subparsers.add_parser("check", help="检查特定命令的状态") + check_parser.add_argument("command", help="要检查的命令名") + + # install 命令 + subparsers.add_parser("install", help="显示安装建议") + + # validate 命令 + subparsers.add_parser("validate", help="验证配置文件") + + args = parser.parse_args() + + if args.command == "list": + list_commands() + elif args.command == "check": + check_command(args.command) + elif args.command == "install": + install_suggestions() + elif args.command == "validate": + validate_config() + else: + parser.print_help() + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock index e96ee09..01e8bc2 100644 --- a/uv.lock +++ b/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.12" [[package]] name = "ai-shell" -version = "0.1.0" +version = "0.2.0" source = { editable = "." } dependencies = [ { name = "openai" }, @@ -19,6 +19,7 @@ requires-dist = [ { name = "pydantic-ai" }, { name = "python-dotenv", specifier = ">=1.0.0" }, { name = "requests", specifier = ">=2.32.4" }, + { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=1.2.0" }, ] [[package]] diff --git a/基于配置文件的现代化命令管理完成总结.md b/基于配置文件的现代化命令管理完成总结.md new file mode 100644 index 0000000..70868a6 --- /dev/null +++ b/基于配置文件的现代化命令管理完成总结.md @@ -0,0 +1,201 @@ +# 基于配置文件的现代化命令管理完成总结 + +## 🎯 问题解决 + +您提出的问题非常重要:**有些用户主机上可能没有这些工具,如果默认设置了一些替代,可能会导致无法运行**。 + +我已经完全重构了现代化命令管理系统,采用基于配置文件的安全方案。 + +## ✅ 新的解决方案 + +### 1. **配置文件驱动** +- 创建了 `ai_shell/modern_commands.toml` 配置文件 +- 所有现代化命令映射都在配置文件中定义 +- 支持工具描述、分类和安装提示 + +### 2. **智能检测机制** +- **只推荐已安装的工具**:系统会检测哪些现代化工具实际可用 +- **安全回退**:如果现代化工具不存在,保持使用原始命令 +- **避免错误**:绝不会推荐不存在的命令 + +### 3. **完整的配置管理** +- 详细的配置状态显示 +- 缺失工具的安装建议 +- 配置验证和管理工具 + +## 📋 技术实现 + +### 配置文件结构 (`ai_shell/modern_commands.toml`) + +```toml +[commands] +# 命令映射 +ls = "eza" +cat = "bat" +find = "fd" +# ... 更多映射 + +[descriptions] +# 工具描述 +eza = "现代化的 ls 替代,支持图标、颜色和更好的格式化" +bat = "带语法高亮和行号的 cat 替代" +# ... 更多描述 + +[categories] +# 工具分类 +file_operations = ["ls", "cat", "find", "tree", "rm"] +text_processing = ["grep", "sed", "awk", "cut", "diff"] +# ... 更多分类 + +[installation_hints] +# 安装提示 +eza = "brew install eza # macOS\nsudo apt install eza # Ubuntu" +bat = "brew install bat # macOS\nsudo apt install bat # Ubuntu" +# ... 更多提示 +``` + +### 智能检测逻辑 + +```python +def get_available_modern_commands() -> Dict[str, str]: + """只返回系统中实际可用的现代化命令""" + all_alternatives = get_modern_commands() + available_alternatives = {} + + for old_cmd, new_cmd in all_alternatives.items(): + # 检查现代化命令是否可用 + if shutil.which(new_cmd): + available_alternatives[old_cmd] = new_cmd + # 如果不可用,保持原始命令(如果存在) + elif shutil.which(old_cmd): + available_alternatives[old_cmd] = old_cmd + + return available_alternatives +``` + +## 🔧 用户体验 + +### 配置状态显示 + +```bash +ai --config +``` + +输出示例: +``` +现代化命令替代: + ✅ 已启用的替代 (5 个): + find → fd + npm → pnpm + rm → trash + scp → rsync + yarn → pnpm + + ⚠️ 可配置但未安装的工具 (21 个): + cat → bat + 安装: brew install bat + ls → eza + 安装: brew install eza + # ... 更多工具和安装提示 +``` + +### 管理工具 + +```bash +# 验证配置文件 +uv run python scripts/manage_modern_commands.py validate + +# 列出所有配置状态 +uv run python scripts/manage_modern_commands.py list + +# 显示安装建议 +uv run python scripts/manage_modern_commands.py install + +# 检查特定命令 +uv run python scripts/manage_modern_commands.py check ls +``` + +## 🛡️ 安全保障 + +### 1. **绝不推荐不存在的工具** +- 系统启动时检测所有工具的可用性 +- AI 提示词中只包含实际可用的替代 +- 用户永远不会收到无法执行的命令 + +### 2. **优雅降级** +- 如果现代化工具不存在,自动使用原始命令 +- 保持系统的完全兼容性 +- 不影响基本功能 + +### 3. **清晰的状态反馈** +- 明确显示哪些工具已启用 +- 列出可配置但未安装的工具 +- 提供具体的安装指导 + +## 📊 配置统计 + +当前配置包含: +- **28 个命令映射** +- **20 个工具描述** +- **8 个工具分类** +- **6 个安装提示** + +支持的现代化工具类别: +- **文件操作**: eza, bat, fd, tree, trash +- **文本处理**: rg, sd, choose, delta +- **系统监控**: procs, htop, ncdu, duf +- **网络工具**: gping, httpie, aria2c +- **编辑器**: nvim, micro +- **其他**: zoxide, ouch, pnpm + +## 🎯 用户价值 + +### 1. **安全性** +- 不会推荐不存在的工具 +- 避免命令执行失败 +- 保持系统稳定性 + +### 2. **灵活性** +- 用户可以选择安装感兴趣的工具 +- 支持自定义配置 +- 渐进式采用现代化工具 + +### 3. **指导性** +- 提供安装建议和说明 +- 展示工具的优势和特性 +- 帮助用户了解现代化选择 + +### 4. **可维护性** +- 配置文件易于维护和扩展 +- 支持版本控制 +- 便于社区贡献 + +## 🚀 使用建议 + +### 对于新用户 +1. 运行 `ai --config` 查看当前状态 +2. 根据安装提示安装感兴趣的工具 +3. 重新运行 `ai --config` 验证新工具 + +### 对于高级用户 +1. 编辑 `ai_shell/modern_commands.toml` 自定义配置 +2. 使用环境变量覆盖特定映射 +3. 使用管理工具验证和维护配置 + +### 对于开发者 +1. 使用 `scripts/manage_modern_commands.py` 管理配置 +2. 添加新的工具映射和描述 +3. 贡献安装提示和最佳实践 + +--- + +## 🎉 总结 + +这个新的基于配置文件的方案完美解决了您提出的问题: + +✅ **安全性**: 只推荐已安装的工具,避免执行失败 +✅ **灵活性**: 用户可以选择性安装和配置工具 +✅ **可维护性**: 配置文件易于管理和扩展 +✅ **用户友好**: 提供清晰的状态显示和安装指导 + +现在用户可以安全地使用 AI Shell,无论他们的系统中安装了哪些工具!🚀