chore: 移除所有 emoji 及对标文案

- 删除全部文件中的 emoji 字符(29 个文件)
- 移除 tui.py 中「对标 Claude Code」表述
- 保持代码缩进和格式不变
This commit is contained in:
xiaoli-bot committed 2026-04-26 12:35:27 +08:00
1 parent 40ab129ba2
commit 29df2a4ac1
29 files changed
+365 -365

No files matched your search

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