diff --git a/docs/comparison/qwen-code-improvement-report-p1-arch.md b/docs/comparison/qwen-code-improvement-report-p1-arch.md new file mode 100644 index 00000000..ce9b59a3 --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p1-arch.md @@ -0,0 +1,752 @@ +# Qwen Code 改进建议 — P1 架构与性能增强 + +> 中高优先级改进项(架构与性能方向)。每项包含:问题场景、现状分析、改进前后对比、实现成本评估、Claude Code 源码索引、Qwen Code 修改方向。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. 分层上下文压缩策略增强(P1) + +Claude Code 的上下文压缩不是单一机制,而是 **3 条独立路径**——根据成本和紧急程度选择最合适的路径。当前 Qwen Code 仅有单一压缩(`/compress` 手动触发或 70% 阈值自动触发),缺少精细控制。 + +**Claude Code 的 3 条压缩路径**: + +| 路径 | 触发条件 | 成本 | 效果 | +|------|---------|------|------| +| **Auto-compact** | token 达 ~83% 窗口 | 中(一次 LLM 调用) | 9 章节摘要 + 自动恢复文件 | +| **Cached Micro-compact** | 每轮自动 | **零**(不破坏 cache) | 通过 `cache_edits` API 原地删除旧 tool results | +| **Time-based Micro-compact** | 空闲 >60 分钟 | **零**(不破坏 cache) | content-clear 旧 tool results | + +**关键差异分析**: + +| 方面 | Claude Code | Qwen Code | +|------|-------------|-----------| +| 触发阈值 | ~83%(200K 窗口 - 13K buffer) | 70% | +| 压缩后恢复 | 最近 5 文件 + 活跃 Skill + Plan | 无恢复 | +| Micro-compact | 有(`cache_edits` API) | 无 | +| Time-based MC | 有(60 分钟空闲) | 无 | +| 熔断器 | 连续 3 次失败停止 | 无 | +| 摘要章节 | 9 章节(详细) | 5 章节(简略) | + +**改进方案——引入 Time-based Micro-compact**(最容易实现的增益): + +当用户离开终端超过阈值(默认 60 分钟,对应服务端 prompt cache 1h TTL),直接在消息数组中标记旧 tool results 为已清除——不破坏缓存前缀,下次 API 调用自动受益: + +```typescript +// 伪代码:API 调用前检查 +function maybeTimeBasedMicroCompact(messages: Message[]): Message[] { + const lastAssistantAt = findLastAssistantTimestamp(messages); + const gapMinutes = (Date.now() - lastAssistantAt) / 60000; + + if (gapMinutes < 60) return messages; // 未达阈值 + + // 保留最近 5 个 tool results,其余清除 + const keepRecent = 5; + const toolResults = messages.filter(m => m.role === 'tool'); + const toClear = toolResults.slice(0, -keepRecent); + + return messages.map(m => { + if (toClear.includes(m)) { + return { ...m, content: '[Old tool result content cleared]' }; + } + return m; + }); +} +``` + +**改进方案——增强 Auto-compact**(中等难度): + +| 改进项 | 当前 | 改进后 | +|--------|------|--------| +| 触发阈值 | 70% | ~83%(给模型更多工作空间) | +| 压缩后恢复 | 无 | 自动恢复最近 5 文件 + 活跃 Skill | +| 熔断器 | 无 | 连续 3 次失败停止重试 | +| 摘要章节 | 5 章节 | 9 章节(更详细) | + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `services/compact/autoCompact.ts` | `AUTOCOMPACT_BUFFER_TOKENS = 13_000`、`MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3` | +| `services/compact/microCompact.ts` | `COMPACTABLE_TOOLS`(8 种可清除工具)、cache_edits 路径 | +| `services/compact/timeBasedMCConfig.ts` | `gapThresholdMinutes = 60`、`keepRecent = 5` | +| `services/compact/compact.ts` (1705行) | 9 章节摘要模板、自动恢复逻辑 | + +**Qwen Code 修改方向**: + +1. **Time-based Micro-compact**(~100 行,~1 天): + - `coreToolScheduler.ts` 中 API 调用前检查空闲时间 + - 超过 60 分钟则清除旧 tool results(保留最近 5 个) + - 标记为 `[Old tool result content cleared]` + +2. **Auto-compact 增强**(~300 行,~3 天): + - 阈值从 70% 改为 ~83% + - 压缩后自动恢复最近 5 文件(从历史消息中提取文件路径) + - 增加熔断器(连续 3 次失败停止) + +**实现成本评估**: +- Time-based MC:~100 行,~1 天 +- Auto-compact 增强:~300 行,~3 天 +- 难点:文件恢复逻辑(从历史消息中识别文件路径和内容) + +**改进前后对比**: +- **改进前**:用户离开 2 小时后回来,旧 tool results 仍占上下文——浪费 token +- **改进后**:Time-based MC 自动清除——上下文精简,token 节省 + +**意义**:用户经常离开终端(开会、吃饭),回来后旧上下文仍占 token——浪费。 +**缺失后果**:旧 tool results 不清除——上下文浪费,压缩触发过早。 +**改进收益**:Time-based MC 自动清理——用户回来时上下文已精简,token 节省。 + +--- + + + +### 2. API 指数退避与智能重试(P1) + +你让 Agent 执行一个复杂任务,突然 API 返回 429(Too Many Requests)——请求被限流。当前 Qwen Code 的重试逻辑是固定次数重试(如 3 次),但问题在于: + +- **固定间隔重试**:如果 API 限流是渐进式的(1s → 5s → 30s),固定间隔(如每次等 1s)会快速耗尽重试次数 +- **缺少降级策略**:连续限流后没有模型降级(如从高端模型切到标准模型) +- **401 Token 过期**:API Key 过期时没有自动刷新逻辑 + +**Claude Code 的解决方案——10 次指数退避 + 模型降级**: + +| 场景 | 重试策略 | +|------|---------| +| 429 Too Many Requests | 10 次指数退避(1s → 2s → 4s → 8s → ... → 512s) | +| 529 模型不可用 | 降级到备用模型(如 Opus → Sonnet) | +| 401 Unauthorized | 刷新 token 后重试(如 OAuth token 过期) | +| 5xx 服务器错误 | 3 次指数退避 | + +**指数退避实现**: + +```typescript +async function retryWithBackoff( + fn: () => Promise, + maxRetries = 10, + baseDelay = 1000 +): Promise { + for (let i = 0; i < maxRetries; i++) { + try { + const response = await fn(); + if (response.ok) return response; + + if (response.status === 429) { + const delay = baseDelay * Math.pow(2, i); + const retryAfter = response.headers.get('Retry-After'); + const waitMs = retryAfter ? parseInt(retryAfter) * 1000 : delay; + await sleep(waitMs); + continue; + } + + if (response.status === 529) { + // 模型降级到备用模型 + return await fnWithFallbackModel(); + } + + throw new Error(`API error: ${response.status}`); + } catch (error) { + if (i === maxRetries - 1) throw error; + await sleep(baseDelay * Math.pow(2, i)); + } + } +} +``` + +**关键设计**: +- `Retry-After` 头优先(API 返回的建议等待时间) +- 退避上限 512 秒(~8.5 分钟,防止无限等待) +- 模型降级需要用户预配置备用模型 +- 401 刷新 token 仅适用于 OAuth 场景 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `services/api/withRetry.ts` (822行) | 指数退避逻辑、`Retry-After` 头解析、`maxRetries`、`maxDelayMs` | +| `services/api/client.ts` | 401/429/529 处理、模型降级 | + +**Qwen Code 现状**:`api.ts` 中有基础重试逻辑,但缺少指数退避、模型降级、401 刷新。 + +**Qwen Code 修改方向**:① `api.ts` 新增指数退避逻辑(`Math.pow(2, i)`);② 解析 `Retry-After` 头;③ 429 处理;④ 529 时降级到备用模型(需配置);⑤ 401 时刷新 token(如适用)。 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~150 行 +- 开发周期:~1.5 天(1 人) +- 难点:模型降级逻辑(需要备用模型配置)、401 刷新(取决于认证方式) + +**改进前后对比**: +- **改进前**:429 限流 → 固定间隔重试 3 次 → 快速失败 → 任务中断 +- **改进后**:429 限流 → 10 次指数退避(最长等 512s)→ 模型降级 → 任务继续 + +**意义**:API 限流是常见场景——指数退避提高成功率,模型降级避免完全失败。 +**缺失后果**:固定间隔重试快速失败——限流期间任务中断。 +**改进收益**:指数退避 + 模型降级——限流期间自动适应,任务不中断。 + +--- + + + +### 3. 同步 I/O 异步化(P1) + +Node.js 事件循环是单线程的——任何同步阻塞操作都会阻塞整个事件循环,导致: + +- 键盘输入响应延迟(用户打字卡顿) +- TUI 渲染卡顿(UI 闪烁或不更新) +- 工具执行延迟(本该并行的 I/O 被阻塞) + +**Claude Code 的做法——全面异步 I/O**: + +Claude Code 在源码中避免使用 `readFileSync`/`writeFileSync`/`statSync`,全部替换为 `async/await` 版本: + +```typescript +// ❌ 错误:同步 I/O(阻塞事件循环) +const content = fs.readFileSync(filePath, 'utf-8'); +const stat = fs.statSync(filePath); + +// ✅ 正确:异步 I/O(不阻塞) +const content = await fs.promises.readFile(filePath, 'utf-8'); +const stat = await fs.promises.stat(filePath); +``` + +**关键异步化点**: + +| 操作 | 同步(阻塞) | 异步(非阻塞) | +|------|-------------|---------------| +| 文件读取 | `readFileSync()` | `fs.promises.readFile()` | +| 文件写入 | `writeFileSync()` | `fs.promises.writeFile()` | +| 文件状态 | `statSync()` | `fs.promises.stat()` | +| 目录列表 | `readdirSync()` | `fs.promises.readdir()` | +| 文件删除 | `unlinkSync()` | `fs.promises.unlink()` | +| 目录创建 | `mkdirSync()` | `fs.promises.mkdir()` | + +**性能影响**: + +| 场景 | 同步 I/O | 异步 I/O | +|------|---------|---------| +| 读取 10 个文件 | ~50ms(阻塞 50ms) | ~5ms(并行,阻塞 <1ms) | +| 大文件读取(10MB) | ~100ms(阻塞 100ms) | ~100ms(不阻塞其他操作) | +| 用户感知 | 键盘输入卡顿 | 流畅 | + +**Claude Code 源码审查**: + +在整个 Claude Code 源码库中搜索 `readFileSync`/`writeFileSync`/`statSync`,发现: +- **0 处** `readFileSync`(全部异步) +- **0 处** `writeFileSync`(全部异步) +- **少量** `statSync`(仅在启动初始化阶段,可接受) + +**Qwen Code 现状**:通过 grep 搜索 `readFileSync`/`writeFileSync`/`statSync`,发现多处使用——特别是在文件操作工具(`read-file.ts`、`write-file.ts`)和配置加载(`config.ts`)中。 + +**Qwen Code 修改方向**:① 搜索所有 `*Sync` 调用(`grep -r "readFileSync\|writeFileSync\|statSync" packages/core/src/tools/`);② 逐一替换为 `async/await` 版本;③ 启动阶段可保留(不影响运行时性能);④ 工具执行路径必须全部异步。 + +**实现成本评估**: +- 涉及文件:~10 个(需 grep 确认具体数量) +- 新增代码:~200 行(修改现有代码) +- 开发周期:~2 天(1 人) +- 难点:调用链上游也需要异步化(否则异步变同步) + +**改进前后对比**: +- **改进前**:读取 10 个文件 → 阻塞事件循环 50ms → 用户打字卡顿 +- **改进后**:读取 10 个文件 → 异步并行 → 不阻塞事件循环 → 用户输入流畅 + +**意义**:同步 I/O 阻塞事件循环——影响用户输入、TUI 渲染、工具执行。 +**缺失后果**:文件操作期间用户输入卡顿、UI 不更新。 +**改进收益**:全面异步 I/O——用户输入流畅、TUI 不闪烁、工具并行执行。 + +--- + + + +### 4. 文件读取缓存 + 批量并行 I/O(P1) + +Agent 在探索代码时,经常重复读取相同文件——比如第一轮读了 `package.json` 了解依赖,第三轮又读 `package.json` 确认版本。每次读取都是磁盘 I/O(~5ms),累积起来可观。更严重的是,当 Agent 需要读取 10 个文件时,当前 Qwen Code 逐个顺序读取——总延迟 = 10 × 5ms = 50ms。 + +**Claude Code 的解决方案——文件读取缓存 + 批量并行**: + +**缓存层**: +```typescript +// 1000 条 LRU 缓存,mtime 失效 +const fileReadCache = new LRUCache({ + max: 1000, + ttl: 5 * 60 * 1000, // 5 分钟过期 +}); + +async function readFileCached(path: string): Promise { + const cached = fileReadCache.get(path); + if (cached) { + const stat = await fs.promises.stat(path); + if (stat.mtimeMs === cached.mtime) { + return cached.content; // 缓存命中 + } + } + // 缓存未命中,读取磁盘 + const content = await fs.promises.readFile(path, 'utf-8'); + const stat = await fs.promises.stat(path); + fileReadCache.set(path, { content, mtime: stat.mtimeMs }); + return content; +} +``` + +**批量并行**: +```typescript +// 并行读取 10 个文件(最多 32 并发) +async function readFilesBatch(paths: string[]): Promise { + return pMap(paths, readFileCached, { concurrency: 32 }); +} +``` + +**性能收益**: + +| 场景 | 无缓存 | 有缓存 | 增益 | +|------|--------|--------|------| +| 重复读同一文件 | 5ms | <0.1ms | **50×** | +| 读 10 个不同文件(并行) | 50ms(顺序) | 5ms(并行) | **10×** | +| 读 10 个文件(缓存命中) | 50ms | <1ms | **50×** | + +**关键参数**: +- LRU 缓存:1000 条上限(防止内存膨胀) +- TTL:5 分钟(平衡新鲜度和命中率) +- mtime 校验:文件修改后缓存自动失效 +- 并行度:32 并发(避免打开太多文件描述符) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `utils/fileCache.ts` | 文件读取缓存(LRU + mtime) | +| `services/tools/toolOrchestration.ts` | 批量并行工具执行 | + +**Qwen Code 现状**:`read-file.ts` 每次从磁盘读取文件——无缓存。多个文件读取顺序执行——无并行。 + +**Qwen Code 修改方向**:① 新建 `utils/fileCache.ts`(LRU 缓存 + mtime 失效);② `read-file.ts` 使用缓存读取;③ 工具调度器支持批量并行(`pMap` 或 `Promise.all` 分片)。 + +**实现成本评估**: +- 涉及文件:~4 个 +- 新增代码:~200 行 +- 开发周期:~2 天(1 人) +- 难点:缓存失效策略(确保文件修改后不返回旧缓存) + +**改进前后对比**: +- **改进前**:Agent 探索代码 → 10 个文件顺序读取 → 50ms 延迟 +- **改进后**:Agent 探索代码 → 缓存命中 70% + 并行 → <10ms 延迟 + +**意义**:文件读取是 Agent 最频繁的操作之一——缓存 + 并行加速代码探索。 +**缺失后果**:重复读取相同文件 + 顺序 I/O——探索速度慢。 +**改进收益**:LRU 缓存 + 批量并行——代码探索快 5-10×。 + +--- + + + +### 5. Prompt Cache 分段与工具稳定排序(P1) + +Anthropic/DashScope API 的 prompt cache 机制要求**缓存前缀字节完全一致**才能命中缓存。如果工具定义的顺序变化、或系统提示内容微调,整个缓存失效——每次 API 调用都需重新缓存(浪费 token + 增加延迟)。 + +**Claude Code 的解决方案——静态/动态分段 + 工具稳定排序**: + +``` +API 请求消息结构: +┌─────────────────────────────────┐ +│ Static Prefix(缓存前缀) │ ← 系统提示 + 工具定义 + 早期消息 +│ - system prompt │ +│ - tool definitions (sorted) │ ← 稳定排序(按工具名字母序) +│ - messages[0..N] │ ← 早期对话历史 +├─────────────────────────────────┤ +│ Dynamic Suffix(动态后缀) │ ← 最近消息(每轮变化) +│ - messages[N+1..end] │ +│ - new tool results │ +└─────────────────────────────────┘ +``` + +**关键设计**: + +| 机制 | 说明 | +|------|------| +| **工具稳定排序** | 工具定义按名字字母序排列(`tools.sort((a,b) => a.name.localeCompare(b.name))`),确保每次 API 请求的工具顺序一致 | +| **工具 schema 锁定** | 工具参数 schema 不动态变化(如 `description` 字段不注入运行时信息) | +| **内置工具前缀** | 内置工具始终在 MCP 工具之前(防止 MCP 工具数量变化影响缓存前缀) | +| **Static/Dynamic 分界** | 前 N 条消息标记为 static(不变),后续消息为 dynamic(每轮变化) | + +**缓存命中率影响**: + +| 场景 | 无稳定排序 | 有稳定排序 | +|------|-----------|-----------| +| 工具顺序不变 | ~90% | ~90% | +| MCP 工具增减 | ~20%(缓存失效) | ~85%(前缀不变) | +| 工具 schema 变化 | ~10%(缓存失效) | ~85%(schema 锁定) | + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `services/api/claude.ts` | prompt cache 管理、`cache_reference` 标记、缓存前缀优化 | +| `services/api/promptCacheBreakDetection.ts` | 缓存失效检测、TTL 阈值监控 | +| `services/api/withRetry.ts` | 重试时保留模型名防止缓存失效 | + +> **注**:工具顺序稳定性是基于 Claude Code 架构的推断——工具注册层保证顺序一致, +> API 层通过 `cache_reference` 标记缓存前缀。未发现显式的字母序排序代码, +> 但 `tools` 数组顺序在请求间保持稳定是缓存命中的必要条件。 + +**Qwen Code 现状**:工具注册顺序即 API 请求顺序——无稳定排序。MCP 工具动态发现后插入——可能改变缓存前缀。 + +**Qwen Code 修改方向**:① 工具定义按名字母序排序(`tools.sort(...)`);② 内置工具始终在前,MCP 工具在后;③ 工具 schema 不注入运行时信息(保持静态);④ 系统提示中静态部分和动态部分分离。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~80 行 +- 开发周期:~1 天(1 人) +- 难点:确保所有工具注册点都遵循稳定排序 + +**改进前后对比**: +- **改进前**:MCP 工具增减 → 工具顺序变化 → 缓存失效 → 每次多花 20K token 重建缓存 +- **改进后**:MCP 工具增减 → 前缀不变 → 缓存命中 → 每次省 20K token + +**意义**:Prompt cache 命中率直接影响 API 成本和延迟——稳定排序是关键。 +**缺失后果**:工具顺序变化导致缓存失效——浪费 token + 增加延迟。 +**改进收益**:稳定排序 + schema 锁定——缓存命中率 ~85%+,API 成本降低。 + +--- + + + +### 6. 记忆/附件异步 Prefetch(P1) + +Agent 在每轮工具执行期间,经常需要搜索相关记忆(Session Memory)、加载附件(文件、图片)、收集 LSP 诊断信息。当前这些操作是**顺序执行**的——先搜索记忆 → 再加载附件 → 再收集 LSP 诊断——总延迟 = 记忆搜索 + 附件加载 + LSP 诊断。 + +**Claude Code 的解决方案——异步 Prefetch 流水线**: + +在工具执行的**同时**,后台并行搜索相关记忆和加载附件——当工具完成后,记忆和附件已经准备好: + +``` +工具执行开始: + ├─ 执行工具(如 ReadFile) ← 主要操作 + ├─ Prefetch 记忆搜索 ← 后台并行 + ├─ Prefetch 附件加载 ← 后台并行 + └─ Prefetch LSP 诊断 ← 后台并行 + +工具执行完成: + ├─ 工具结果就绪 + ├─ 记忆结果就绪(已预取) + └─ 附件结果就绪(已预取) +``` + +**关键设计**: +- `Promise.all` 并行获取(记忆 + 附件 + LSP) +- 超时保护(prefetch 超过 2s 则放弃,不阻塞主流程) +- 结果缓存(同一轮多次工具执行共享 prefetch 结果) +- 内存限制(prefetch 结果上限 100KB,防止膨胀) + +**性能收益**: + +| 场景 | 顺序执行 | 异步 Prefetch | 增益 | +|------|---------|--------------|------| +| 记忆搜索 500ms + 附件 300ms + LSP 200ms | 1000ms | 500ms(并行) | **2×** | +| 工具执行 2s + 记忆 500ms | 2500ms | 2000ms(重叠) | **1.25×** | + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `services/contextPrefetch/prefetch.ts` | 异步 prefetch 编排 | +| `services/SessionMemory/sessionMemory.ts` | 记忆搜索集成 | + +**Qwen Code 现状**:记忆搜索、附件加载、LSP 诊断顺序执行——无 prefetch。 + +**Qwen Code 修改方向**:① 新建 `services/contextPrefetch/prefetch.ts`;② 工具执行开始时触发 `Promise.all` 并行获取;③ 超时保护(2s 放弃);④ 结果缓存(同轮共享)。 + +**实现成本评估**: +- 涉及文件:~4 个 +- 新增代码:~150 行 +- 开发周期:~1.5 天(1 人) +- 难点:prefetch 与主流程的同步(确保工具完成时 prefetch 也完成) + +**改进前后对比**: +- **改进前**:工具执行 → 等完成 → 搜索记忆 → 加载附件 → 收集 LSP(总 2500ms) +- **改进后**:工具执行 + 搜索记忆 + 加载附件 + 收集 LSP 并行(总 2000ms) + +**意义**:上下文收集是每轮必需操作——prefetch 减少串行延迟。 +**缺失后果**:顺序执行上下文收集——每轮多花 500ms。 +**改进收益**:异步 prefetch——工具执行与上下文收集并行——每轮省 500ms。 + +--- + + + +### 7. 优雅关闭序列与信号处理(P1) + +用户按 `Ctrl+C` 退出 Agent 时,如果 Agent 正在执行工具(如写入文件、运行测试),直接退出可能导致: + +- 文件写入中断(文件内容不完整或损坏) +- 测试运行中断(测试数据库未清理) +- Session 状态未保存(对话历史丢失) +- 子进程孤儿化(后台进程未清理) + +**Claude Code 的解决方案——5 阶段优雅关闭**: + +| 阶段 | 操作 | 超时 | +|------|------|------| +| 1. 信号捕获 | 捕获 SIGINT(Ctrl+C)/SIGTERM(kill) | 立即 | +| 2. 停止接收 | 停止接受新输入(键盘、队列、MCP) | 100ms | +| 3. 清理注册 | 调用所有清理回调(文件句柄、子进程、临时文件) | 1s | +| 4. 状态保存 | 保存 session 状态(对话历史、内存、检查点) | 2s | +| 5. Failsafe | 如果上述超时,强制退出 | 5s 总计 | + +**实现伪代码**: + +```typescript +let isShuttingDown = false; + +async function gracefulShutdown(signal: string) { + if (isShuttingDown) return; // 防止重复信号 + isShuttingDown = true; + + // 1. 停止接收输入 + stopInputQueue(); + disconnectMCP(); + + // 2. 清理子进程 + await killAllChildProcesses(1000); // 1s 超时 + + // 3. 保存 session 状态 + await saveSessionState(2000); // 2s 超时 + + // 4. 清理临时文件 + cleanupTempFiles(); + + // 5. 退出 + process.exit(0); +} + +process.on('SIGINT', () => gracefulShutdown('SIGINT')); +process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); +``` + +**关键设计**: +- **去重**:`isShuttingDown` 标志防止重复信号导致多次清理 +- **超时**:每个阶段有独立超时(防止某个阶段卡死) +- **Failsafe**:5s 总超时后强制退出(防止无限卡住) +- **清理回调注册**:关键操作(文件写入、子进程启动)时注册清理回调 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `utils/gracefulShutdown.ts` | 信号处理、5 阶段关闭 | +| `tasks/LocalShellTask/LocalShellTask.tsx` | 子进程清理 | + +**Qwen Code 现状**:non-interactive 模式(`nonInteractiveCli.ts`)有基础 SIGINT/SIGTERM 处理;interactive 模式(`useBracketedPaste.ts`)有 cleanup。但**缺少 5 阶段优雅关闭序列**(停止接收→清理子进程→保存状态→清理临时文件→failsafe),直接退出可能中断文件写入或子进程。 + +**Qwen Code 修改方向**:① 新建 `utils/gracefulShutdown.ts`;② 注册 SIGINT/SIGTERM 处理函数;③ 关键操作注册清理回调;④ 5s failsafe 强制退出。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~120 行 +- 开发周期:~1 天(1 人) +- 难点:识别所有需要清理的资源(文件句柄、子进程、临时文件、网络连接) + +**改进前后对比**: +- **改进前**:Ctrl+C 退出 → 文件写入中断 → 文件损坏 +- **改进后**:Ctrl+C 退出 → 优雅关闭 → 文件写完再保存状态 → 安全退出 + +**意义**:优雅关闭防止数据损坏——文件、状态、子进程安全清理。 +**缺失后果**:直接退出可能损坏文件、丢失状态、孤儿进程。 +**改进收益**:5 阶段优雅关闭——数据安全、状态完整、无孤儿进程。 + +--- + + + +### 8. 原子文件写入与事务回滚(P1) + +Agent 写入文件时,如果中途中断(用户 Ctrl+C、系统崩溃、进程被 kill),可能导致文件内容不完整——只写了一半的文件既不是旧版本也不是新版本,处于损坏状态。 + +**Claude Code 的解决方案——原子写入**: + +```typescript +// ❌ 错误:直接写入(中断时文件损坏) +await fs.promises.writeFile(filePath, content, 'utf-8'); + +// ✅ 正确:原子写入(temp + rename) +const tempPath = `${filePath}.tmp.${Date.now()}`; +try { + await fs.promises.writeFile(tempPath, content, 'utf-8'); + await fs.promises.rename(tempPath, filePath); // rename 是原子操作 +} catch (error) { + // 失败时清理临时文件 + await fs.promises.unlink(tempPath).catch(() => {}); + throw error; +} +``` + +**原子性保证**: +- `rename()` 在同一文件系统上是原子操作(POSIX 保证) +- 如果 rename 成功:文件要么是新版本,要么是旧版本(不会中间状态) +- 如果 rename 失败:原始文件不变,临时文件被清理 + +**大结果持久化**: + +工具执行结果(如 Bash 输出)可能非常大(>1MB)。Claude Code 不将其保留在内存中,而是持久化到磁盘: + +```typescript +// 工具结果 >1MB 时写入临时文件 +if (toolResultSize > 1_000_000) { + const resultPath = `/tmp/tool-results-${taskId}.json`; + await fs.promises.writeFile(resultPath, JSON.stringify(toolResult)); + return { content: `Result too large, saved to ${resultPath}` }; +} +``` + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `utils/atomicWrite.ts` | 原子写入(temp + rename) | +| `services/tools/toolResultStorage.ts` | 大结果持久化 | + +**Qwen Code 现状**:`write-file.ts` 直接写入文件——中途中断时文件可能损坏。工具结果全部保留在内存中——大结果可能占大量内存。 + +**Qwen Code 修改方向**:① 新建 `utils/atomicWrite.ts`;② `write-file.ts` 使用原子写入;③ 工具结果 >1MB 时持久化到临时文件。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~100 行 +- 开发周期:~1 天(1 人) +- 难点:无(原子写入是标准模式) + +**改进前后对比**: +- **改进前**:写入文件时中断 → 文件损坏(一半内容) +- **改进后**:写入文件时中断 → 原文件不变(临时文件被清理) + +**意义**:原子写入防止文件损坏——中途中断时文件完整性有保证。 +**缺失后果**:写入中断时文件可能损坏——既不是旧版本也不是新版本。 +**改进收益**:原子写入(temp + rename)——文件要么旧版本要么新版本,不会损坏。 + +--- + + + +### 9. Token Budget 续行与自动交接(P1) + +Agent 执行复杂任务时,token 使用量持续增长。当前 Qwen Code 在 token 达到 70% 时触发压缩——但压缩是一次性的,如果压缩后 token 仍然紧张,Agent 可能很快再次触发压缩,陷入"压缩→执行→再压缩"的循环。 + +**Claude Code 的解决方案——Token Budget 续行与分层回退**: + +| 阶段 | 触发条件 | 操作 | +|------|---------|------| +| **正常执行** | <83% 窗口 | 正常工具执行 | +| **一级警告** | 83%-90% | 提示用户,准备压缩 | +| **自动压缩** | >90% | auto-compact(9 章节摘要 + 恢复文件) | +| **续行检测** | 压缩后 >85% | 继续执行但监控增长速度 | +| **递减检测** | 连续 2 轮 token 增长 <5% | 判定任务接近完成,允许继续 | +| **分层回退** | 压缩后仍 >90% | micro-compact → session memory compact → full compact | + +**关键设计**: +- **90% 续行**:压缩后如果 <85%,允许继续执行(不立即中断) +- **递减检测**:如果 token 增长速度递减(如 8% → 5% → 3%),说明任务接近完成,不需要再次压缩 +- **分层回退**:一级压缩不够时升级(micro → session memory → full) +- **紧急停止**:>95% 强制停止(防止 API 报错) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `services/compact/autoCompact.ts` | 分层回退、`MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3` | +| `query/tokenBudget.ts` | Token Budget 管理、续行逻辑 | +| `utils/tokenBudget.ts` | Token Budget 状态追踪 | + +**Qwen Code 现状**:70% 阈值一次性压缩——压缩后不检查 token 使用情况,可能很快再次触发。 + +**Qwen Code 修改方向**:① 新建 `services/tokenBudget.ts`;② 实现 4 阶段管理(正常/警告/压缩/紧急停止);③ 递减检测(连续 2 轮增长 <5% 允许继续);④ 分层回退(micro → session memory → full)。 + +**实现成本评估**: +- 涉及文件:~4 个 +- 新增代码:~200 行 +- 开发周期:~2 天(1 人) +- 难点:递减检测算法(如何判定任务接近完成) + +**改进前后对比**: +- **改进前**:70% 压缩 → 执行 2 轮又到 70% → 再压缩——循环浪费 token +- **改进后**:90% 压缩 → 续行检测 → 递减判断——接近完成时不重复压缩 + +**意义**:Token Budget 管理避免频繁压缩——续行 + 递减检测减少不必要操作。 +**缺失后果**:压缩后很快再次触发——"压缩→执行→再压缩"循环。 +**改进收益**:Token Budget 续行 + 递减检测 + 分层回退——压缩次数减少,token 更高效。 + +--- + + + +### 10. 反应式压缩(P1) + +当 API 返回 `prompt_too_long` 错误时,当前请求直接被拒绝——用户需要手动 `/compress` 后再重试。这个错误是完全可以自动恢复的。 + +**Claude Code 的解决方案——反应式压缩自动重试**: + +``` +API 返回 prompt_too_long + ↓ +捕获错误,进入反应式压缩 + ↓ +裁剪最早的消息组(按 token 超限量或 20%) + ↓ +重试 API 调用(最多 3 次) + ↓ +成功 / 仍然失败(给用户错误提示) +``` + +**关键设计**: +- **裁剪策略**:优先裁剪最早的消息组(用户消息 + 工具结果配对裁剪) +- **裁剪量计算**:`max(超出 token 数, 总 token × 20%)`(确保裁剪足够多) +- **重试上限**:3 次(防止无限重试) +- **失败回退**:3 次后仍失败,给用户友好错误提示("上下文过长,请手动 /compress") + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `services/compact/compact.ts` (1705行) | 反应式压缩、重试逻辑、`prompt_too_long` 处理 | + +**Qwen Code 现状**:API 返回错误时直接展示给用户——无自动恢复。 + +**Qwen Code 修改方向**:① API 错误处理中捕获 `prompt_too_long`;② 裁剪最早的消息组;③ 重试(最多 3 次);④ 失败时给用户友好提示。 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~120 行 +- 开发周期:~1 天(1 人) +- 难点:消息组配对裁剪(确保 user + assistant + tool results 完整裁剪) + +**改进前后对比**: +- **改进前**:API 报错 prompt_too_long → 用户手动 /compress → 重试任务 +- **改进后**:API 报错 prompt_too_long → 自动裁剪 + 重试 → 用户无感知 + +**意义**:反应式压缩自动恢复——用户不需手动干预。 +**缺失后果**:API 报错后用户需手动压缩再重试——打断工作流。 +**改进收益**:自动裁剪 + 重试(最多 3 次)——用户无感知恢复。 + +--- + +## 总结 + +本文件涵盖 10 项 P1 架构与性能增强改进: + +| # | 改进点 | 优先级 | 开发周期 | 意义 | +|---|--------|:------:|:--------:|------| +| 1 | [分层上下文压缩增强](#item-1) | P1 | ~4 天 | Time-based MC + Auto-compact 增强 | +| 2 | [API 指数退避与智能重试](#item-2) | P1 | ~1.5 天 | 10 次退避 + 模型降级 | +| 3 | [同步 I/O 异步化](#item-3) | P1 | ~2 天 | 防止事件循环阻塞 | +| 4 | [文件读取缓存 + 批量并行](#item-4) | P1 | ~2 天 | 代码探索快 5-10× | +| 5 | [Prompt Cache 分段与稳定排序](#item-5) | P1 | ~1 天 | 缓存命中率 ~85%+ | +| 6 | [记忆/附件异步 Prefetch](#item-6) | P1 | ~1.5 天 | 每轮省 500ms | +| 7 | [优雅关闭序列与信号处理](#item-7) | P1 | ~1 天 | 数据安全 + 状态完整 | +| 8 | [原子文件写入与事务回滚](#item-8) | P1 | ~1 天 | 防止文件损坏 | +| 9 | [Token Budget 续行与交接](#item-9) | P1 | ~2 天 | 减少频繁压缩 | +| 10 | [反应式压缩自动重试](#item-10) | P1 | ~1 天 | 自动恢复 prompt_too_long | + +**总计**:~17 天(1 人) + +> **免责声明**: 以上分析基于 2026 年 Q1 Claude Code(`../claude-code-leaked`)与 Qwen Code(`../qwen-code`)源码对比,可能已过时。 diff --git a/docs/comparison/qwen-code-improvement-report-p1-command-namespace.md b/docs/comparison/qwen-code-improvement-report-p1-command-namespace.md new file mode 100644 index 00000000..d7cfaf54 --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p1-command-namespace.md @@ -0,0 +1,107 @@ +# Qwen Code 改进建议 — P1 命令命名空间治理 + +> 命令系统改进项:当 built-in commands、文件命令、extension commands、MCP prompt commands 同时存在时,除了“能加载”,还需要解决命名冲突、来源隔离、前缀策略与治理边界。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. Slash Command Namespace Governance / 命令命名空间治理(P1) + +**思路**:Qwen Code 的 slash command 系统已经进入“平台化”阶段,而不再只是几十个内置命令。当前至少有四类来源会往命令空间里注入名字: + +1. built-in commands +2. user / project 文件命令 +3. extension commands +4. MCP prompt commands + +当来源越来越多时,真正的挑战不再是“怎么加载命令”,而是: + +- 谁可以占用顶级命令名? +- 重名时谁覆盖谁? +- extension 是否必须带命名空间前缀? +- MCP prompt 暴露成 slash command 时,是否应默认隔离到 server namespace? +- 用户如何知道某个命令来自 built-in、extension 还是 MCP? +- 团队/企业如何禁用某些来源或保留关键命令名? + +Claude Code 在这方面采取的是更保守的合并策略:命令合并时倾向于保持稳定、可预测的名字集合;插件命令则走独立管理路径。Qwen Code 当前虽然有基础冲突处理,但规则仍偏“实现导向”,还没有发展成完整的 namespace governance。 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `hooks/useMergedCommands.ts` | `uniqBy([...initialCommands, ...mcpCommands], 'name')`,保持命令名唯一 | +| `services/plugins/pluginCliCommands.ts` | 插件命令走独立 CLI 管理入口(install/uninstall/enable/disable/update) | +| `commands.ts` | 命令总表与内置命令体系 | + +**Qwen Code 现状**:`packages/cli/src/services/CommandService.ts` 会并行加载所有 loader 返回的命令,然后统一放入一个 `Map`。当前冲突规则是: + +- 如果是 extension command 且名字冲突,则自动改名为 `extensionName.commandName`,必要时再追加数字后缀; +- 非 extension commands(built-in / user / project / MCP prompt)则按 loader 顺序“后者覆盖前者”; +- `packages/cli/src/services/McpPromptLoader.ts` 会把 MCP prompt 直接暴露为 slash command 名,不默认带 server namespace。 + +这套策略“能工作”,但存在几个隐患: + +1. **顶级命令名竞争**:MCP prompt 与 user/project 命令都可能占用短名字; +2. **来源不透明**:用户看到 `/deploy`,并不知道它来自 project file command、某个 MCP server prompt,还是 extension; +3. **覆盖策略不够显式**:非 extension 冲突靠 loader 顺序决定,行为可预测但不够易理解; +4. **治理能力不足**:缺少 reserved names、per-source enable/disable、source visibility 等平台机制。 + +**Qwen Code 修改方向**: +1. 为 slash command 引入显式 `source namespace` 概念,例如: + - built-in: `/model` + - extension: `/ext.foo.bar` + - MCP prompt: `/mcp.github.review` + - file command: `/local.deploy` +2. 对用户常用命令保留短别名,但短别名应由治理层决定,而不是“谁最后加载谁赢”; +3. 在补全列表与帮助界面中显示命令来源(built-in / extension / MCP / local); +4. 增加 reserved name 策略,防止扩展或 MCP prompt 抢占关键命令; +5. 增加 per-source enable/disable 配置,方便团队/企业限制命令暴露面; +6. 对 MCP prompt 默认使用 `serverName.promptName` 命名,避免直接污染顶级命令空间。 + +**实现成本评估**: +- 涉及文件:~4 个 +- 新增代码:~220 行 +- 开发周期:~3 天(1 人) +- 难点:兼容现有短命令习惯,避免破坏已有用户工作流 + +**改进前后对比**: +- **改进前**:所有来源往同一个命令表注册——extension 有改名兜底,但 user/project/MCP prompt 之间仍可能靠加载顺序决定覆盖关系 +- **改进后**:每类命令先进入各自 namespace,再由治理层决定哪些短别名暴露到顶级空间——冲突规则清晰、来源可见、企业可控 + +**意义**:命令系统一旦可扩展,就必须治理命名空间。 +**缺失后果**:命令来源越多,顶级命令空间越混乱——冲突、覆盖、误调用会越来越频繁。 +**改进收益**:命令来源透明 + 冲突策略清晰 + 保留字治理,让 slash command 系统从“加载器集合”升级为“可管理的平台能力”。 + +--- + +## 为什么这不是现有 slash command / MCP 文档的重复 + +- 现有 slash command 对比更多回答“有哪些命令”; +- MCP 集成对比更多回答“能否接入 MCP”; +- 本文讨论的是:**当命令来源变多后,命令名如何治理、如何隔离、如何防冲突**。 + +也就是说,它关注的是 **命令平台治理**,不是命令功能列表。 + +--- + +## 可分阶段演进路径 + +| 阶段 | 能力 | 说明 | +|------|------|------| +| Stage 1 | source 可视化 | 补全列表/帮助页展示命令来源 | +| Stage 2 | MCP / extension 默认命名空间 | 避免顶级命令空间污染 | +| Stage 3 | reserved names + alias policy | 保留关键短命令,统一别名分配 | +| Stage 4 | team policy | 团队/企业按来源禁用命令或限定前缀 | + +这样 Qwen Code 的命令系统才能在继续开放扩展的同时保持可预测性。 + +--- + +## 相关文章 + +- [内置命令总览](./slash-commands-deep-dive.md) +- [MCP 集成深度对比](./mcp-integration-deep-dive.md) +- [Qwen Code 改进建议总览](./qwen-code-improvement-report.md) diff --git a/docs/comparison/qwen-code-improvement-report-p1-hooks-runtime.md b/docs/comparison/qwen-code-improvement-report-p1-hooks-runtime.md new file mode 100644 index 00000000..9817c7c8 --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p1-hooks-runtime.md @@ -0,0 +1,78 @@ +# Qwen Code 改进建议 — P1 Hook Runtime 扩展 + +> Hook 运行时改进项:从 shell command-only 扩展到多后端执行模型,支持 Prompt Hook、异步 Hook 编排与更强的语义策略能力。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. Prompt Hooks / LLM 语义 Hook(P1) + +**思路**:当前 Qwen Code 的 Hook 已有较完整的事件总线(`PreToolUse`、`PostToolUse`、`Notification`、`SessionStart` 等),但执行器本质上仍只有 `type: "command"`——所有 Hook 都必须落到 shell 命令。这样虽然足够通用,却不适合“语义判断”类场景:例如“这次 `git push` 是否违反团队发布策略?”、“本次工具调用是否与当前任务目标冲突?”、“这段用户输入是否包含敏感数据,应该先二次确认?”。 + +Claude Code 在 shell / HTTP 之外,还支持 **Prompt Hook**:把 Hook prompt 连同当前上下文交给一个小模型执行,要求模型返回严格 JSON(`{ok:true}` 或 `{ok:false, reason:"..."}`)。这使 Hook 从“脚本式规则”扩展为“语义策略判断器”。适合 shell/regex 难以表达的治理场景。 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `utils/hooks/execPromptHook.ts` | `execPromptHook()`,调用小模型执行 Hook prompt,强制 `json_schema` 输出 | +| `types/hooks.ts` | Hook 类型体系、sync/async JSON 响应协议、Prompt/Callback Hook 类型定义 | +| `utils/hooks/AsyncHookRegistry.ts` | 异步 Hook 注册、进度轮询、stdout JSON 响应解析 | + +**Qwen Code 现状**:Hook 类型仍是单一 `command`。`packages/core/src/hooks/types.ts` 中 `HookType` 仅有 `Command`,`HookConfig = CommandHookConfig`;`packages/core/src/hooks/hookRunner.ts` 也只实现 `executeCommandHook()`。这意味着即使事件体系很丰富,运行时仍局限于 shell 脚本 + stdin/stdout JSON。 + +**Qwen Code 修改方向**: +1. `packages/core/src/hooks/types.ts` 扩展 `HookType`:在 `command` 之外新增 `prompt`(后续也可继续扩展 `http`、`callback`); +2. 新建 `packages/core/src/hooks/execPromptHook.ts`:复用现有模型调用栈,采用小模型执行 Hook prompt; +3. 要求 Prompt Hook 输出严格 JSON Schema,避免自由文本导致的不确定性; +4. 在 `hookRunner.ts` 增加分发逻辑:`type === 'prompt'` 时走 LLM Hook 分支; +5. 在 `hooksCommand.ts` / Hook UI 中展示 Hook 类型、模型、超时与阻断原因。 + +**实现成本评估**: +- 涉及文件:~5 个 +- 新增代码:~250 行 +- 开发周期:~3 天(1 人) +- 难点:Hook prompt 的安全边界与超时控制 + +**改进前后对比**: +- **改进前**:Hook 只能执行 shell 命令——复杂语义检查需要开发者自己写脚本、调用外部模型、再拼 JSON 返回 +- **改进后**:`type: "prompt"` 直接把语义判断下沉到 Hook Runtime——可用小模型做轻量审批、策略校验、提示增强 + +**意义**:很多治理策略本质是语义问题,而不是字符串匹配问题。 +**缺失后果**:复杂 Hook 只能壳套壳——shell 调脚本,脚本再调模型,配置脆弱且调试困难。 +**改进收益**:Prompt Hook 让 Hook 成为一等语义策略层——更适合审批、安全、规范、上下文增强。 + +--- + +## 为什么这不是现有“HTTP Hooks / Conditional Hooks”的重复 + +- **Conditional Hooks** 解决的是“哪些 Hook 应该触发”; +- **HTTP Hooks** 解决的是“Hook 是否可以直接请求远程服务”; +- **Prompt Hooks / Hook Runtime 扩展** 解决的是“Hook Runtime 本身是否支持多执行后端,尤其是 LLM 语义执行”。 + +三者分别对应 **触发条件**、**传输通道**、**执行模型**,不是同一个层次的问题。 + +--- + +## 进一步演进方向 + +如果后续继续向 Claude Code 靠拢,Qwen Code 的 Hook Runtime 可以按下面路径递进演化: + +| 阶段 | 能力 | 说明 | +|------|------|------| +| Stage 1 | `command` + `prompt` | 本地脚本与 LLM 语义判断双后端 | +| Stage 2 | 统一 async registry | 所有 Hook 类型共享异步调度、超时、进度与结果回传 | +| Stage 3 | typed hook backends | `http` / `callback` / `remote-policy` 等可插拔执行器 | +| Stage 4 | explainability | 展示“哪个 Hook 阻断了继续执行、原因是什么、来自哪层策略” | + +这样 Hook 系统才能从“事件很多的 shell 执行器”升级为“可扩展的策略运行时”。 + +--- + +## 相关文章 + +- [Hook/插件扩展深度对比](./hook-plugin-extension-deep-dive.md) +- [Qwen Code 改进建议总览](./qwen-code-improvement-report.md) diff --git a/docs/comparison/qwen-code-improvement-report-p1-permission-explainability.md b/docs/comparison/qwen-code-improvement-report-p1-permission-explainability.md new file mode 100644 index 00000000..8f0288c3 --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p1-permission-explainability.md @@ -0,0 +1,94 @@ +# Qwen Code 改进建议 — P1 权限决策可解释性 + +> 权限系统改进项:不仅要“做出 allow / ask / deny 决策”,还要向用户解释“为什么会这样判定、命中了哪条规则、下一步如何调整”。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. Permission Decision Trace / 权限决策解释链(P1) + +**思路**:Qwen Code 这两版在权限引擎层面其实已经不弱:支持 `allow / ask / deny` 三类规则、session/persistent 两级规则、shell compound command 拆分、shell virtual operations 推导(把 `cat` / `curl` / redirect 等映射为 `read_file` / `web_fetch` / `write_file`),还会用 AST 判断 shell 命令是否只读。这意味着它已经能“算出一个合理决策”。 + +问题在于,**用户几乎看不到这条决策链**。 + +当一个工具调用被拒绝或要求确认时,用户真正想知道的是: + +- 是哪一条规则命中了? +- 是 shell 规则命中,还是 virtual file/web 规则命中? +- 是 `deny` 规则覆盖了 `allow`,还是没有任何规则命中而回退到默认模式? +- 如果我想放行,应该改 `/permissions` 里的哪条规则? +- 如果是 Hook 导致 ask/block,具体是哪一个 Hook? + +Claude Code 在这方面明显更成熟:不仅有权限判定,还有一整套 **decision reason → UI explanation → debug info** 链路。它把“结果”与“原因”一起展示,让权限系统从黑盒变成可调试、可学习的交互系统。 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `components/permissions/PermissionDecisionDebugInfo.tsx` | 展示 decision reason、rule/hook/mode/classifier/sandboxOverride/workingDir 等来源 | +| `components/permissions/PermissionRuleExplanation.tsx` | 把 `decisionReason` 转成用户可读解释,并给出 `/permissions` / `/hooks` 调整提示 | +| `components/permissions/PermissionExplanation.tsx` | 懒加载权限解释,展示 risk level / explanation / reasoning | +| `hooks/toolPermission/PermissionContext.ts` | 权限上下文状态 | +| `hooks/toolPermission/permissionLogging.ts` | 权限日志记录 | +| `tools/BashTool/commandSemantics.ts` | shell 语义分类辅助解释 | + +**Qwen Code 现状**:权限判定逻辑很强,但可解释性弱。`packages/core/src/permissions/permission-manager.ts` 负责规则优先级计算(`deny > ask > allow > default`),还会结合 `extractShellOperations()` 做 shell virtual operation 判定;但返回结果主要是最终 decision,没有面向 UI 的“命中链路对象”。`packages/cli/src/ui/components/PermissionsDialog.tsx` 更像规则管理器:列出 allow/ask/deny 规则、支持搜索/增删,却不展示“某次具体决策为何发生”。用户能改规则,却不容易理解当前规则系统到底是怎么工作的。 + +**Qwen Code 修改方向**: +1. 在 `permission-manager.ts` 中新增 explain 模式:除了最终 decision,还返回 `decisionTrace`,至少包括: + - 命中的规则(类型、来源、原始 rule 文本) + - 是否发生 deny/ask 覆盖 + - 是否来自 shell virtual operations + - 是否走了默认回退 +2. 在 shell 场景下,把 `extractShellOperations()` 的推导结果挂入 trace,让用户知道“`cat foo` 为何等价于 `read_file(foo)`”; +3. 在工具确认 UI 中增加“Why?”/“Explain”视图,展示命中链和建议操作; +4. 在 `/permissions` 界面中增加“最近一次命中示例”或 dry-run tester,方便用户调试规则; +5. 后续可与 Hook Runtime 联动:若是 Hook 导致 ask/block,也统一走同一套 decision trace UI。 + +**实现成本评估**: +- 涉及文件:~5 个 +- 新增代码:~250 行 +- 开发周期:~3 天(1 人) +- 难点:在不破坏现有权限 API 的前提下为 UI 暴露结构化 trace + +**改进前后对比**: +- **改进前**:用户只看到“被拒绝 / 需要确认”——但不知道是哪条规则、哪个层级、哪种语义命中导致的 +- **改进后**:用户可看到完整 decision trace——例如“命中 project deny 规则 `WriteFile(/secrets/**)`,同时 shell 语义推导出 `echo > secrets.txt` 属于写文件操作,因此最终为 deny” + +**意义**:权限系统越强,越需要 explainability。否则规则一多,用户只能靠试错。 +**缺失后果**:权限引擎是黑盒——用户难以调试规则,常见结果是要么过度放权,要么频繁误拦截。 +**改进收益**:decision trace 让权限系统可学习、可调试、可审计——特别适合复杂 shell、团队策略和企业治理场景。 + +--- + +## 为什么这不是现有“Denial Tracking / 权限对话框文件预览”的重复 + +- **Denial Tracking** 解决的是“连续拒绝后如何自动回退模式”; +- **权限对话框文件预览** 解决的是“审批时展示将要修改的文件内容”; +- **Permission Decision Trace** 解决的是“这次 allow / ask / deny 到底是怎么推导出来的”。 + +三者分别是 **回退策略**、**审批信息展示**、**决策可解释性**,层次不同。 + +--- + +## 可分阶段落地的演进路径 + +| 阶段 | 能力 | 说明 | +|------|------|------| +| Stage 1 | 基础 decision trace | 命中 rule、source、default fallback、virtual ops | +| Stage 2 | 确认 UI explain 面板 | 在工具确认框中展示“为什么 ask/deny” | +| Stage 3 | `/permissions test` dry-run | 给一条工具调用/命令,输出命中链与最终结果 | +| Stage 4 | 审计与导出 | 记录最近 N 次权限判定链,便于排障与企业审计 | + +这样 Qwen Code 的权限系统才能从“规则引擎”进一步升级为“可调试的权限平台”。 + +--- + +## 相关文章 + +- [Hook Runtime 扩展](./qwen-code-improvement-report-p1-hooks-runtime.md) +- [Hook/插件扩展深度对比](./hook-plugin-extension-deep-dive.md) +- [Qwen Code 改进建议总览](./qwen-code-improvement-report.md) diff --git a/docs/comparison/qwen-code-improvement-report-p1-resume-discovery.md b/docs/comparison/qwen-code-improvement-report-p1-resume-discovery.md new file mode 100644 index 00000000..449f8c7b --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p1-resume-discovery.md @@ -0,0 +1,102 @@ +# Qwen Code 改进建议 — P1 会话恢复发现与导航 + +> 会话恢复改进项:不仅要“能 resume”,还要在多目录、多 worktree、长历史会话中更容易找到并恢复正确的 session。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. Worktree-aware Resume + Agentic Session Search(P1) + +**思路**:现有“会话恢复”讨论通常聚焦在崩溃后如何继续执行、如何重建 transcript、如何恢复上下文状态。但从日常使用体验看,用户在 `/resume` 前真正遇到的第一个问题往往不是“能不能恢复”,而是: + +- 我到底该恢复哪一个 session? +- 这个 session 是不是在另一个 worktree 里启动的? +- 如果它来自同一仓库的另一个 worktree,能不能直接恢复? +- 如果它来自完全不同的目录,能不能给我正确的恢复命令? +- 当我只记得“之前聊过某个 bug / 某个 API 设计”,能不能靠语义而不是时间顺序把它找出来? + +Claude Code 在这一层明显更完整:它不仅有 resume 命令,还实现了 **跨项目 / worktree 感知的恢复导航**,以及 **基于 session 元数据与 transcript 的 agentic semantic search**。这使 `/resume` 从“打开一个历史列表”变成“帮用户重新回到正确工作上下文”的恢复工作流。 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `utils/crossProjectResume.ts` | `checkCrossProjectResume()`:区分同目录、同 repo worktree、不同项目三类恢复场景 | +| `utils/agenticSessionSearch.ts` | `agenticSessionSearch()`:综合 title/tag/branch/summary/transcript 做语义检索 | +| `commands/resume/resume.tsx` | `/resume` 交互入口 | + +从 `crossProjectResume.ts` 可以直接看到 Claude Code 会区分三种结果: +- `isCrossProject: false`:当前目录直接恢复; +- `isSameRepoWorktree: true`:同一仓库 worktree,可直接恢复; +- 不同项目:生成 `cd && claude --resume ` 的正确命令。 + +而 `agenticSessionSearch.ts` 则不是简单的字符串过滤:它会综合 `title`、`tag`、`branch`、`summary`、`first message`、`transcript` 等字段,优先用字面命中做预筛,再把候选交给小模型做更宽松的语义召回与排序。 + +**Qwen Code 现状**:Qwen Code 已有基础 session 恢复能力,但更偏“列表式浏览”。 + +- `packages/cli/src/ui/commands/resumeCommand.ts`:`/resume` 只是打开 dialog; +- `packages/cli/src/ui/components/SessionPicker.tsx`:主要展示 `prompt + 相对时间 + messageCount + gitBranch`,支持上下移动与按 branch 过滤; +- `packages/core/src/services/sessionService.ts`:支持分页列出本项目会话、按 mtime 排序、加载完整会话数据; +- 但当前没有看到: + - 跨目录 / worktree 恢复导航; + - 不同项目时生成正确恢复命令; + - 基于 transcript 的语义搜索; + - “我只记得聊过什么,不记得时间和标题”这种使用场景下的高召回检索。 + +换句话说,Qwen Code 现在更像“session list picker”,而不是“resume discovery system”。 + +**Qwen Code 修改方向**: +1. 在 session metadata 中显式保留项目路径 / worktree 信息; +2. `/resume` 入口增加 cross-project/worktree 判断: + - 当前目录:直接恢复; + - 同 repo worktree:直接恢复或提示 worktree 路径; + - 不同项目:给出可复制的 `cd ... && qwen --resume ...` 命令; +3. 在 `SessionPicker` 上层增加搜索模式,不只按时间排序和 branch 过滤; +4. 引入 agentic session search:在 title/branch/summary 命中的基础上,再把 transcript 摘要交给小模型做相关性排序; +5. 将“恢复导航”与“崩溃恢复”分层:前者解决“找得到正确 session”,后者解决“恢复后能否无缝续跑”。 + +**实现成本评估**: +- 涉及文件:~6 个 +- 新增代码:~320 行 +- 开发周期:~4 天(1 人) +- 难点:session 元数据扩展与语义搜索结果排序 + +**改进前后对比**: +- **改进前**:`/resume` 主要是按时间顺序列历史会话——跨目录场景需要用户自己判断,想找老会话主要靠滚动和记忆 +- **改进后**:`/resume auth bug` 可直接按语义找回相关 session;若 session 属于同仓库其他 worktree,则直接提示正确恢复路径;若来自不同项目,则生成可执行恢复命令 + +**意义**:长周期、多分支、多 worktree 工作流下,找对 session 和恢复 session 同样重要。 +**缺失后果**:历史会话越多,`/resume` 越像时间排序日志——用户知道“以前聊过”,却很难高效回到那次上下文。 +**改进收益**:恢复导航 worktree-aware + 语义搜索,让 session 从“日志文件”升级成“可检索、可回到的工作资产”。 + +--- + +## 为什么这不是现有“会话崩溃恢复”条目的重复 + +- **会话崩溃恢复与中断检测** 关注的是:session 异常中断后如何重建状态并继续执行; +- **Worktree-aware Resume + Agentic Search** 关注的是:用户如何在大量历史 session 中找到正确会话,并在跨目录 / worktree 场景下恢复到正确位置。 + +前者是 **恢复执行引擎**,后者是 **恢复发现与导航层**,问题层次不同。 + +--- + +## 可分阶段演进路径 + +| 阶段 | 能力 | 说明 | +|------|------|------| +| Stage 1 | 路径感知 resume | 区分当前目录 / 同 repo worktree / 不同项目 | +| Stage 2 | resume command suggestion | 对跨项目 session 自动生成恢复命令 | +| Stage 3 | metadata search | title/branch/summary 搜索 | +| Stage 4 | agentic transcript search | transcript 摘要 + 小模型语义召回 | + +这样 Qwen Code 的 session 恢复才能从“按时间翻列表”升级为“按上下文找回工作”。 + +--- + +## 相关文章 + +- [Git 工作流与会话管理](./git-workflow-session-deep-dive.md) +- [Qwen Code 改进建议总览](./qwen-code-improvement-report.md) diff --git a/docs/comparison/qwen-code-improvement-report-p2-uncovered.md b/docs/comparison/qwen-code-improvement-report-p2-uncovered.md new file mode 100644 index 00000000..a48882d8 --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p2-uncovered.md @@ -0,0 +1,204 @@ +# Qwen Code 改进建议 — P2 未覆盖功能深度分析 + +> 本文件记录的是**现有改进总览表中完全未提及**的功能模块。每项都经过源码级验证,确保不与已有报告重复。 +> +> 验证方法:所有改进点已对照 `qwen-code-improvement-report.md` 总览表、所有 deep-dive 文档、所有 P0-P3 分报告、所有 single-file Agent 文档(`tools/` 目录),确认无重复。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. Plugin Marketplace 系统(P2) + +**做什么**:Claude Code 的 `/plugin` 命令不仅是启用/禁用管理,还是一个完整的**插件市场客户端**——支持浏览市场、搜索、安装、卸载、信任验证、选项配置全流程: + +| 子功能 | 文件 | 行数 | 说明 | +|--------|------|------|------| +| 市场浏览 | `BrowseMarketplace.tsx` | ~200 | 搜索/筛选/浏览可用插件 | +| 发现插件 | `DiscoverPlugins.tsx` | ~150 | 推荐相关插件 | +| 安装管理 | `ManagePlugins.tsx` + `ManageMarketplaces.tsx` | ~400 | 安装/卸载/启用/禁用 | +| 信任验证 | `PluginTrustWarning.tsx` + `ValidatePlugin.tsx` | ~300 | 安装前安全警告和验证 | +| 选项配置 | `PluginOptionsDialog.tsx` + `PluginOptionsFlow.tsx` + `PluginSettings.tsx` | ~400 | 安装后配置用户偏好 | +| 分页/详情 | `usePagination.ts` + `pluginDetailsHelpers.tsx` + `PluginErrors.tsx` | ~200 | UI 辅助 | +| 添加市场源 | `AddMarketplace.tsx` | ~100 | 添加第三方市场 | +| 统一已安装列表 | `UnifiedInstalledCell.tsx` | ~100 | 已安装插件展示 | + +**总规模**:17 文件,~7575 行 + +**为什么 Qwen Code 应该学习**: + +Qwen Code 有 Skill 系统(SKILL.md 本地文件),但没有**市场**概念。用户无法浏览、搜索、一键安装社区插件。关键差距: + +| 能力 | Claude Code | Qwen Code | +|------|-------------|-----------| +| 浏览市场 | ✓ Marketplace UI | ✗ 无 | +| 搜索插件 | ✓ 按标签/关键词搜索 | ✗ 无 | +| 一键安装 | ✓ 市场内直接安装 | ✗ 手动复制文件 | +| 信任验证 | ✓ 安装前安全审查 | ✗ 无 | +| 选项引导 | ✓ 安装后配置偏好 | ✗ 无 | +| 卸载/禁用 | ✓ UI 管理 | ✗ 手动删除文件 | + +**Qwen Code 现状**:Skill 系统是本地文件(`~/.qwen/SKILL.md` 或项目内 `SKILL.md`),没有市场、搜索、安装、信任验证、选项配置等能力。 + +**Qwen Code 修改方向**: +1. 设计 Plugin Manifest schema(name/version/description/permissions/commands/skills) +2. 实现 `/plugin` 命令(浏览/搜索/安装/卸载/启用/禁用) +3. 添加 Marketplace API 对接(或基于 GitHub 的简单市场) +4. 安装前信任验证(权限声明、文件审查) +5. 安装后选项引导流 + +**实现成本评估**: +- 涉及文件:~15 个 +- 新增代码:~2000 行 +- 开发周期:~10 天(1 人) +- 难点:插件沙箱化、权限验证、市场源可信度 + +**意义**:Skill 系统是本地扩展,Plugin Marketplace 是生态——用户可发现、安装、管理社区插件。 +**缺失后果**:用户需手动创建/复制 SKILL.md——无法发现社区扩展。 +**改进收益**:Plugin Marketplace = 一键安装 + 安全验证 + 配置引导——生态繁荣。 + +--- + + + +### 2. 上下文 Tips 系统(P2) + +> **注意**:`services/tips/tipRegistry.ts` 在 `qwen-code-improvement-report-p2-tools.md#item-19` 中被提及为"上下文 Tips 系统",但**没有详细源码分析**。本项补充完整的实现细节。 + +**做什么**:Claude Code 内建一个提示(tips)系统——在用户等待期间(如 API 调用中、工具执行时),显示上下文相关的使用技巧: + +**关键源码**: + +| 文件 | 行数 | 职责 | +|------|------|------| +| `services/tips/tipRegistry.ts` | 686 | 注册表——数百条预设 tips,按标签/场景分类 | +| `services/tips/tipScheduler.ts` | 58 | 调度器——根据等待时间/场景选择展示哪条 tip | +| `services/tips/tipHistory.ts` | 17 | 历史记录——防止重复展示同一条 tip | + +**Tip 分类**(基于 `tipRegistry.ts` 686 行分析): +- **通用技巧**:"按 Escape 取消当前操作" +- **命令提示**:"试试 `/review` 审查 PR" +- **功能发现**:"你可以用 `/model` 切换模型" +- **高级用法**:"在 CLAUDE.md 中定义项目规范" +- **上下文相关**:如果检测到用户在用 MCP,展示 "试试 `/mcp` 管理服务器" + +**调度策略**: +- 等待 >3 秒时展示(避免打断快速操作) +- 每条 tip 有冷却时间(不重复展示) +- 按场景标签过滤(MCP/Agent/Git 等) + +**为什么 Qwen Code 应该学习**: + +Qwen Code 有 `/tips` 命令(手动查看技巧),但没有**自动展示**机制。用户在等待 API 响应时的空白时间没有被利用来教育用户。 + +**Qwen Code 现状**:Tips 需要用户手动 `/tips` 查看——没有自动调度、没有上下文感知、没有防重复机制。 + +**Qwen Code 修改方向**: +1. 新建 `services/tips/tipRegistry.ts`——预设 tips 库(按场景分类) +2. 新建 `services/tips/tipScheduler.ts`——等待期间自动展示 +3. 新建 `services/tips/tipHistory.ts`——防重复 +4. 在 `useGeminiStream.ts` 的等待状态中集成 tip 展示 + +**实现成本评估**: +- 涉及文件:~5 个 +- 新增代码:~500 行 +- 开发周期:~3 天(1 人) +- 难点:编写数百条高质量 tips 并按场景分类 + +--- + + + +### 3. /clear 清屏与会话重置(P2) + +**做什么**:Claude Code 的 `/clear` 不只是清屏——它提供多种清除模式: + +| 模式 | 命令 | 说明 | +|------|------|------| +| 清屏 | `/clear` | 清除终端显示,保留对话历史 | +| 清对话 | `/clear --history` | 清除对话历史,保留系统提示 | +| 全新开始 | `/clear --all` | 清除一切,如同新 session | + +**关键设计**: +- 清屏时保持 scrollback buffer 可选择(不清空终端历史) +- 清对话后保留 memory/attachments 等上下文 +- 清一切后重新初始化系统提示和工具注册 +- 交互确认(防止误操作) + +**为什么 Qwen Code 应该学习**: + +Qwen Code 有 `/clear` 命令,但只有清屏功能——没有清除对话历史或完全重置的能力。用户在想"重新开始"但保留当前 session(不重启)时没有选项。 + +**Qwen Code 修改方向**: +1. 扩展 `/clear` 命令支持 `--history` 和 `--all` 标志 +2. `--history`:清空 messages 数组,保留 system prompt + memory +3. `--all`:完全重置,重新初始化 +4. 交互确认 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~100 行 +- 开发周期:~0.5 天(1 人) + +--- + + + +### 4. Thinkback 回忆功能(P2) + +**做什么**:`/thinkback` 让 Agent 回顾整个会话的历程——从开始到现在的关键决策、修改的文件、解决的问题: + +``` +/thinkback # 回顾整个 session +/thinkback --from "30 min ago" # 回顾最近 30 分钟 +/thinkback --topic "auth" # 回顾认证相关的讨论 +``` + +**实现方式**: +- 分析完整 transcript(JSONL) +- 提取关键决策点(模型调用、文件修改、错误修复) +- 生成结构化的回顾报告 +- 可选按时间范围或主题过滤 + +**为什么 Qwen Code 应该学习**: + +长会话(50+ 轮)后,用户经常想不起来刚才做了什么。`/thinkback` 提供结构化的回顾——"你在 10:30 重构了 auth middleware,在 11:00 修复了 3 个测试失败"。 + +Qwen Code 有 `/summary` 命令,但它是即时摘要(总结当前状态),不是回顾(时间线式的关键事件列表)。 + +**Qwen Code 修改方向**: +1. 新建 `/thinkback` 命令 +2. 分析 transcript 提取关键事件(文件修改、错误修复、决策点) +3. 按时间线排序 +4. 支持 `--from` 和 `--topic` 过滤 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~300 行 +- 开发周期:~2 天(1 人) +- 难点:从 transcript 中识别关键事件 + +--- + +## 总结 + +本文件涵盖 4 项**现有改进总览表完全未提及**的功能: + +| # | 改进点 | 源码规模 | 开发周期 | 意义 | +|---|--------|:--------:|:--------:|------| +| 1 | [Plugin Marketplace](#item-1) | 17 文件, 7575 行 | ~10 天 | 生态扩展 | +| 2 | [上下文 Tips 系统](#item-2) | 3 文件, 761 行 | ~3 天 | 功能发现 | +| 3 | [/clear 增强](#item-3) | 已有基础 | ~0.5 天 | 会话管理 | +| 4 | [Thinkback 回忆](#item-4) | 2 文件, 566 行 | ~2 天 | 长会话回顾 | + +**总计**:~15.5 天(1 人) + +> **验证声明**:本文件所有改进点已对照以下文档确认无重复: +> - `qwen-code-improvement-report.md` 总览表(全部 P0-P3 条目) +> - 所有 deep-dive 文档(33 个文件) +> - 所有 P0-P3 分报告(p0-p1-core/engine/platform、p2-core/perf/stability/tools、p3) +> - 所有 single-file Agent 文档(`tools/claude-code/` 目录下 10 个文件) +> +> 注意:`install-github-app` 和 `add-dir` 已在其他报告中覆盖,已从本文件移除。 diff --git a/docs/comparison/qwen-code-improvement-report-p2-ux.md b/docs/comparison/qwen-code-improvement-report-p2-ux.md new file mode 100644 index 00000000..b8dfdb39 --- /dev/null +++ b/docs/comparison/qwen-code-improvement-report-p2-ux.md @@ -0,0 +1,842 @@ +# Qwen Code 改进建议 — P2 用户体验与交互增强 + +> 中等优先级改进项(用户体验方向)。每项包含:问题场景、现状分析、改进前后对比、实现成本评估、Claude Code 源码索引、Qwen Code 修改方向。 +> +> 返回 [改进建议总览](./qwen-code-improvement-report.md) + +--- + + + +### 1. /plan 计划模式(P2) + +你让 Agent 做一个复杂任务:"重构认证模块,从 JWT 迁移到 OAuth2"。Agent 立刻开始改代码——但它可能理解不全需求,直接动手导致方向偏差。Plan 模式解决这个问题——通过明确的"规划→审批→执行"三阶段流程: + +``` +规划阶段(收集需求 + 制定计划)→ 用户审批(确认计划是否正确)→ 执行阶段(按计划实施) +``` + +**Claude Code 的实现——/plan 命令**: + +| 特性 | 说明 | +|------|------| +| 命令入口 | `/plan` 或 `/plan open` 打开当前会话计划 | +| UI 组件 | Ink JSX 渲染计划卡片(含状态、步骤、审批按钮) | +| 计划格式 | Markdown checklist(`- [ ]` 未做,`- [x]` 已完成) | +| 审批流 | 用户确认后才能执行,防止 Agent 自作主张 | +| 退出工具 | `exitPlanMode` 工具请求用户批准退出 | + +**工作流程**: + +| 步骤 | 做什么 | +|------|--------| +| 1. 用户输入 `/plan` | 进入计划模式 | +| 2. Agent 分析需求 | 生成 Markdown 计划(含步骤、依赖、风险) | +| 3. 渲染计划卡片 | 显示状态(Draft/Approved/Executing)、进度、步骤列表 | +| 4. 用户审批 | 按 Enter 批准或要求修改 | +| 5. Agent 执行计划 | 按计划逐步执行,勾选完成步骤 | + +**关键设计细节**: +- 计划模式期间 Agent 不能直接编辑文件(必须通过 `exitPlanMode` 获得批准) +- 计划文件持久化到 `.claude/plans/` 目录,可按 `/plan open` 重新查看 +- 支持增量更新——执行中发现新步骤可追加到计划 +- `plan_mode` 状态抑制其他功能(如 prompt suggestion 在计划模式期间不触发) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/plan/plan.tsx` | `/plan` 命令入口、Ink 组件 | +| `tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts` | 退出计划 + 审批流 | +| `utils/planMode/` | 计划持久化、状态管理 | + +**Qwen Code 现状**:已有 `exitPlanMode` 工具(支持退出规划模式),但缺少 `/plan` 命令主动查看/管理当前计划。用户无法在规划期间查看进度或修改计划。 + +**Qwen Code 修改方向**:① 新建 `/plan` 命令(`commands/plan.tsx`);② Ink 组件渲染计划卡片(状态 + 步骤 + 进度);③ 从 AppState 读取当前计划并显示;④ 支持非交互模式(`/plan` 输出纯文本计划)。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~200 行 +- 开发周期:~2 天(1 人) +- 难点:Ink UI 布局(状态卡片、步骤列表、进度条) + +**改进前后对比**: +- **改进前**:规划期间无法查看计划全貌——只能等 Agent 执行完才知道做了什么 +- **改进后**:`/plan` 显示当前计划(状态 + 步骤 + 进度)——随时掌握 Agent 在做什么 + +**意义**:复杂任务需要明确的计划可视性和审批流程——防止 Agent 方向偏差。 +**缺失后果**:用户无法主动查看/管理计划——只能等 Agent 执行完。 +**改进收益**:`/plan` = 计划可视化 + 进度追踪 + 审批流程——用户掌控全局。 + +--- + + + +### 2. /review PR 审查(P2) + +你在 GitHub 上创建了一个 PR,想让 Agent 自动审查代码质量、找出潜在 Bug、检查测试覆盖。但当前流程是:手动切到浏览器 → 打开 PR 页面 → 复制 diff → 粘贴给 Agent → 等待分析。更糟的是,PR 可能包含 10+ 文件、500+ 行变更,手动整理 diff 费时且容易遗漏。 + +**Claude Code 的解决方案——/review 命令**: + +一键自动 PR 审查——使用 `gh` CLI 获取 PR 列表、详情、diff,然后用模型分析代码: + +```bash +/review # 审查当前分支的 PR +/review 123 # 审查 PR #123 +/review --ultra # UltraReview(远程深度审查,10-20 分钟) +``` + +**工作流程**: + +| 步骤 | 做什么 | +|------|--------| +| 1. `gh pr list` | 获取当前分支关联的 PR(或指定 PR 号) | +| 2. `gh pr view` | 获取 PR 标题、描述、作者、标签 | +| 3. `gh pr diff` | 获取完整 diff(限制 1MB) | +| 4. 构建 Prompt | 注入 PR 元数据 + diff + 审查指导 | +| 5. 模型分析 | 按 4 步流程审查(PR 列表→详情→Diff→分析) | +| 6. 输出报告 | 代码正确性、项目规范、性能影响、测试覆盖、安全考虑 | + +**审查 Prompt 模板**(4 步流程): + +``` +1. 使用 `gh pr list` 获取当前仓库和分支上所有开放 PR 的列表 +2. 使用 `gh pr view ` 获取每个 PR 的详情 +3. 使用 `gh pr diff ` 获取每个 PR 的 diff +4. 分析代码变更并提供反馈 + +重点关注: +- 代码正确性(Bug、边界情况、错误处理) +- 项目规范(命名、架构、设计模式) +- 性能影响(时间复杂度、内存使用、N+1 查询) +- 测试覆盖(单元测试、集成测试、边界案例) +- 安全考虑(注入攻击、敏感数据暴露、权限检查) +``` + +**UltraReview(远程深度审查)**: +- 调用 Claude Code on the web 的 bughunter 服务 +- 10-20 分钟深度分析(远长于本地审查) +- 查找更难发现的 Bug(逻辑错误、竞态条件、内存泄漏) +- 配额追踪 + 进度心跳 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/review/` | `/review` 命令目录(reviewRemote.ts、ultrareviewCommand.tsx 等) | +| `commands/review/reviewRemote.ts` | 远程 review 实现、`gh` CLI 集成 | +| `commands/review/ultrareviewCommand.tsx` | UltraReview 远程审查 UI | + +**Qwen Code 现状**:无 `/review` 命令。用户需手动获取 PR diff 再交给 Agent 分析。Qwen Code 有 `/insight` 命令做会话分析,但没有 PR 专用审查工具。 + +**Qwen Code 修改方向**:① 新建 `/review` 命令(`commands/review.ts`);② 集成 `gh` CLI(或 GitHub API)获取 PR 信息;③ 构建审查 Prompt(4 步流程 + 5 关注点);④ 输出结构化审查报告。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~300 行 +- 开发周期:~2 天(1 人) +- 难点:`gh` CLI 依赖检测(用户未安装时的回退)、大 diff 的分批处理 + +**改进前后对比**: +- **改进前**:审查 PR → 手动切浏览器 → 复制 diff → 粘贴给 Agent(~2 分钟) +- **改进后**:`/review` → 自动获取 PR + diff → 模型分析 → 输出报告(~30 秒) + +**意义**:PR 审查是开发工作流的高频操作——自动化省时且更一致。 +**缺失后果**:用户需手动获取 PR diff——打断工作流。 +**改进收益**:`/review` = 一键自动 PR 审查——代码质量、规范、性能、安全全覆盖。 + +--- + + + +### 3. /branch 会话分支(P2) + +你和 Agent 讨论了 20 轮,决定用"方案 A"重构认证模块。Agent 已经改了 5 个文件。但你突然想到:"如果用方案 B(JWT 替换 Session)会不会更好?" 现在你面临两难: + +- **继续方案 A**:放弃探索方案 B 的可能 +- **尝试方案 B**:让 Agent 撤销方案 A 的所有修改,从头开始——但如果方案 B 不好,方案 A 的工作全部丢失 +- **手动保存**:手动 `git stash`、复制对话历史……太繁琐 + +**Claude Code 的方案——/branch 命令**:从当前对话的任意位置创建一个"分支",就像 git 分支一样——原始对话保留不动,分支独立探索: + +``` +原始 session(方案 A): + 轮次 1 → 轮次 2 → ... → 轮次 20 → [继续方案 A] + ↘ +分支 session(方案 B): 轮次 20 → "试试 JWT 方案" → ... + (完整继承前 20 轮上下文) +``` + +**工作原理**: + +| 步骤 | 做什么 | +|------|--------| +| 1. 用户输入 `/branch` | 触发分支创建 | +| 2. 复制 transcript JSONL | 完整对话历史复制到新文件 | +| 3. 写入溯源元数据 | `forkedFrom: { sessionId, messageUuid }` | +| 4. 自动命名 | 原名 + " (Branch)",支持去重 | +| 5. 切换到分支 | 分支成为当前活跃 session | +| 6. 原始可恢复 | 随时 `--resume` 回到方案 A | + +**关键设计**: +- 分支独立文件(不修改原始 transcript) +- 完整的上下文继承(前 20 轮对话全部保留) +- 溯源链(`forkedFrom` 元数据追踪父子关系) +- 自动命名去重(`My Session (Branch)`、`My Session (Branch 2)`、...) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/branch/branch.ts` (296行) | `getUniqueForkName()`、transcript 复制 + `forkedFrom` 元数据 | + +**Qwen Code 现状**:没有 `/branch` 命令。用户想探索替代方案只能:手动 `git stash` 保存文件变更 → 开新 session → 重新描述上下文 → 尝试新方案 → 不满意再手动恢复。 + +**Qwen Code 修改方向**:① 新建 `/branch` 命令;② `sessionService.ts` 新增 `forkSession()` 方法(复制 JSONL + 写入 `forkedFrom` 元数据);③ 自动命名 + 去重(`getUniqueForkName()`);④ `/resume` 命令支持列出原始和分支 session。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~200 行 +- 开发周期:~2 天(1 人) +- 难点:JSONL transcript 的高效复制(大 session 可能有数 MB) + +**改进前后对比**: +- **改进前**:想尝试替代方案 → 要么丢弃当前进度,要么手动保存/恢复 +- **改进后**:`/branch` → 分支继承完整上下文独立探索 → 不满意随时切回原始 + +**意义**:探索替代方案是软件开发的日常——架构选型、算法对比、重构策略 A/B 测试。 +**缺失后果**:探索替代方案必须丢弃当前进度——开发者不敢轻易尝试。 +**改进收益**:`/branch` = 零风险探索——不满意切回原始,满意继续分支,两边进度都保留。 + +--- + + + +### 4. /doctor 环境诊断(P2) + +你在新机器上部署 Agent,遇到各种问题:git 没配置导致无法 commit、node 版本不兼容导致启动失败、API Key 过期无法调用模型、代理设置错误无法联网。每次排查都要手动检查——`which git`、`node --version`、`echo $API_KEY`、`curl -I https://api.example.com`——费时且容易遗漏。 + +**Claude Code 的解决方案——/doctor 命令**: + +一键系统诊断——检查所有关键依赖是否就绪,输出结构化报告: + +``` +Doctor Diagnosis +━━━━━━━━━━━━━━━━ +✓ git 2.39.2 +✓ node 20.11.0 +✓ npm 10.2.4 +✓ shell zsh 5.9 +✓ API key configured +✓ Proxy: none +✓ Network: reachable +✓ Permissions: default + +All checks passed. +``` + +**检查清单**: + +| 检查项 | 检查什么 | 失败表现 | +|--------|---------|---------| +| git | 版本 + 用户配置(name/email) | "git not found" / "git user not configured" | +| node | 版本(要求 ≥ 特定版本) | "node version too old" | +| shell | 类型 + 版本(bash/zsh/fish) | "shell not detected" | +| API Key | 是否配置 + 是否有效 | "API key not set" / "API key invalid" | +| Proxy | 代理设置(HTTP_PROXY/HTTPS_PROXY) | "proxy configured" 显示代理地址 | +| Network | 网络可达性(ping API 端点) | "network unreachable" | +| Permissions | 默认权限模式(default/auto-edit/yolo) | "permission mode: yolo" | + +**关键设计**: +- 每个检查独立执行(一个失败不影响其他) +- 失败项显示详细错误信息(如 `git` 失败显示 "Run `git config --global user.name 'Your Name'`") +- 非交互模式也支持(`--non-interactive`) +- 结果可复制(便于贴到 Issue 报告) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/doctor/doctor.tsx` | `/doctor` 命令入口 | +| `screens/Doctor.tsx` | 诊断 UI 组件、检查清单实现 | + +**Qwen Code 现状**:无 `/doctor` 命令。用户遇到环境问题时,需手动排查——费时且可能遗漏关键检查项。 + +**Qwen Code 修改方向**:① 新建 `/doctor` 命令(`commands/doctor.ts`);② 实现检查清单(git/node/shell/API Key/proxy/network/permissions);③ 输出结构化报告(✓/✗ 标记 + 版本号);④ 失败项显示修复建议。 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~200 行 +- 开发周期:~1.5 天(1 人) +- 难点:各项检查的跨平台兼容性(macOS/Linux/Windows) + +**改进前后对比**: +- **改进前**:排查环境问题 → 手动检查 6+ 项 → 费时且可能遗漏(~5 分钟) +- **改进后**:`/doctor` → 一键诊断 → 结构化报告 + 修复建议(~5 秒) + +**意义**:环境诊断对用户体验很重要——尤其是新用户首次启动。 +**缺失后果**:用户需手动排查环境问题——费时且容易遗漏。 +**改进收益**:`/doctor` = 一键诊断 + 修复建议——新用户快速上手,老用户快速排障。 + +--- + + + +### 5. /cost 费用追踪(P2) + +你使用 Agent 完成了一个复杂任务——重构了 10 个文件、执行了 50+ 工具调用、跑了 3 次测试。但你不知道这次花了多少钱——token 用量、API 调用次数、预估费用完全黑盒。对于按 token 计费的 API 用户来说,无法追踪成本是个严重问题。 + +**Claude Code 的解决方案——/cost 命令**: + +显示当前 session 的 API 费用估算——输入 token、输出 token、总费用、模型单价: + +``` +Session Cost +━━━━━━━━━━━━ +Input tokens: 125,430 ($3.76) +Output tokens: 18,920 ($0.95) +Total: 144,350 ($4.71) + +Model: claude-sonnet-4-20250514 +Pricing: $30/$15 per Mtok (input/output) +``` + +**关键设计**: +- 实时追踪(每轮 API 调用后更新) +- 按模型计费(不同模型单价不同) +- 分区显示(输入/输出 token 分别计费) +- 支持多 session 汇总(`/cost --all`) +- 费用预警(超过阈值时警告) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/cost/cost.ts` | `/cost` 命令实现、费用计算 | +| `commands/cost/index.ts` | 命令入口 | + +**Qwen Code 现状**:无 `/cost` 命令。用户无法直接查看 session 费用——只能通过 `/stats` 查看基础统计(不含费用估算)。对于按 token 计费的 DashScope API 用户,成本黑盒。 + +**Qwen Code 修改方向**:① 新建 `/cost` 命令(`commands/cost.tsx`);② 从 API 响应中提取 token 用量(input/output);③ 按模型单价计算费用;④ Ink UI 显示(输入/输出/总计)。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~150 行 +- 开发周期:~1 天(1 人) +- 难点:获取准确的模型定价(DashScope/Gemini 各模型单价) + +**改进前后对比**: +- **改进前**:完成任务 → 不知道花了多少钱——成本黑盒 +- **改进后**:`/cost` → 显示输入/输出 token + 费用——成本透明 + +**意义**:API 用户需要追踪费用——尤其是长会话和高频使用场景。 +**缺失后果**:用户无法了解 session 费用——成本不可控。 +**改进收益**:`/cost` = 实时费用追踪——输入/输出 token + 模型单价 + 总费用一目了然。 + +--- + + + +### 6. /session 会话管理(P2) + +你运行 Agent 一段时间后,积累了多个 session——有的在做重构、有的在修 Bug、有的在做代码审查。但当前只能看到最近一个 session——无法列出所有会话、无法按项目名称搜索、无法删除旧 session。更麻烦的是,你无法知道每个 session 的工作状态(进行中/已完成/已放弃)。 + +**Claude Code 的解决方案——/session 命令**: + +会话管理——列出、搜索、删除、重命名 session: + +```bash +/session # 列出所有 session +/session --search auth # 搜索包含 "auth" 的 session +/session rename "New Name" # 重命名当前 session +/session delete # 删除指定 session +/session clear # 删除所有已完成 session +``` + +**显示格式**: + +| ID | 名称 | 目录 | 状态 | 时间 | +|----|------|------|------|------| +| 12345 | Refactor Auth | /project-a | completed | 2h ago | +| 12346 | Fix Login Bug | /project-a | active | now | +| 12347 | Code Review | /project-b | abandoned | 1d ago | + +**关键设计**: +- 从 transcript 文件扫描(`.claude/sessions/*.jsonl`) +- 状态推断:`completed`(最后一条消息是 assistant 回复)、`active`(最近 30 分钟有活动)、`abandoned`(超过 24 小时无活动) +- 删除确认(防止误删活跃 session) +- 搜索支持(按 session 名称/目录/内容) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/session/session.tsx` | `/session` 命令、Ink UI | + +**Qwen Code 现状**:无 `/session` 命令。用户可以通过 `--resume` 恢复最近 session,但无法列出/搜索/管理历史 session。 + +**Qwen Code 修改方向**:① 新建 `/session` 命令(`commands/session.tsx`);② 扫描 `.qwen/sessions/` 目录;③ 解析 transcript 提取元数据(名称、目录、时间、状态);④ Ink UI 列表显示;⑤ 支持 `--search`/`--delete`/`--rename` 子命令。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~300 行 +- 开发周期:~2 天(1 人) +- 难点:状态推断逻辑(如何区分 completed vs abandoned)、大 session 文件的快速扫描 + +**改进前后对比**: +- **改进前**:管理多个 session → 只能靠记忆——不知道哪个在做哪个任务 +- **改进后**:`/session` → 列表显示所有 session + 状态 + 搜索——一目了然 + +**意义**:多 session 管理是高频使用场景——尤其是并行处理多个任务。 +**缺失后果**:用户无法列出/搜索/管理 session——只能恢复最近一个。 +**改进收益**:`/session` = 会话列表 + 搜索 + 删除 + 重命名——多任务管理不再混乱。 + +--- + + + +### 7. /share 分享会话(P2) + +你让 Agent 解决了一个复杂的 Bug——花了 30 轮对话、尝试了 5 种方案、最终找到了根因。你想把这次排查过程分享给团队——但当前只能手动复制粘贴整个对话历史到文档或聊天工具,格式混乱且丢失代码高亮。 + +**Claude Code 的解决方案——/share 命令**: + +生成可分享链接——将整个 session 导出为格式化的 HTML/Markdown,或上传到云端生成 URL: + +```bash +/share # 生成分享链接(上传到云端) +/share --copy # 复制 Markdown 格式到剪贴板 +/share --html # 导出为 HTML 文件 +``` + +**分享链接格式**(云端 URL): +``` +https://claude.ai/share/ +``` + +页面显示: +- Session 名称 + 时间 +- 完整对话历史(用户消息 + Agent 回复 + 工具调用) +- 代码块语法高亮 +- 可折叠的工具结果 +- 时间戳显示每轮耗时 + +**关键设计**: +- 隐私保护:默认不分享(用户必须显式执行 `/share`) +- 脱敏处理:自动隐藏 API Key、密码等敏感信息 +- 有效期:分享链接 7 天过期(可配置) +- 只读:查看者不能修改原始 session + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/share/index.js` | `/share` 命令、云端上传 | + +**Qwen Code 现状**:无 `/share` 命令。用户无法直接分享 session——只能手动复制对话历史。Qwen Code 有 `/export` 命令导出对话到文件,但没有云端分享链接。 + +**Qwen Code 修改方向**:① 新建 `/share` 命令(`commands/share.ts`);② 将 session 导出为 Markdown/HTML 格式;③ (可选)上传到阿里云 OSS 生成 URL;④ `--copy` 选项复制 Markdown 到剪贴板(OSC 52)。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~250 行 +- 开发周期:~2 天(1 人) +- 难点:云端上传(需要后端支持)、脱敏处理(识别并隐藏敏感信息) + +**改进前后对比**: +- **改进前**:分享 session → 手动复制粘贴 → 格式混乱 + 丢失高亮(~5 分钟) +- **改进后**:`/share` → 生成链接/复制 Markdown → 格式完整 + 代码高亮(~3 秒) + +**意义**:分享 session 是协作场景的刚需——团队学习、排查记录、最佳实践沉淀。 +**缺失后果**:用户无法直接分享——只能手动复制,格式差且易丢失信息。 +**改进收益**:`/share` = 一键生成链接/Markdown——格式完整 + 代码高亮 + 脱敏保护。 + +--- + + + +### 8. /diff 代码差异查看(P2) + +你让 Agent 修改了 10 个文件后,想快速查看具体改了什么——哪些行加了、哪些行删了。但当前只能手动切到另一个终端执行 `git diff`——打断工作流,而且 diff 输出没有语法高亮,大文件难以浏览。 + +**Claude Code 的解决方案——/diff 命令**: + +内嵌 diff 查看——在终端内显示结构化差异,支持语法高亮和文件过滤: + +```bash +/diff # 显示所有未提交变更 +/diff --staged # 显示已暂存变更 +/diff src/auth/ # 只显示指定目录的 diff +/diff --stat # 只显示统计信息(文件数 + 行数) +``` + +**显示格式**: + +```diff +--- a/src/auth/middleware.ts ++++ b/src/auth/middleware.ts +@@ -15,7 +15,7 @@ +- const token = req.headers.authorization; ++ const token = req.headers.authorization?.split(' ')[1]; +``` + +**关键设计**: +- Rust NAPI bindings 快速着色(比纯 JS 快 10×) +- 行号 gutter(显示 `15 |`) +- 语法高亮(TypeScript/Python/Markdown 等) +- 文件头分隔线(`─── src/auth/middleware.ts ───`) +- 限制:50 文件上限、1MB/文件、400 行/文件(防止大 diff 卡顿) +- merge/rebase 期间自动跳过 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/diff/diff.tsx` | `/diff` 命令入口 | +| `components/diff/DiffDialog.tsx` | Diff 对话框 UI 组件 | +| `utils/gitDiff.ts` (532行) | diff 解析、限制逻辑 | + +**Qwen Code 现状**:无 `/diff` 命令。用户需手动执行 `git diff`——无语法高亮、无文件过滤、无行数限制。 + +**Qwen Code 修改方向**:① 新建 `/diff` 命令(`commands/diff.tsx`);② 调用 `git diff` 获取 diff;③ 解析 diff 格式(`---`/`+++`/`@@`/`+`/`-`);④ 语法高亮(使用现有 highlight.js 或类似库);⑤ Ink UI 渲染(颜色 + 行号 + 文件头)。 + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~250 行 +- 开发周期:~2 天(1 人) +- 难点:diff 解析的正确性(处理边缘情况如二进制文件、merge commit)、语法高亮性能 + +**改进前后对比**: +- **改进前**:查看变更 → 手动 `git diff` → 切换终端 + 无高亮(~10 秒) +- **改进后**:`/diff` → 内嵌显示 + 语法高亮 + 文件过滤(~2 秒) + +**意义**:diff 查看是代码工作流的基础操作——内嵌显示减少上下文切换。 +**缺失后果**:用户需手动切终端执行 `git diff`——打断工作流。 +**改进收益**:`/diff` = 内嵌差异查看 + 语法高亮 + 文件过滤——变更一目了然。 + +--- + + + +### 9. /rename 重命名会话(P2) + +你运行 Agent 完成了一个任务——session 的自动命名是 "Refactor auth module and add tests and update docs"。这个名称太长且不直观——第二天你想找到这个 session 时完全想不起来它做了什么。你希望能给 session 起一个简短易记的名称,如 "Auth Refactor"。 + +**Claude Code 的解决方案——/rename 命令**: + +重命名当前 session——修改 session 元数据中的名称字段: + +```bash +/rename "Auth Refactor" # 重命名当前 session +``` + +**工作原理**: +- 修改 `.claude/sessions/.json` 中的 `name` 字段 +- 名称显示在 `/session` 列表、`--resume` 选择器、终端标题栏 +- 名称长度限制:≤ 100 字符 +- 支持特殊字符(空格、中文、emoji) + +**关键设计**: +- 立即生效(不需重启 session) +- 名称持久化(写入 session 元数据文件) +- 空名称拒绝(必须提供非空名称) +- 名称历史记录(可选——保留原始自动名称) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/rename/rename.ts` | `/rename` 命令、元数据修改 | + +**Qwen Code 现状**:无 `/rename` 命令。Session 名称由 Agent 自动生成(通常是第一条消息的摘要),用户无法修改。 + +**Qwen Code 修改方向**:① 新建 `/rename` 命令(`commands/rename.ts`);② 修改 session 元数据文件中的 `name` 字段;③ 验证名称(非空 + 长度限制);④ 立即生效(更新内存中的 session 名称)。 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~60 行 +- 开发周期:~0.5 天(1 人) +- 难点:无 + +**改进前后对比**: +- **改进前**:session 名称自动生成——长且不直观——难以查找 +- **改进后**:`/rename "Auth Refactor"`——简短易记——快速定位 + +**意义**:session 命名影响后续查找和恢复——用户自定义名称更符合记忆习惯。 +**缺失后果**:自动生成的名称长且不直观——难以查找历史 session。 +**改进收益**:`/rename` = 自定义 session 名称——简短易记、快速定位。 + +--- + + + +### 10. /upgrade 版本升级(P2) + +新版本 Agent 发布了——包含重要的 Bug 修复和性能改进。但你不知道当前版本是多少、是否有新版本可用、升级需要做什么。你只能手动检查——`npm list -g` 看版本号 → 去 GitHub 看 Release Notes → 再手动执行 `npm update`——流程繁琐。 + +**Claude Code 的解决方案——/upgrade 命令**: + +版本检查 + 一键升级——显示当前版本、最新版本、变更日志: + +```bash +/upgrade # 检查更新 + 提示升级 +/upgrade --check # 只检查更新(不升级) +/upgrade --changelog # 显示变更日志 +``` + +**工作流程**: + +| 步骤 | 做什么 | +|------|--------| +| 1. 检查 npm registry | 获取最新版本号 | +| 2. 对比当前版本 | 判断是否需要升级 | +| 3. 显示变更日志 | 显示新版本的关键变更 | +| 4. 提示升级 | `Run: npm update -g @anthropic-ai/claude-code` | + +**显示格式**: + +``` +Current version: 2.0.50 +Latest version: 2.0.53 + +Changes in 2.0.53: +- Fixed: Shell command timeout issue +- Added: New /review command +- Improved: Tool execution speed by 30% + +To upgrade: npm update -g @anthropic-ai/claude-code +``` + +**关键设计**: +- 非阻塞检查(后台异步,不阻塞启动) +- 版本号语义化(semver 对比) +- 变更日志从 GitHub Release API 获取 +- 可选自动升级(`--auto` 标志) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `commands/upgrade/upgrade.ts` | `/upgrade` 命令、npm registry 检查 | + +**Qwen Code 现状**:无 `/upgrade` 命令。用户需手动检查版本和执行升级。Qwen Code 有 `/version` 显示当前版本号,但没有检查更新和升级指导。 + +**Qwen Code 修改方向**:① 新建 `/upgrade` 命令(`commands/upgrade.ts`);② 查询 npm registry 获取最新版本;③ 对比当前版本(semver);④ 如有新版本,显示变更日志 + 升级命令。 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~120 行 +- 开发周期:~1 天(1 人) +- 难点:npm registry API 的可靠性(可能需回退到 GitHub Release API) + +**改进前后对比**: +- **改进前**:检查更新 → 手动 `npm list` + 查 GitHub → 手动升级(~1 分钟) +- **改进后**:`/upgrade` → 自动检查 + 显示变更 + 指导升级(~5 秒) + +**意义**:版本升级是用户保持最新的关键——简化流程提高升级率。 +**缺失后果**:用户需手动检查版本——升级率低,可能错过重要修复。 +**改进收益**:`/upgrade` = 自动检查 + 变更日志 + 升级指导——用户快速保持最新。 + +--- + + + +### 11. Plugin 系统增强(P2) + +当前 Qwen Code 的扩展机制主要是 Skills(SKILL.md 文件)。Skill 系统很好用,但有一个限制:一个 Skill 只能定义一个 prompt 模板——不能提供命令(commands)、hooks(生命周期钩子)、MCP 服务器配置、或子代理(agents)定义。 + +**Claude Code 的 Plugin 系统——组件容器**: + +一个 Plugin 可以提供 5 种组件(`PluginComponent`): + +| 组件类型 | 说明 | 示例 | +|---------|------|------| +| `commands` | 用户可交互的命令 | `/review`、`/bughunter` | +| `skills` | 模型可调用的技能 | "React 组件规范"、"Python 测试指南" | +| `hooks` | 生命周期钩子 | session 启动时加载特定配置 | +| `mcpServers` | MCP 服务器配置 | 数据库查询 MCP、Slack MCP | +| `output-styles` | 输出样式 | Learning 模式、Explanatory 模式 | + +**Plugin 来源**: +- `builtin` — 随 CLI 分发,用户可通过 `/plugin` UI 启用/禁用 +- `marketplace` — 第三方插件市场 +- `--plugin-dir` — 本地开发调试 + +**Plugin 加载流程**: + +``` +1. 启动时:initBuiltinPlugins() 注册内置插件 +2. getCommands() 调用时(memoized by cwd): + ├── getPluginSkills() → 从 plugin 的 skills/ 目录加载 + ├── getPluginCommands() → 从 plugin 的 commands/ 目录加载 + └── 合并到命令注册中心 +3. 运行时:/reload-plugins 命令清除缓存,重新加载 +``` + +**Plugin 定义格式**(Markdown + frontmatter): + +```markdown +--- +name: github-review +version: 1.0.0 +commands: + - name: review + description: Review PRs with GitHub API +--- + +# GitHub Review Plugin + +This plugin provides PR review capabilities using the GitHub API. + +## Commands + +### /review + +Review the current branch's PR... +``` + +**关键设计**: +- 变量替换:`${CLAUDE_PLUGIN_ROOT}`、`${CLAUDE_SKILL_DIR}`、`${CLAUDE_SESSION_ID}`、`${user_config.X}` +- 启用/禁用:用户可通过 `/plugin` UI 切换 built-in plugins +- 缓存:`memoize` 加载结果,`clearPluginCommandCache()` 失效 +- 错误处理:16 种 PluginError 类型(加载失败、解析错误、依赖缺失等) + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `plugins/builtinPlugins.ts` | 内置插件注册表 | +| `utils/plugins/loadPluginCommands.ts` | 从插件目录加载 Command 的核心逻辑 | +| `types/plugin.ts` | Plugin 类型定义 | +| `utils/plugins/schemas.ts` | PluginManifest JSON Schema | + +**Qwen Code 现状**:Skill 系统支持良好(SKILL.md),但缺少 Plugin 概念——无法聚合多个组件(commands + skills + hooks + MCP servers)。用户也无法通过 UI 启用/禁用内置功能。 + +**Qwen Code 修改方向**:① 引入 Plugin 概念(`types/plugin.ts`);② Plugin 作为组件容器(commands/skills/hooks/MCP);③ `/plugin` UI 管理启用/禁用;④ 变量替换机制(`${PLUGIN_ROOT}` 等);⑤ 缓存 + 失效策略。 + +**实现成本评估**: +- 涉及文件:~6 个 +- 新增代码:~400 行 +- 开发周期:~3 天(1 人) +- 难点:Plugin 与现有 Skill 系统的兼容性、变量替换的完整性 + +**改进前后对比**: +- **改进前**:扩展只能提供 Skill(prompt 模板)——无法聚合命令/hooks/MCP +- **改进后**:Plugin 提供多种组件——一个安装包包含完整功能——用户可启用/禁用 + +**意义**:Plugin 作为组件容器——聚合 commands/skills/hooks/MCP——扩展能力更强。 +**缺失后果**:Skill 只能定义 prompt——无法提供更复杂的扩展(命令 + hooks + MCP)。 +**改进收益**:Plugin 系统 = 组件容器 + 启用/禁用管理 + 变量替换——扩展能力大幅提升。 + +--- + + + +### 12. Task 统一框架(P2) + +当前 Qwen Code 如果有多种后台执行体(Subagent、Shell 命令、Cron 任务等),它们可能各自独立管理——状态追踪、通知、内存管理分散在不同模块。这导致:难以统一查看所有后台任务、无法一致地切换前台/后台、内存管理策略不一致。 + +**Claude Code 的 Task 框架——统一任务管理**: + +所有后台执行体统一为 `Task` 接口——共享注册、轮询、通知、内存管理机制: + +```typescript +// Task 接口(极简设计) +type Task = { + name: string + type: TaskType + kill(taskId: string): Promise +} +``` + +**7 种 Task 类型**: + +| 类型 | 说明 | 典型场景 | +|------|------|---------| +| `local_bash` | 本地 Shell 命令 | 运行测试、构建、lint | +| `local_agent` | 本地后台 Agent | 子代理并行执行 | +| `remote_agent` | 远程 Agent 会话 | CCR 远程审查 | +| `in_process_teammate` | 进程内队友 | Swarm 协作 | +| `local_workflow` | 工作流脚本 | 自动化流水线 | +| `monitor_mcp` | MCP 监控 | 监听 MCP 事件 | +| `dream` | 记忆整理 | Auto Dream 后台 consolidation | + +**Task 状态机**: + +``` +pending → running → completed/failed/killed + ↑ + notified=true(可被 GC 驱逐) +``` + +**框架机制**: + +| 机制 | 说明 | +|------|------| +| 注册(`registerTask`) | 创建任务状态 → 添加到 AppState.tasks | +| 轮询(`pollTasks`) | 1000ms 间隔 → 读取磁盘输出 delta → 应用 offset + 驱逐 | +| 通知(`enqueueTaskNotification`) | 各任务类型自行发送完成/失败通知 | +| 内存管理(`evictTerminalTask`) | 终端任务 + notified + 超出 grace period → 删除 | +| 前台/后台切换(`registerForeground`) | Shell/Agent 任务支持一次性后台化 | + +**关键设计**: +- **被动式任务管理**:Task 实现只提供 kill 逻辑,其余由外部驱动 +- **Grace Period**:本地 Agent 任务终止后保留 30 秒供 UI 查看(`PANEL_GRACE_MS = 30000`) +- **消息上限**:队友消息上限 500 条(`TEAMMATE_MESSAGES_UI_CAP = 500`),超出丢弃最旧的 +- **Stall Watchdog**:45 秒无输出增长 + 尾部匹配 prompt 模式 → 通知用户 + +**Claude Code 源码索引**: + +| 文件 | 关键函数/常量 | +|------|-------------| +| `Task.ts` | `TaskType`(7种)、`TaskStatus`(5种)、`Task` 接口 | +| `tasks.ts` | Task 注册中心、`getAllTasks()`、`getTaskByType()` | +| `utils/task/framework.ts` | `registerTask()`、`pollTasks()`、`generateTaskAttachments()`、`evictTerminalTask()` | +| `tasks/LocalAgentTask/LocalAgentTask.tsx` | 本地后台 Agent 任务 | +| `tasks/LocalShellTask/LocalShellTask.tsx` | 本地 Shell 任务 | +| `tasks/RemoteAgentTask/RemoteAgentTask.tsx` | 远程 Agent 任务 | +| `tasks/InProcessTeammateTask/InProcessTeammateTask.tsx` | 进程内队友任务 | +| `tasks/DreamTask/DreamTask.ts` | Dream 任务(记忆整理) | + +**Qwen Code 现状**:Subagent、Shell、Cron 任务可能各自管理状态——缺少统一的 Task 框架。用户无法统一查看所有后台任务(`/tasks` 命令)。 + +**Qwen Code 修改方向**:① 定义统一 Task 接口(`types/task.ts`);② 实现 Task 框架(`utils/task/framework.ts`);③ 将 Subagent/Shell/Cron 适配为 Task 类型;④ 新建 `/tasks` 命令列出所有后台任务。 + +**实现成本评估**: +- 涉及文件:~8 个 +- 新增代码:~500 行 +- 开发周期:~4 天(1 人) +- 难点:现有任务系统的重构(Subagent/Shell/Cron 状态管理迁移) + +**改进前后对比**: +- **改进前**:后台任务分散管理——Subagent/Shell/Cron 各自独立——无法统一查看 +- **改进后**:统一 Task 框架——所有任务共享注册/轮询/通知/内存管理——`/tasks` 一目了然 + +**意义**:统一 Task 框架简化后台任务管理——一致性 + 可观测性。 +**缺失后果**:后台任务管理分散——难以统一查看/管理。 +**改进收益**:Task 框架 = 统一接口 + 注册/轮询/通知/内存管理 + `/tasks` 命令——后台任务一目了然。 + +--- + +## 总结 + +本文件涵盖 12 项 P2 用户体验与交互增强改进: + +| # | 改进点 | 优先级 | 开发周期 | 意义 | +|---|--------|:------:|:--------:|------| +| 1 | [/plan 计划模式](#item-1) | P2 | ~2 天 | 计划可视化 + 审批流程 | +| 2 | [/review PR 审查](#item-2) | P2 | ~2 天 | 自动 PR 审查 | +| 3 | [/branch 会话分支](#item-3) | P2 | ~2 天 | 零风险探索替代方案 | +| 4 | [/doctor 环境诊断](#item-4) | P2 | ~1.5 天 | 一键环境诊断 | +| 5 | [/cost 费用追踪](#item-5) | P2 | ~1 天 | API 费用透明化 | +| 6 | [/session 会话管理](#item-6) | P2 | ~2 天 | 列表/搜索/删除 session | +| 7 | [/share 分享会话](#item-7) | P2 | ~2 天 | 一键分享 session | +| 8 | [/diff 代码差异](#item-8) | P2 | ~2 天 | 内嵌 diff 查看 | +| 9 | [/rename 重命名会话](#item-9) | P2 | ~0.5 天 | 自定义 session 名称 | +| 10 | [/upgrade 版本升级](#item-10) | P2 | ~1 天 | 自动检查 + 升级指导 | +| 11 | [Plugin 系统增强](#item-11) | P2 | ~3 天 | 组件容器 + 启用管理 | +| 12 | [Task 统一框架](#item-12) | P2 | ~4 天 | 统一后台任务管理 | + +**总计**:~23 天(1 人) + +> **免责声明**: 以上分析基于 2026 年 Q1 Claude Code(`../claude-code-leaked`)与 Qwen Code(`../qwen-code`)源码对比,可能已过时。 diff --git a/docs/comparison/qwen-code-improvement-report-p3.md b/docs/comparison/qwen-code-improvement-report-p3.md index 1e3f6dcd..05ccf607 100644 --- a/docs/comparison/qwen-code-improvement-report-p3.md +++ b/docs/comparison/qwen-code-improvement-report-p3.md @@ -371,241 +371,550 @@ Claude Code 的解决方案:官方 marketplace——支持插件发布、搜 -### 12. sandbox excludedCommands 排除机制(P3) +### 12. 沙箱排除命令 excludedCommands(P3) -**问题**:sandbox 模式下所有 shell 命令受限,但某些命令(如 `npm install`)需要网络访问。用户需要逐次审批或全局禁用 sandbox,没有"sandbox 默认开但某些命令排除"的选项。 +**做什么**:Claude Code 允许用户配置一组命令模式,这些命令**不被沙箱执行**——直接在宿主机运行: -**Claude Code 源码索引**: +```json +{ "sandbox": { "excludedCommands": ["docker:*", "npm run test:*", "bazel:*"] } } +``` -| 文件 | 关键函数/常量 | -|------|-------------| -| `tools/BashTool/shouldUseSandbox.ts` | excludedCommands 配置 + GrowthBook 动态列表 | +**关键源码**: -**Qwen Code 现状**:sandbox 有 984 行实现,但无 excludedCommands 排除机制。 +| 文件 | 行数 | 职责 | +|------|------|------| +| `commands/sandbox-toggle/sandbox-toggle.tsx` | 132 | `/sandbox` 命令 + `exclude` 子命令 | +| `utils/sandbox/sandbox-adapter.ts` | ~900 | `addToExcludedCommands()` 函数 | +| `tools/BashTool/shouldUseSandbox.ts` | ~100 | excludedCommands 匹配逻辑 | +| `components/sandbox/SandboxSettings.tsx` | 295 | 沙箱设置 UI(3 种模式) | +| `components/sandbox/SandboxOverridesTab.tsx` | 192 | excludedCommands 展示 | -**Qwen Code 修改方向**:设置中新增 `sandbox.excludedCommands` 列表,匹配时跳过 sandbox。 +**总规模**:~1700 行 -**实现成本评估**:涉及 ~2 个文件,~50 行,~0.5 天。难点:命令匹配粒度(完整命令 vs 前缀)。 +**Qwen Code 现状**:Qwen Code 的 `sandbox.ts`(984 行)支持 docker/podman/sandbox-exec,但**没有 excludedCommands 功能**,也没有交互式沙箱设置 UI。 -**意义**:sandbox 排除 = 安全与便利兼得。 -**缺失后果**:要么全 sandbox(`npm install` 每次审批)要么全不 sandbox(无保护)。 -**改进收益**:excludedCommands = 安全命令自动放行,危险命令仍受限。 +**Qwen Code 修改方向**: +1. 在 `settingsSchema.ts` sandbox 配置中添加 `excludedCommands` 字段 +2. 新建 `utils/sandbox/excludedCommands.ts`——命令模式匹配逻辑 +3. 修改 `shouldUseSandbox()` 逻辑——检查命令是否匹配 excludedCommands +4. 扩展 `/sandbox` 命令——添加 excludedCommands 管理 UI + +**实现成本评估**: +- 涉及文件:~5 个 +- 新增代码:~300 行 +- 开发周期:~2 天(1 人) +- 难点:命令模式匹配(通配符 + 环境变量剥离 + 复合命令拆分) --- -### 13. /privacy-settings 交互式隐私对话框(P3) +### 13. 交互式隐私设置对话框 /privacy-settings(P3) -**问题**:用户想控制哪些数据被收集(遥测/错误报告/使用统计),但只能手动编辑配置文件——不知道有哪些选项、每个选项控制什么。 +**做什么**:Claude Code 的 `/privacy-settings` 命令提供**交互式对话框**,让用户切换 "Help improve Claude" 设置: -**Claude Code 源码索引**: +``` +Data Privacy +━━━━━━━━━━━━ +Help improve Claude true/false ← Enter/Tab/Space 切换 +``` -| 文件 | 关键函数/常量 | -|------|-------------| -| `commands/privacy-settings/privacy-settings.tsx` | 交互式隐私设置 UI | -| `utils/privacyLevel.ts` | 隐私级别定义 | +**关键源码**: + +| 文件 | 行数 | 职责 | +|------|------|------| +| `commands/privacy-settings/privacy-settings.tsx` | 71 | 命令入口 + Grove 资格检查 | +| `components/grove/Grove.tsx` | 462 | `GroveDialog` + `PrivacySettingsDialog` 组件 | +| `services/api/grove.ts` | 348 | Grove API——`getGroveSettings()`、`updateGroveSettings()` | -**Qwen Code 现状**:有 privacy schema 但无交互式 UI。 +**总规模**:~893 行 -**Qwen Code 修改方向**:新增 `/privacy-settings` 命令,展示各隐私选项的开关 + 说明。 +**Qwen Code 现状**:Qwen Code 有 `privacy` 配置 schema(`usageStatisticsEnabled` 字段),但**没有交互式对话框**。 -**实现成本评估**:涉及 ~2 个文件,~100 行,~1 天。 +**Qwen Code 修改方向**: +1. 新建 `components/PrivacySettingsDialog.tsx` +2. 修改 `/settings` 命令——添加隐私设置快捷入口 -**意义**:隐私控制透明化——用户知道收集了什么、如何关闭。 -**缺失后果**:用户不知道隐私选项 → 要么全开(隐私风险)要么全关(影响改进数据)。 -**改进收益**:交互式 UI = 精确控制每项数据收集。 +**实现成本评估**: +- 涉及文件:~4 个 +- 新增代码:~200 行 +- 开发周期:~1.5 天(1 人) --- -### 14. /extra-usage 企业用量管理(P3) +### 14. 自动发布说明 /release-notes(P3) -**问题**:企业用户需要查看和管理 API 用量配额——当前用量、剩余额度、历史趋势。 +**做什么**:Claude Code 的 `/release-notes` 命令自动从 GitHub 获取并显示发布说明: -**Claude Code 源码索引**: +``` +Version 2.0.53: +· Fixed: Shell command timeout issue +· Added: New /review command +``` -| 文件 | 关键函数/常量 | -|------|-------------| -| `commands/extra-usage/extra-usage.tsx` | 用量查看 UI | -| `commands/extra-usage/extra-usage-core.ts` | 用量数据获取 | +**关键源码**: -**Qwen Code 现状**:有 `/cost` 显示当前 session 花费,但无企业级用量管理。 +| 文件 | 行数 | 职责 | +|------|------|------| +| `commands/release-notes/release-notes.ts` | 61 | 命令入口 | +| `utils/releaseNotes.ts` | 370 | 获取、解析、缓存、显示 | -**Qwen Code 修改方向**:新增 `/usage` 命令,对接 DashScope 用量 API 展示配额和历史。 +**总规模**:~443 行 -**实现成本评估**:涉及 ~3 个文件,~200 行,~2 天。难点:对接各 API 提供商的用量接口。 +**Qwen Code 现状**:Qwen Code 有 `/status` 显示版本信息,但**没有 release notes 功能**。 -**意义**:企业成本管控的基础——看得到才管得住。 -**缺失后果**:不知道用了多少配额 → 突然限速 → 任务中断。 -**改进收益**:用量可视化 = 提前发现配额不足,主动调整。 +**Qwen Code 修改方向**: +1. 新建 `utils/releaseNotes.ts` +2. 新建 `/release-notes` 命令 +3. 启动时后台获取 changelog + +**实现成本评估**: +- 涉及文件:~3 个 +- 新增代码:~300 行 +- 开发周期:~2 天(1 人) +- 难点:CHANGELOG 格式解析 --- -### 15. /rate-limit-options 限速选项菜单(P3) +### 15. 企业用量管理 /extra-usage(P3) -**问题**:API 限速时用户只看到错误消息,不知道有什么选项——等待?切换模型?升级套餐? +**做什么**:Claude Code 的 `/extra-usage` 命令让企业/团队用户管理额外 API 用量——检查用量、向管理员申请增加: -**Claude Code 源码索引**: +**关键源码**: -| 文件 | 关键函数/常量 | -|------|-------------| -| `services/rateLimitMessages.ts` | 限速消息格式化 + 选项建议 | -| `hooks/notifs/useRateLimitWarningNotification.tsx` | 限速预警通知 | +| 文件 | 行数 | 职责 | +|------|------|------| +| `commands/extra-usage/extra-usage-core.ts` | 118 | 用量管理核心——检查资格、申请 | +| `services/api/adminRequests.ts` | ~150 | Admin Request API | +| `services/api/usage.ts` | ~100 | Usage API | -**Qwen Code 现状**:限速时显示错误消息,无交互选项。 +**总规模**:~487 行 -**Qwen Code 修改方向**:限速时展示选项菜单(等待/切换模型/查看用量)。 +**Qwen Code 现状**:Qwen Code 的 `/stats` 显示会话级统计,但**没有企业用量管理**。 -**实现成本评估**:涉及 ~2 个文件,~100 行,~1 天。 +**Qwen Code 修改方向**: +1. 新建 `commands/extra-usage/` 目录 +2. 实现 `/extra-usage` 命令 +3. (需要后端支持)DashScope Admin Request API -**意义**:限速是常见场景——给用户选择比让用户困惑好。 -**缺失后果**:限速 → 红色错误 → 用户不知道怎么办。 -**改进收益**:选项菜单 = 限速时也有行动路径。 +**实现成本评估**: +- 涉及文件:~5 个 +- 新增代码:~300 行 +- 开发周期:~2 天(1 人) --- -### 16. /remote-setup CCR 远程环境设置(P3) +### 16. 交互式限速选项菜单 /rate-limit-options(P3) -**问题**:企业用户需要配置远程执行环境(CCR)——注册 worker、配置认证、测试连接。当前只能手动配置环境变量。 +**做什么**:Claude Code 的 `/rate-limit-options` 提供交互式菜单,帮助用户在遇到限速时选择操作: -**Claude Code 源码索引**: +``` +Rate Limit Options +[ ] Add funds to continue with extra usage +[ ] Upgrade your plan +[ ] Stop and wait for limit to reset +``` -| 文件 | 关键函数/常量 | -|------|-------------| -| `commands/remote-setup/remote-setup.tsx` | 远程环境配置向导 | +**关键源码**: -**Qwen Code 现状**:无远程执行环境配置功能。 +| 文件 | 行数 | 职责 | +|------|------|------| +| `commands/rate-limit-options/rate-limit-options.tsx` | 209 | 限速选项菜单 UI | -**Qwen Code 修改方向**:新增 `/remote-setup` 向导——引导用户配置远程执行端点。 +**总规模**:~221 行 -**实现成本评估**:涉及 ~3 个文件,~200 行,~2 天。难点:需要先有远程执行基础设施。 +**Qwen Code 现状**:Qwen Code 的 API 客户端有重试逻辑,但**没有用户交互式的限速选项菜单**。 -**意义**:远程执行是企业级功能的前提。 -**缺失后果**:无引导 → 配置复杂 → 企业用户放弃。 -**改进收益**:向导引导 = 3 分钟完成远程配置。 +**Qwen Code 修改方向**: +1. 新建 `/rate-limit-options` 命令 +2. 集成到限速错误处理流程 + +**实现成本评估**: +- 涉及文件:~2 个 +- 新增代码:~150 行 +- 开发周期:~1 天(1 人) --- -### 17. Virtual Scrolling 虚拟滚动(P3) +### 17. CustomSelect 自定义下拉选择(P3) -**问题**:长会话(1000+ 轮)时终端滚动卡顿——所有消息节点都在 DOM 中渲染。 +**做什么**:Claude Code 自定义下拉选择组件——支持搜索、键盘导航、多选、过滤: -**Claude Code 源码索引**:`components/VirtualMessageList.tsx`、`hooks/useVirtualScroll.ts` +**关键源码**: -**Qwen Code 现状**:无虚拟滚动——所有消息全量渲染。 +| 文件 | 行数 | 职责 | +|------|------|------| +| `components/CustomSelect/select.tsx` | ~400 | 主组件——选项列表、搜索 | +| `components/CustomSelect/SelectMulti.tsx` | ~300 | 多选组件 | +| `components/CustomSelect/use-select-state.ts` | ~300 | 状态管理 | +| `components/CustomSelect/use-select-navigation.ts` | ~200 | 键盘导航 | +| `components/CustomSelect/use-select-input.ts` | ~250 | 搜索过滤 | -**Qwen Code 修改方向**:仅渲染可视区域 ± buffer 的消息节点。 +**总规模**:~3019 行 -**实现成本评估**:~3 文件,~300 行,~3 天。难点:滚动位置精确计算(消息高度不等)。 +**Qwen Code 现状**:Qwen Code 使用 Ink 标准 `