Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
245413b2cd | ||
|
|
3fa1d56632 | ||
|
|
62aa5ed128 |
No files matched your search
@@ -36,6 +36,14 @@ Thumbs.db
|
||||
# 嵌入式 Python
|
||||
embedded_python/
|
||||
|
||||
# 记忆系统数据(运行时生成)
|
||||
MEMORY.md
|
||||
memory/
|
||||
|
||||
# 生成的图片
|
||||
generated_*.png
|
||||
screenshots/gen_*.png
|
||||
|
||||
# 临时文件
|
||||
*.tmp
|
||||
*.bak
|
||||
@@ -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)
|
||||
|
||||
### 新增功能
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
# 小狸 Pro-CLI
|
||||
|
||||
<p align="center">
|
||||
<strong>智能编程助手 — 代码编辑 · Git 集成 · 浏览器自动化 · 多 Agent 协作</strong>
|
||||
<strong>智能编程助手 — 代码编辑 · Git 集成 · 浏览器自动化 · 多 Agent 协作 · 图像生成 · 记忆系统</strong>
|
||||
</p>
|
||||
|
||||
<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/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/plugins-17-blueviolet" alt="plugins">
|
||||
<img src="https://img.shields.io/badge/MCP-supported-brightgreen" alt="mcp">
|
||||
</p>
|
||||
|
||||
---
|
||||
@@ -21,8 +23,14 @@
|
||||
- **浏览器自动化** — Playwright 驱动,导航/交互/截图/JS 执行/PDF
|
||||
- **子 Agent 系统** — 多 Agent 并行协作,独立任务分配与结果回收
|
||||
- **统一安全层** — AI 风险识别 + 三模式切换(普通/人工/无限制)
|
||||
- **15 个插件 141 个操作** — 代码编辑、Git、浏览器、工程化、文件管理、任务管理等
|
||||
- **三模式界面** — TUI 图形化 + 传统命令行 + **Web UI 浏览器界面**
|
||||
- **图像生成** — 基于 ComfyUI 在线服务,自然语言/Tag 双模式,支持中文描述
|
||||
- **记忆系统** — 长期记忆 + 每日日记 + AI 写日记 + 全局搜索 + 自动保存对话
|
||||
- **Clawli 远程模式** — PC-手机 WebSocket 双向通信,支持内网穿透代理
|
||||
- **定时任务** — 支持相对时间、绝对时间、重复任务,到期自动激活 AI
|
||||
- **系统通知** — 跨平台任务完成通知(Windows / macOS / Linux)
|
||||
- **MCP 协议** — 17 个插件全部实现 MCP 定义,支持 Function Calling 原生调用
|
||||
- **17 个插件 141+ 个操作** — 代码编辑、Git、浏览器、工程化、文件管理、图像生成、记忆等
|
||||
- **三模式界面** — TUI 图形化 + 传统命令行 + **Web UI 浏览器界面**
|
||||
- **113 个自动化测试** — pytest 覆盖全部插件和核心模块
|
||||
|
||||
## 快速开始
|
||||
@@ -43,6 +51,9 @@ python ai_cli.py
|
||||
|
||||
# 指定引擎
|
||||
python ai_cli.py --engine openai
|
||||
|
||||
# Windows 一键启动(无需 Python 环境)
|
||||
launcher.exe
|
||||
```
|
||||
|
||||
## AI 引擎
|
||||
@@ -76,17 +87,17 @@ python ai_cli.py --engine openai
|
||||
}
|
||||
```
|
||||
|
||||
## 插件列表 (15 个)
|
||||
## 插件列表 (17 个)
|
||||
|
||||
### 核心生产力
|
||||
|
||||
| 插件 | 操作数 | 说明 |
|
||||
|------|--------|------|
|
||||
| `code_editor` | 23 | 代码编辑+搜索。精准替换、批量编辑、find/regex/symbols/imports/callers/todo/structure + 自动语法检查 |
|
||||
| `git_tools` | 20 | Git 版本控制。status/diff/log/commit/branch + smart-commit/changelog/contributors |
|
||||
| `code_editor` | 24 | 代码编辑+搜索。精准替换、批量编辑、find/regex/symbols/imports/callers/todo/structure + 自动语法检查 + diff 弹窗 |
|
||||
| `git_tools` | 17 | Git 版本控制。status/diff/log/commit/branch + smart-commit/changelog/contributors/stale |
|
||||
| `cmd_executor` | 1 | Shell 命令执行。跨平台,超时控制,危险命令拦截 |
|
||||
| `file_manager` | 11 | 文件系统。list/read/write/copy/move/delete/search/info/mkdir |
|
||||
| `auto_engineer` | 16 | 工程化。lint/format/test/build/deps + 复杂度/安全扫描/质量指标 |
|
||||
| `file_manager` | 10 | 文件系统。list/read/write/copy/move/delete/search/info/mkdir/append |
|
||||
| `auto_engineer` | 12 | 工程化。lint/format/test/build/deps + 复杂度/安全扫描/质量指标/项目初始化 |
|
||||
| `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 并行协作 |
|
||||
| `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 按需调用) |
|
||||
|
||||
### 辅助工具
|
||||
@@ -104,10 +118,43 @@ python ai_cli.py --engine openai
|
||||
| `network_tools` | 网络工具。ping/get/status/headers/ip |
|
||||
| `ai_search` | AI 搜索。jina.ai 智能搜索 + 网页内容提取 |
|
||||
| `frontend_tester` | 前端测试。HTML/CSS/JS 语法检查、响应式验证 |
|
||||
| `speech_recognition` | 语音识别。录音 + 语音转文字 |
|
||||
| `speech_recognition` | 语音识别。录音 + 语音转文字(Whisper) |
|
||||
| `audio_player` | 音频播放 |
|
||||
| `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`)
|
||||
@@ -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` | 显示帮助 |
|
||||
| `/safe` | 切换安全模式(普通→人工→无限制) |
|
||||
| `/safe off` | 直接切换到无限制模式 |
|
||||
| `/safe manual` | 直接切换到人工确认模式 |
|
||||
| `/engine list` | 列出可用引擎 |
|
||||
| `/engine switch <引擎>` | 切换引擎 |
|
||||
| `/engine.openai models` | 列出 OpenAI 引擎模型 |
|
||||
| `/chat save/list/open` | 聊天记录管理 |
|
||||
| `/file.read <路径>` | 读取文件 |
|
||||
| `/remote` | Clawli 远程连接帮助 |
|
||||
| `/notify` | 切换任务完成通知 |
|
||||
| `/scheduler` / `/remind` | 管理定时任务 |
|
||||
| `/memory` | 管理记忆系统 |
|
||||
| `/tui` | 切换 TUI 模式 |
|
||||
| `/quit` | 退出 |
|
||||
|
||||
@@ -158,70 +219,64 @@ python ai_cli.py --engine openai
|
||||
纯静态 HTML 界面,无需后端,浏览器直接打开。
|
||||
|
||||
```bash
|
||||
# 直接用浏览器打开
|
||||
open webui.html # macOS
|
||||
xdg-open webui.html # Linux
|
||||
start webui.html # Windows
|
||||
```
|
||||
|
||||
### 功能
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 对话界面 | 聊天气泡、快捷指令、打字动画 |
|
||||
| 代码编辑器 | 行号显示、Tab 缩进、Ctrl+S 保存、语法高亮 |
|
||||
| 文件浏览 | 侧栏项目文件树,点击查看 |
|
||||
| ️ 系统状态 | 插件/操作/引擎/测试统计 |
|
||||
| 引擎面板 | Ollama / OpenAI 引擎一览 |
|
||||
| 工具面板 | 15 个插件及操作数一览 |
|
||||
| 日志面板 | 系统操作实时记录 |
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
xiaoli-cli/
|
||||
├── ai_cli.py # 主入口
|
||||
├── webui.html # Web UI 界面 (纯静态 HTML)
|
||||
├── launcher.py # 智能启动器
|
||||
├── launcher.py # 智能启动器(自动检测环境/安装依赖)
|
||||
├── config.json.example # 配置模板
|
||||
├── easter_egg.py # 彩蛋
|
||||
│
|
||||
├── xcli_core/ # 核心模块
|
||||
│ ├── cli_core.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_history.py # 聊天记录
|
||||
│ ├── cli_code_exec.py # 代码执行
|
||||
│ ├── config.py # 配置管理
|
||||
│ ├── constants.py # 常量定义
|
||||
│ ├── safety.py # 统一安全层
|
||||
│ ├── sandbox.py # 代码安全沙箱
|
||||
│ ├── plugin_manager.py # 插件管理器
|
||||
│ └── tui.py # TUI 界面
|
||||
│ ├── fc_tools.py # MCP → FC 格式转换
|
||||
│ ├── memory.py # 记忆系统(长期记忆+日记+搜索+压缩)
|
||||
│ ├── notification.py # 跨平台系统通知
|
||||
│ ├── plugin_manager.py # 插件管理器(Liugin/Plugin 双协议)
|
||||
│ ├── safety.py # 统一安全层(AI 风险分析)
|
||||
│ ├── sandbox.py # 代码安全沙箱(AST 级检测)
|
||||
│ └── tui.py # TUI 界面(Textual + 动画)
|
||||
│
|
||||
├── ai_engines/ # AI 引擎
|
||||
│ ├── ollama_engine.py # Ollama 本地模型
|
||||
│ └── openai_engine.py # OpenAI 兼容格式
|
||||
│
|
||||
├── plugins/ # 插件 (15 个)
|
||||
│ ├── code_editor.py # 代码编辑+搜索
|
||||
│ ├── git_tools.py # Git 版本控制
|
||||
├── plugins/ # 插件 (17 个)
|
||||
│ ├── code_editor.py # 代码编辑+搜索 (24 操作)
|
||||
│ ├── git_tools.py # Git 版本控制 (17 操作)
|
||||
│ ├── cmd_executor.py # Shell 命令执行
|
||||
│ ├── file_manager.py # 文件管理
|
||||
│ ├── auto_engineer.py # 工程化自动化
|
||||
│ ├── file_manager.py # 文件管理 (10 操作)
|
||||
│ ├── auto_engineer.py # 工程化自动化 (12 操作)
|
||||
│ ├── task_manager.py # 任务管理
|
||||
│ ├── sub_agent.py # 子 Agent 系统
|
||||
│ ├── browser_auto.py # 浏览器自动化
|
||||
│ ├── sub_agent.py # 子 Agent 系统 (8 操作)
|
||||
│ ├── browser_auto.py # 浏览器自动化 (28 操作)
|
||||
│ ├── image_generator.py # 图像生成 (7 操作) ⭐ NEW
|
||||
│ ├── memory_plugin.py # 记忆系统 (11 操作) ⭐ NEW
|
||||
│ ├── scheduler.py # 定时任务
|
||||
│ ├── tool_search.py # 工具搜索
|
||||
│ ├── network_tools.py # 网络工具
|
||||
│ ├── ai_search.py # AI 搜索
|
||||
│ ├── frontend_tester.py # 前端测试
|
||||
│ ├── speech_recognition.py # 语音识别
|
||||
│ ├── audio_player.py # 音频播放
|
||||
│ └── send_image.py # 图片发送
|
||||
│
|
||||
├── skills/ # 技能 (Skill 协议)
|
||||
├── image_engine/ # 图像识别引擎
|
||||
├── image_engine/ # 图像识别引擎(Ollama 视觉模型)
|
||||
├── tests/ # 测试套件 (113 用例)
|
||||
├── love.txt # 彩蛋情话
|
||||
└── about.txt # 关于信息
|
||||
@@ -239,8 +294,10 @@ python -c "import py_compile; py_compile.compile('ai_cli.py', doraise=True)"
|
||||
|
||||
## 插件开发
|
||||
|
||||
小狸支持 `Liugin`(自研协议)和 `Plugin`(通用协议)两种类名,均可被插件管理器自动识别:
|
||||
|
||||
```python
|
||||
class Plugin:
|
||||
class Plugin: # 或 class Liugin
|
||||
"""我的插件"""
|
||||
|
||||
def __init__(self):
|
||||
@@ -258,6 +315,18 @@ class Plugin:
|
||||
"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:
|
||||
return "处理结果"
|
||||
```
|
||||
@@ -271,3 +340,4 @@ class Plugin:
|
||||
- Gitee: https://gitee.com/shuiyu1123/xiaoli-cli
|
||||
- [更新日志](CHANGELOG.md)
|
||||
- [使用指南](HELP.md)
|
||||
- [AI 编程助手横评](compare.html)
|
||||
@@ -1,7 +1,7 @@
|
||||
**产品标识**
|
||||
- **产品名称**:小狸智能体 增强-终端(Xiaoli Pro-CLI)
|
||||
- **内部版本号**:20260426
|
||||
- **发布版本**:发行版5.1.1
|
||||
- **内部版本号**:20260428
|
||||
- **发布版本**:发行版5.1.3
|
||||
|
||||
**技术规格**
|
||||
- **主要语言**:简体中文(UTF-8)
|
||||
|
||||
+1161
File diff suppressed because it is too large.
Load diff
@@ -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}"
|
||||
@@ -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"""
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user