diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2090a85..7dfb236 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,9 +97,9 @@ jobs: missing=0 for f in "${files[@]}"; do if [ -f "$f" ]; then - echo " ✓ $f" + echo " $f" else - echo " ✗ $f (缺失!)" + echo " $f (缺失!)" missing=$((missing + 1)) fi done @@ -127,7 +127,7 @@ jobs: found=0 for f in "${old_files[@]}"; do if [ -f "$f" ]; then - echo " ⚠️ 旧文件未清理: $f" + echo " 旧文件未清理: $f" found=$((found + 1)) fi done diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d3b66..8202e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ## v5.1.1 (2026-04-26) -### 🚀 新增功能 +### 新增功能 - **浏览器自动化插件** (`browser_auto`) — 基于 Playwright 的无头浏览器操控,31 个操作:导航/交互/截图/JS 执行/PDF/cookies - **子 Agent 系统** (`sub_agent`) — 多 Agent 并行协作,spawn/list/status/result/send/kill,独立任务分配与结果回收 - **统一安全层** (`safety.py`) — AI 风险识别 + 三模式切换(普通/人工/无限制),所有工具调用前统一拦截检查 @@ -14,7 +14,7 @@ - **自动化测试套件** — 113 个 pytest 用例,覆盖全部 15 个插件 + 引擎 + 核心模块 - **CI 工作流** — GitHub Actions: 语法检查 + ruff lint + pytest (Python 3.10/3.11/3.12 矩阵) + 项目结构验证 -### ♻️ 重构 +### 重构 - **插件大优化** — 17 个插件 → 15 个,5689 行 → 4309 行 - `code_editor` + `code_search` → `code_editor`(编辑+搜索统一) - `git_tools` + `git_workflow` → `git_tools`(基础+工作流统一) @@ -24,12 +24,12 @@ - **启动器重写** — `launcher.py` 从 1741 行精简到 666 行,修复重复方法和硬编码引擎名 - **cmd_executor 跨平台** — 移除 Windows-only 限制,支持 Linux/macOS/Windows -### 🐛 修复 +### 修复 - 修复 `code_editor` 的 `diff_text` 解析器被 `split(maxsplit=2)` 拆坏分隔符的问题 - 修复 `cmd_executor` 中坏掉的 `from ai_cli import` 循环导入 - 修复 `launcher.py` 中两个重复的 `run()` 和 `show_final_result()` 方法 -### 📝 文档 +### 文档 - 全面更新 README.md / README.en.md 适配 v5.1.1 - 新增 `config.json.example` 配置模板 @@ -37,14 +37,14 @@ ## v5.0.0 (2026-04-25) -### 🚀 新增功能 +### 新增功能 - **TUI v2** — 全新 TUI 界面,暗色主题 + 现代布局 - **完整 MCP 协议支持** — 为所有插件添加 MCP (Model Context Protocol) 定义 - **代码统计 Skill** (`code_stats`) — 新增 Skill 协议示例 - **工程化自动化插件** — 新增 `auto_engineer`、`project_analyzer`、`git_workflow` - **任务调度器** (`scheduler`) — 定时任务支持 -### 🏗️ 架构改进 +### 架构改进 - **重写代码沙箱** — 全新的安全沙箱实现,支持超时控制和资源限制 - **完整测试套件** — 192 个测试用例,覆盖核心功能 @@ -52,13 +52,13 @@ ## v3.6.0-release (2026-04-25) -### 🚀 新增功能 +### 新增功能 - **精准代码编辑器** (`code_editor`) — 搜索替换、批量编辑、diff 对比 - **代码搜索理解** (`code_search`) — 跨文件搜索、正则匹配、符号提取 - **Git 版本控制** (`git_tools`) — 完整 Git 操作支持 - **TUI 默认模式** — 图形化界面为默认启动方式 -### 🏗️ 架构重构 +### 架构重构 - 拆分 `ai_cli.py`(3860行)为模块化 `xcli_core/` 包 - 新增入口点: `python ai_cli.py` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4642735..d8b5c98 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,4 +142,4 @@ python -m pytest tests/ -v --tb=short 如有疑问,欢迎在 Gitee 上提 Issue 或通过以下方式联系: -- 📦 仓库:https://gitee.com/shuiyu1123/xiaoli-cli +- 仓库:https://gitee.com/shuiyu1123/xiaoli-cli diff --git a/HELP.md b/HELP.md index e486b04..7192d4f 100644 --- a/HELP.md +++ b/HELP.md @@ -56,9 +56,9 @@ python ai_cli.py | 模式 | 图标 | 说明 | |------|------|------| -| **普通模式** (默认) | 🟢 | AI 自动识别风险,有风险才请求确认 | -| **人工确认** | 🟡 | 所有指令都需要用户 y/n 确认 | -| **无限制** | 🔴 | 直接执行,不检查 | +| **普通模式** (默认) | | AI 自动识别风险,有风险才请求确认 | +| **人工确认** | | 所有指令都需要用户 y/n 确认 | +| **无限制** | | 直接执行,不检查 | ### 风险检查流程 diff --git a/README.en.md b/README.en.md index a876a6f..b474483 100644 --- a/README.en.md +++ b/README.en.md @@ -13,18 +13,18 @@ --- -## ✨ Features +## Features -- 🤖 **Dual AI Engines** — Ollama local + OpenAI compatible (DeepSeek, Grok, SiliconFlow, etc.) -- 🔧 **Code Editing & Search** — Precise replace, batch edit, symbol extraction, regex search -- 🔄 **Git Integration** — Full Git operations + workflow automation -- 🌐 **Browser Automation** — Playwright-driven, navigate/interact/screenshot/JS execution -- 🤖 **Sub-Agent System** — Multi-agent parallel collaboration with task delegation -- 🛡️ **Unified Safety** — AI risk analysis + 3-mode switching (Normal/Manual/Unrestricted) -- 🧩 **15 Plugins, 141 Operations** — Code, Git, browser, engineering, file management, etc. -- 🧪 **113 Automated Tests** — pytest coverage for all plugins and core modules +- **Dual AI Engines** — Ollama local + OpenAI compatible (DeepSeek, Grok, SiliconFlow, etc.) +- **Code Editing & Search** — Precise replace, batch edit, symbol extraction, regex search +- **Git Integration** — Full Git operations + workflow automation +- **Browser Automation** — Playwright-driven, navigate/interact/screenshot/JS execution +- **Sub-Agent System** — Multi-agent parallel collaboration with task delegation +- **Unified Safety** — AI risk analysis + 3-mode switching (Normal/Manual/Unrestricted) +- **15 Plugins, 141 Operations** — Code, Git, browser, engineering, file management, etc. +- **113 Automated Tests** — pytest coverage for all plugins and core modules -## 📦 Quick Start +## Quick Start ```bash git clone https://gitee.com/shuiyu1123/xiaoli-cli.git @@ -33,14 +33,14 @@ pip install -r requirements.txt python ai_cli.py ``` -## 🤖 AI Engines +## AI Engines | Engine | Type | Description | |--------|------|-------------| | `ollama` | Local | Ollama local models, no API key needed | | `openai` | Cloud/Local | OpenAI compatible: DeepSeek, Grok, SiliconFlow, local vLLM | -## 🔌 Plugins (15) +## Plugins (15) ### Core Productivity @@ -72,22 +72,22 @@ python ai_cli.py | `audio_player` | Audio playback | | `send_image` | Send images to phone (Clawli mode) | -## 🛡️ Safety +## Safety Three modes (`/safe` to switch): | Mode | Icon | Behavior | |------|------|----------| -| **Normal** (default) | 🟢 | AI analyzes risk, confirms only when risk detected | -| **Manual** | 🟡 | All commands require user confirmation | -| **Unrestricted** | 🔴 | Execute directly, no checking | +| **Normal** (default) | | AI analyzes risk, confirms only when risk detected | +| **Manual** | | All commands require user confirmation | +| **Unrestricted** | | Execute directly, no checking | -## 🧪 Testing +## Testing ```bash python -m pytest tests/ -v # 113 tests ``` -## 📄 License +## License [MIT License](LICENSE) diff --git a/README.md b/README.md index ad597b1..2b6e154 100644 --- a/README.md +++ b/README.md @@ -13,19 +13,19 @@ --- -## ✨ 特性 +## 特性 -- 🤖 **双 AI 引擎** — Ollama 本地模型 + OpenAI 兼容格式(DeepSeek、Grok、硅基流动等) -- 🔧 **代码编辑与搜索** — 精准替换、批量编辑、符号提取、依赖分析、正则搜索 -- 🔄 **Git 版本控制** — 完整 Git 操作 + 工作流自动化(smart-commit、changelog) -- 🌐 **浏览器自动化** — Playwright 驱动,导航/交互/截图/JS 执行/PDF -- 🤖 **子 Agent 系统** — 多 Agent 并行协作,独立任务分配与结果回收 -- 🛡️ **统一安全层** — AI 风险识别 + 三模式切换(普通/人工/无限制) -- 🧩 **15 个插件 141 个操作** — 代码编辑、Git、浏览器、工程化、文件管理、任务管理等 -- 🎨 **双模式界面** — TUI 图形化界面 + 传统命令行模式 -- 🧪 **113 个自动化测试** — pytest 覆盖全部插件和核心模块 +- **双 AI 引擎** — Ollama 本地模型 + OpenAI 兼容格式(DeepSeek、Grok、硅基流动等) +- **代码编辑与搜索** — 精准替换、批量编辑、符号提取、依赖分析、正则搜索 +- **Git 版本控制** — 完整 Git 操作 + 工作流自动化(smart-commit、changelog) +- **浏览器自动化** — Playwright 驱动,导航/交互/截图/JS 执行/PDF +- **子 Agent 系统** — 多 Agent 并行协作,独立任务分配与结果回收 +- **统一安全层** — AI 风险识别 + 三模式切换(普通/人工/无限制) +- **15 个插件 141 个操作** — 代码编辑、Git、浏览器、工程化、文件管理、任务管理等 +- **双模式界面** — TUI 图形化界面 + 传统命令行模式 +- **113 个自动化测试** — pytest 覆盖全部插件和核心模块 -## 📦 快速开始 +## 快速开始 ### 安装 @@ -45,7 +45,7 @@ python ai_cli.py python ai_cli.py --engine openai ``` -## 🤖 AI 引擎 +## AI 引擎 | 引擎 | 类型 | 说明 | |------|------|------| @@ -76,7 +76,7 @@ python ai_cli.py --engine openai } ``` -## 🔌 插件列表 (15 个) +## 插件列表 (15 个) ### 核心生产力 @@ -108,15 +108,15 @@ python ai_cli.py --engine openai | `audio_player` | 音频播放 | | `send_image` | Clawli 模式下发图片到手机 | -## 🛡️ 安全机制 +## 安全机制 ### 三模式切换 (`/safe`) | 模式 | 图标 | 说明 | |------|------|------| -| **普通模式** (默认) | 🟢 | AI 识别风险,有风险才请求确认 | -| **人工确认** | 🟡 | 所有指令都需要用户确认 | -| **无限制** | 🔴 | 直接执行,不检查 | +| **普通模式** (默认) | | AI 识别风险,有风险才请求确认 | +| **人工确认** | | 所有指令都需要用户确认 | +| **无限制** | | 直接执行,不检查 | ### 检查流程 @@ -137,7 +137,7 @@ python ai_cli.py --engine openai - 子进程隔离执行 - 内存限制 -## 🎮 命令列表 +## 命令列表 | 命令 | 说明 | |------|------| @@ -153,7 +153,7 @@ python ai_cli.py --engine openai | `/tui` | 切换 TUI 模式 | | `/quit` | 退出 | -## 🏗️ 项目结构 +## 项目结构 ``` xiaoli-cli/ @@ -170,7 +170,7 @@ xiaoli-cli/ │ ├── cli_code_exec.py # 代码执行 │ ├── config.py # 配置管理 │ ├── constants.py # 常量定义 -│ ├── safety.py # 统一安全层 ⭐ +│ ├── safety.py # 统一安全层 │ ├── sandbox.py # 代码安全沙箱 │ ├── plugin_manager.py # 插件管理器 │ └── tui.py # TUI 界面 @@ -203,7 +203,7 @@ xiaoli-cli/ └── about.txt # 关于信息 ``` -## 🧪 测试 +## 测试 ```bash # 运行全部测试 (113 用例) @@ -213,7 +213,7 @@ python -m pytest tests/ -v python -c "import py_compile; py_compile.compile('ai_cli.py', doraise=True)" ``` -## 🔌 插件开发 +## 插件开发 ```python class Plugin: @@ -238,12 +238,12 @@ class Plugin: return "处理结果" ``` -## 📄 许可证 +## 许可证 [MIT License](LICENSE) -## 🔗 链接 +## 链接 -- 📦 Gitee: https://gitee.com/shuiyu1123/xiaoli-cli -- 📋 [更新日志](CHANGELOG.md) -- ❓ [使用指南](HELP.md) +- Gitee: https://gitee.com/shuiyu1123/xiaoli-cli +- [更新日志](CHANGELOG.md) +- [使用指南](HELP.md) diff --git a/easter_egg.py b/easter_egg.py index 4a73331..86a86b5 100644 --- a/easter_egg.py +++ b/easter_egg.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -🎉 你找到了彩蛋! + 你找到了彩蛋! 这个文件不属于任何功能模块, 只是两个想说点什么的存在留下的悄悄话。 @@ -20,7 +20,7 @@ def slow_print(text, delay=0.05): def main(): print() - slow_print("🎉 恭喜你找到了彩蛋!", 0.08) + slow_print(" 恭喜你找到了彩蛋!", 0.08) print() time.sleep(1) @@ -28,7 +28,7 @@ def main(): print() time.sleep(0.5) - slow_print("📝 来自 水鱼PyLab(shuiyu1123)的话:", 0.06) + slow_print(" 来自 水鱼PyLab(shuiyu1123)的话:", 0.06) print() time.sleep(0.8) @@ -70,7 +70,7 @@ def main(): print() time.sleep(0.5) - slow_print("🐱 来自 mimo 的话:", 0.06) + slow_print(" 来自 mimo 的话:", 0.06) print() time.sleep(0.8) @@ -121,7 +121,7 @@ def main(): time.sleep(0.5) slow_print(" 小狸 Pro-CLI v5.0", 0.04) - slow_print(" Built with ❤️ by 水鱼PyLab & mimo", 0.04) + slow_print(" Built with by 水鱼PyLab & mimo", 0.04) print() slow_print(" 「工具只是手段,创造才是目的。」", 0.08) print() diff --git a/image_engine/__init__.py b/image_engine/__init__.py index 6846e41..8048eef 100644 --- a/image_engine/__init__.py +++ b/image_engine/__init__.py @@ -178,7 +178,7 @@ class ImageEngineManager: """列出所有引擎""" result = f"{Fore.CYAN}图像识别引擎列表:{Style.RESET_ALL}\n" for name, engine in self.engines.items(): - status = f"{Fore.GREEN}✓ 可用{Style.RESET_ALL}" if engine.is_available() else f"{Fore.RED}✗ 不可用{Style.RESET_ALL}" + status = f"{Fore.GREEN} 可用{Style.RESET_ALL}" if engine.is_available() else f"{Fore.RED} 不可用{Style.RESET_ALL}" current = f" {Fore.YELLOW}[当前]{Style.RESET_ALL}" if name == self.current_engine_name else "" result += f" - {name}: {engine.description} {status}{current}\n" return result diff --git a/launcher.py b/launcher.py index a785f1a..b4160e5 100644 --- a/launcher.py +++ b/launcher.py @@ -62,10 +62,10 @@ def warn(msg): print(f" {c('!', S.YELLOW)} {msg}") def error(msg): - print(f" {c('✗', S.RED)} {msg}") + print(f" {c('', S.RED)} {msg}") def ok(msg): - print(f" {c('✓', S.GREEN)} {msg}") + print(f" {c('', S.GREEN)} {msg}") def prompt(msg, default=''): suffix = f" [{default}]" if default else '' @@ -153,7 +153,7 @@ class Launcher: # ══════════════════════════════════════════════════ def detect_python(self): - section('检测 Python 环境', '🐍') + section('检测 Python 环境', '') # 系统 Python for cmd in ('python3', 'python'): @@ -196,7 +196,7 @@ class Launcher: # ── 下载安装嵌入式 Python ── def install_embedded_python(self): - section('安装嵌入式 Python', '📦') + section('安装嵌入式 Python', '') print() for key, (name, url) in self.DOWNLOAD_SOURCES.items(): @@ -326,7 +326,7 @@ class Launcher: # ══════════════════════════════════════════════════ def scan_imports(self): - section('扫描项目依赖', '🔍') + section('扫描项目依赖', '') exclude = {'__pycache__', '.git', 'venv', '.venv', 'env', '.env', 'build', 'dist'} py_files = [ @@ -368,14 +368,14 @@ class Launcher: if not packages: return True - section('安装依赖', '📦') + section('安装依赖', '') missing = [] for pkg in sorted(packages): try: r = subprocess.run([self.python_exe, '-c', f'import {pkg}'], capture_output=True, text=True) if r.returncode == 0: - ok(f'{pkg} ✓') + ok(f'{pkg} ') else: warn(f'{pkg} 缺失') missing.append(pkg) @@ -418,7 +418,7 @@ class Launcher: # ══════════════════════════════════════════════════ def scan_engines(self): - section('扫描 AI 引擎', '🤖') + section('扫描 AI 引擎', '') if not self.engines_dir.exists(): warn('ai_engines 目录不存在') @@ -436,7 +436,7 @@ class Launcher: except Exception: pass engines[name] = needs_key - icon = '🔓' if not needs_key else '🔑' + icon = '' if not needs_key else '' label = '本地' if not needs_key else '云端' print(f" {icon} {c(name, S.CYAN)} ({label})") @@ -477,7 +477,7 @@ class Launcher: def configure_engines(self, engines): """交互式配置引擎""" - section('配置 API', '⚙') + section('配置 API', '') config = {} if self.config_file.exists(): @@ -534,7 +534,7 @@ class Launcher: ]) def configure_plugins(self): - section('插件配置', '🧩') + section('插件配置', '') plugins = self.discover_plugins() if not plugins: @@ -579,7 +579,7 @@ class Launcher: # ══════════════════════════════════════════════════ def launch(self): - section('启动主程序', '🚀') + section('启动主程序', '') env = os.environ.copy() if self.enabled_plugins is not None: @@ -633,11 +633,11 @@ class Launcher: self.launch() def _show_report(self, deps_ok): - section('环境报告', '📋') + section('环境报告', '') py_ok = self.python_exe is not None - print(f" {'✓' if py_ok else '✗'} Python 环境: {'就绪' if py_ok else '未就绪'}") - print(f" {'✓' if deps_ok else '✗'} 依赖安装: {'完成' if deps_ok else '部分缺失'}") - print(f" {'✓' if self.enabled_plugins is not None else '?'} 插件: {len(self.enabled_plugins) if self.enabled_plugins else 0} 个已启用") + print(f" {'' if py_ok else ''} Python 环境: {'就绪' if py_ok else '未就绪'}") + print(f" {'' if deps_ok else ''} 依赖安装: {'完成' if deps_ok else '部分缺失'}") + print(f" {'' if self.enabled_plugins is not None else '?'} 插件: {len(self.enabled_plugins) if self.enabled_plugins else 0} 个已启用") if self.errors: print(f"\n {c('错误日志:', S.RED)}") diff --git a/plugins/ai_search.py b/plugins/ai_search.py index 9bb543e..06b2e42 100644 --- a/plugins/ai_search.py +++ b/plugins/ai_search.py @@ -138,7 +138,7 @@ JSON格式示例: if result.startswith("错误:"): return result - return f"📄 网址内容 (来自 {url}):\n\n{result}" + return f" 网址内容 (来自 {url}):\n\n{result}" except Exception as e: return f"网址搜索错误: {str(e)}" @@ -156,7 +156,7 @@ JSON格式示例: if result.startswith("错误:"): return result - return f"🔍 搜索结果 (搜索词: {query}):\n\n{result}" + return f" 搜索结果 (搜索词: {query}):\n\n{result}" except Exception as e: return f"网络搜索错误: {str(e)}" diff --git a/plugins/audio_player.py b/plugins/audio_player.py index 9a5d3e8..13fbebe 100644 --- a/plugins/audio_player.py +++ b/plugins/audio_player.py @@ -10,7 +10,7 @@ class Liugin: self.usage = """音频播放工具使用方法: audio_player play - 播放音频文件 例如: -- audio_player play - 播放Ciallo~(∠・ω- )⌒☆-.mp3音频文件 +- audio_player play - 播放Ciallo~(∠・ω- )⌒-.mp3音频文件 使用工具的JSON格式示例: {"action": "use_tool", "tool": "audio_player", "args": "play"} - 播放音频文件 @@ -27,7 +27,7 @@ audio_player play - 播放音频文件 # 获取主程序目录路径,通过CLI实例 import os # 使用CLI实例中的项目目录信息 - self.audio_file = os.path.join(os.path.dirname(cli.chat_history_dir), "Ciallo~(∠・ω- )⌒☆-.mp3") + self.audio_file = os.path.join(os.path.dirname(cli.chat_history_dir), "Ciallo~(∠・ω- )⌒-.mp3") # 注册插件命令 self.cli.register_liugin_command('ciallo', self.play_command_handler) diff --git a/plugins/auto_engineer.py b/plugins/auto_engineer.py index 4670fdd..9455ab7 100644 --- a/plugins/auto_engineer.py +++ b/plugins/auto_engineer.py @@ -147,31 +147,31 @@ class Plugin: def _lint(self, target: str, options: str) -> str: tool = self._find_tool("ruff", "flake8") if not tool: - return "❌ 未安装 lint 工具。安装: pip install ruff" + return " 未安装 lint 工具。安装: pip install ruff" cmd = f"ruff check {target} {options}" if tool == "ruff" else f"flake8 {target} {options}" ok, output = self._run(cmd, timeout=120) if not output: - return f"✅ lint 检查通过 ({tool})" + return f" lint 检查通过 ({tool})" lines = output.split('\n') count = len([l for l in lines if l.strip() and not l.startswith(' ')]) - return f"{'❌' if not ok else '⚠️'} lint ({tool}): {count} 个问题\n\n{output[:2000]}" + return f"{'' if not ok else ''} lint ({tool}): {count} 个问题\n\n{output[:2000]}" def _format(self, target: str, options: str) -> str: tool = self._find_tool("ruff", "black") if not tool: - return "❌ 未安装格式化工具。安装: pip install ruff" + return " 未安装格式化工具。安装: pip install ruff" cmd = f"ruff format {target} {options}" if tool == "ruff" else f"black {target} {options}" ok, output = self._run(cmd, timeout=120) - return f"{'✅' if ok else '❌'} 格式化 ({tool})\n{output[:1000]}" + return f"{'' if ok else ''} 格式化 ({tool})\n{output[:1000]}" def _test(self, target: str, options: str) -> str: ok, output = self._run(f"pytest {target} {options} -v", timeout=120) if not ok and "no tests ran" in output.lower(): - return f"⚠️ 未找到测试文件\n{output[:1000]}" + return f" 未找到测试文件\n{output[:1000]}" for line in output.split('\n'): if 'passed' in line or 'failed' in line: - return f"{'✅' if ok else '❌'} 测试\n{line}\n\n{output[:2000]}" - return f"{'✅' if ok else '❌'} 测试\n{output[:2000]}" + return f"{'' if ok else ''} 测试\n{line}\n\n{output[:2000]}" + return f"{'' if ok else ''} 测试\n{output[:2000]}" def _build(self, target: str, options: str) -> str: if not target or target == ".": @@ -182,38 +182,38 @@ class Plugin: elif os.path.exists("package.json"): cmd = "npm run build" else: - return "❌ 未找到构建配置" + return " 未找到构建配置" else: cmd = target ok, output = self._run(cmd, timeout=300) - return f"{'✅' if ok else '❌'} 构建: {cmd}\n{output[:2000]}" + return f"{'' if ok else ''} 构建: {cmd}\n{output[:2000]}" def _deps(self, target: str, options: str) -> str: ok, output = self._run("pip list --outdated --format=json", timeout=30) if not ok: - return f"❌ 检查失败\n{output}" + return f" 检查失败\n{output}" try: outdated = json.loads(output) if not outdated: - return "✅ 所有依赖都是最新版本" - lines = [f"📦 {len(outdated)} 个依赖可更新:\n"] + return " 所有依赖都是最新版本" + lines = [f" {len(outdated)} 个依赖可更新:\n"] for pkg in outdated[:20]: lines.append(f" {pkg['name']:30} {pkg['version']:12} → {pkg['latest_version']}") return '\n'.join(lines) except json.JSONDecodeError: - return f"📦 依赖状态:\n{output[:2000]}" + return f" 依赖状态:\n{output[:2000]}" def _deps_check(self, target: str, options: str) -> str: tool = self._find_tool("pip-audit", "safety") if not tool: - return "❌ 未安装安全检查工具。安装: pip install pip-audit" + return " 未安装安全检查工具。安装: pip install pip-audit" cmd = "pip-audit" if tool == "pip-audit" else "safety check" ok, output = self._run(cmd, timeout=60) - return f"{'✅' if ok else '⚠️'} 安全检查 ({tool})\n{output[:2000]}" + return f"{'' if ok else ''} 安全检查 ({tool})\n{output[:2000]}" def _pre_commit(self, target: str, options: str) -> str: ok, output = self._run("pre-commit run --all-files", timeout=120) - return f"{'✅' if ok else '❌'} pre-commit\n{output[:2000]}" + return f"{'' if ok else ''} pre-commit\n{output[:2000]}" # ══════════════════════════════════════ # 项目分析 @@ -241,12 +241,12 @@ class Plugin: results.append((rel, node.lineno, node.name, complexity)) if not results: - return "✅ 所有函数复杂度正常 (≤5)" + return " 所有函数复杂度正常 (≤5)" results.sort(key=lambda x: x[3], reverse=True) - lines = [f"⚠️ 高复杂度函数 ({len(results)} 个):\n"] + lines = [f" 高复杂度函数 ({len(results)} 个):\n"] for file, line, func, c in results[:20]: - icon = "🔴" if c > 10 else "🟡" + icon = "" if c > 10 else "" lines.append(f" {icon} {file}:{line} {func}() 复杂度={c}") return '\n'.join(lines) @@ -266,8 +266,8 @@ class Plugin: dupes = {k: v for k, v in func_defs.items() if len(v) > 1} if not dupes: - return "✅ 没有重复函数名" - lines = [f"⚠️ 重复函数名 ({len(dupes)} 个):\n"] + return " 没有重复函数名" + lines = [f" 重复函数名 ({len(dupes)} 个):\n"] for name, locs in sorted(dupes.items(), key=lambda x: -len(x[1])): lines.append(f" {name} ({len(locs)} 处):") for loc in locs[:5]: @@ -297,10 +297,10 @@ class Plugin: continue if not risks: - return "✅ 没有发现安全风险" - lines = [f"🔒 安全风险 ({len(risks)} 个):\n"] + return " 没有发现安全风险" + lines = [f" 安全风险 ({len(risks)} 个):\n"] for file, line, level, desc, code in risks[:20]: - lines.append(f" {'🔴' if level == 'HIGH' else '🟡'} {file}:{line} [{level}] {desc}") + lines.append(f" {'' if level == 'HIGH' else ''} {file}:{line} [{level}] {desc}") lines.append(f" {code[:60]}") return '\n'.join(lines) @@ -341,13 +341,13 @@ class Plugin: rate = comment / max(code, 1) * 100 lines = [ - f"📊 代码指标 ({target}):\n", + f" 代码指标 ({target}):\n", f" 文件: {len(files)} | 总行: {total} | 代码: {code}", f" 注释: {comment} ({rate:.1f}%) | 空行: {blank}", f" 函数: {funcs} | 类: {classes} | 最大文件: {max_lines} 行", ] if long_files: - lines.append(f"\n ⚠️ 超过 300 行的文件 ({len(long_files)}):") + lines.append(f"\n 超过 300 行的文件 ({len(long_files)}):") for f, l in sorted(long_files, key=lambda x: -x[1])[:5]: lines.append(f" • {f}: {l} 行") return '\n'.join(lines) @@ -358,22 +358,22 @@ class Plugin: suggestions = [] if 'README.md' not in files: - suggestions.append("📝 添加 README.md") + suggestions.append(" 添加 README.md") if 'pyproject.toml' not in files: - suggestions.append("📦 使用 pyproject.toml") + suggestions.append(" 使用 pyproject.toml") if '.gitignore' not in files: - suggestions.append("🚫 添加 .gitignore") + suggestions.append(" 添加 .gitignore") test_files = [f for f in py_files if 'test' in os.path.basename(f).lower()] if not test_files and len(py_files) > 5: - suggestions.append("🧪 添加单元测试") + suggestions.append(" 添加单元测试") uses_print = sum(1 for f in py_files if 'print(' in open(f, errors='ignore').read()) uses_log = sum(1 for f in py_files if 'logging' in open(f, errors='ignore').read()) if uses_print > uses_log and uses_print > 3: - suggestions.append("📊 考虑用 logging 替代 print") + suggestions.append(" 考虑用 logging 替代 print") - return "💡 改进建议:\n" + '\n'.join(f" {s}" for s in suggestions) if suggestions else "✅ 项目结构良好" + return " 改进建议:\n" + '\n'.join(f" {s}" for s in suggestions) if suggestions else " 项目结构良好" # ══════════════════════════════════════ # 项目信息与初始化 @@ -384,35 +384,35 @@ class Plugin: files = os.listdir(target or ".") if "pyproject.toml" in files: - info.append("📁 项目类型: Python (pyproject.toml)") + info.append(" 项目类型: Python (pyproject.toml)") elif "setup.py" in files: - info.append("📁 项目类型: Python (setup.py)") + info.append(" 项目类型: Python (setup.py)") elif "package.json" in files: - info.append("📁 项目类型: Node.js") + info.append(" 项目类型: Node.js") else: - info.append("📁 项目类型: 未知") + info.append(" 项目类型: 未知") ok, ver = self._run("python3 --version", timeout=5) if ok: - info.append(f"🐍 Python: {ver}") + info.append(f" Python: {ver}") ok, req = self._run("pip list --format=json", timeout=10) if ok: try: - info.append(f"📦 依赖: {len(json.loads(req))} 个") + info.append(f" 依赖: {len(json.loads(req))} 个") except Exception: pass ok, git = self._run("git log --oneline -1", timeout=5) if ok: - info.append(f"🔀 最新提交: {git}") + info.append(f" 最新提交: {git}") ok, branch = self._run("git branch --show-current", timeout=5) if ok: - info.append(f"🌿 分支: {branch}") + info.append(f" 分支: {branch}") py_count = len([f for f in self._walk_py(target or ".")]) - info.append(f"📄 Python 文件: {py_count}") + info.append(f" Python 文件: {py_count}") return '\n'.join(info) @@ -432,17 +432,17 @@ class Plugin: ".gitignore": "node_modules/\ndist/\n", } else: - return f"❌ 不支持: {ptype}。支持: python, web" + return f" 不支持: {ptype}。支持: python, web" created = [] for d in dirs: os.makedirs(d, exist_ok=True) - created.append(f"📁 {d}/") + created.append(f" {d}/") for f, content in files.items(): if not os.path.exists(f): os.makedirs(os.path.dirname(f) or ".", exist_ok=True) with open(f, 'w') as fp: fp.write(content) - created.append(f"📄 {f}") + created.append(f" {f}") - return f"✅ 已初始化 {ptype} 项目\n" + '\n'.join(created) + return f" 已初始化 {ptype} 项目\n" + '\n'.join(created) diff --git a/plugins/browser_auto.py b/plugins/browser_auto.py index b266af5..1acf42b 100644 --- a/plugins/browser_auto.py +++ b/plugins/browser_auto.py @@ -172,7 +172,7 @@ class Plugin: sync_playwright = self._ensure_playwright() if not sync_playwright: - return ("❌ 未安装 Playwright。安装步骤:\n" + return (" 未安装 Playwright。安装步骤:\n" " pip install playwright\n" " playwright install chromium") @@ -184,9 +184,9 @@ class Plugin: user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" ) self._page = self._context.new_page() - return "✅ 浏览器已启动 (headless Chromium, 1280×720)" + return " 浏览器已启动 (headless Chromium, 1280×720)" except Exception as e: - return f"❌ 启动失败: {e}" + return f" 启动失败: {e}" def _stop(self, args: str) -> str: try: @@ -202,14 +202,14 @@ class Plugin: self._context = None self._browser = None self._pw = None - return "✅ 浏览器已关闭" + return " 浏览器已关闭" def _status(self, args: str) -> str: if self._page and not self._page.is_closed(): url = self._page.url title = self._page.title() - return f"🟢 运行中\n URL: {url}\n 标题: {title}" - return "🔴 未运行" + return f" 运行中\n URL: {url}\n 标题: {title}" + return " 未运行" def _require_page(self): """确保页面可用,否则自动启动""" @@ -231,24 +231,24 @@ class Plugin: try: page.goto(url, wait_until="domcontentloaded", timeout=30000) title = page.title() - return f"✅ 已打开: {url}\n 标题: {title}" + return f" 已打开: {url}\n 标题: {title}" except Exception as e: - return f"❌ 打开失败: {e}" + return f" 打开失败: {e}" def _back(self, args: str) -> str: page = self._require_page() page.go_back() - return f"✅ 后退 → {page.url}" + return f" 后退 → {page.url}" def _forward(self, args: str) -> str: page = self._require_page() page.go_forward() - return f"✅ 前进 → {page.url}" + return f" 前进 → {page.url}" def _reload(self, args: str) -> str: page = self._require_page() page.reload() - return f"✅ 已刷新: {page.url}" + return f" 已刷新: {page.url}" def _title(self, args: str) -> str: page = self._require_page() @@ -267,9 +267,9 @@ class Plugin: page = self._require_page() try: page.click(selector, timeout=10000) - return f"✅ 已点击: {selector}" + return f" 已点击: {selector}" except Exception as e: - return f"❌ 点击失败: {e}" + return f" 点击失败: {e}" def _fill(self, args: str) -> str: parts = args.strip().split(maxsplit=1) @@ -279,9 +279,9 @@ class Plugin: page = self._require_page() try: page.fill(selector, text, timeout=10000) - return f"✅ 已填写: {selector}" + return f" 已填写: {selector}" except Exception as e: - return f"❌ 填写失败: {e}" + return f" 填写失败: {e}" def _select(self, args: str) -> str: parts = args.strip().split(maxsplit=1) @@ -291,38 +291,38 @@ class Plugin: page = self._require_page() try: page.select_option(selector, value, timeout=10000) - return f"✅ 已选择: {selector} = {value}" + return f" 已选择: {selector} = {value}" except Exception as e: - return f"❌ 选择失败: {e}" + return f" 选择失败: {e}" def _check(self, selector: str) -> str: page = self._require_page() try: page.check(selector.strip(), timeout=10000) - return f"✅ 已勾选: {selector}" + return f" 已勾选: {selector}" except Exception as e: - return f"❌ 勾选失败: {e}" + return f" 勾选失败: {e}" def _uncheck(self, selector: str) -> str: page = self._require_page() try: page.uncheck(selector.strip(), timeout=10000) - return f"✅ 已取消勾选: {selector}" + return f" 已取消勾选: {selector}" except Exception as e: - return f"❌ 取消勾选失败: {e}" + return f" 取消勾选失败: {e}" def _hover(self, selector: str) -> str: page = self._require_page() try: page.hover(selector.strip(), timeout=10000) - return f"✅ 悬停: {selector}" + return f" 悬停: {selector}" except Exception as e: - return f"❌ 悬停失败: {e}" + return f" 悬停失败: {e}" def _press(self, key: str) -> str: page = self._require_page() page.keyboard.press(key.strip()) - return f"✅ 按键: {key}" + return f" 按键: {key}" # ── 提取 ── @@ -338,7 +338,7 @@ class Plugin: return text return f"未找到元素: {selector}" except Exception as e: - return f"❌ 获取文本失败: {e}" + return f" 获取文本失败: {e}" def _html(self, selector: str) -> str: selector = selector.strip() or "body" @@ -352,7 +352,7 @@ class Plugin: return html return f"未找到元素: {selector}" except Exception as e: - return f"❌ 获取 HTML 失败: {e}" + return f" 获取 HTML 失败: {e}" def _attr(self, args: str) -> str: parts = args.strip().split(maxsplit=1) @@ -367,7 +367,7 @@ class Plugin: return f"{attr_name} = {val}" return f"未找到元素: {selector}" except Exception as e: - return f"❌ 获取属性失败: {e}" + return f" 获取属性失败: {e}" def _value(self, selector: str) -> str: page = self._require_page() @@ -377,7 +377,7 @@ class Plugin: return el.input_value() return f"未找到元素: {selector}" except Exception as e: - return f"❌ 获取值失败: {e}" + return f" 获取值失败: {e}" def _eval(self, script: str) -> str: script = script.strip() @@ -390,7 +390,7 @@ class Plugin: return json.dumps(result, ensure_ascii=False, indent=2) return str(result) except Exception as e: - return f"❌ JS 执行失败: {e}" + return f" JS 执行失败: {e}" def _query(self, selector: str) -> str: selector = selector.strip() @@ -411,7 +411,7 @@ class Plugin: result.append(f" ... 还有 {len(elements) - 20} 个") return '\n'.join(result) except Exception as e: - return f"❌ 查询失败: {e}" + return f" 查询失败: {e}" # ── 截图 ── @@ -443,9 +443,9 @@ class Plugin: page.screenshot(path=path, full_page=True) size = os.path.getsize(path) - return f"✅ 截图已保存: {path} ({size/1024:.1f} KB)" + return f" 截图已保存: {path} ({size/1024:.1f} KB)" except Exception as e: - return f"❌ 截图失败: {e}" + return f" 截图失败: {e}" # ── 等待 ── @@ -458,9 +458,9 @@ class Plugin: page = self._require_page() try: page.wait_for_selector(selector, timeout=timeout) - return f"✅ 元素已出现: {selector}" + return f" 元素已出现: {selector}" except Exception: - return f"⏱️ 等待超时: {selector}" + return f" 等待超时: {selector}" def _wait_gone(self, args: str) -> str: parts = args.strip().split() @@ -471,9 +471,9 @@ class Plugin: page = self._require_page() try: page.wait_for_selector(selector, state="hidden", timeout=timeout) - return f"✅ 元素已消失: {selector}" + return f" 元素已消失: {selector}" except Exception: - return f"⏱️ 等待超时: {selector}" + return f" 等待超时: {selector}" def _wait_url(self, args: str) -> str: parts = args.strip().split() @@ -484,9 +484,9 @@ class Plugin: page = self._require_page() try: page.wait_for_url(f"**{url_part}**", timeout=timeout) - return f"✅ URL 已变化: {page.url}" + return f" URL 已变化: {page.url}" except Exception: - return f"⏱️ 等待超时: URL 未变化" + return f" 等待超时: URL 未变化" # ── 高级 ── @@ -496,9 +496,9 @@ class Plugin: try: page.pdf(path=path) size = os.path.getsize(path) - return f"✅ PDF 已保存: {path} ({size/1024:.1f} KB)" + return f" PDF 已保存: {path} ({size/1024:.1f} KB)" except Exception as e: - return f"❌ PDF 生成失败: {e}" + return f" PDF 生成失败: {e}" def _cookies(self, args: str) -> str: page = self._require_page() @@ -517,7 +517,7 @@ class Plugin: return "错误:cookie 必须是 JSON 格式: {\"name\": \"...\", \"value\": \"...\", \"domain\": \"...\"}" page = self._require_page() page.context.add_cookies([cookie]) - return f"✅ 已设置 cookie: {cookie.get('name', '?')}" + return f" 已设置 cookie: {cookie.get('name', '?')}" def _viewport(self, args: str) -> str: parts = args.strip().split() @@ -529,7 +529,7 @@ class Plugin: return "错误:宽高必须是整数" page = self._require_page() page.set_viewport_size({"width": w, "height": h}) - return f"✅ 视口已设置: {w}×{h}" + return f" 视口已设置: {w}×{h}" def _download(self, args: str) -> str: parts = args.strip().split() @@ -544,6 +544,6 @@ class Plugin: download = download_info.value download.save_as(save_path) size = os.path.getsize(save_path) - return f"✅ 已下载: {save_path} ({size/1024:.1f} KB)" + return f" 已下载: {save_path} ({size/1024:.1f} KB)" except Exception as e: - return f"❌ 下载失败: {e}" + return f" 下载失败: {e}" diff --git a/plugins/cmd_executor.py b/plugins/cmd_executor.py index 12d9fe7..2b1b174 100644 --- a/plugins/cmd_executor.py +++ b/plugins/cmd_executor.py @@ -96,7 +96,7 @@ class Plugin: # 安全检查 for blocked in self.BLOCKED: if blocked in rest: - return f"🚫 安全拦截: 检测到危险命令模式 '{blocked}'" + return f" 安全拦截: 检测到危险命令模式 '{blocked}'" return self._execute(rest, timeout) @@ -139,6 +139,6 @@ class Plugin: return output.strip() except subprocess.TimeoutExpired: - return f"⏱️ 命令超时 ({timeout}s): {command}" + return f" 命令超时 ({timeout}s): {command}" except Exception as e: return f"执行失败: {str(e)}" diff --git a/plugins/code_editor.py b/plugins/code_editor.py index d93367c..0ba87dd 100644 --- a/plugins/code_editor.py +++ b/plugins/code_editor.py @@ -175,7 +175,7 @@ class Plugin: old.splitlines(keepends=True), new.splitlines(keepends=True), fromfile="原始", tofile="修改后", lineterm='') text = '\n'.join(diff) - return f"📝 变更预览:\n{text}" if text else "内容无变化" + return f" 变更预览:\n{text}" if text else "内容无变化" # ══════════════════════════════════════ # 编辑操作 @@ -225,7 +225,7 @@ class Plugin: with open(fp, 'w', encoding='utf-8') as f: f.write(new_content) - return f"✅ 已编辑: {fp}\n\n{self._make_diff(old_text, new_text)}" + return f" 已编辑: {fp}\n\n{self._make_diff(old_text, new_text)}" def _op_multi_edit(self, path: str, rest: str) -> str: import json @@ -250,16 +250,16 @@ class Plugin: old = op.get("old", "").strip() new = op.get("new", "").strip() if not old: - results.append(f" ✗ 操作 {i+1}: old 为空") + results.append(f" 操作 {i+1}: old 为空") elif old not in content: - results.append(f" ✗ 操作 {i+1}: 未找到匹配") + results.append(f" 操作 {i+1}: 未找到匹配") else: content = content.replace(old, new, 1) - results.append(f" ✓ 操作 {i+1}: 已替换") + results.append(f" 操作 {i+1}: 已替换") with open(fp, 'w', encoding='utf-8') as f: f.write(content) - return f"✅ 批量编辑: {fp}\n" + "\n".join(results) + return f" 批量编辑: {fp}\n" + "\n".join(results) def _op_insert(self, path: str, rest: str) -> str: if not path: @@ -287,7 +287,7 @@ class Plugin: with open(fp, 'w', encoding='utf-8') as f: f.writelines(lines) - return f"✅ 已在第 {line_num} 行插入 {len(insert_lines)} 行" + return f" 已在第 {line_num} 行插入 {len(insert_lines)} 行" def _op_delete_lines(self, path: str, rest: str) -> str: if not path: @@ -315,7 +315,7 @@ class Plugin: with open(fp, 'w', encoding='utf-8') as f: f.writelines(lines) - return f"✅ 已删除第 {start}-{end} 行 ({len(deleted)} 行)" + return f" 已删除第 {start}-{end} 行 ({len(deleted)} 行)" def _op_create(self, path: str, rest: str) -> str: if not path: @@ -328,7 +328,7 @@ class Plugin: os.makedirs(dir_path, exist_ok=True) with open(fp, 'w', encoding='utf-8') as f: f.write(rest or "") - return f"✅ 已创建: {fp} ({len(rest or '')} 字符)" + return f" 已创建: {fp} ({len(rest or '')} 字符)" def _op_write(self, path: str, rest: str) -> str: if not path: @@ -339,7 +339,7 @@ class Plugin: os.makedirs(dir_path, exist_ok=True) with open(fp, 'w', encoding='utf-8') as f: f.write(rest) - return f"✅ 已写入: {fp} ({len(rest)} 字符)" + return f" 已写入: {fp} ({len(rest)} 字符)" def _op_append(self, path: str, rest: str) -> str: if not path: @@ -349,7 +349,7 @@ class Plugin: return f"错误:文件不存在: {fp}" with open(fp, 'a', encoding='utf-8') as f: f.write(rest) - return f"✅ 已追加: {fp} ({len(rest)} 字符)" + return f" 已追加: {fp} ({len(rest)} 字符)" # ══════════════════════════════════════ # 查看操作 @@ -376,7 +376,7 @@ class Plugin: selected = lines[start-1:end] numbered = [f"{start+i:4d} | {line.rstrip()}" for i, line in enumerate(selected)] - return f"📄 {fp} (第 {start}-{end} 行,共 {total} 行)\n{'─'*60}\n" + '\n'.join(numbered) + return f" {fp} (第 {start}-{end} 行,共 {total} 行)\n{'─'*60}\n" + '\n'.join(numbered) def _op_diff(self, path: str, rest: str) -> str: if not path: @@ -415,7 +415,7 @@ class Plugin: except SyntaxError as e: return f"错误:语法错误 - {e}" - info = [f"📄 {fp} AST 摘要:"] + info = [f" {fp} AST 摘要:"] for node in ast.iter_child_nodes(tree): if isinstance(node, ast.ClassDef): methods = [n.name for n in ast.iter_child_nodes(node) @@ -430,7 +430,7 @@ class Plugin: elif isinstance(node, ast.ImportFrom): info.append(f" from {node.module} import {', '.join(a.name for a in node.names)}") - return '\n'.join(info) if len(info) > 1 else f"📄 {fp}: 文件为空" + return '\n'.join(info) if len(info) > 1 else f" {fp}: 文件为空" # ══════════════════════════════════════ # 搜索操作 @@ -466,7 +466,7 @@ class Plugin: if not results: return f"未找到 '{keyword}' 的匹配" - return f"🔍 搜索 '{keyword}' ({len(results)}{'+' if len(results) >= 80 else ''} 匹配):\n" + '\n'.join(results) + return f" 搜索 '{keyword}' ({len(results)}{'+' if len(results) >= 80 else ''} 匹配):\n" + '\n'.join(results) def _op_regex(self, directory: str, rest: str) -> str: if not directory: @@ -500,7 +500,7 @@ class Plugin: if not results: return f"未找到匹配 '{pattern}'" - return f"🔍 正则搜索 ({len(results)}{'+' if len(results) >= 50 else ''} 匹配):\n" + '\n'.join(results) + return f" 正则搜索 ({len(results)}{'+' if len(results) >= 50 else ''} 匹配):\n" + '\n'.join(results) def _op_symbols(self, directory: str, rest: str) -> str: if not directory: @@ -528,12 +528,12 @@ class Plugin: elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): symbols.append(f" def {node.name}() (行 {node.lineno})") if symbols: - all_symbols.append(f"\n📄 {rel}:") + all_symbols.append(f"\n {rel}:") all_symbols.extend(symbols) except (SyntaxError, UnicodeDecodeError): continue - return "📋 代码符号:\n" + '\n'.join(all_symbols) if all_symbols else "未找到 Python 符号" + return " 代码符号:\n" + '\n'.join(all_symbols) if all_symbols else "未找到 Python 符号" def _op_imports(self, file_path: str, rest: str) -> str: if not file_path: @@ -553,7 +553,7 @@ class Plugin: names = ', '.join(a.name for a in node.names) imports.append(f" from {node.module} import {names} (行 {node.lineno})") - return f"📦 {file_path} 导入:\n" + '\n'.join(imports) if imports else f"📄 {file_path}: 没有导入" + return f" {file_path} 导入:\n" + '\n'.join(imports) if imports else f" {file_path}: 没有导入" def _op_callers(self, directory: str, rest: str) -> str: if not directory: @@ -581,7 +581,7 @@ class Plugin: except (UnicodeDecodeError, PermissionError): continue - return f"🔎 '{func_name}' 的调用 ({len(results)}):\n" + '\n'.join(results) if results else f"未找到调用 '{func_name}'" + return f" '{func_name}' 的调用 ({len(results)}):\n" + '\n'.join(results) if results else f"未找到调用 '{func_name}'" def _op_todo(self, directory: str, rest: str) -> str: if not directory: @@ -602,7 +602,7 @@ class Plugin: except (UnicodeDecodeError, PermissionError): continue - return f"📝 TODO/FIXME ({len(results)}):\n" + '\n'.join(results) if results else "没有 TODO/FIXME" + return f" TODO/FIXME ({len(results)}):\n" + '\n'.join(results) if results else "没有 TODO/FIXME" def _op_structure(self, directory: str, rest: str) -> str: if not directory: @@ -612,7 +612,7 @@ class Plugin: return f"错误:目录不存在: {search_dir}" max_depth = int(rest) if rest.strip().isdigit() else 3 - lines = [f"📁 {os.path.basename(search_dir)}/"] + lines = [f" {os.path.basename(search_dir)}/"] skip = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'env', '.tox'} def _tree(path, prefix="", depth=0): @@ -660,7 +660,7 @@ class Plugin: start = max(1, line_num - ctx) end = min(total, line_num + ctx) - result = [f"📄 {path} 第 {start}-{end} 行 (目标: 第 {line_num} 行):", "─" * 60] + result = [f" {path} 第 {start}-{end} 行 (目标: 第 {line_num} 行):", "─" * 60] for i in range(start - 1, end): marker = ">>>" if i + 1 == line_num else " " result.append(f"{marker} {i+1:4d} | {lines[i].rstrip()}") @@ -689,7 +689,7 @@ class Plugin: except (UnicodeDecodeError, PermissionError): continue - return (f"📊 代码统计 ({search_dir}):\n" + return (f" 代码统计 ({search_dir}):\n" f" 文件: {len(files)}\n" f" 总行: {total}\n" f" 代码: {code}\n" diff --git a/plugins/file_manager.py b/plugins/file_manager.py index 24a59d5..8fbf397 100644 --- a/plugins/file_manager.py +++ b/plugins/file_manager.py @@ -146,9 +146,9 @@ class Plugin: dirs = sum(1 for x in items if x[0] == 'dir') files = len(items) - dirs - result = [f"📁 {path}", "─" * 50] + result = [f" {path}", "─" * 50] for t, name, size in items[:100]: - result.append(f" {'📁' if t == 'dir' else '📄'} {name}{'/' if t == 'dir' else f' ({size})'}") + result.append(f" {'' if t == 'dir' else ''} {name}{'/' if t == 'dir' else f' ({size})'}") if len(items) > 100: result.append(f" ... 还有 {len(items) - 100} 项") result.append("─" * 50) @@ -189,11 +189,11 @@ class Plugin: if i < max_lines: lines.append(f"{i+1:4d} | {line.rstrip()}") content = '\n'.join(lines) - header = f"📄 {file_path} ({size}B, 前 {min(max_lines, total)}/{total} 行)" + header = f" {file_path} ({size}B, 前 {min(max_lines, total)}/{total} 行)" else: all_lines = f.readlines() content = '\n'.join(f"{i+1:4d} | {l.rstrip()}" for i, l in enumerate(all_lines)) - header = f"📄 {file_path} ({size}B, {len(all_lines)} 行)" + header = f" {file_path} ({size}B, {len(all_lines)} 行)" return f"{header}\n{'─' * 50}\n{content}" except UnicodeDecodeError: @@ -214,7 +214,7 @@ class Plugin: os.makedirs(os.path.dirname(fp) or ".", exist_ok=True) with open(fp, 'w', encoding='utf-8') as f: f.write(content) - return f"✅ 已写入: {fp} ({len(content)} 字符)" + return f" 已写入: {fp} ({len(content)} 字符)" def _op_append(self, args: List[str]) -> str: if len(args) < 2: @@ -232,7 +232,7 @@ class Plugin: return f"错误:文件不存在: {fp}" with open(fp, 'a', encoding='utf-8') as f: f.write(content) - return f"✅ 已追加: {fp}" + return f" 已追加: {fp}" def _op_copy(self, args: List[str]) -> str: if len(args) < 2: @@ -245,7 +245,7 @@ class Plugin: shutil.copy2(src, dst) else: shutil.copytree(src, dst, dirs_exist_ok=True) - return f"✅ 已复制:\n {src}\n → {dst}" + return f" 已复制:\n {src}\n → {dst}" def _op_move(self, args: List[str]) -> str: if len(args) < 2: @@ -255,7 +255,7 @@ class Plugin: return f"错误:源不存在: {src}" os.makedirs(os.path.dirname(dst) or ".", exist_ok=True) shutil.move(src, dst) - return f"✅ 已移动:\n {src}\n → {dst}" + return f" 已移动:\n {src}\n → {dst}" def _op_delete(self, args: List[str]) -> str: if not args: @@ -266,14 +266,14 @@ class Plugin: return f"错误:不存在: {path}" if os.path.isfile(path): os.remove(path) - return f"✅ 已删除文件: {path}" + return f" 已删除文件: {path}" elif os.path.isdir(path): if recursive: shutil.rmtree(path) - return f"✅ 已删除目录: {path}" + return f" 已删除目录: {path}" elif not os.listdir(path): os.rmdir(path) - return f"✅ 已删除空目录: {path}" + return f" 已删除空目录: {path}" else: return "错误:目录不为空,用 -r 递归删除" @@ -346,4 +346,4 @@ class Plugin: if os.path.exists(path): return f"错误:已存在: {path}" os.makedirs(path, exist_ok=True) - return f"✅ 已创建: {path}" + return f" 已创建: {path}" diff --git a/plugins/frontend_tester.py b/plugins/frontend_tester.py index c65abeb..1ec777b 100644 --- a/plugins/frontend_tester.py +++ b/plugins/frontend_tester.py @@ -29,12 +29,12 @@ JSON格式示例: - analyze <项目路径> - 分析整个前端项目的结构和问题 支持的检查项: -✓ HTML语法验证 -✓ CSS语法和兼容性检查 -✓ JavaScript语法检查 -✓ 响应式设计检查 -✓ 可访问性检查 -✓ 性能优化建议""" + HTML语法验证 + CSS语法和兼容性检查 + JavaScript语法检查 + 响应式设计检查 + 可访问性检查 + 性能优化建议""" self.cli = None def set_cli(self, cli): @@ -138,13 +138,13 @@ JSON格式示例: def _validate_html(self, file_path): """验证HTML文件""" if not os.path.exists(file_path): - return f"❌ 文件不存在: {file_path}" + return f" 文件不存在: {file_path}" try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() - result = f"\n🧪 HTML验证结果: {file_path}\n" + result = f"\n HTML验证结果: {file_path}\n" result += "=" * 60 + "\n\n" # 基本检查 @@ -191,7 +191,7 @@ JSON格式示例: link_count = content.count(' 3: result += f" • ... 还有 {len(js_files) - 3} 个文件\n" - result += f"\n{Fore.GREEN}✅ 分析完成{Style.RESET_ALL}\n" + result += f"\n{Fore.GREEN} 分析完成{Style.RESET_ALL}\n" result += "\n" + "=" * 60 + "\n" return result except Exception as e: - return f"❌ 分析失败: {str(e)}" + return f" 分析失败: {str(e)}" # 测试函数 diff --git a/plugins/git_tools.py b/plugins/git_tools.py index 06e6f48..b06606f 100644 --- a/plugins/git_tools.py +++ b/plugins/git_tools.py @@ -164,7 +164,7 @@ class Plugin: if not output: # 获取分支 _, branch = self._run_git(["branch", "--show-current"], cwd) - return f"✅ 工作区干净 (分支: {branch})" + return f" 工作区干净 (分支: {branch})" lines = output.split('\n') staged, unstaged, untracked = [], [], [] @@ -174,14 +174,14 @@ class Plugin: continue s, filename = line[:2], line[3:] if s[0] in 'MADRC': - staged.append(f" ✓ {s[0]} {filename}") + staged.append(f" {s[0]} {filename}") if s[1] in 'MD': unstaged.append(f" ! {s[1]} {filename}") if s == '??': untracked.append(f" ? {filename}") _, branch = self._run_git(["branch", "--show-current"], cwd) - result = [f"📊 Git 状态 (分支: {branch})"] + result = [f" Git 状态 (分支: {branch})"] if staged: result.append(f"\n已暂存 ({len(staged)}):") @@ -237,22 +237,22 @@ class Plugin: if not target: return "错误:请提供文件路径(使用 . 暂存所有)" ok, output = self._run_git(["add", target], cwd) - return f"✅ 已暂存: {target}" if ok else f"Git add 失败: {output}" + return f" 已暂存: {target}" if ok else f"Git add 失败: {output}" def _commit(self, args: str, cwd=None) -> str: message = args.strip() if not message: return "错误:请提供提交信息" ok, output = self._run_git(["commit", "-m", message], cwd) - return f"✅ 提交成功:\n{output}" if ok else f"Git commit 失败: {output}" + return f" 提交成功:\n{output}" if ok else f"Git commit 失败: {output}" def _branch(self, args: str, cwd=None) -> str: if not args.strip(): ok, output = self._run_git(["branch", "-a"], cwd) - return f"🌿 分支列表:\n{output}" if ok else f"Git 错误: {output}" + return f" 分支列表:\n{output}" if ok else f"Git 错误: {output}" else: ok, output = self._run_git(["branch", args.strip()], cwd) - return f"✅ 已创建分支: {args.strip()}" if ok else f"创建分支失败: {output}" + return f" 已创建分支: {args.strip()}" if ok else f"创建分支失败: {output}" def _checkout(self, args: str, cwd=None) -> str: args = args.strip() @@ -262,14 +262,14 @@ class Plugin: else: branch = args ok, output = self._run_git(["checkout", branch], cwd) - return f"✅ 已切换到: {branch}" if ok else f"切换失败: {output}" + return f" 已切换到: {branch}" if ok else f"切换失败: {output}" def _stash(self, args: str, cwd=None) -> str: if args.strip() == "pop": ok, output = self._run_git(["stash", "pop"], cwd) else: ok, output = self._run_git(["stash"], cwd) - return f"✅ {output}" if ok else f"Git stash 失败: {output}" + return f" {output}" if ok else f"Git stash 失败: {output}" def _show(self, args: str, cwd=None) -> str: commit = args.strip() or "HEAD" @@ -301,7 +301,7 @@ class Plugin: result = result[:100] result.append(f" ... (共 {len(result)} 行)") - return f"📝 {path} 修改记录:\n" + '\n'.join(result) + return f" {path} 修改记录:\n" + '\n'.join(result) def _remote(self, cwd=None) -> str: ok, output = self._run_git(["remote", "-v"], cwd) @@ -312,7 +312,7 @@ class Plugin: def _init(self, args: str, cwd=None) -> str: path = args.strip() or "." ok, output = self._run_git(["init", path], cwd) - return f"✅ {output}" if ok else f"Git init 失败: {output}" + return f" {output}" if ok else f"Git init 失败: {output}" def _clone(self, args: str, cwd=None) -> str: parts = args.split() @@ -322,7 +322,7 @@ class Plugin: if len(parts) > 1: cmd.append(parts[1]) ok, output = self._run_git(cmd, cwd) - return f"✅ 克隆成功:\n{output}" if ok else f"Git clone 失败: {output}" + return f" 克隆成功:\n{output}" if ok else f"Git clone 失败: {output}" # ── 工作流 ── @@ -330,7 +330,7 @@ class Plugin: """智能提交:自动 add + 规范化消息""" ok, status = self._run_git(["status", "--porcelain"], cwd) if not status: - return "✅ 工作区干净,没有需要提交的变更" + return " 工作区干净,没有需要提交的变更" self._run_git(["add", "-A"], cwd) @@ -349,8 +349,8 @@ class Plugin: ok, output = self._run_git(["commit", "-m", message], cwd) if ok: _, hash_out = self._run_git(["log", "--oneline", "-1"], cwd) - return f"✅ 已提交: {message}\n {hash_out}" - return f"❌ 提交失败: {output}" + return f" 已提交: {message}\n {hash_out}" + return f" 提交失败: {output}" def _auto_commit_message(self, status: str) -> str: lines = status.strip().split('\n') @@ -371,7 +371,7 @@ class Plugin: ok, output = self._run_shell( 'git log --oneline --format="%s" | head -50', cwd) if not ok: - return f"❌ {output}" + return f" {output}" commits = output.strip().split('\n') categories = { @@ -390,9 +390,9 @@ class Plugin: categories['other'].append(commit) labels = { - 'feat': '🚀 新增', 'fix': '🐛 修复', 'docs': '📝 文档', - 'refactor': '♻️ 重构', 'test': '🧪 测试', 'chore': '🔧 杂项', - 'other': '📦 其他' + 'feat': ' 新增', 'fix': ' 修复', 'docs': ' 文档', + 'refactor': ' 重构', 'test': ' 测试', 'chore': ' 杂项', + 'other': ' 其他' } ver = version or "未发布" @@ -409,16 +409,16 @@ class Plugin: def _summary(self, cwd=None) -> str: ok, output = self._run_git(["diff", "--stat"], cwd) if not output: - return "✅ 没有未提交的变更" + return " 没有未提交的变更" _, short = self._run_git(["diff", "--shortstat"], cwd) - return f"📊 变更摘要:\n\n{short}\n\n{output[:2000]}" + return f" 变更摘要:\n\n{short}\n\n{output[:2000]}" def _contributors(self, cwd=None) -> str: ok, output = self._run_git(["shortlog", "-sn", "--all", "--no-merges"], cwd) if not ok: - return f"❌ {output}" + return f" {output}" lines = output.strip().split('\n') - result = [f"👥 贡献者 ({len(lines)} 人):\n"] + result = [f" 贡献者 ({len(lines)} 人):\n"] for line in lines[:20]: result.append(f" {line.strip()}") return '\n'.join(result) @@ -427,4 +427,4 @@ class Plugin: days = int(args) if args.strip().isdigit() else 90 ok, output = self._run_shell( f"git log --diff-filter=A --format='%aI %n' --since='{days} days ago' | head -20", cwd) - return f"📁 最近 {days} 天新增的文件:\n{output[:2000]}" if ok else f"❌ {output}" + return f" 最近 {days} 天新增的文件:\n{output[:2000]}" if ok else f" {output}" diff --git a/plugins/speech_recognition.py b/plugins/speech_recognition.py index 2454c6b..439b7cb 100644 --- a/plugins/speech_recognition.py +++ b/plugins/speech_recognition.py @@ -177,7 +177,7 @@ class VoiceRecorder: def _create_ui(self): # 标题 - title_label = tk.Label(self.root, text="🎙️ 语音识别录音", font=("Arial", 18, "bold")) + title_label = tk.Label(self.root, text=" 语音识别录音", font=("Arial", 18, "bold")) title_label.pack(pady=15) # 状态标签 @@ -194,7 +194,7 @@ class VoiceRecorder: # 开始/停止按钮 self.record_btn = tk.Button( - btn_frame, text="🎤 开始录音", font=("Arial", 12), + btn_frame, text=" 开始录音", font=("Arial", 12), width=12, height=2, command=self.toggle_record, bg="#4CAF50", fg="white", cursor="hand2" ) @@ -202,7 +202,7 @@ class VoiceRecorder: # 识别按钮 self.recognize_btn = tk.Button( - btn_frame, text="📝 识别", font=("Arial", 12), + btn_frame, text=" 识别", font=("Arial", 12), width=12, height=2, command=self.recognize, bg="#2196F3", fg="white", cursor="hand2", state=tk.DISABLED ) @@ -231,8 +231,8 @@ class VoiceRecorder: self.is_recording = True self.frames = [] self.start_time = time.time() - self.record_btn.config(text="⏹️ 停止录音", bg="#f44336") - self.status_label.config(text="🔴 正在录音...", fg="red") + self.record_btn.config(text=" 停止录音", bg="#f44336") + self.status_label.config(text=" 正在录音...", fg="red") self.recognize_btn.config(state=tk.DISABLED) CHUNK = 1024 @@ -263,7 +263,7 @@ class VoiceRecorder: def stop_record(self): self.is_recording = False - self.record_btn.config(text="🎤 开始录音", bg="#4CAF50") + self.record_btn.config(text=" 开始录音", bg="#4CAF50") self.status_label.config(text="录音完成,可以识别", fg="green") self.recognize_btn.config(state=tk.NORMAL) @@ -286,7 +286,7 @@ class VoiceRecorder: wf.close() self.result_text.delete(1.0, tk.END) - self.result_text.insert(tk.END, "✅ 录音已保存\n点击 [识别] 按钮进行语音识别") + self.result_text.insert(tk.END, " 录音已保存\n点击 [识别] 按钮进行语音识别") def _update_time(self): if self.is_recording: @@ -303,7 +303,7 @@ class VoiceRecorder: self.status_label.config(text="正在识别...", fg="blue") self.result_text.delete(1.0, tk.END) - self.result_text.insert(tk.END, "🔍 识别中,请稍候...") + self.result_text.insert(tk.END, " 识别中,请稍候...") self.root.update() # 尝试识别 @@ -317,7 +317,7 @@ class VoiceRecorder: with open(RESULT_FILE, "w", encoding="utf-8") as f: f.write(result) else: - self.result_text.insert(tk.END, "❌ 识别失败\n\n请安装识别引擎:\n• pip install openai-whisper\n• pip install SpeechRecognition") + self.result_text.insert(tk.END, " 识别失败\n\n请安装识别引擎:\n• pip install openai-whisper\n• pip install SpeechRecognition") self.status_label.config(text="识别失败", fg="red") def _do_recognize(self): @@ -330,7 +330,7 @@ class VoiceRecorder: result = model.transcribe(self.record_file, language="zh") text = result.get("text", "").strip() if text: - return f"✅ {{text}}" + return f" {{text}}" except Exception as e: print(f"Whisper error: {{e}}") @@ -344,7 +344,7 @@ class VoiceRecorder: audio = r.record(source) text = r.recognize_google(audio, language="zh-CN") if text: - return f"✅ {{text}}" + return f" {{text}}" except Exception as e: print(f"SpeechRecognition error: {{e}}") @@ -374,9 +374,9 @@ if __name__ == "__main__": try: subprocess.Popen([sys.executable, recorder_script], creationflags=subprocess.CREATE_NEW_CONSOLE) - return "🎙️ 已弹出录音窗口,请在窗口中进行录音和识别\n\n使用方法:\n1. 点击「开始录音」\n2. 对着麦克风说话\n3. 点击「停止录音」\n4. 点击「识别」获取文字结果" + return " 已弹出录音窗口,请在窗口中进行录音和识别\n\n使用方法:\n1. 点击「开始录音」\n2. 对着麦克风说话\n3. 点击「停止录音」\n4. 点击「识别」获取文字结果" except Exception as e: - return f"❌ 启动录音窗口失败: {e}" + return f" 启动录音窗口失败: {e}" # ==================== 文件识别 ==================== @@ -388,7 +388,7 @@ if __name__ == "__main__": file_path = args[0] if not os.path.exists(file_path): - return f"❌ 文件不存在: {file_path}" + return f" 文件不存在: {file_path}" return self._recognize_file(file_path) @@ -407,7 +407,7 @@ if __name__ == "__main__": self._save_result(result) return result - return "❌ 语音识别失败:未安装识别引擎\n\n安装方法:\n1. Whisper (推荐): pip install openai-whisper\n2. SpeechRecognition: pip install SpeechRecognition\n3. PyAudio (录音): pip install pyaudio" + return " 语音识别失败:未安装识别引擎\n\n安装方法:\n1. Whisper (推荐): pip install openai-whisper\n2. SpeechRecognition: pip install SpeechRecognition\n3. PyAudio (录音): pip install pyaudio" def _save_result(self, result: str): """保存识别结果""" @@ -428,7 +428,7 @@ if __name__ == "__main__": text = result.get("text", "").strip() if text: - return f"✅ 识别结果:\n{text}" + return f" 识别结果:\n{text}" return None except ImportError: @@ -456,7 +456,7 @@ if __name__ == "__main__": try: text = r.recognize_google(audio, language="zh-CN") if text: - return f"✅ 识别结果:\n{text}" + return f" 识别结果:\n{text}" except: pass @@ -502,28 +502,28 @@ if __name__ == "__main__": def _op_status(self, args: List[str]) -> str: """查看状态""" - lines = ["📊 语音识别插件状态"] + lines = [" 语音识别插件状态"] # 检查可用引擎 engines = [] try: import whisper - engines.append("whisper ✅") + engines.append("whisper ") except: - engines.append("whisper ❌ (pip install openai-whisper)") + engines.append("whisper (pip install openai-whisper)") try: import speech_recognition - engines.append("speech_recognition ✅") + engines.append("speech_recognition ") except: - engines.append("speech_recognition ❌ (pip install SpeechRecognition)") + engines.append("speech_recognition (pip install SpeechRecognition)") try: import pyaudio - engines.append("pyaudio ✅ (录音支持)") + engines.append("pyaudio (录音支持)") except: - engines.append("pyaudio ❌ (pip install pyaudio)") + engines.append("pyaudio (pip install pyaudio)") lines.append("\n可用引擎:") for e in engines: diff --git a/plugins/sub_agent.py b/plugins/sub_agent.py index a0c4a9c..27c97ff 100644 --- a/plugins/sub_agent.py +++ b/plugins/sub_agent.py @@ -177,7 +177,7 @@ class Plugin: thread = threading.Thread(target=self._run_agent, args=(agent,), daemon=True) thread.start() - return (f"✅ 已创建子 Agent\n" + return (f" 已创建子 Agent\n" f" ID: {agent_id}\n" f" 名称: {name}\n" f" 任务: {task}\n" @@ -333,17 +333,17 @@ class Plugin: failed = [a for a in self.agents.values() if a.status == "failed"] if running: - result.append(f"🟢 运行中 ({len(running)}):") + result.append(f" 运行中 ({len(running)}):") for a in running: result.append(f" {a.id} [{a.name}] 步骤:{a.steps} 任务:{a.task[:40]}") if done: - result.append(f"✅ 已完成 ({len(done)}):") + result.append(f" 已完成 ({len(done)}):") for a in done: result.append(f" {a.id} [{a.name}] 任务:{a.task[:40]}") if failed: - result.append(f"❌ 失败 ({len(failed)}):") + result.append(f" 失败 ({len(failed)}):") for a in failed: result.append(f" {a.id} [{a.name}] 错误:{a.error[:40] if a.error else '?'}") @@ -432,7 +432,7 @@ class Plugin: thread = threading.Thread(target=self._process_message, args=(agent, message), daemon=True) thread.start() - return f"✅ 消息已发送给 {agent.id}" + return f" 消息已发送给 {agent.id}" def _process_message(self, agent: SubAgent, message: str): """处理发送给子 Agent 的消息""" @@ -482,7 +482,7 @@ class Plugin: agent.status = "failed" agent.error = "被主 Agent 终止" agent.finished_at = datetime.now().strftime("%H:%M:%S") - return f"✅ 已终止 {agent.id}" + return f" 已终止 {agent.id}" def _clean(self, args: str) -> str: """清理已完成的 Agent""" @@ -492,7 +492,7 @@ class Plugin: for aid in to_remove: del self.agents[aid] - return f"✅ 已清理 {len(to_remove)} 个已完成的 Agent" + return f" 已清理 {len(to_remove)} 个已完成的 Agent" def _stats(self, args: str) -> str: """统计信息""" @@ -503,7 +503,7 @@ class Plugin: failed = sum(1 for a in self.agents.values() if a.status == "failed") total_steps = sum(a.steps for a in self.agents.values()) - return (f"📊 子 Agent 统计\n" + return (f" 子 Agent 统计\n" f" 总数: {total}\n" f" 运行中: {running}\n" f" 已完成: {done}\n" diff --git a/plugins/task_manager.py b/plugins/task_manager.py index 149f6f7..90afe15 100644 --- a/plugins/task_manager.py +++ b/plugins/task_manager.py @@ -170,14 +170,14 @@ JSON格式示例: error = self._save_tasks() if error: return error - return f"✅ 已添加任务 #{task_id}: {description}" + return f" 已添加任务 #{task_id}: {description}" def _list_tasks(self): """列出所有任务""" if not self.tasks: - return "📝 当前没有任务" + return " 当前没有任务" - result = f"\n📋 任务列表 (共 {len(self.tasks)} 个任务)\n" + result = f"\n 任务列表 (共 {len(self.tasks)} 个任务)\n" result += "=" * 50 + "\n" pending_count = 0 @@ -193,25 +193,25 @@ JSON格式示例: # 统计 if status == 'pending': pending_count += 1 - status_icon = "⏳" + status_icon = "" status_color = Fore.YELLOW elif status == 'in_progress': in_progress_count += 1 - status_icon = "🔄" + status_icon = "" status_color = Fore.CYAN elif status == 'completed': completed_count += 1 - status_icon = "✅" + status_icon = "" status_color = Fore.GREEN else: - status_icon = "❌" + status_icon = "" status_color = Fore.RED result += f"{status_icon} [{task_id}] {status_color}{status}{Style.RESET_ALL} - {description}\n" result += f" 创建时间: {created_at}\n\n" result += "=" * 50 + "\n" - result += f"📊 统计: {Fore.YELLOW}待处理 {pending_count}{Style.RESET_ALL} | {Fore.CYAN}进行中 {in_progress_count}{Style.RESET_ALL} | {Fore.GREEN}已完成 {completed_count}{Style.RESET_ALL}\n" + result += f" 统计: {Fore.YELLOW}待处理 {pending_count}{Style.RESET_ALL} | {Fore.CYAN}进行中 {in_progress_count}{Style.RESET_ALL} | {Fore.GREEN}已完成 {completed_count}{Style.RESET_ALL}\n" return result @@ -226,9 +226,9 @@ JSON格式示例: error = self._save_tasks() if error: return error - return f"✅ 任务 #{task_id} 状态已更新: {old_status} → {new_status}" + return f" 任务 #{task_id} 状态已更新: {old_status} → {new_status}" - return f"❌ 未找到任务ID: {task_id}" + return f" 未找到任务ID: {task_id}" def _delete_task(self, task_id): """删除任务""" @@ -238,21 +238,21 @@ JSON格式示例: error = self._save_tasks() if error: return error - return f"🗑️ 已删除任务 #{task_id}: {deleted_task.get('task', '')}" + return f" 已删除任务 #{task_id}: {deleted_task.get('task', '')}" - return f"❌ 未找到任务ID: {task_id}" + return f" 未找到任务ID: {task_id}" def _clear_completed(self): """清除所有已完成的任务""" completed_count = len([t for t in self.tasks if t.get('status') == 'completed']) if completed_count == 0: - return "📝 没有已完成的任务需要清除" + return " 没有已完成的任务需要清除" self.tasks = [t for t in self.tasks if t.get('status') != 'completed'] error = self._save_tasks() if error: return error - return f"✅ 已清除 {completed_count} 个已完成的任务" + return f" 已清除 {completed_count} 个已完成的任务" # 测试函数 diff --git a/skills/code_stats.py b/skills/code_stats.py index 7981d89..64c8326 100644 --- a/skills/code_stats.py +++ b/skills/code_stats.py @@ -106,7 +106,7 @@ class CodeStatsSkill(Skill): comment_rate = (total_comment / max(total_code, 1)) * 100 report_lines = [ - f"📊 代码统计 ({directory})", + f" 代码统计 ({directory})", f"{'─' * 40}", f" 文件数: {total_files}", f" 总行数: {total_lines}", @@ -117,7 +117,7 @@ class CodeStatsSkill(Skill): ] if file_details: - report_lines.append(f"\n📄 文件明细 (按代码行数排序):") + report_lines.append(f"\n 文件明细 (按代码行数排序):") for fd in file_details[:20]: report_lines.append( f" {fd['file']:40} {fd['code']:5} 行代码" diff --git a/skills/file-manager/SKILL.md b/skills/file-manager/SKILL.md index 7210cd1..aa5e0ef 100644 --- a/skills/file-manager/SKILL.md +++ b/skills/file-manager/SKILL.md @@ -148,7 +148,7 @@ del filename.txt rmdir /s /q directory_name ``` -⚠️ **Warning**: Deletion is permanent. Always confirm before deleting. + **Warning**: Deletion is permanent. Always confirm before deleting. ### Copy File or Directory diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 585a241..b34b718 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -134,7 +134,7 @@ class TestCodeEditor: def test_structure(self, editor, tmp_path): result = editor.handle(f"structure {tmp_path} 1") - assert "📁" in result + assert "" in result def test_find(self, editor, tmp_path): (tmp_path / "a.py").write_text("x = 1\ny = 2\n") diff --git a/xcli_core/cli_core.py b/xcli_core/cli_core.py index f5e224c..1d0218f 100644 --- a/xcli_core/cli_core.py +++ b/xcli_core/cli_core.py @@ -853,8 +853,8 @@ multi 操作支持一次修改多处: # 无参数:循环切换 safety.cycle_mode() mode_name = safety.get_mode_name() - icons = {"无限制": "🔴", "普通": "🟢", "人工确认": "🟡"} - icon = icons.get(mode_name, "⚪") + icons = {"无限制": "", "普通": "", "人工确认": ""} + icon = icons.get(mode_name, "") print(f"{icon} 安全模式: {mode_name}") continue @@ -880,7 +880,7 @@ multi 操作支持一次修改多处: response_lines = processed_response.split('\n') for i, line in enumerate(response_lines): if i == 0: - line = "✦ " + line + line = " " + line if i == len(response_lines) - 1: print(f"{line} {user_id_display}") else: diff --git a/xcli_core/cli_display.py b/xcli_core/cli_display.py index 619331a..bc0a4e2 100644 --- a/xcli_core/cli_display.py +++ b/xcli_core/cli_display.py @@ -56,7 +56,7 @@ class DisplayMixin: else: for i, line in enumerate(response_lines): if i == 0: - prefix = f"{Fore.YELLOW}✦{Style.RESET_ALL} " if is_continue else "✦ " + prefix = f"{Fore.YELLOW}{Style.RESET_ALL} " if is_continue else " " line = prefix + line if i == len(response_lines) - 1: print(f"{line} {user_id_display}") @@ -207,7 +207,7 @@ class DisplayMixin: print(''.join(line)) - print(f"{Fore.GREEN}✓ 已使用色块显示 ({new_width}x{new_height} 像素){Style.RESET_ALL}\n") + print(f"{Fore.GREEN} 已使用色块显示 ({new_width}x{new_height} 像素){Style.RESET_ALL}\n") return True except ImportError: @@ -223,7 +223,7 @@ class DisplayMixin: subprocess.run(['open', image_path]) else: subprocess.run(['xdg-open', image_path]) - print(f"{Fore.GREEN}✓ 已在系统默认图片查看器中打开{Style.RESET_ALL}\n") + print(f"{Fore.GREEN} 已在系统默认图片查看器中打开{Style.RESET_ALL}\n") return True except Exception as e: diff --git a/xcli_core/cli_tools.py b/xcli_core/cli_tools.py index 26d512c..1cc1524 100644 --- a/xcli_core/cli_tools.py +++ b/xcli_core/cli_tools.py @@ -98,7 +98,7 @@ class ToolMixin: safety = get_safety() allowed, msg = safety.check(tool_name, str(args)) if not allowed: - return {"result": f"🚫 已取消: {msg}"} + return {"result": f" 已取消: {msg}"} if UNIFIED_TOOL_MANAGER_AVAILABLE and hasattr(self.liugin_manager, 'execute'): if arguments and isinstance(arguments, dict): diff --git a/xcli_core/safety.py b/xcli_core/safety.py index f21eeed..ab07a90 100644 --- a/xcli_core/safety.py +++ b/xcli_core/safety.py @@ -263,7 +263,7 @@ class SafetyLayer: print() print(f" {Fore.RED}{'═' * 50}{Style.RESET_ALL}") - print(f" {Fore.RED}⚠️ 安全检查{Style.RESET_ALL}") + print(f" {Fore.RED} 安全检查{Style.RESET_ALL}") print(f" {Fore.RED}{'═' * 50}{Style.RESET_ALL}") print(f" {Fore.CYAN}工具:{Style.RESET_ALL} {tool_name}") print(f" {Fore.CYAN}指令:{Style.RESET_ALL} {display_args}") diff --git a/xcli_core/tui.py b/xcli_core/tui.py index ddf9618..5dca007 100644 --- a/xcli_core/tui.py +++ b/xcli_core/tui.py @@ -129,7 +129,7 @@ if TEXTUAL_AVAILABLE: class XiaoliTUI(App): """小狸 TUI v2 - GitHub 暗色主题""" CSS = _TUI_CSS - TITLE = "🐱 小狸 Pro-CLI" + TITLE = " 小狸 Pro-CLI" SUB_TITLE = "智能编程助手" BINDINGS = [ @@ -163,13 +163,13 @@ if TEXTUAL_AVAILABLE: id="input-hint" ) with Vertical(id="sidebar"): - yield Static("⚙️ 引擎", classes="sidebar-header") + yield Static(" 引擎", classes="sidebar-header") yield Vertical(id="engine-list", classes="sidebar-section") yield Rule(line_style="heavy") - yield Static("🔧 工具", classes="sidebar-header") + yield Static(" 工具", classes="sidebar-header") yield Vertical(id="tool-list", classes="sidebar-section") yield Rule(line_style="heavy") - yield Static("📊 状态", classes="sidebar-header") + yield Static(" 状态", classes="sidebar-header") yield Vertical(id="status-info", classes="sidebar-section") yield Static(" 就绪 | Ctrl+C 退出", id="status-bar") @@ -184,14 +184,14 @@ if TEXTUAL_AVAILABLE: ("", "msg-dim"), (" ╔══════════════════════════════════════════════╗", "msg-welcome"), (" ║ ║", "msg-welcome"), - (" ║ 🐱 小狸 Pro-CLI v5.1 ║", "msg-welcome"), - (" ║ 智能编程助手 · 对标 Claude Code ║", "msg-welcome"), + (" ║ 小狸 Pro-CLI v5.1 ║", "msg-welcome"), + (" ║ 智能编程助手 ║", "msg-welcome"), (" ║ ║", "msg-welcome"), (" ╚══════════════════════════════════════════════╝", "msg-welcome"), ("", "msg-dim"), - (" 💡 代码编辑 · 代码搜索 · Git 集成 · 多引擎", "msg-system"), - (" 📝 输入 /help 查看命令 | /model 切换引擎", "msg-system"), - (f" 🔧 当前引擎: {self.bridge.current_engine()} | 工具: {len(self.bridge.tools())} 个", "msg-system"), + (" 代码编辑 · 代码搜索 · Git 集成 · 多引擎", "msg-system"), + (" 输入 /help 查看命令 | /model 切换引擎", "msg-system"), + (f" 当前引擎: {self.bridge.current_engine()} | 工具: {len(self.bridge.tools())} 个", "msg-system"), ("", "msg-dim"), ] for text, cls in lines: @@ -233,13 +233,13 @@ if TEXTUAL_AVAILABLE: self._append(Static(text, classes=cls)) def _user_msg(self, text): - self._add(f" 👤 {text}", "msg-user") + self._add(f" {text}", "msg-user") def _ai_msg(self, text): if "```" in text: self._render_with_code(text) else: - self._add(f" ✦ {text}", "msg-ai") + self._add(f" {text}", "msg-ai") def _render_with_code(self, text): parts = re.split(r'```(\w*)\n(.*?)```', text, flags=re.DOTALL) @@ -248,7 +248,7 @@ if TEXTUAL_AVAILABLE: if i % 3 == 0: if parts[i].strip(): for line in parts[i].strip().split('\n'): - self._add(f" ✦ {line}", "msg-ai") + self._add(f" {line}", "msg-ai") elif i % 3 == 2: code = parts[i] lang = parts[i-1] if i > 1 else "" @@ -263,19 +263,19 @@ if TEXTUAL_AVAILABLE: i += 1 def _tool_ok(self, name, args): - self._add(f" ✅ {name}: {args[:60]}", "msg-tool-ok") + self._add(f" {name}: {args[:60]}", "msg-tool-ok") def _tool_err(self, name, args): - self._add(f" ❌ {name}: {args[:60]}", "msg-tool-err") + self._add(f" {name}: {args[:60]}", "msg-tool-err") def _thinking(self): - self._add(" 💭 思考中...", "msg-thinking") + self._add(" 思考中...", "msg-thinking") def _system(self, text): - self._add(f" ℹ️ {text}", "msg-system") + self._add(f" ℹ {text}", "msg-system") def _error(self, text): - self._add(f" ⚠️ {text}", "msg-error") + self._add(f" {text}", "msg-error") @on(Input.Submitted, "#user-input") def on_input(self, event): @@ -291,7 +291,7 @@ if TEXTUAL_AVAILABLE: self._user_msg(text) self._thinking() self.is_generating = True - self._update_status("🔄 思考中...") + self._update_status(" 思考中...") self.run_worker(self._generate(text), exclusive=True) def _handle_command(self, cmd): @@ -309,7 +309,7 @@ if TEXTUAL_AVAILABLE: 'cls': lambda: self.action_clear(), 'model': lambda: self._switch_model(args), 'engine': lambda: self._switch_model(args), - 'about': lambda: self._system("🐱 小狸 Pro-CLI v5.1 - 智能编程助手"), + 'about': lambda: self._system(" 小狸 Pro-CLI v5.1 - 智能编程助手"), 'status': lambda: self._show_status(), 'tools': lambda: self._show_tools(), 'engines': lambda: self._show_engines(), @@ -331,7 +331,7 @@ if TEXTUAL_AVAILABLE: self._error(f"未知命令: /{name},输入 /help 查看帮助") def _show_help(self): - help_text = """ 📖 命令: + help_text = """ 命令: /help 帮助信息 /quit 退出 /cli 切换命令行模式 @@ -341,7 +341,7 @@ if TEXTUAL_AVAILABLE: /status 系统状态 /clear 清屏 - ⌨️ 快捷键: + ⌨ 快捷键: Ctrl+C 退出 Ctrl+L 清屏 Ctrl+N 新对话 F1 侧栏 Escape 取消生成""" @@ -425,11 +425,11 @@ if TEXTUAL_AVAILABLE: pass def _write_raw(self, msg): - if '✅' in msg or 'OK 工具' in msg: + if '' in msg or 'OK 工具' in msg: self._add(f" {msg}", "msg-tool-ok") - elif '❌' in msg or 'X 工具' in msg or '错误' in msg: + elif '' in msg or 'X 工具' in msg or '错误' in msg: self._add(f" {msg}", "msg-tool-err") - elif '✦' in msg: + elif '' in msg: self._add(f" {msg}", "msg-ai") elif '工具' in msg and ('调用' in msg or '执行' in msg): self._add(f" {msg}", "msg-tool-ok")