3 Commits
Author SHA1 Message Date
OpenClaw 245413b2cd release: v5.1.3 — 图像生成 + 记忆系统插件 + 横评页面
- 新增 image_generator 插件(ComfyUI 在线生图)
- 新增 memory_plugin 插件(包装记忆系统供 AI 调用)
- 新增 compare.html 7工具横评页面
- 更新 README.md 全面重写(MCP/Clawli/记忆/通知/定时任务)
- 更新 CHANGELOG.md 新增 v5.1.3 条目
- 更新 about.txt 版本号至 5.1.3
- 插件数: 15 → 17, 操作数: 141 → 141+
2026-04-28 03:37:37 +08:00
OpenClaw 3fa1d56632 feat: 新增图像生成插件 + 记忆系统插件 + 7工具横评页面
- plugins/image_generator.py: 基于 ai.2x.nz ComfyUI 的图像生成插件
  - 自然语言/Tag 双模式,支持中文描述
  - WebSocket 实时进度,28 个角色工作流
  - 分辨率可调(最大 1344x1344)

- plugins/memory_plugin.py: 包装 xcli_core/memory.py 的记忆插件
  - AI 可写日记、读日记、搜索日记
  - 全局搜索(MEMORY + 日记 + 聊天记录)
  - 自动保存对话 + 上下文压缩
  - 长期记忆 MEMORY.md 管理

- compare.html: 7 款 AI 编程助手横评页面
  - Claude Code / Codex CLI / Gemini CLI / Aider / Copilot CLI / 小狸 / TG HELPER
  - 25+ 维度功能对比 + 评分 + 场景推荐

- .gitignore: 排除运行时生成的记忆数据和图片
2026-04-28 03:13:53 +08:00
shuiyu1123 62aa5ed128 docs: v5.1.2 竞品实力对比分析页面 2026-04-27 01:14:49 +08:00
8 changed files with 2242 additions and 44 deletions

No files matched your search

+8
View File
@@ -36,6 +36,14 @@ Thumbs.db
# 嵌入式 Python # 嵌入式 Python
embedded_python/ embedded_python/
# 记忆系统数据(运行时生成)
MEMORY.md
memory/
# 生成的图片
generated_*.png
screenshots/gen_*.png
# 临时文件 # 临时文件
*.tmp *.tmp
*.bak *.bak
+23
View File
@@ -4,6 +4,29 @@
--- ---
## v5.1.3 (2026-04-28)
### 新增功能
- **图像生成插件** (`image_generator`) — 基于 ai.2x.nz 的 ComfyUI 在线服务,自然语言/Tag 双模式,支持中文描述,28 个角色工作流可选,分辨率可调(最大 1344×1344)
- **记忆系统插件** (`memory_plugin`) — 包装 `xcli_core/memory.py` 的完整记忆工具,AI 可写日记、读日记、搜索记忆、管理聊天记录、操作长期记忆 MEMORY.md
- **AI 编程助手横评页面** (`compare.html`) — 7 款工具(Claude Code / Codex CLI / Gemini CLI / Aider / Copilot CLI / 小狸 / TG HELPER)25+ 维度同口径对比
### 修复
- 修复记忆系统插件(`Liugin` 类在 `xcli_core/memory.py` 中定义但未被插件管理器加载)导致 AI 无法调用记忆工具的问题,新增 `plugins/memory_plugin.py` 包装层
### 文档
- 全面更新 README.md 至 v5.1.3
- 新增记忆系统、Clawli 远程模式、MCP 协议支持、定时任务、系统通知等功能说明
- 更新插件列表:15 个 → 17 个(+image_generator, +memory_plugin)
- 更新操作数:141 → 141+
- 补充 MCP 协议支持说明(17 个插件全部实现 MCP 定义)
- 补充插件开发文档中 `Liugin` / `Plugin` 双协议说明
### 贡献者
- 感谢 **艾轮 卧壳** 对本版本的贡献 🖤
---
## v5.1.2 (2026-04-26) ## v5.1.2 (2026-04-26)
### 新增功能 ### 新增功能
+112 -42
View File
@@ -1,14 +1,16 @@
# 小狸 Pro-CLI # 小狸 Pro-CLI
<p align="center"> <p align="center">
<strong>智能编程助手 — 代码编辑 · Git 集成 · 浏览器自动化 · 多 Agent 协作</strong> <strong>智能编程助手 — 代码编辑 · Git 集成 · 浏览器自动化 · 多 Agent 协作 · 图像生成 · 记忆系统</strong>
</p> </p>
<p align="center"> <p align="center">
<img src="https://img.shields.io/badge/version-5.1.2-blue" alt="version"> <img src="https://img.shields.io/badge/version-5.1.3-blue" alt="version">
<img src="https://img.shields.io/badge/python-3.10+-green" alt="python"> <img src="https://img.shields.io/badge/python-3.10+-green" alt="python">
<img src="https://img.shields.io/badge/license-MIT-orange" alt="license"> <img src="https://img.shields.io/badge/license-MIT-orange" alt="license">
<img src="https://img.shields.io/badge/tests-113%20passed-brightgreen" alt="tests"> <img src="https://img.shields.io/badge/tests-113%20passed-brightgreen" alt="tests">
<img src="https://img.shields.io/badge/plugins-17-blueviolet" alt="plugins">
<img src="https://img.shields.io/badge/MCP-supported-brightgreen" alt="mcp">
</p> </p>
--- ---
@@ -21,7 +23,13 @@
- **浏览器自动化** — Playwright 驱动,导航/交互/截图/JS 执行/PDF - **浏览器自动化** — Playwright 驱动,导航/交互/截图/JS 执行/PDF
- **子 Agent 系统** — 多 Agent 并行协作,独立任务分配与结果回收 - **子 Agent 系统** — 多 Agent 并行协作,独立任务分配与结果回收
- **统一安全层** — AI 风险识别 + 三模式切换(普通/人工/无限制) - **统一安全层** — AI 风险识别 + 三模式切换(普通/人工/无限制)
- **15 个插件 141 个操作** — 代码编辑、Git、浏览器、工程化、文件管理、任务管理等 - **图像生成** — 基于 ComfyUI 在线服务,自然语言/Tag 双模式,支持中文描述
- **记忆系统** — 长期记忆 + 每日日记 + AI 写日记 + 全局搜索 + 自动保存对话
- **Clawli 远程模式** — PC-手机 WebSocket 双向通信,支持内网穿透代理
- **定时任务** — 支持相对时间、绝对时间、重复任务,到期自动激活 AI
- **系统通知** — 跨平台任务完成通知(Windows / macOS / Linux)
- **MCP 协议** — 17 个插件全部实现 MCP 定义,支持 Function Calling 原生调用
- **17 个插件 141+ 个操作** — 代码编辑、Git、浏览器、工程化、文件管理、图像生成、记忆等
- **三模式界面** — TUI 图形化 + 传统命令行 + **Web UI 浏览器界面** - **三模式界面** — TUI 图形化 + 传统命令行 + **Web UI 浏览器界面**
- **113 个自动化测试** — pytest 覆盖全部插件和核心模块 - **113 个自动化测试** — pytest 覆盖全部插件和核心模块
@@ -43,6 +51,9 @@ python ai_cli.py
# 指定引擎 # 指定引擎
python ai_cli.py --engine openai python ai_cli.py --engine openai
# Windows 一键启动(无需 Python 环境)
launcher.exe
``` ```
## AI 引擎 ## AI 引擎
@@ -76,17 +87,17 @@ python ai_cli.py --engine openai
} }
``` ```
## 插件列表 (15 个) ## 插件列表 (17 个)
### 核心生产力 ### 核心生产力
| 插件 | 操作数 | 说明 | | 插件 | 操作数 | 说明 |
|------|--------|------| |------|--------|------|
| `code_editor` | 23 | 代码编辑+搜索。精准替换、批量编辑、find/regex/symbols/imports/callers/todo/structure + 自动语法检查 | | `code_editor` | 24 | 代码编辑+搜索。精准替换、批量编辑、find/regex/symbols/imports/callers/todo/structure + 自动语法检查 + diff 弹窗 |
| `git_tools` | 20 | Git 版本控制。status/diff/log/commit/branch + smart-commit/changelog/contributors | | `git_tools` | 17 | Git 版本控制。status/diff/log/commit/branch + smart-commit/changelog/contributors/stale |
| `cmd_executor` | 1 | Shell 命令执行。跨平台,超时控制,危险命令拦截 | | `cmd_executor` | 1 | Shell 命令执行。跨平台,超时控制,危险命令拦截 |
| `file_manager` | 11 | 文件系统。list/read/write/copy/move/delete/search/info/mkdir | | `file_manager` | 10 | 文件系统。list/read/write/copy/move/delete/search/info/mkdir/append |
| `auto_engineer` | 16 | 工程化。lint/format/test/build/deps + 复杂度/安全扫描/质量指标 | | `auto_engineer` | 12 | 工程化。lint/format/test/build/deps + 复杂度/安全扫描/质量指标/项目初始化 |
| `task_manager` | 7 | 任务管理。add/list/complete/delete/clear,JSON 持久化 | | `task_manager` | 7 | 任务管理。add/list/complete/delete/clear,JSON 持久化 |
### 高级功能 ### 高级功能
@@ -94,7 +105,10 @@ python ai_cli.py --engine openai
| 插件 | 操作数 | 说明 | | 插件 | 操作数 | 说明 |
|------|--------|------| |------|--------|------|
| `sub_agent` | 8 | 子 Agent 系统。spawn/list/status/result/send/kill,多 Agent 并行协作 | | `sub_agent` | 8 | 子 Agent 系统。spawn/list/status/result/send/kill,多 Agent 并行协作 |
| `browser_auto` | 31 | 浏览器自动化。导航/点击/填写/截图/JS执行/PDF/cookies(基于 Playwright) | | `browser_auto` | 28 | 浏览器自动化。导航/点击/填写/截图/JS执行/PDF/cookies(基于 Playwright) |
| `image_generator` | 7 | **图像生成**。基于 ComfyUI 在线服务,自然语言/Tag 双模式,28 个角色工作流 |
| `memory_plugin` | 11 | **记忆系统**。AI 写日记/搜索记忆/管理聊天记录/长期记忆 MEMORY.md |
| `scheduler` | 4 | **定时任务**。支持相对时间/绝对时间/重复任务,到期自动激活 AI |
| `tool_search` | — | 工具搜索。按关键词发现可用插件(供 AI 按需调用) | | `tool_search` | — | 工具搜索。按关键词发现可用插件(供 AI 按需调用) |
### 辅助工具 ### 辅助工具
@@ -104,10 +118,43 @@ python ai_cli.py --engine openai
| `network_tools` | 网络工具。ping/get/status/headers/ip | | `network_tools` | 网络工具。ping/get/status/headers/ip |
| `ai_search` | AI 搜索。jina.ai 智能搜索 + 网页内容提取 | | `ai_search` | AI 搜索。jina.ai 智能搜索 + 网页内容提取 |
| `frontend_tester` | 前端测试。HTML/CSS/JS 语法检查、响应式验证 | | `frontend_tester` | 前端测试。HTML/CSS/JS 语法检查、响应式验证 |
| `speech_recognition` | 语音识别。录音 + 语音转文字 | | `speech_recognition` | 语音识别。录音 + 语音转文字(Whisper) |
| `audio_player` | 音频播放 | | `audio_player` | 音频播放 |
| `send_image` | Clawli 模式下发图片到手机 | | `send_image` | Clawli 模式下发图片到手机 |
## 记忆系统
内置持久化记忆系统,AI 可以记住之前的工作:
| 功能 | 说明 |
|------|------|
| 长期记忆 | `MEMORY.md` — AI 自己维护的精华记忆 |
| 每日日记 | `memory/YYYY-MM-DD.md` — 带时间戳和标签 |
| AI 写日记 | `memory_plugin diary_ai` — 自动标记 [AI观察] |
| 自动保存对话 | 每轮对话后自动存 JSON |
| 上下文压缩 | 超过 50 条自动 AI 总结,保留最近 10 条 |
| 全局搜索 | 搜索 MEMORY + 日记 + 聊天记录 |
```
memory_plugin diary 今天完成了API对接
memory_plugin search 定时任务
memory_plugin remember 用户偏好深色主题
memory_plugin chat_search 图像生成
```
## Clawli 远程模式
通过 WebSocket 实现 PC-手机双向通信:
```bash
/remote start 9079 mypassword # 启动本地服务
/remote proxy relay.example.com # 通过中继服务器穿透内网
/remote stop # 停止服务
/remote status # 查看状态
```
功能:手机发消息给 AI、AI 回复推到手机、文件传输、图片识别。
## 安全机制 ## 安全机制
### 三模式切换 (`/safe`) ### 三模式切换 (`/safe`)
@@ -137,19 +184,33 @@ python ai_cli.py --engine openai
- 子进程隔离执行 - 子进程隔离执行
- 内存限制 - 内存限制
## MCP 协议支持
所有 17 个插件均实现 MCP (Model Context Protocol) 定义,支持三种工具调用协议:
| 协议 | 说明 |
|------|------|
| **MCP** | Model Context Protocol 标准定义 |
| **FC** | OpenAI Function Calling 原生调用 |
| **JSON** | 传统 `{"action": "use_tool", ...}` 格式 |
`fc_tools.py` 自动将 MCP 定义转换为 OpenAI FC 格式,支持混合响应解析。
## 命令列表 ## 命令列表
| 命令 | 说明 | | 命令 | 说明 |
|------|------| |------|------|
| `/help` | 显示帮助 | | `/help` | 显示帮助 |
| `/safe` | 切换安全模式(普通→人工→无限制) | | `/safe` | 切换安全模式(普通→人工→无限制) |
| `/safe off` | 直接切换到无限制模式 |
| `/safe manual` | 直接切换到人工确认模式 |
| `/engine list` | 列出可用引擎 | | `/engine list` | 列出可用引擎 |
| `/engine switch <引擎>` | 切换引擎 | | `/engine switch <引擎>` | 切换引擎 |
| `/engine.openai models` | 列出 OpenAI 引擎模型 | | `/engine.openai models` | 列出 OpenAI 引擎模型 |
| `/chat save/list/open` | 聊天记录管理 | | `/chat save/list/open` | 聊天记录管理 |
| `/file.read <路径>` | 读取文件 | | `/file.read <路径>` | 读取文件 |
| `/remote` | Clawli 远程连接帮助 |
| `/notify` | 切换任务完成通知 |
| `/scheduler` / `/remind` | 管理定时任务 |
| `/memory` | 管理记忆系统 |
| `/tui` | 切换 TUI 模式 | | `/tui` | 切换 TUI 模式 |
| `/quit` | 退出 | | `/quit` | 退出 |
@@ -158,70 +219,64 @@ python ai_cli.py --engine openai
纯静态 HTML 界面,无需后端,浏览器直接打开。 纯静态 HTML 界面,无需后端,浏览器直接打开。
```bash ```bash
# 直接用浏览器打开
open webui.html # macOS open webui.html # macOS
xdg-open webui.html # Linux xdg-open webui.html # Linux
start webui.html # Windows start webui.html # Windows
``` ```
### 功能
| 功能 | 说明 |
|------|------|
| 对话界面 | 聊天气泡、快捷指令、打字动画 |
| 代码编辑器 | 行号显示、Tab 缩进、Ctrl+S 保存、语法高亮 |
| 文件浏览 | 侧栏项目文件树,点击查看 |
| ️ 系统状态 | 插件/操作/引擎/测试统计 |
| 引擎面板 | Ollama / OpenAI 引擎一览 |
| 工具面板 | 15 个插件及操作数一览 |
| 日志面板 | 系统操作实时记录 |
## 项目结构 ## 项目结构
``` ```
xiaoli-cli/ xiaoli-cli/
├── ai_cli.py # 主入口 ├── ai_cli.py # 主入口
├── webui.html # Web UI 界面 (纯静态 HTML) ├── webui.html # Web UI 界面 (纯静态 HTML)
├── launcher.py # 智能启动器 ├── launcher.py # 智能启动器(自动检测环境/安装依赖)
├── config.json.example # 配置模板 ├── config.json.example # 配置模板
├── easter_egg.py # 彩蛋
│ │
├── xcli_core/ # 核心模块 ├── xcli_core/ # 核心模块
│ ├── cli_core.py # 主循环 + 提示词构建 │ ├── cli_core.py # 主循环 + 提示词构建
│ ├── cli_base.py # 初始化 + 引擎/插件加载 │ ├── cli_base.py # 初始化 + 引擎/插件加载
│ ├── cli_tools.py # 工具调用执行 │ ├── cli_tools.py # 工具调用执行(支持 MCP/FC/JSON)
│ ├── cli_clawli.py # Clawli 远程模式
│ ├── cli_code_exec.py # 代码沙箱执行
│ ├── cli_display.py # 显示输出 │ ├── cli_display.py # 显示输出
│ ├── cli_history.py # 聊天记录 │ ├── cli_history.py # 聊天记录
│ ├── cli_code_exec.py # 代码执行
│ ├── config.py # 配置管理 │ ├── config.py # 配置管理
│ ├── constants.py # 常量定义 │ ├── constants.py # 常量定义
│ ├── safety.py # 统一安全层 │ ├── fc_tools.py # MCP → FC 格式转换
│ ├── sandbox.py # 代码安全沙箱 │ ├── memory.py # 记忆系统(长期记忆+日记+搜索+压缩)
│ ├── plugin_manager.py # 插件管理器 │ ├── notification.py # 跨平台系统通知
│ └── tui.py # TUI 界面 │ ├── plugin_manager.py # 插件管理器(Liugin/Plugin 双协议)
│ ├── safety.py # 统一安全层(AI 风险分析)
│ ├── sandbox.py # 代码安全沙箱(AST 级检测)
│ └── tui.py # TUI 界面(Textual + 动画)
│ │
├── ai_engines/ # AI 引擎 ├── ai_engines/ # AI 引擎
│ ├── ollama_engine.py # Ollama 本地模型 │ ├── ollama_engine.py # Ollama 本地模型
│ └── openai_engine.py # OpenAI 兼容格式 │ └── openai_engine.py # OpenAI 兼容格式
│ │
├── plugins/ # 插件 (15 个) ├── plugins/ # 插件 (17 个)
│ ├── code_editor.py # 代码编辑+搜索 │ ├── code_editor.py # 代码编辑+搜索 (24 操作)
│ ├── git_tools.py # Git 版本控制 │ ├── git_tools.py # Git 版本控制 (17 操作)
│ ├── cmd_executor.py # Shell 命令执行 │ ├── cmd_executor.py # Shell 命令执行
│ ├── file_manager.py # 文件管理 │ ├── file_manager.py # 文件管理 (10 操作)
│ ├── auto_engineer.py # 工程化自动化 │ ├── auto_engineer.py # 工程化自动化 (12 操作)
│ ├── task_manager.py # 任务管理 │ ├── task_manager.py # 任务管理
│ ├── sub_agent.py # 子 Agent 系统 │ ├── sub_agent.py # 子 Agent 系统 (8 操作)
│ ├── browser_auto.py # 浏览器自动化 │ ├── browser_auto.py # 浏览器自动化 (28 操作)
│ ├── image_generator.py # 图像生成 (7 操作) ⭐ NEW
│ ├── memory_plugin.py # 记忆系统 (11 操作) ⭐ NEW
│ ├── scheduler.py # 定时任务
│ ├── tool_search.py # 工具搜索 │ ├── tool_search.py # 工具搜索
│ ├── network_tools.py # 网络工具 │ ├── network_tools.py # 网络工具
│ ├── ai_search.py # AI 搜索 │ ├── ai_search.py # AI 搜索
│ ├── frontend_tester.py # 前端测试 │ ├── frontend_tester.py # 前端测试
│ ├── speech_recognition.py # 语音识别 │ ├── speech_recognition.py # 语音识别
│ ├── audio_player.py # 音频播放
│ └── send_image.py # 图片发送 │ └── send_image.py # 图片发送
│ │
├── skills/ # 技能 (Skill 协议) ├── skills/ # 技能 (Skill 协议)
├── image_engine/ # 图像识别引擎 ├── image_engine/ # 图像识别引擎(Ollama 视觉模型)
├── tests/ # 测试套件 (113 用例) ├── tests/ # 测试套件 (113 用例)
├── love.txt # 彩蛋情话 ├── love.txt # 彩蛋情话
└── about.txt # 关于信息 └── about.txt # 关于信息
@@ -239,8 +294,10 @@ python -c "import py_compile; py_compile.compile('ai_cli.py', doraise=True)"
## 插件开发 ## 插件开发
小狸支持 `Liugin`(自研协议)和 `Plugin`(通用协议)两种类名,均可被插件管理器自动识别:
```python ```python
class Plugin: class Plugin: # 或 class Liugin
"""我的插件""" """我的插件"""
def __init__(self): def __init__(self):
@@ -258,6 +315,18 @@ class Plugin:
"usage": self.usage "usage": self.usage
} }
def get_mcp_definition(self):
return {
"name": "my_tool",
"description": "工具描述",
"inputSchema": {
"type": "object",
"properties": {
"args": {"type": "string", "description": "参数"}
}
}
}
def handle(self, args: str) -> str: def handle(self, args: str) -> str:
return "处理结果" return "处理结果"
``` ```
@@ -271,3 +340,4 @@ class Plugin:
- Gitee: https://gitee.com/shuiyu1123/xiaoli-cli - Gitee: https://gitee.com/shuiyu1123/xiaoli-cli
- [更新日志](CHANGELOG.md) - [更新日志](CHANGELOG.md)
- [使用指南](HELP.md) - [使用指南](HELP.md)
- [AI 编程助手横评](compare.html)
+2 -2
View File
@@ -1,7 +1,7 @@
**产品标识** **产品标识**
- **产品名称**:小狸智能体 增强-终端(Xiaoli Pro-CLI) - **产品名称**:小狸智能体 增强-终端(Xiaoli Pro-CLI)
- **内部版本号**:20260426 - **内部版本号**:20260428
- **发布版本**:发行版5.1.1 - **发布版本**:发行版5.1.3
**技术规格** **技术规格**
- **主要语言**:简体中文(UTF-8) - **主要语言**:简体中文(UTF-8)
+1161
View File
File diff suppressed because it is too large. Load diff
+370
View File
@@ -0,0 +1,370 @@
"""
图像生成插件 - 基于 ai.2x.nz 的 ComfyUI 在线服务
支持自然语言描述和英文 Tag 两种模式
"""
import os
import json
import asyncio
import urllib.request
import time
from typing import Optional
class Plugin:
"""图像生成工具 — 自然语言/Tag 生图,基于 ComfyUI 在线服务"""
def __init__(self):
self.usage = """图像生成工具 — 基于 ai.2x.nz 的 ComfyUI 在线服务
操作:
generate <描述> - 自然语言描述生成图片(中文/英文均可)
tag <英文tags> - 直接 Tag 模式(逗号分隔的英文标签)
list - 列出可用的工作流/角色
status - 查看 GPU 状态
示例:
image_generator generate 一个白发蓝眼的猫耳少女在写代码
image_generator tag masterpiece, 1girl, white hair, blue eyes, cat ears, coding
image_generator generate 画一个赛博朋克风格的城市夜景 --width 1024 --height 768
说明:
- 自然语言模式会经过 LLM 翻译为 Tag,效果更好
- 直接 Tag 模式适合熟悉 Danbooru 标签的用户
- 默认分辨率 1024x1344(WAI 推荐)
- 最大分辨率 1344x1344
- 生成的图片保存在 screenshots/ 目录
"""
self.cli = None
self.api_base = "https://ai.2x.nz"
self.ws_url = "wss://ai.2x.nz/ws/run"
self.default_workflow = "WAI - 无Lora.json"
self.output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "screenshots")
def set_cli(self, cli):
self.cli = cli
def get_tool_info(self):
return {
"name": "image_generator",
"description": "图像生成 — 自然语言/Tag 生图,基于 ComfyUI 在线服务(ai.2x.nz),支持中文描述",
"keywords": ["图像", "生成", "画图", "绘图", "AI画", "生图", "image", "generate", "draw", "paint",
"diffusion", "comfyui", "stable", "sd", "文生图", "text2img"],
"usage": self.usage
}
def handle(self, args: str) -> str:
try:
parts = args.strip().split(maxsplit=1)
if not parts:
return "错误:请提供操作类型\n\n" + self.usage
op = parts[0].lower()
rest = parts[1] if len(parts) > 1 else ""
handlers = {
"generate": self._generate,
"tag": self._generate_tag,
"gen": self._generate,
"g": self._generate,
"list": self._list_workflows,
"ls": self._list_workflows,
"status": self._gpu_status,
}
handler = handlers.get(op)
if not handler:
# 如果没有指定操作,把整个 args 当作自然语言描述
return self._generate(args)
return handler(rest)
except Exception as e:
return f"图像生成错误: {e}"
def _generate(self, args: str) -> str:
"""自然语言模式生成图片"""
# 解析 --width 和 --height 参数
width, height = 1024, 1344
prompt = args.strip()
if "--width" in prompt or "--height" in prompt or "--w" in prompt or "--h" in prompt:
import re
w_match = re.search(r'--w(?:idth)?\s+(\d+)', prompt)
h_match = re.search(r'--h(?:eight)?\s+(\d+)', prompt)
if w_match:
width = int(w_match.group(1))
prompt = prompt[:w_match.start()] + prompt[w_match.end():]
if h_match:
height = int(h_match.group(1))
prompt = prompt[:h_match.start()] + prompt[h_match.end():]
prompt = prompt.strip()
if not prompt:
return "错误:请提供图片描述\n示例: image_generator generate 一个白发猫耳少女"
# 限制分辨率
width = min(width, 1344)
height = min(height, 1344)
return self._run_generation(prompt, "", width, height, rewrite=True, override=False)
def _generate_tag(self, args: str) -> str:
"""直接 Tag 模式"""
width, height = 1024, 1344
prompt = args.strip()
if "--width" in prompt or "--height" in prompt or "--w" in prompt or "--h" in prompt:
import re
w_match = re.search(r'--w(?:idth)?\s+(\d+)', prompt)
h_match = re.search(r'--h(?:eight)?\s+(\d+)', prompt)
if w_match:
width = int(w_match.group(1))
prompt = prompt[:w_match.start()] + prompt[w_match.end():]
if h_match:
height = int(h_match.group(1))
prompt = prompt[:h_match.start()] + prompt[h_match.end():]
prompt = prompt.strip()
if not prompt:
return "错误:请提供 Tag\n示例: image_generator tag masterpiece, 1girl, white hair, blue eyes"
width = min(width, 1344)
height = min(height, 1344)
return self._run_generation("", prompt, width, height, rewrite=False, override=False)
def _run_generation(self, nl_prompt: str, direct_prompt: str, width: int, height: int,
rewrite: bool = False, override: bool = False) -> str:
"""执行图像生成(同步包装)"""
try:
import websocket as ws_lib
except ImportError:
# 回退:用 urllib 的方式不行,WebSocket 必须用专用库
# 尝试用 subprocess 调用 python 脚本
return self._run_generation_subprocess(nl_prompt, direct_prompt, width, height, rewrite, override)
try:
start_time = time.time()
ws = ws_lib.create_connection(self.ws_url, timeout=180)
payload = {
"workflow_path": self.default_workflow,
"inline_workflow": None,
"direct_prompt": direct_prompt,
"nl_prompt": nl_prompt,
"rewrite": rewrite,
"override": override,
"width": width,
"height": height,
}
ws.send(json.dumps(payload))
image_path = None
final_prompt = ""
error_msg = ""
while True:
try:
raw = ws.recv()
data = json.loads(raw)
msg_type = data.get("type", "")
if msg_type == "image":
url = data.get("url", "")
filename = data.get("filename", "")
if url:
image_path = self._download_image(url, filename)
elif msg_type == "final_prompt":
final_prompt = data.get("final_prompt", "") if isinstance(data.get("final_prompt"), str) else data.get("prompt", "")
elif msg_type == "done":
break
elif msg_type == "error":
error_msg = data.get("message", "未知错误")
break
except Exception as e:
error_msg = str(e)
break
ws.close()
elapsed = time.time() - start_time
if error_msg:
return f" 生成失败: {error_msg}"
if image_path:
size = os.path.getsize(image_path)
size_str = f"{size/1024:.0f}KB" if size < 1024*1024 else f"{size/1024/1024:.1f}MB"
result = f" 图片生成成功!\n"
result += f" 路径: {image_path}\n"
result += f" 大小: {size_str}\n"
result += f" 分辨率: {width}x{height}\n"
result += f"⏱ 耗时: {elapsed:.1f}s\n"
if final_prompt:
result += f" Prompt: {final_prompt[:120]}...\n"
result += f"\n💡 提示: 用 'send_image {image_path}' 可以推送到手机"
return result
else:
return " 生成完成但未收到图片数据"
except Exception as e:
return f" 连接失败: {e}\n💡 请检查网络连接或稍后重试"
def _run_generation_subprocess(self, nl_prompt: str, direct_prompt: str, width: int, height: int,
rewrite: bool, override: bool) -> str:
"""用子进程执行 WebSocket 生成(无需 websocket 库)"""
import subprocess
import tempfile
script = f'''
import json, asyncio, urllib.request, os, sys
async def main():
try:
import websockets
except ImportError:
print("ERROR:需要安装 websockets: pip install websockets")
sys.exit(1)
uri = "wss://ai.2x.nz/ws/run"
async with websockets.connect(uri) as ws:
payload = {{
"workflow_path": "{self.default_workflow}",
"inline_workflow": None,
"direct_prompt": {json.dumps(direct_prompt)},
"nl_prompt": {json.dumps(nl_prompt)},
"rewrite": {"true" if rewrite else "false"},
"override": {"true" if override else "false"},
"width": {width},
"height": {height},
}}
await ws.send(json.dumps(payload))
image_url = None
while True:
try:
msg = await asyncio.wait_for(ws.recv(), timeout=180)
data = json.loads(msg)
t = data.get("type", "")
if t == "image":
image_url = data.get("url", "")
elif t == "done":
break
elif t == "error":
print(f"ERROR:{{data.get('message','')}}")
break
except asyncio.TimeoutError:
print("ERROR:超时")
break
if image_url:
full_url = f"https://ai.2x.nz{{image_url}}"
out_path = os.path.join("{self.output_dir}", f"generated_{{os.path.basename(image_url)}}")
os.makedirs(os.path.dirname(out_path), exist_ok=True)
urllib.request.urlretrieve(full_url, out_path)
print(f"OK:{{out_path}}")
asyncio.run(main())
'''
script_path = os.path.join(self.output_dir, "_gen_temp.py")
os.makedirs(self.output_dir, exist_ok=True)
with open(script_path, 'w') as f:
f.write(script)
try:
result = subprocess.run(
["python3", script_path],
capture_output=True, text=True, timeout=200
)
output = result.stdout.strip()
if output.startswith("OK:"):
image_path = output[3:]
size = os.path.getsize(image_path)
size_str = f"{size/1024:.0f}KB" if size < 1024*1024 else f"{size/1024/1024:.1f}MB"
res = f" 图片生成成功!\n"
res += f" 路径: {image_path}\n"
res += f" 大小: {size_str}\n"
res += f" 分辨率: {width}x{height}\n"
res += f"\n💡 提示: 用 'send_image {image_path}' 可以推送到手机"
return res
elif output.startswith("ERROR:"):
return f" {output[6:]}"
else:
return f" 生成异常:\n{result.stdout}\n{result.stderr}"
except subprocess.TimeoutExpired:
return " 生成超时(>200s),请稍后重试"
finally:
try:
os.remove(script_path)
except:
pass
def _download_image(self, url: str, filename: str) -> str:
"""下载生成的图片"""
full_url = f"{self.api_base}{url}"
os.makedirs(self.output_dir, exist_ok=True)
out_path = os.path.join(self.output_dir, f"gen_{filename}")
urllib.request.urlretrieve(full_url, out_path)
return out_path
def _list_workflows(self, args: str) -> str:
"""列出可用的工作流"""
try:
import urllib.request
req = urllib.request.Request(f"{self.api_base}/api/workflows")
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
workflows = data.get("workflows", [])
result = f" 可用工作流 ({len(workflows)} 个):\n\n"
lora_workflows = []
no_lora = []
for w in workflows:
name = w.get("path", "")
if "无Lora" in name or "no" in name.lower():
no_lora.append(name)
else:
lora_workflows.append(name)
if no_lora:
result += " 通用(无角色绑定):\n"
for w in no_lora:
result += f" • {w}\n"
if lora_workflows:
result += "\n 角色工作流:\n"
for w in lora_workflows:
result += f" • {w}\n"
result += "\n💡 使用 'image_generator generate <描述>' 自然语言生图"
result += "\n💡 使用 'image_generator tag <tags>' 直接 Tag 生图"
return result
except Exception as e:
return f" 获取工作流列表失败: {e}"
def _gpu_status(self, args: str) -> str:
"""查看 GPU 状态"""
try:
import urllib.request
req = urllib.request.Request(f"{self.api_base}/api/gpu")
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
result = " 服务器 GPU 状态:\n"
for gpu in data.get("gpus", []):
name = gpu.get("name", "未知")
util = gpu.get("utilization", 0)
mem_used = gpu.get("memory_used", 0)
mem_total = gpu.get("memory_total", 0)
temp = gpu.get("temperature", 0)
result += f" {name}\n"
result += f" GPU 负载: {util}%\n"
result += f" 显存: {mem_used}/{mem_total} MiB\n"
result += f" 温度: {temp}°C\n"
return result
except Exception as e:
return f" 获取 GPU 状态失败: {e}"
+185
View File
@@ -0,0 +1,185 @@
"""
记忆系统插件 — 包装 xcli_core/memory.py 中的 MemoryManager
使 AI 可以通过工具接口读写日记、搜索记忆、管理聊天记录
"""
import os
import sys
# 添加项目根目录到 path
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(current_dir)
sys.path.insert(0, project_root)
from xcli_core.memory import MemoryManager
class Plugin:
"""持久化记忆系统 — AI 可写日记、搜索记忆、管理聊天记录"""
def __init__(self):
self.cli = None
self.memory = None
self.usage = """持久化记忆系统工具
操作:
diary <内容> - 写当日日记
diary_ai <内容> - AI 写观察日记(标记为 AI 观察)
remember <内容> - 记录到长期记忆 (MEMORY.md)
search <关键词> - 全局搜索(日记+记忆+聊天记录)
context - 查看当前注入的记忆上下文
diary_list - 列出所有日记文件
diary_read <日期> - 读取指定日期的日记(如 2026-04-27)
chat_list - 列出最近的聊天记录
chat_search <关键词> - 在聊天记录中搜索
memory_read - 读取 MEMORY.md 长期记忆
memory_write <内容> - 写入 MEMORY.md(追加)
JSON 格式示例:
{"action": "use_tool", "tool": "memory_plugin", "args": "diary 今天完成了API对接"}
{"action": "use_tool", "tool": "memory_plugin", "args": "search 定时任务"}
{"action": "use_tool", "tool": "memory_plugin", "args": "remember 用户偏好深色主题"}
"""
def set_cli(self, cli):
self.cli = cli
# 初始化 MemoryManager
project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.memory = MemoryManager(project_dir)
# 挂载到 cli 实例上,让 cli_core.py 能访问
cli.memory_manager = self.memory
def get_tool_info(self):
return {
"name": "memory_plugin",
"description": "持久化记忆系统 — AI 可写日记、记录长期记忆、搜索历史对话和日记。支持自动压缩上下文。",
"keywords": ["记忆", "memory", "日记", "diary", "搜索", "search", "历史", "history",
"remember", "聊天记录", "chat", "上下文", "context", "压缩", "compress"],
"usage": self.usage
}
def handle(self, args: str) -> str:
if not self.memory:
return "错误:记忆系统未初始化"
if not args or not args.strip():
return self._help()
parts = args.strip().split(None, 1)
action = parts[0].lower()
rest = parts[1].strip() if len(parts) > 1 else ""
handlers = {
"diary": self._diary,
"diary_ai": self._diary_ai,
"remember": self._remember,
"search": self._search,
"context": self._context,
"diary_list": self._diary_list,
"diary_read": self._diary_read,
"chat_list": self._chat_list,
"chat_search": self._chat_search,
"memory_read": self._memory_read,
"memory_write": self._memory_write,
"help": lambda _: self._help(),
}
handler = handlers.get(action)
if not handler:
return f"未知操作: {action}\n" + self._help()
return handler(rest)
def _diary(self, content: str) -> str:
if not content:
return "错误:请提供日记内容\n用法: diary <内容>"
self.memory.write_diary(content)
return f" 日记已写入 {self.memory._today_file()}"
def _diary_ai(self, content: str) -> str:
if not content:
return "错误:请提供 AI 观察内容\n用法: diary_ai <内容>"
self.memory.write_ai_diary(content)
return f" AI 观察日记已写入"
def _remember(self, content: str) -> str:
if not content:
return "错误:请提供要记住的内容\n用法: remember <内容>"
self.memory.append_memory("备忘", f"- {content}")
return f" 已记录到 MEMORY.md 长期记忆"
def _search(self, keyword: str) -> str:
if not keyword:
return "错误:请提供搜索关键词\n用法: search <关键词>"
results = self.memory.search_memory(keyword)
if not results:
return f" 未找到与 '{keyword}' 相关的记忆"
lines = [f" 搜索 '{keyword}' 的结果 ({len(results)} 条):"]
for r in results:
source = r.get("source", "")
snippet = r.get("snippet", "")
role = r.get("role", "")
line_num = r.get("line", "")
prefix = f"[{role}] " if role else ""
line_info = f" (L{line_num})" if line_num else ""
lines.append(f" {source}{line_info}: {prefix}{snippet}")
return "\n".join(lines)
def _context(self, _: str) -> str:
ctx = self.memory.build_memory_context()
return ctx if ctx else " 当前没有记忆上下文"
def _diary_list(self, _: str) -> str:
files = self.memory.list_diary_files()
if not files:
return " 还没有日记文件"
return " 日记文件:\n" + "\n".join(f" {f}" for f in files[:20])
def _diary_read(self, date_str: str) -> str:
if not date_str:
return "错误:请提供日期\n用法: diary_read <日期,如 2026-04-27>"
content = self.memory.load_diary(date_str)
return content if content else f" 没有找到 {date_str} 的日记"
def _chat_list(self, _: str) -> str:
chats = self.memory.list_chats()
if not chats:
return " 没有保存的聊天记录"
lines = [" 最近的聊天记录:"]
for c in chats:
lines.append(f" {c['name']} ({c['time']}, {c['size_kb']}KB)")
return "\n".join(lines)
def _chat_search(self, keyword: str) -> str:
if not keyword:
return "错误:请提供关键词\n用法: chat_search <关键词>"
results = self.memory.search_chats(keyword)
if not results:
return f" 未在聊天记录中找到 '{keyword}'"
lines = [f" 聊天记录搜索 '{keyword}':"]
for r in results:
lines.append(f" {r['file']} [{r['role']}]: {r['snippet']}")
return "\n".join(lines)
def _memory_read(self, _: str) -> str:
content = self.memory.load_memory()
return content if content else " MEMORY.md 为空"
def _memory_write(self, content: str) -> str:
if not content:
return "错误:请提供内容\n用法: memory_write <内容>"
self.memory.append_memory("备忘", f"- {content}")
return f" 已写入 MEMORY.md"
def _help(self) -> str:
return """ 记忆系统用法:
diary <内容> - 写当日日记
diary_ai <内容> - AI 写观察日记
remember <内容> - 记到长期记忆 (MEMORY.md)
search <关键词> - 全局搜索记忆
context - 查看记忆上下文
diary_list - 列出日记
diary_read <日期> - 读取日记
chat_list - 列出聊天记录
chat_search <关键词> - 搜索聊天记录
memory_read - 读取 MEMORY.md
memory_write <内容> - 写入 MEMORY.md"""
+381
View File
@@ -0,0 +1,381 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小狸 Pro-CLI v5.1.2 · 竞品实力对比</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#06080d;--bg2:#0d1117;--bg3:#161b22;--border:#21262d;--txt:#e6edf3;--dim:#8b949e;--mute:#484f58;--blue:#58a6ff;--purple:#bc8cff;--cyan:#39d2c0;--green:#3fb950;--red:#f85149;--yellow:#d29922;--orange:#f0883e}
body{background:var(--bg);color:var(--txt);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;line-height:1.7}
/* ── Hero ── */
.hero{text-align:center;padding:80px 20px 50px;background:linear-gradient(180deg,#0d1117 0%,#06080d 100%);position:relative;overflow:hidden}
.hero::before{content:'';position:absolute;top:0;left:50%;width:600px;height:600px;transform:translateX(-50%);background:radial-gradient(circle,rgba(88,166,255,.08) 0%,transparent 70%);pointer-events:none}
.hero h1{font-size:2.6em;font-weight:800;background:linear-gradient(135deg,#58a6ff,#bc8cff,#39d2c0);-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:8px}
.hero .sub{color:var(--dim);font-size:1.1em;margin-bottom:24px}
.hero .tags{display:flex;justify-content:center;gap:10px;flex-wrap:wrap}
.tag{padding:5px 14px;border-radius:20px;font-size:.82em;font-weight:600;border:1px solid}
.tag-b{background:rgba(88,166,255,.1);color:var(--blue);border-color:rgba(88,166,255,.25)}
.tag-p{background:rgba(188,140,255,.1);color:var(--purple);border-color:rgba(188,140,255,.25)}
.tag-g{background:rgba(63,185,80,.1);color:var(--green);border-color:rgba(63,185,80,.25)}
.tag-c{background:rgba(57,210,192,.1);color:var(--cyan);border-color:rgba(57,210,192,.25)}
.tag-y{background:rgba(210,153,34,.1);color:var(--yellow);border-color:rgba(210,153,34,.25)}
.container{max-width:1100px;margin:0 auto;padding:0 24px}
section{padding:56px 0;border-bottom:1px solid rgba(33,38,45,.5)}
section:last-child{border:none}
h2{font-size:1.7em;margin-bottom:6px;background:linear-gradient(90deg,var(--blue),var(--cyan));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
h2 .em{-webkit-text-fill-color:initial}
.sec-desc{color:var(--dim);margin-bottom:32px;font-size:1.02em}
/* ── What's New ── */
.new-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px}
.new-card{background:var(--bg3);border:1px solid var(--border);border-radius:12px;padding:24px;transition:.3s;position:relative;overflow:hidden}
.new-card:hover{border-color:var(--blue);box-shadow:0 0 24px rgba(88,166,255,.1);transform:translateY(-2px)}
.new-card .icon{font-size:1.8em;margin-bottom:8px}
.new-card h3{font-size:1.08em;margin-bottom:8px;color:#f0f6fc}
.new-card p{color:var(--dim);font-size:.93em}
.new-card .badge-new{position:absolute;top:12px;right:12px;background:var(--green);color:#000;font-size:.72em;font-weight:700;padding:2px 8px;border-radius:10px}
/* ── Compare Table ── */
.tbl-wrap{overflow-x:auto;border-radius:12px;border:1px solid var(--border)}
table{width:100%;border-collapse:collapse;font-size:.9em}
thead th{background:var(--bg3);color:#f0f6fc;padding:13px 16px;text-align:left;font-weight:700;position:sticky;top:0;border-bottom:1px solid var(--border)}
tbody td{padding:12px 16px;border-bottom:1px solid rgba(33,38,45,.5)}
tbody tr:hover{background:rgba(88,166,255,.04)}
tbody td:first-child{font-weight:600;color:var(--dim);white-space:nowrap}
.y{color:var(--green);font-weight:700}
.n{color:var(--red);opacity:.5}
.p{color:var(--yellow)}
.hl{background:rgba(88,166,255,.06);font-weight:600}
/* ── Score Cards ── */
.score-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:16px;margin-top:20px}
.score{background:var(--bg3);border:1px solid var(--border);border-radius:12px;padding:22px;text-align:center;transition:.3s}
.score:hover{border-color:var(--blue);box-shadow:0 0 20px rgba(88,166,255,.08)}
.score .nm{font-size:1.05em;font-weight:700;margin-bottom:4px}
.score .tot{font-size:2.6em;font-weight:800;margin:6px 0}
.score .sub{font-size:.82em;color:var(--dim)}
.score .bars{text-align:left;margin-top:14px;font-size:.86em;color:var(--dim)}
.score .bars .row{display:flex;justify-content:space-between;margin-bottom:3px}
.score .bars .bw{background:rgba(255,255,255,.05);border-radius:4px;height:6px;margin-bottom:8px;overflow:hidden}
.score .bars .bd{height:100%;border-radius:4px}
/* ── Radar ── */
.radar-wrap{display:flex;justify-content:center;margin:30px 0}
.radar{position:relative;width:400px;height:400px}
.radar svg{width:100%;height:100%}
/* ── SWOT ── */
.swot{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.sc{border-radius:12px;padding:24px;border:1px solid}
.sc h3{font-size:1.08em;margin-bottom:12px}
.sc ul{list-style:none;padding:0}
.sc li{padding:5px 0 5px 22px;position:relative;color:var(--dim);font-size:.93em}
.sc li::before{content:'→';position:absolute;left:0;font-weight:700}
.sc-s{background:rgba(63,185,80,.04);border-color:rgba(63,185,80,.2)}.sc-s h3{color:var(--green)}.sc-s li::before{color:var(--green)}
.sc-w{background:rgba(248,81,73,.04);border-color:rgba(248,81,73,.2)}.sc-w h3{color:var(--red)}.sc-w li::before{color:var(--red)}
.sc-o{background:rgba(88,166,255,.04);border-color:rgba(88,166,255,.2)}.sc-o h3{color:var(--blue)}.sc-o li::before{color:var(--blue)}
.sc-t{background:rgba(240,136,62,.04);border-color:rgba(240,136,62,.2)}.sc-t h3{color:var(--orange)}.sc-t li::before{color:var(--orange)}
/* ── Verdict ── */
.verdict{background:linear-gradient(135deg,rgba(88,166,255,.06),rgba(188,140,255,.06));border:1px solid rgba(88,166,255,.2);border-radius:14px;padding:36px;text-align:center;margin-top:28px}
.verdict h3{font-size:1.4em;margin-bottom:10px;color:#f0f6fc}
.verdict p{color:var(--dim);max-width:680px;margin:0 auto;font-size:1.02em}
footer{text-align:center;padding:36px 20px;color:var(--mute);font-size:.86em;border-top:1px solid rgba(33,38,45,.5)}
footer a{color:var(--blue);text-decoration:none}
@media(max-width:768px){.hero h1{font-size:1.7em}.swot{grid-template-columns:1fr}table{font-size:.8em}}
</style>
</head>
<body>
<div class="hero">
<h1>小狸 Pro-CLI v5.1.2</h1>
<p class="sub">新增自动语法检查 · Diff 弹窗 · Web UI 后,与同类产品的实力对比</p>
<div class="tags">
<span class="tag tag-g"> 新增语法检查 · 11 种语言</span>
<span class="tag tag-b"> 新增 Diff 弹窗 · 可开关</span>
<span class="tag tag-p"> 新增 Web UI · 纯静态</span>
<span class="tag tag-c">v5.1.2 · 2026-04-27</span>
<span class="tag tag-y">16 插件 · 142 操作 · 约 19K 行</span>
</div>
</div>
<!-- ════════════════ 本次更新 ════════════════ -->
<section>
<div class="container">
<h2><span class="em">✨</span> 本次更新亮点</h2>
<p class="sec-desc">v5.1.2 新增 3 大功能,补齐了编辑后自动验证和可视化界面的短板。</p>
<div class="new-grid">
<div class="new-card">
<span class="badge-new">NEW</span>
<div class="icon"> </div>
<h3>自动语法检查</h3>
<p>编辑操作完成后自动触发,覆盖 <strong>11 种语言</strong>:Python (ast.parse + py_compile 双重验证)、JavaScript、TypeScript、JSON、YAML、TOML、HTML/XML、CSS、Shell (bash -n)、SQL。通过显示 ✓,失败显示精确的行号/列号/错误描述。AI 也可主动调用 <code>syntax_check</code>。</p>
</div>
<div class="new-card">
<span class="badge-new">NEW</span>
<div class="icon"> </div>
<h3>Diff 弹窗</h3>
<p>每次编辑后自动弹出新终端窗口,显示修改前/后的完整内容(带行号)、unified diff 差异、+N/-M 行数统计。兼容 <strong>Windows (cmd) / macOS (Terminal) / Linux (gnome-terminal 等 6 种)</strong>。异步不阻塞,<code>diff_popup on/off</code> 一键开关。</p>
</div>
<div class="new-card">
<span class="badge-new">NEW</span>
<div class="icon"> </div>
<h3>Web UI</h3>
<p>纯静态 HTML 界面,<strong>零依赖、零后端</strong>,浏览器直接打开。三栏布局:左侧文件树、中间对话/编辑器(Tab 切换)、右侧状态面板。暗色主题、动画效果、快捷芯片、行号编辑器、Ctrl+S 保存。</p>
</div>
</div>
</div>
</section>
<!-- ════════════════ 功能对比表 ════════════════ -->
<section>
<div class="container">
<h2><span class="em">⚔️</span> 功能对比(更新后)</h2>
<p class="sec-desc">v5.1.2 新增功能后,小狸在语法验证和界面维度补齐了关键差距。绿色高亮 = 本次新增优势。</p>
<div class="tbl-wrap">
<table>
<thead>
<tr><th>维度</th><th>小狸 v5.1.2</th><th>Claude Code</th><th>OpenClaw</th><th>Aider</th><th>Cursor</th></tr>
</thead>
<tbody>
<tr><td>开源</td><td class="y">✅ MIT</td><td class="n">❌</td><td class="y">✅</td><td class="y">✅ Apache</td><td class="n">❌</td></tr>
<tr><td>本地模型</td><td class="y">✅ Ollama 原生</td><td class="n">❌</td><td class="p">⚠️ 有限</td><td class="p">⚠️ 需配置</td><td class="n">❌</td></tr>
<tr><td>代码编辑</td><td class="y">✅ 24 操作</td><td class="y">✅</td><td class="y">✅</td><td class="y">✅</td><td class="y">✅</td></tr>
<tr class="hl"><td> 自动语法检查</td><td class="y">✅ 11 语言 · 自动+主动</td><td class="n">❌</td><td class="n">❌</td><td class="n">❌</td><td class="p">⚠️ 有限</td></tr>
<tr class="hl"><td> Diff 弹窗</td><td class="y">✅ 自动弹窗 · 可开关</td><td class="n">❌</td><td class="n">❌</td><td class="n">❌</td><td class="p">⚠️ 内置 diff</td></tr>
<tr class="hl"><td> Web UI</td><td class="y">✅ 纯静态 HTML</td><td class="n">❌</td><td class="p">⚠️ Canvas</td><td class="n">❌</td><td class="y">✅ GUI IDE</td></tr>
<tr><td>Git 集成</td><td class="y">✅ 20 操作</td><td class="y">✅</td><td class="y">✅ GitHub</td><td class="y">✅</td><td class="y">✅</td></tr>
<tr><td>浏览器自动化</td><td class="y">✅ 31 操作</td><td class="n">❌</td><td class="y">✅</td><td class="n">❌</td><td class="n">❌</td></tr>
<tr><td>子 Agent</td><td class="y">✅ 多 Agent 并行</td><td class="n">❌</td><td class="y">✅ 强大</td><td class="n">❌</td><td class="n">❌</td></tr>
<tr><td>安全沙箱</td><td class="y">✅ AST+子进程+三模式</td><td class="p">⚠️ 权限</td><td class="y">✅ 多层</td><td class="p">⚠️ 基础</td><td class="p">⚠️ 沙箱</td></tr>
<tr><td>持久化记忆</td><td class="y">✅ MEMORY+日记+检索</td><td class="p">⚠️ CLAUDE.md</td><td class="y">✅ 完整</td><td class="p">⚠️ 有限</td><td class="p">⚠️ 有限</td></tr>
<tr><td>TUI 界面</td><td class="y">✅ Textual 动画</td><td class="n">❌ 纯 CLI</td><td class="p">⚠️</td><td class="n">❌</td><td class="y">✅ GUI</td></tr>
<tr><td>工程化工具</td><td class="y">✅ lint/format/test/build</td><td class="p">⚠️</td><td class="p">⚠️</td><td class="p">⚠️</td><td class="y">✅</td></tr>
<tr><td>语音识别</td><td class="y">✅ STT</td><td class="n">❌</td><td class="p">⚠️ TTS</td><td class="n">❌</td><td class="n">❌</td></tr>
<tr><td>远程控制</td><td class="y">✅ Clawli+WebSocket</td><td class="n">❌</td><td class="y">✅ 多渠道</td><td class="n">❌</td><td class="n">❌</td></tr>
<tr><td>测试覆盖</td><td class="y">✅ 113 用例</td><td class="n">❌</td><td class="p">⚠️</td><td class="y">✅</td><td class="n">❌</td></tr>
<tr><td>中文原生</td><td class="y">✅</td><td class="p">⚠️</td><td class="y">✅</td><td class="p">⚠️</td><td class="p">⚠️</td></tr>
<tr><td>价格</td><td class="y">免费</td><td>$20/月</td><td class="y">免费</td><td>$20/月</td><td>$20/月</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- ════════════════ 评分对比 ════════════════ -->
<section>
<div class="container">
<h2><span class="em"> </span> 多维度评分(v5.1.2 更新后)</h2>
<p class="sec-desc">满分 10 分,基于代码审查和功能实测。</p>
<div class="score-row">
<div class="score" style="border-color:rgba(88,166,255,.35)">
<div class="nm" style="color:var(--blue)">小狸 v5.1.2</div>
<div class="tot" style="color:var(--blue)">7.3</div>
<div class="sub">↑ 0.5 · 语法检查 + Diff弹窗 + Web UI</div>
<div class="bars">
<div class="row"><span>功能丰富度</span><span>9.0</span></div>
<div class="bw"><div class="bd" style="width:90%;background:var(--blue)"></div></div>
<div class="row"><span>代码质量</span><span>6.5</span></div>
<div class="bw"><div class="bd" style="width:65%;background:var(--blue)"></div></div>
<div class="row"><span>架构设计</span><span>6.5</span></div>
<div class="bw"><div class="bd" style="width:65%;background:var(--blue)"></div></div>
<div class="row"><span>安全机制</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--blue)"></div></div>
<div class="row"><span>用户体验</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--blue)"></div></div>
<div class="row"><span>生态与社区</span><span>4.0</span></div>
<div class="bw"><div class="bd" style="width:40%;background:var(--blue)"></div></div>
<div class="row"><span>文档完整度</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--blue)"></div></div>
<div class="row"><span>工程化水平</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--blue)"></div></div>
</div>
</div>
<div class="score" style="border-color:rgba(240,136,62,.35)">
<div class="nm" style="color:var(--orange)">Claude Code</div>
<div class="tot" style="color:var(--orange)">8.5</div>
<div class="sub">模型能力碾压,但无语法检查/Diff弹窗</div>
<div class="bars">
<div class="row"><span>功能丰富度</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--orange)"></div></div>
<div class="row"><span>代码质量</span><span>9.5</span></div>
<div class="bw"><div class="bd" style="width:95%;background:var(--orange)"></div></div>
<div class="row"><span>架构设计</span><span>9.0</span></div>
<div class="bw"><div class="bd" style="width:90%;background:var(--orange)"></div></div>
<div class="row"><span>安全机制</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--orange)"></div></div>
<div class="row"><span>用户体验</span><span>9.0</span></div>
<div class="bw"><div class="bd" style="width:90%;background:var(--orange)"></div></div>
<div class="row"><span>生态与社区</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--orange)"></div></div>
<div class="row"><span>文档完整度</span><span>9.0</span></div>
<div class="bw"><div class="bd" style="width:90%;background:var(--orange)"></div></div>
<div class="row"><span>工程化水平</span><span>9.0</span></div>
<div class="bw"><div class="bd" style="width:90%;background:var(--orange)"></div></div>
</div>
</div>
<div class="score" style="border-color:rgba(63,185,80,.35)">
<div class="nm" style="color:var(--green)">OpenClaw</div>
<div class="tot" style="color:var(--green)">7.8</div>
<div class="sub">Agent 平台标杆,多渠道生态</div>
<div class="bars">
<div class="row"><span>功能丰富度</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--green)"></div></div>
<div class="row"><span>代码质量</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--green)"></div></div>
<div class="row"><span>架构设计</span><span>8.5</span></div>
<div class="bw"><div class="bd" style="width:85%;background:var(--green)"></div></div>
<div class="row"><span>安全机制</span><span>8.5</span></div>
<div class="bw"><div class="bd" style="width:85%;background:var(--green)"></div></div>
<div class="row"><span>用户体验</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--green)"></div></div>
<div class="row"><span>生态与社区</span><span>7.0</span></div>
<div class="bw"><div class="bd" style="width:70%;background:var(--green)"></div></div>
<div class="row"><span>文档完整度</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--green)"></div></div>
<div class="row"><span>工程化水平</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--green)"></div></div>
</div>
</div>
<div class="score" style="border-color:rgba(188,140,255,.35)">
<div class="nm" style="color:var(--purple)">Aider</div>
<div class="tot" style="color:var(--purple)">7.2</div>
<div class="sub">专注代码编辑,简洁高效</div>
<div class="bars">
<div class="row"><span>功能丰富度</span><span>6.5</span></div>
<div class="bw"><div class="bd" style="width:65%;background:var(--purple)"></div></div>
<div class="row"><span>代码质量</span><span>8.5</span></div>
<div class="bw"><div class="bd" style="width:85%;background:var(--purple)"></div></div>
<div class="row"><span>架构设计</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--purple)"></div></div>
<div class="row"><span>安全机制</span><span>5.0</span></div>
<div class="bw"><div class="bd" style="width:50%;background:var(--purple)"></div></div>
<div class="row"><span>用户体验</span><span>8.0</span></div>
<div class="bw"><div class="bd" style="width:80%;background:var(--purple)"></div></div>
<div class="row"><span>生态与社区</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--purple)"></div></div>
<div class="row"><span>文档完整度</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--purple)"></div></div>
<div class="row"><span>工程化水平</span><span>7.5</span></div>
<div class="bw"><div class="bd" style="width:75%;background:var(--purple)"></div></div>
</div>
</div>
</div>
</div>
</section>
<!-- ════════════════ 差异化优势 ════════════════ -->
<section>
<div class="container">
<h2><span class="em"> </span> v5.1.2 新增的独有优势</h2>
<p class="sec-desc">这三项功能在同类产品中均无直接竞品。</p>
<div class="new-grid">
<div class="new-card" style="border-left:3px solid var(--green)">
<h3> 自动语法检查 — 行业空白</h3>
<p><strong>Claude Code</strong>:不做语法检查,依赖模型自身判断。<br>
<strong>Aider</strong>:不做语法检查。<br>
<strong>Cursor</strong>:有 lint 集成但非自动触发。<br><br>
<strong>小狸</strong>:编辑后 <strong>自动</strong> 触发,11 种语言,AST 级精确错误定位。AI 修改代码后立刻知道对不对,不用等运行时才发现。<strong>这是编程 CLI 赛道的首创。</strong></p>
</div>
<div class="new-card" style="border-left:3px solid var(--blue)">
<h3> Diff 弹窗 — 所见即所得</h3>
<p><strong>Claude Code</strong>:终端内显示 diff 文本。<br>
<strong>Aider</strong>:终端内显示 diff。<br>
<strong>Cursor</strong>:IDE 内置 diff 视图。<br><br>
<strong>小狸</strong>:每次编辑后 <strong>弹出独立窗口</strong>,完整显示修改前后内容 + 行号 + unified diff + 统计。不挤在终端里,一目了然。<code>diff_popup off</code> 一键关闭。</p>
</div>
<div class="new-card" style="border-left:3px solid var(--purple)">
<h3> Web UI — 零门槛</h3>
<p><strong>Claude Code</strong>:纯 CLI,无 UI。<br>
<strong>Aider</strong>:纯 CLI,无 UI。<br>
<strong>OpenClaw</strong>:Canvas 组件,非完整 UI。<br><br>
<strong>小狸</strong>:纯静态 HTML 文件,<strong>双击打开</strong>。暗色主题三栏布局,对话 + 编辑器 + 文件树 + 状态面板。不需要 npm、不需要 Flask、不需要任何后端。</p>
</div>
</div>
</div>
</section>
<!-- ════════════════ SWOT ════════════════ -->
<section>
<div class="container">
<h2><span class="em"> </span> SWOT 分析(更新后)</h2>
<div class="swot">
<div class="sc sc-s">
<h3> Strengths</h3>
<ul>
<li><strong>自动语法检查</strong> — 行业首创,11 语言,编辑后即时反馈</li>
<li><strong>Diff 弹窗</strong> — 独立窗口对比,所见即所得</li>
<li><strong>三模式界面</strong> — CLI + TUI + Web UI,覆盖所有场景</li>
<li><strong>功能密度极高</strong> — 16 插件 142 操作,2 个月一人完成</li>
<li><strong>安全纵深</strong> — AST 沙箱 + 子进程隔离 + 三模式</li>
<li><strong>本地模型原生</strong> — Ollama 开箱即用,完全离线</li>
<li><strong>中文原生 + MIT 开源</strong> — 国内开发者零门槛</li>
</ul>
</div>
<div class="sc sc-w">
<h3> Weaknesses</h3>
<ul>
<li><strong>模型能力差距</strong> — 本地模型 vs Claude/GPT-4 鸿沟仍在</li>
<li><strong>单人维护</strong> — 长期迭代速度和可持续性存疑</li>
<li><strong>社区生态空白</strong> — 无插件市场、无活跃贡献者</li>
<li><strong>架构复杂度</strong> — cli_core.py 对话循环待拆分</li>
<li><strong>Web UI 是静态</strong> — 无后端,不能真正执行操作</li>
</ul>
</div>
<div class="sc sc-o">
<h3> Opportunities</h3>
<ul>
<li><strong>国产替代</strong> — 中文原生 + 本地模型是巨大优势</li>
<li><strong>本地 AI 爆发</strong> — Ollama/llama.cpp 快速发展</li>
<li><strong>语法检查可产品化</strong> — 独立为 CI/CD 工具或 IDE 插件</li>
<li><strong>教育市场</strong> — 免费 + 中文 + 有趣(彩蛋情书)</li>
<li><strong>Web UI 可进化</strong> — 加后端即可变为完整 Web IDE</li>
</ul>
</div>
<div class="sc sc-t">
<h3>⚠️ Threats</h3>
<ul>
<li><strong>大厂碾压</strong> — Claude Code / Cursor 资金和模型优势</li>
<li><strong>开源竞品</strong> — Aider、Cline、Continue.dev 社区更活跃</li>
<li><strong>AI 工具快速迭代</strong> — 功能可能被快速复制</li>
<li><strong>维护可持续性</strong> — 单人项目最大风险</li>
</ul>
</div>
</div>
</div>
</section>
<!-- ════════════════ 结论 ════════════════ -->
<section>
<div class="container">
<h2><span class="em"> </span> 结论</h2>
<div class="verdict">
<h3>能不能抗衡?</h3>
<p><strong>功能维度:能。</strong>16 插件 142 操作 + 自动语法检查 + Diff 弹窗 + 三模式界面,功能广度已经超过 Claude Code 和 Aider,在语法验证维度甚至领先全行业。</p>
<p style="margin-top:14px"><strong>体验维度:接近。</strong>Web UI 补齐了可视化短板,TUI 动画体验独特。但底层模型能力差距决定了对话质量和代码生成精度仍有代差。</p>
<p style="margin-top:14px"><strong>生态维度:差距大。</strong>社区、插件市场、贡献者体系是最大的结构性劣势。功能做得再好,一个人扛不住长期迭代。</p>
<p style="margin-top:18px;color:var(--blue);font-weight:600">一句话:功能够打,体验能看,生态要追。v5.1.2 是一次关键的能力补齐。</p>
</div>
</div>
</section>
<footer>
<p>基于 <a href="https://gitee.com/shuiyu1123/xiaoli-cli">xiaoli-cli v5.1.2</a> 全部源代码逐行审查生成 · 2026-04-27</p>
</footer>
</body>
</html>