From b534bd2b188abd221631122b9bedc75996b734a4 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Thu, 20 Nov 2025 10:05:12 +0800 Subject: [PATCH] chore: rm wip doc --- .../docs-tmp/ACP_IMPLEMENTATION_STATUS.md | 236 ---- .../docs-tmp/AUTH_FLOW.md | 378 ----- .../docs-tmp/CLAUDE_CODE_COMPARISON.md | 1029 -------------- .../docs-tmp/CLAUDE_CODE_DEEP_ANALYSIS.md | 1257 ----------------- .../docs-tmp/CLAUDE_CODE_UI_IMPLEMENTATION.md | 211 --- .../docs-tmp/COMPARISON.md | 1047 -------------- .../docs-tmp/DEBUGGING_DOUBLE_LOGIN.md | 327 ----- .../docs-tmp/DOUBLE_AUTH_FIX.md | 289 ---- .../docs-tmp/EXTRACTABLE_CODE_FROM_CLAUDE.md | 919 ------------ .../docs-tmp/HTML_TO_JS_MAPPING.md | 848 ----------- .../docs-tmp/IMPLEMENTATION_STATUS.md | 485 ------- .../docs-tmp/IMPLEMENTATION_SUMMARY.md | 764 ---------- .../docs-tmp/MIGRATION_FEASIBILITY.md | 981 ------------- .../docs-tmp/MIGRATION_SUMMARY.md | 210 --- .../docs-tmp/PR_DESCRIPTION.md | 100 -- .../docs-tmp/PR_DESCRIPTION_EN.md | 100 -- .../docs-tmp/PR_DESCRIPTION_FORMATTED.md | 111 -- .../docs-tmp/TAILWIND_INTEGRATION.md | 239 ---- .../docs-tmp/TODO_QUICK_WIN_FEATURES.md | 442 ------ .../WEBVIEW_PERSISTENCE_IMPLEMENTATION.md | 401 ------ .../docs-tmp/WEBVIEW_UI_RESTORATION.md | 574 -------- packages/vscode-ide-companion/docs-tmp/tmp.md | 1026 -------------- 22 files changed, 11974 deletions(-) delete mode 100644 packages/vscode-ide-companion/docs-tmp/ACP_IMPLEMENTATION_STATUS.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/AUTH_FLOW.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_COMPARISON.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_DEEP_ANALYSIS.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_UI_IMPLEMENTATION.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/COMPARISON.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/DEBUGGING_DOUBLE_LOGIN.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/DOUBLE_AUTH_FIX.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/EXTRACTABLE_CODE_FROM_CLAUDE.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/HTML_TO_JS_MAPPING.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/IMPLEMENTATION_STATUS.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/IMPLEMENTATION_SUMMARY.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/MIGRATION_FEASIBILITY.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/MIGRATION_SUMMARY.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/PR_DESCRIPTION.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/PR_DESCRIPTION_EN.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/PR_DESCRIPTION_FORMATTED.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/TAILWIND_INTEGRATION.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/TODO_QUICK_WIN_FEATURES.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/WEBVIEW_PERSISTENCE_IMPLEMENTATION.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/WEBVIEW_UI_RESTORATION.md delete mode 100644 packages/vscode-ide-companion/docs-tmp/tmp.md diff --git a/packages/vscode-ide-companion/docs-tmp/ACP_IMPLEMENTATION_STATUS.md b/packages/vscode-ide-companion/docs-tmp/ACP_IMPLEMENTATION_STATUS.md deleted file mode 100644 index 06b78785..00000000 --- a/packages/vscode-ide-companion/docs-tmp/ACP_IMPLEMENTATION_STATUS.md +++ /dev/null @@ -1,236 +0,0 @@ -# ACP 协议实现状态对比 - -## 概述 - -ACP (Agent Communication Protocol) 是基于 JSON-RPC 2.0 的双向通信协议,用于 IDE 客户端与 AI Agent 服务器之间的通信。 - -- **协议定义**: Google 开源的标准协议(Apache-2.0 License) -- **协议版本**: 1 -- **传输格式**: JSON-RPC 2.0,通过 stdin/stdout 进行行分隔的 JSON 通信 - -## 架构说明 - -``` -┌─────────────────┐ ┌──────────────────┐ -│ IDE Client │ │ Agent Server │ -│ (VSCode 扩展) │◄──── JSON-RPC ────►│ (qwen CLI) │ -└─────────────────┘ └──────────────────┘ -``` - -### 角色定义 - -- **Client (VSCode 扩展)**: - - 提供 UI 界面 - - 处理文件读写 - - 请求用户权限 - - 接收并展示 Agent 的消息 - -- **Server (qwen CLI)**: - - 处理 LLM 交互 - - 执行工具调用 - - 管理会话状态 - - 流式返回响应 - -## 协议方法对比 - -### 1. Agent Methods (CLI 实现,VSCode 调用) - -这些是 **qwen CLI** 作为 Server 实现的方法,**VSCode 扩展** 作为 Client 调用: - -| 方法 | CLI 实现 | VSCode 调用 | 功能描述 | 文件位置 | -| ---------------- | -------- | ----------- | ------------------------- | ------------------------------------------------------------------------------------ | -| `initialize` | ✅ | ✅ | 协议初始化,交换能力信息 | CLI: `zedIntegration.ts:105-136`
VSCode: `AcpConnection.ts:439-461` | -| `authenticate` | ✅ | ✅ | 用户认证(OAuth/API Key) | CLI: `zedIntegration.ts:138-148`
VSCode: `AcpConnection.ts:463-471` | -| `session/new` | ✅ | ✅ | 创建新的聊天会话 | CLI: `zedIntegration.ts:150-191`
VSCode: `AcpConnection.ts:473-485` | -| `session/load` | ❌ | ✅ | 加载历史会话 | CLI: 已定义但禁用(返回 `loadSession: false`)
VSCode: `AcpConnection.ts:541-553` | -| `session/prompt` | ✅ | ✅ | 发送用户消息给 Agent | CLI: `zedIntegration.ts:234-240`
VSCode: `AcpConnection.ts:487-496` | -| `session/cancel` | ✅ | ❌ | 取消当前生成 | CLI: `zedIntegration.ts:226-232`
VSCode: **未实现** | - -**自定义扩展方法(非标准 ACP):** - -| 方法 | CLI 实现 | VSCode 调用 | 功能描述 | 文件位置 | -| ---------------- | -------- | ----------- | -------------- | ---------------------------------- | -| `session/list` | ❌ | ✅ | 列出所有会话 | VSCode: `AcpConnection.ts:498-511` | -| `session/switch` | ❌ | ✅ | 切换到指定会话 | VSCode: `AcpConnection.ts:513-521` | - -### 2. Client Methods (VSCode 实现,CLI 调用) - -这些是 **VSCode 扩展** 作为 Client 实现的方法,**qwen CLI** 作为 Server 调用: - -| 方法 | VSCode 实现 | CLI 调用 | 功能描述 | 文件位置 | -| ---------------------------- | ----------- | -------- | -------------------------------- | ------------------------------------------------------------------------ | -| `session/update` | ✅ | ✅ | 流式发送会话更新(notification) | CLI: `acp.ts:69-74`
VSCode: `AcpConnection.ts:280-283` (via callback) | -| `session/request_permission` | ✅ | ✅ | 请求用户授权工具执行 | CLI: `acp.ts:82-89`
VSCode: `AcpConnection.ts:330-359` | -| `fs/read_text_file` | ✅ | ✅ | 读取文件内容 | CLI: `acp.ts:91-98`
VSCode: `AcpConnection.ts:361-403` | -| `fs/write_text_file` | ✅ | ✅ | 写入文件内容 | CLI: `acp.ts:100-107`
VSCode: `AcpConnection.ts:405-436` | - -## Session Update 类型对比 - -`session/update` 是一个 notification(不需要响应),支持多种更新类型: - -| 更新类型 | CLI 发送 | VSCode 处理 | 功能描述 | 实现位置 | -| --------------------- | -------- | ----------- | -------------------- | ------------------------------------------------------------------- | -| `user_message_chunk` | ✅ | ✅ | 用户消息片段 | CLI: `zedIntegration.ts:N/A` (echo back)
VSCode: Webview 渲染 | -| `agent_message_chunk` | ✅ | ✅ | Agent 回复片段 | CLI: `zedIntegration.ts:310-322`
VSCode: Webview 渲染 | -| `agent_thought_chunk` | ✅ | ⚠️ | Agent 思考过程 | CLI: `zedIntegration.ts:318` (thought=true)
VSCode: 需要特殊样式 | -| `tool_call` | ✅ | ✅ | 工具调用开始 | CLI: `zedIntegration.ts:500-509`
VSCode: 显示 ToolCall 组件 | -| `tool_call_update` | ✅ | ✅ | 工具调用完成/失败 | CLI: `zedIntegration.ts:560-566`
VSCode: 更新 ToolCall 状态 | -| `plan` | ✅ | ⚠️ | 任务计划(TodoList) | CLI: `zedIntegration.ts:547-552`
VSCode: 需要实现 Plan UI | - -## 功能缺失对比 - -### VSCode 扩展缺失的功能 - -| 功能 | 影响 | 建议优先级 | -| -------------------------- | -------------------------- | ---------- | -| `session/cancel` 方法 | 用户无法取消正在运行的请求 | 🔴 高 | -| `agent_thought_chunk` 展示 | 看不到 Agent 的思考过程 | 🟡 中 | -| `plan` 类型展示 | 看不到 Agent 的任务计划 | 🟡 中 | -| Audio/Image content blocks | 不支持多模态输入 | 🟢 低 | -| Embedded resources | 不支持嵌入式资源 | 🟢 低 | -| `session/load` | CLI 本身不支持,优先级低 | 🟢 低 | - -### CLI 缺失的功能 - -| 功能 | 影响 | 建议优先级 | -| ---------------- | ------------------------ | ---------- | -| `session/load` | 无法恢复历史会话 | 🟡 中 | -| `session/list` | 需要 VSCode 扩展自己管理 | 🟢 低 | -| `session/switch` | 需要 VSCode 扩展自己管理 | 🟢 低 | - -## 能力声明对比 - -### CLI Agent Capabilities - -```typescript -{ - protocolVersion: 1, - authMethods: [ - { id: 'use_openai', name: 'Use OpenAI API key' }, - { id: 'qwen_oauth', name: 'Qwen OAuth' } - ], - agentCapabilities: { - loadSession: false, // ❌ 不支持加载历史会话 - promptCapabilities: { - image: true, // ✅ 支持图片输入 - audio: true, // ✅ 支持音频输入 - embeddedContext: true // ✅ 支持嵌入式上下文 - } - } -} -``` - -### VSCode Client Capabilities - -```typescript -{ - protocolVersion: 1, - clientCapabilities: { - fs: { - readTextFile: true, // ✅ 支持读文件 - writeTextFile: true // ✅ 支持写文件 - } - } -} -``` - -## 工具类型 (Tool Kinds) - -所有工具调用都有一个 `kind` 字段,用于分类: - -| Kind | 描述 | 示例 | -| --------- | -------- | ------------------------- | -| `read` | 读取操作 | Read, ReadManyFiles, Glob | -| `edit` | 编辑操作 | Edit, Write | -| `delete` | 删除操作 | Delete files/directories | -| `move` | 移动操作 | Move/rename files | -| `search` | 搜索操作 | Grep, Search | -| `execute` | 执行操作 | Bash, RunCommand | -| `think` | 思考操作 | Task (sub-agent) | -| `fetch` | 网络请求 | WebFetch, API calls | -| `other` | 其他操作 | TodoWrite, etc. | - -## 权���确认流程 - -```mermaid -sequenceDiagram - participant CLI as qwen CLI - participant VSCode as VSCode Extension - participant User as User - - CLI->>VSCode: session/request_permission - Note over CLI,VSCode: 包含 toolCall 详情和选项 - VSCode->>User: 显示权限请求 UI - User->>VSCode: 选择选项 (allow_once/always/reject) - VSCode->>CLI: 返回用户选择 - CLI->>CLI: 根据选择执行或取消工具 -``` - -权限选项类型: - -- `allow_once`: 仅允许一次 -- `allow_always`: 始终允许(针对文件/命令/服务器) -- `reject_once`: 拒绝一次 -- `reject_always`: 始终拒绝 - -## Schema ���证 - -### 如何使用 Schema - -VSCode 扩展现在有完整的 Zod schema 定义: - -```typescript -import * as schema from './acp/schema.js'; - -// 验证请求 -const params: schema.InitializeRequest = { - protocolVersion: schema.PROTOCOL_VERSION, - clientCapabilities: { ... } -}; - -// 运行时验证 -schema.initializeRequestSchema.parse(params); -``` - -### 验证的好处 - -1. **类型安全**: TypeScript 编译时检查 -2. **运行时验证**: 捕获协议不匹配错误 -3. **文档化**: Schema 即文档 -4. **一目了然**: 清楚知道哪些字段是必需的 - -## 下一步建议 - -### 高优先级 - -1. **实现 `session/cancel`**: 允许用户取消正在运行的请求 - - 在 `AcpConnection` 中实现 `cancel()` 方法 - - 在 Webview UI 添加取消按钮 - -2. **实现 `agent_thought_chunk` 展示**: 显示 Agent 的思考过程 - - 在 Webview 中添加 "思考中..." 样式 - - 可折叠显示详细思考内容 - -### 中优先级 - -3. **实现 `plan` 类型展示**: 显示任务计划列表 - - 设计 Todo/Plan 组件 - - 实时更新任务状态 - -4. **添加 Schema 验证**: 在更多关键位置添加运行时验证 - - `session/new` 参数验证 - - `session/prompt` 参数验证 - - 所有 `session/update` 类型验证 - -### 低优先级 - -5. **支持多模态内容**: 图片、音频输入 -6. **支持嵌入式资源**: Resource blocks -7. **实现 `session/load`**: 需要先等 CLI 支持 - -## 参考资源 - -- **Schema 定义**: `packages/vscode-ide-companion/src/acp/schema.ts` -- **CLI 实现**: `packages/cli/src/zed-integration/` -- **VSCode 实现**: `packages/vscode-ide-companion/src/acp/AcpConnection.ts` -- **协议来源**: Google (Apache-2.0 License) diff --git a/packages/vscode-ide-companion/docs-tmp/AUTH_FLOW.md b/packages/vscode-ide-companion/docs-tmp/AUTH_FLOW.md deleted file mode 100644 index 5ffe995f..00000000 --- a/packages/vscode-ide-companion/docs-tmp/AUTH_FLOW.md +++ /dev/null @@ -1,378 +0,0 @@ -# Qwen Code 认证流程说明 - -## 🔐 认证流程概览 - -``` -用户打开 Chat UI - ↓ -WebViewProvider.show() - ↓ -检查 agentInitialized 标志 - ├─ 如果为 true → 跳过初始化(使用现有连接) - └─ 如果为 false → 继续初始化 - ↓ - authStateManager.hasValidAuth() - ├─ 有效缓存 → needsAuth = false - └─ 无缓存/过期 → needsAuth = true - ↓ - 尝试恢复本地 session - ├─ 成功 → sessionRestored = true, needsAuth = false - └─ 失败 → 继续 - ↓ - 如果 !sessionRestored && needsAuth - ↓ - authenticate() (仅一次!) ✅ - ↓ - newSession() - ↓ - saveAuthState() - ↓ - agentInitialized = true -``` - -## ✅ 已修复的问题 - -### 问题 1: 嵌套 try-catch 导致重复认证(已修复) - -**之前的代码**: - -```typescript -try { - if (switchSession fails) { - authenticate(); // 第 1 次 - } else { - authenticate(); // 第 1 次 - } -} catch { - authenticate(); // 第 2 次!❌ -} -``` - -**修复后的代码**: - -```typescript -let needsAuth = true; -let sessionRestored = false; - -// 检查缓存 -if (hasValidAuth) { - needsAuth = false; -} - -// 尝试恢复 session -try { - if (switchSession succeeds) { - sessionRestored = true; - needsAuth = false; - } -} catch { - // 只记录日志,不触发认证 -} - -// 只在必要时认证(最多一次) -if (!sessionRestored && needsAuth) { - authenticate(); // 只会执行一次!✅ - newSession(); -} -``` - -### 问题 2: agentInitialized 标志未重置(已修复) - -**问题描述**: -清除认证缓存后,`agentInitialized` 标志仍为 `true`,导致不会重新初始化。 - -**修复方案**: - -```typescript -// WebViewProvider.ts -resetAgentState(): void { - this.agentInitialized = false; - this.agentManager.disconnect(); -} - -// extension.ts -vscode.commands.registerCommand('qwenCode.clearAuthCache', async () => { - await authStateManager.clearAuthState(); - webViewProvider.resetAgentState(); // ✅ 重置状态 -}); -``` - -## 🎯 正确的使用方式 - -### 场景 1: 正常使用(无需手动操作) - -``` -第1次打开 Chat UI: - → 没有缓存 - → 需要登录 (1 次) - → 保存缓存 (24小时) - -第2次打开 Chat UI (24小时内): - → 有缓存 - → 不需要登录 ✅ - -第3次打开 Chat UI (24小时后): - → 缓存过期 - → 需要登录 (1 次) - → 更新缓存 -``` - -### 场景 2: 手动清除缓存 - -``` -1. 执行命令: Qwen Code: Clear Authentication Cache - → 清除缓存 - → 重置 agentInitialized 标志 - → 断开现有连接 - -2. 下次打开 Chat UI: - → 没有缓存 - → 需要登录 (1 次) ✅ - → 保存新缓存 -``` - -### 场景 3: 缓存有效但 token 失效 - -``` -打开 Chat UI: - → 缓存有效,跳过认证 - → 尝试创建 session - → Session 创建失败(token 已过期) - ↓ - 【自动恢复】✅ - → 清除缓存 - → 重新认证 (1 次) - → 保存新缓存 - → 重新创建 session -``` - -## ⚠️ 可能导致多次登录的情况 - -### 情况 1: Session 恢复失败 + 认证重试 - -如果 session 恢复失败,且认证也失败,会触发重试(最多 3 次): - -``` -尝试恢复 session → 失败 - ↓ -认证尝试 #1 → 失败 - ↓ (等待 1 秒) -认证尝试 #2 → 失败 - ↓ (等待 2 秒) -认证尝试 #3 → 失败 - ↓ -抛出错误 -``` - -**这是正常的重试机制**,用于处理网络临时故障。 - -### 情况 2: 多次打开/关闭 Chat UI - -如果频繁打开关闭 Chat UI: - -``` -打开 #1 → 登录 → agentInitialized = true -关闭 -打开 #2 → 使用现有连接 ✅ (不需要登录) -关闭 -打开 #3 → 使用现有连接 ✅ (不需要登录) -``` - -**这是正常行为**,不会重复登录。 - -## 🐛 如何诊断"两次登录"问题 - -### 1. 查看详细日志 - -打开 VSCode 输出面板: - -``` -View → Output → 选择 "Qwen Code Companion" -``` - -查找以下关键日志: - -#### 正常流程(只登录一次): - -``` -[WebViewProvider] Starting initialization, workingDir: /path/to/workspace -[QwenAgentManager] Using cached authentication ← 或者跳过这行(首次登录) -[QwenAgentManager] Creating new session... -[QwenAgentManager] 🔐 AUTHENTICATION CALL STARTED at 2025-11-17T... ← 只出现一次! -[QwenAgentManager] Call stack: ... -[QwenAgentManager] 📝 Authenticating (attempt 1/3)... -[QwenAgentManager] ✅ Authentication successful on attempt 1 -[QwenAgentManager] New session created successfully -[AuthStateManager] Auth state saved -``` - -#### 异常流程(登录多次): - -``` -[QwenAgentManager] 🔐 AUTHENTICATION CALL STARTED at 2025-11-17T10:00:00 ← 第 1 次 -[QwenAgentManager] Call stack: ... -[QwenAgentManager] ✅ Authentication successful on attempt 1 -[QwenAgentManager] 🔐 AUTHENTICATION CALL STARTED at 2025-11-17T10:00:05 ← 第 2 次!❌ -[QwenAgentManager] Call stack: ... -``` - -**如果看到两个 "AUTHENTICATION CALL STARTED",说明 `authenticateWithRetry()` 被调用了两次!** - -### 2. 分析调用栈 - -查看每次认证调用的堆栈信息: - -``` -[QwenAgentManager] Call stack: - at QwenAgentManager.authenticateWithRetry (/path/to/QwenAgentManager.ts:206) - at QwenAgentManager.connect (/path/to/QwenAgentManager.ts:162) ← 正常调用 - at WebViewProvider.show (/path/to/WebViewProvider.ts:131) -``` - -或者: - -``` -[QwenAgentManager] Call stack: - at QwenAgentManager.authenticateWithRetry (/path/to/QwenAgentManager.ts:206) - at QwenAgentManager.connect (/path/to/QwenAgentManager.ts:184) ← 缓存失效重试! - at WebViewProvider.show (/path/to/WebViewProvider.ts:131) -``` - -### 3. 区分"重试"和"重复调用" - -**重要**:需要区分以下两种情况: - -#### 情况 A: 认证重试(正常) - -``` -[QwenAgentManager] 🔐 AUTHENTICATION CALL STARTED ← 只有一次 CALL STARTED -[QwenAgentManager] 📝 Authenticating (attempt 1/3)... ← 第 1 次尝试 -[QwenAgentManager] ❌ Authentication attempt 1 failed -[QwenAgentManager] ⏳ Retrying in 1000ms... -[QwenAgentManager] 📝 Authenticating (attempt 2/3)... ← 第 2 次尝试 -[QwenAgentManager] ✅ Authentication successful on attempt 2 -``` - -**这是正常的!** 这是同一个认证调用的多次尝试。 - -#### 情况 B: 重复认证调用(异常) - -``` -[QwenAgentManager] 🔐 AUTHENTICATION CALL STARTED at ... ← 第 1 个认证调用 -[QwenAgentManager] 📝 Authenticating (attempt 1/3)... -[QwenAgentManager] ✅ Authentication successful on attempt 1 -[QwenAgentManager] 🔐 AUTHENTICATION CALL STARTED at ... ← 第 2 个认证调用!❌ -[QwenAgentManager] 📝 Authenticating (attempt 1/3)... -``` - -**这是异常的!** `authenticateWithRetry()` 被调用了两次。 - -### 4. 检查 agentInitialized 标志 - -查找以下日志: - -``` -[WebViewProvider] Agent already initialized, reusing existing connection -``` - -如果每次打开都看到 "Starting initialization",说明标志没有正确保持。 - -### 5. 检查是否是 OAuth 流程本身的问题 - -如果日志显示只有一次 "AUTHENTICATION CALL STARTED",但浏览器弹出了两次授权页面,那可能是 **Qwen CLI 的 OAuth 流程本身需要两次交互**。 - -这种情况需要检查 Qwen CLI 的实现,不是 VSCode 扩展的问题。 - -## 🔧 手动测试步骤 - -### 测试 1: 正常流程 - -```bash -1. 清除缓存: Cmd+Shift+P → "Clear Authentication Cache" -2. 打开 Chat UI -3. 应该看到: 登录提示 (1 次) -4. 关闭 Chat UI -5. 重新打开 Chat UI -6. 应该看到: 直接连接,不需要登录 ✅ -``` - -### 测试 2: 缓存过期 - -```bash -1. 修改 AUTH_CACHE_DURATION 为 1 分钟: - // AuthStateManager.ts:21 - private static readonly AUTH_CACHE_DURATION = 1 * 60 * 1000; - -2. 打开 Chat UI → 登录 -3. 等待 2 分钟 -4. 重新打开 Chat UI -5. 应该看到: 需要重新登录 (1 次) ✅ -``` - -### 测试 3: 清除缓存 - -```bash -1. 打开 Chat UI (已登录) -2. 执行: "Clear Authentication Cache" -3. 关闭 Chat UI -4. 重新打开 Chat UI -5. 应该看到: 需要重新登录 (1 次) ✅ -``` - -## 📊 认证状态管理 - -### 缓存存储位置 - -``` -macOS: ~/Library/Application Support/Code/User/globalStorage/ -Linux: ~/.config/Code/User/globalStorage/ -Windows: %APPDATA%\Code\User\globalStorage\ -``` - -### 缓存内容 - -```typescript -{ - isAuthenticated: true, - authMethod: "qwen-oauth", // 或 "openai" - workingDir: "/path/to/workspace", - timestamp: 1700000000000 // Unix timestamp -} -``` - -### 缓存有效期 - -- **默认**: 24 小时 -- **修改方式**: 编辑 `AuthStateManager.ts:21` -- **检查方式**: 执行命令(如果添加了)或查看日志 - -## 🎯 关键代码位置 - -| 功能 | 文件 | 行号 | -| ------------ | --------------------- | ------- | -| 认证缓存管理 | `AuthStateManager.ts` | 全文 | -| 认证逻辑 | `QwenAgentManager.ts` | 61-195 | -| 初始化控制 | `WebViewProvider.ts` | 113-154 | -| 清除缓存命令 | `extension.ts` | 148-160 | -| 缓存有效期 | `AuthStateManager.ts` | 21 | - -## ✅ 总结 - -**当前实现已经修复了重复登录的问题**: - -1. ✅ 使用 `needsAuth` 标志确保最多认证一次 -2. ✅ 缓存有效时跳过认证 -3. ✅ Session 恢复成功时跳过认证 -4. ✅ 清除缓存时重置 `agentInitialized` 标志 -5. ✅ 缓存失效时自动重新认证(只一次) - -**如果仍然遇到多次登录**,请: - -1. 检查日志确认是否真的登录了多次 -2. 确认是否是重试机制(3 次尝试是正常的) -3. 检查是否多次打开了不同的 Chat UI 实例 -4. 提供详细的日志帮助诊断 - ---- - -**最后更新**: 2025-11-17 diff --git a/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_COMPARISON.md b/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_COMPARISON.md deleted file mode 100644 index 01145011..00000000 --- a/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_COMPARISON.md +++ /dev/null @@ -1,1029 +0,0 @@ -# AionUI VSCode 插件 vs Claude Code 功能对比 - -> **对标目标**:本文档以 Claude Code 为对标基准,详细分析功能差异并制定实现计划。 - -## 目录 - -- [Claude Code 核心功能](#claude-code-核心功能) -- [功能对比矩阵](#功能对比矩阵) -- [实现优先级规划](#实现优先级规划) -- [技术实现方案](#技术实现方案) - ---- - -## Claude Code 核心功能 - -### 1. **聊天界面** (Chat Interface) - -**功能描述**: - -- 专用的侧边栏面板 -- 实时显示 AI 响应 -- 支持流式输出 -- 消息历史记录 - -**当前状态**: - -- ✅ 已实现:WebView 聊天界面 -- ✅ 已实现:流式响应 -- ✅ 已实现:会话历史 - -**差距**: - -- ⚠️ UI 美观度可以优化 -- ⚠️ 缺少侧边栏集成(目前是独立面板) - -### 2. **内联 Diff 预览** (Inline Diffs) - -**功能描述**: - -``` -Claude 修改代码时: -1. 自动打开 VSCode 原生 diff 视图 -2. 并排显示修改前后代码 -3. 可以一键接受/拒绝修改 -``` - -**当前状态**: - -- ❌ 未实现 - -**实现难度**:⭐⭐⭐(中等) - -**实现方案**: - -```typescript -// 当 Agent 请求文件修改时 -case 'fs/write_text_file': - const oldContent = fs.readFileSync(path); - const newContent = params.content; - - // 打开 diff 视图 - await vscode.commands.executeCommand('vscode.diff', - vscode.Uri.parse(`untitled:${path}?old`).with({ query: oldContent }), - vscode.Uri.parse(`untitled:${path}?new`).with({ query: newContent }), - `${path} (AI Changes)` - ); - - // 等待用户确认 - const accept = await vscode.window.showQuickPick(['Accept', 'Reject']); - if (accept === 'Accept') { - fs.writeFileSync(path, newContent); - } -``` - -### 3. **文件引用** (@-mention files) - -**功能描述**: - -``` -用户输入: - "请优化 @src/App.tsx 的性能" - -系统行为: - 1. 解析 @src/App.tsx - 2. 读取文件内容 - 3. 自动添加到上下文 -``` - -**当前状态**: - -- ❌ 未实现 - -**实现难度**:⭐⭐(简单) - -**实现方案**: - -```typescript -// 1. 解析用户输入 -function parseFileReferences(message: string): { - files: string[]; - cleanMessage: string; -} { - const filePattern = /@([\w\/\.\-]+)/g; - const files = []; - let match; - - while ((match = filePattern.exec(message)) !== null) { - files.push(match[1]); - } - - const cleanMessage = message.replace(filePattern, (_, file) => file); - return { files, cleanMessage }; -} - -// 2. 读取文件内容 -async function injectFileContext(message: string): Promise { - const { files, cleanMessage } = parseFileReferences(message); - - if (files.length === 0) return message; - - let context = ''; - for (const file of files) { - const content = await vscode.workspace.fs.readFile( - vscode.Uri.file(workspaceRoot + '/' + file), - ); - context += `\n\n[File: ${file}]\n\`\`\`\n${content}\n\`\`\`\n`; - } - - return context + '\n\nUser: ' + cleanMessage; -} -``` - -### 4. **自动上下文感知** (Context Awareness) - -**功能描述**: - -``` -自动检测并注入: -- 当前打开的文件 -- 选中的代码 -- 光标位置 -- 工作区路径 -``` - -**当前状态**: - -- ❌ 未实现 - -**实现难度**:⭐(非常简单) - -**实现方案**: - -```typescript -async function collectVSCodeContext(): Promise { - const editor = vscode.window.activeTextEditor; - if (!editor) return ''; - - const document = editor.document; - const selection = editor.selection; - - let context = '[VSCode Context]\n'; - - // 当前文件 - context += `File: ${document.fileName}\n`; - context += `Language: ${document.languageId}\n`; - - // 选中的代码 - if (!selection.isEmpty) { - const selectedText = document.getText(selection); - context += `\nSelected Code (lines ${selection.start.line + 1}-${selection.end.line + 1}):\n`; - context += `\`\`\`${document.languageId}\n${selectedText}\n\`\`\`\n`; - } - - // 光标周围的代码(上下 10 行) - const cursorLine = selection.active.line; - const startLine = Math.max(0, cursorLine - 10); - const endLine = Math.min(document.lineCount - 1, cursorLine + 10); - const surroundingText = document.getText( - new vscode.Range(startLine, 0, endLine, 999), - ); - context += `\nContext Around Cursor:\n\`\`\`${document.languageId}\n${surroundingText}\n\`\`\`\n`; - - return context; -} - -// 在发送消息前自动注入 -async function sendMessage(userMessage: string) { - const context = await collectVSCodeContext(); - const fullMessage = context + '\n\nUser: ' + userMessage; - await agent.sendPrompt(fullMessage); -} -``` - -### 5. **Checkpoint 系统** (Checkpointing) - -**功能描述**: - -``` -自动保存代码状态: -- 每次 AI 修改前自动创建检查点 -- 按 Esc 两次快速回退 -- /rewind 命令回到之前版本 -``` - -**当前状态**: - -- ❌ 未实现 - -**实现难度**:⭐⭐⭐(中等) - -**实现方案**: - -```typescript -interface Checkpoint { - id: string; - timestamp: number; - files: Map; // filePath → content - message: string; -} - -class CheckpointManager { - private checkpoints: Checkpoint[] = []; - - async createCheckpoint(message: string): Promise { - const checkpoint: Checkpoint = { - id: Date.now().toString(), - timestamp: Date.now(), - files: new Map(), - message, - }; - - // 保存所有打开的文件状态 - for (const editor of vscode.window.visibleTextEditors) { - const uri = editor.document.uri; - const content = editor.document.getText(); - checkpoint.files.set(uri.fsPath, content); - } - - this.checkpoints.push(checkpoint); - return checkpoint.id; - } - - async rewind(steps: number = 1): Promise { - if (this.checkpoints.length < steps) { - vscode.window.showWarningMessage('No more checkpoints to rewind'); - return; - } - - const checkpoint = this.checkpoints[this.checkpoints.length - steps]; - - // 恢复文件状态 - for (const [filePath, content] of checkpoint.files) { - await vscode.workspace.fs.writeFile( - vscode.Uri.file(filePath), - Buffer.from(content), - ); - } - - // 移除后续的检查点 - this.checkpoints = this.checkpoints.slice(0, -steps); - vscode.window.showInformationMessage(`Rewound to: ${checkpoint.message}`); - } -} - -// 注册快捷键 -vscode.commands.registerCommand('aionui.rewind', () => { - checkpointManager.rewind(1); -}); - -// Esc 两次触发 -let escPressCount = 0; -let escTimeout: NodeJS.Timeout; - -vscode.commands.registerCommand('type', (args) => { - if (args.text === '\u001b') { - // Esc key - escPressCount++; - clearTimeout(escTimeout); - - if (escPressCount === 2) { - checkpointManager.rewind(1); - escPressCount = 0; - } else { - escTimeout = setTimeout(() => { - escPressCount = 0; - }, 500); - } - } -}); -``` - -### 6. **Extended Thinking** (扩展思考) - -**功能描述**: - -``` -显示 AI 的内部思考过程: -- 切换按钮控制是否显示 -- 查看 AI 如何分析问题 -- 理解 AI 的决策逻辑 -``` - -**当前状态**: - -- ⚠️ 部分实现(Qwen CLI 会输出 thoughts) - -**实现难度**:⭐(简单) - -**实现方案**: - -```typescript -// 在 AcpConnection.ts 中 -case 'session/update': - const update = params.update; - - if (update.sessionUpdate === 'agent_message_chunk') { - // 正常输出 - this.onStreamChunk(update.content?.text); - } - else if (update.sessionUpdate === 'thought') { - // Extended Thinking 输出 - if (this.showThinking) { - this.onThoughtChunk(`💭 ${update.content?.text}`); - } - } - break; - -// 添加切换按钮 - -``` - -### 7. **多会话支持** (Multiple Sessions) - -**功能描述**: - -``` -在不同工作区文件夹中运行并行会话: -- 微服务架构支持 -- 每个项目独立会话 -- 快速切换上下文 -``` - -**当前状态**: - -- ✅ 已实现:跨项目会话查看 -- ❌ 未实现:并行会话 - -**实现难度**:⭐⭐⭐⭐(较难) - -**实现方案**: - -```typescript -// 为每个 workspace folder 创建独立的 AgentManager -class MultiSessionManager { - private sessions = new Map(); - - async getOrCreateSession(workspaceFolder: string): Promise { - if (!this.sessions.has(workspaceFolder)) { - const agent = new QwenAgentManager(); - await agent.connect(workspaceFolder); - this.sessions.set(workspaceFolder, agent); - } - return this.sessions.get(workspaceFolder)!; - } - - async switchSession(workspaceFolder: string): Promise { - const agent = await this.getOrCreateSession(workspaceFolder); - this.currentAgent = agent; - // 更新 UI 显示 - } -} -``` - -### 8. **MCP 服务器支持** (MCP Support) - -**功能描述**: - -``` -支持 Model Context Protocol 服务器: -- 通过 CLI 配置 MCP 服务器 -- 扩展 AI 的工具能力 -- 自定义工具集成 -``` - -**当前状态**: - -- ⚠️ 依赖 Qwen CLI 支持 - -**实现难度**:⭐⭐(简单,主要是配置) - -**实现方案**: - -```typescript -// Qwen CLI 已支持 MCP,我们只需要在 VSCode 设置中配置 -{ - "aionui.qwen.mcpServers": { - "filesystem": { - "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/workspace"] - }, - "github": { - "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-github"], - "env": { - "GITHUB_TOKEN": "${GITHUB_TOKEN}" - } - } - } -} - -// 在启动 Qwen CLI 时传递配置 -const mcpConfig = vscode.workspace.getConfiguration('aionui.qwen').get('mcpServers'); -await agent.connect(workingDir, mcpConfig); -``` - ---- - -## 功能对比矩阵 - -| 功能 | Claude Code | AionUI 插件 | 实现难度 | 优先级 | -| -------------------- | ----------- | ----------- | -------- | --------- | -| **核心功能** | -| 聊天界面 | ✅ | ✅ | - | ✅ 已完成 | -| 流式响应 | ✅ | ✅ | - | ✅ 已完成 | -| 会话历史 | ✅ | ✅ | - | ✅ 已完成 | -| **上下文感知** | -| 自动注入当前文件 | ✅ | ❌ | ⭐ | 🔥 P0 | -| 自动注入选中代码 | ✅ | ❌ | ⭐ | 🔥 P0 | -| 文件引用 (@filename) | ✅ | ❌ | ⭐⭐ | 🔥 P0 | -| 图片上传 | ✅ | ❌ | ⭐⭐ | P2 | -| **代码修改** | -| 内联 Diff 预览 | ✅ | ❌ | ⭐⭐⭐ | 🔥 P0 | -| 一键接受/拒绝 | ✅ | ❌ | ⭐⭐ | 🔥 P0 | -| 多文件编辑 | ✅ | ⚠️ | ⭐⭐⭐ | P1 | -| **历史与撤销** | -| Checkpoint 系统 | ✅ | ❌ | ⭐⭐⭐ | P1 | -| Esc 两次回退 | ✅ | ❌ | ⭐⭐ | P1 | -| /rewind 命令 | ✅ | ❌ | ⭐⭐ | P1 | -| **高级功能** | -| Extended Thinking | ✅ | ⚠️ | ⭐ | P1 | -| 多会话支持 | ✅ | ⚠️ | ⭐⭐⭐⭐ | P2 | -| MCP 服务器 | ✅ | ⚠️ | ⭐⭐ | P1 | -| **独特优势** | -| 多 Agent 切换 | ❌ | ✅ | - | ✅ 已完成 | -| 本地模型支持 | ❌ | ✅ | - | ✅ 已完成 | -| 完全开源 | ❌ | ✅ | - | ✅ 已完成 | - -**优先级说明**: - -- 🔥 **P0**:核心功能,立即实现(1-2 周) -- **P1**:重要功能,短期实现(1 个月) -- **P2**:增强功能,中期实现(2-3 个月) - ---- - -## 实现优先级规划 - -### Phase 0:核心对标功能 (1-2 周) 🔥 - -目标:实现 Claude Code 的核心体验 - -#### 1. 自动上下文注入 ⭐ - -```typescript -// 文件:src/extension/services/ContextCollector.ts -export class ContextCollector { - async collect(): Promise { - let context = ''; - - // 当前文件 - const editor = vscode.window.activeTextEditor; - if (editor) { - context += `[Current File: ${editor.document.fileName}]\n`; - context += editor.document.getText() + '\n\n'; - } - - // 选中代码 - if (editor && !editor.selection.isEmpty) { - const selected = editor.document.getText(editor.selection); - context += `[Selected Code]\n${selected}\n\n`; - } - - return context; - } -} -``` - -**工作量**:2 天 -**优先级**:🔥🔥🔥🔥🔥 - -#### 2. 文件引用 (@filename) ⭐⭐ - -```typescript -// 文件:src/extension/services/FileReferenceParser.ts -export class FileReferenceParser { - parse(message: string): { - files: string[]; - cleanMessage: string; - }; - - async injectFileContents( - message: string, - workspaceRoot: string, - ): Promise; -} -``` - -**工作量**:3 天 -**优先级**:🔥🔥🔥🔥🔥 - -#### 3. 内联 Diff 预览 ⭐⭐⭐ - -```typescript -// 文件:src/extension/services/DiffManager.ts -export class DiffManager { - async showDiff( - filePath: string, - oldContent: string, - newContent: string, - ): Promise<'accept' | 'reject'>; - - async applyChanges(filePath: string, content: string): Promise; -} -``` - -**工作量**:5 天 -**优先级**:🔥🔥🔥🔥🔥 - -#### 4. 一键接受/拒绝修改 ⭐⭐ - -```typescript -// 在 Diff 视图中添加 QuickPick -const action = await vscode.window.showQuickPick([ - { label: '✅ Accept Changes', value: 'accept' }, - { label: '❌ Reject Changes', value: 'reject' }, - { label: '👁️ Review Later', value: 'later' }, -]); -``` - -**工作量**:2 天 -**优先级**:🔥🔥🔥🔥 - -### Phase 1:增强功能 (1 个月) - -#### 5. Checkpoint 系统 ⭐⭐⭐ - -**工作量**:5 天 -**优先级**:🔥🔥🔥 - -#### 6. Extended Thinking 切换 ⭐ - -**工作量**:2 天 -**优先级**:🔥🔥🔥 - -#### 7. MCP 服务器配置 ⭐⭐ - -**工作量**:3 天 -**优先级**:🔥🔥 - -### Phase 2:高级功能 (2-3 个月) - -#### 8. 多会话并行 ⭐⭐⭐⭐ - -**工作量**:10 天 -**优先级**:🔥🔥 - -#### 9. 图片上传支持 ⭐⭐ - -**工作量**:3 天 -**优先级**:🔥 - ---- - -## 技术实现方案 - -### 方案 1:自动上下文注入 - -**架构设计**: - -``` -用户输入消息 - ↓ -ContextCollector.collect() - ├─ 获取当前文件 - ├─ 获取选中代码 - ├─ 获取打开的文件列表 - └─ 获取工作区信息 - ↓ -构建完整的 prompt - ↓ -发送给 Agent -``` - -**代码实现**: - -```typescript -// src/extension/services/ContextCollector.ts -export class ContextCollector { - async collectFullContext(): Promise<{ - currentFile?: string; - selectedCode?: string; - openFiles: string[]; - workspaceInfo: string; - }> { - const context: any = { - openFiles: [], - workspaceInfo: '', - }; - - // 1. 当前文件 - const editor = vscode.window.activeTextEditor; - if (editor) { - context.currentFile = { - path: editor.document.fileName, - language: editor.document.languageId, - content: editor.document.getText(), - }; - - // 2. 选中代码 - if (!editor.selection.isEmpty) { - context.selectedCode = { - text: editor.document.getText(editor.selection), - startLine: editor.selection.start.line + 1, - endLine: editor.selection.end.line + 1, - }; - } - } - - // 3. 打开的文件列表 - context.openFiles = vscode.window.visibleTextEditors - .map((e) => e.document.fileName) - .filter((v, i, a) => a.indexOf(v) === i); // 去重 - - // 4. 工作区信息 - const workspaceFolders = vscode.workspace.workspaceFolders; - if (workspaceFolders) { - context.workspaceInfo = workspaceFolders[0].uri.fsPath; - } - - return context; - } - - formatContext(context: any): string { - let formatted = '[VSCode Context]\n\n'; - - // 当前文件 - if (context.currentFile) { - formatted += `## Current File: ${context.currentFile.path}\n`; - formatted += `Language: ${context.currentFile.language}\n\n`; - formatted += `\`\`\`${context.currentFile.language}\n`; - formatted += context.currentFile.content; - formatted += `\n\`\`\`\n\n`; - } - - // 选中代码 - if (context.selectedCode) { - formatted += `## Selected Code (lines ${context.selectedCode.startLine}-${context.selectedCode.endLine})\n`; - formatted += `\`\`\`\n${context.selectedCode.text}\n\`\`\`\n\n`; - } - - // 打开的文件 - if (context.openFiles.length > 0) { - formatted += `## Open Files\n`; - context.openFiles.forEach((file: string) => { - formatted += `- ${file}\n`; - }); - formatted += '\n'; - } - - return formatted; - } -} -``` - -### 方案 2:文件引用解析 - -**解析策略**: - -```` -输入:"请优化 @src/App.tsx 和 @src/utils/helper.ts" - -步骤 1:正则匹配 - pattern: /@([\w\/\.\-]+)/g - 结果:['src/App.tsx', 'src/utils/helper.ts'] - -步骤 2:读取文件 - for each file: - content = fs.readFile(file) - -步骤 3:构建上下文 - [File: src/App.tsx] - ```tsx - ...file content... -```` - -[File: src/utils/helper.ts] - -```ts -...file content... -``` - -User: 请优化 src/App.tsx 和 src/utils/helper.ts - -```` - -**代码实现**: -```typescript -// src/extension/services/FileReferenceParser.ts -export class FileReferenceParser { - private filePattern = /@([\w\/\.\-]+\.\w+)/g; - - parse(message: string): { - files: string[]; - cleanMessage: string; - } { - const files: string[] = []; - let match; - - while ((match = this.filePattern.exec(message)) !== null) { - files.push(match[1]); - } - - // 移除 @ 符号,保留文件名 - const cleanMessage = message.replace(this.filePattern, (_, file) => file); - - return { files, cleanMessage }; - } - - async injectFileContents( - message: string, - workspaceRoot: string - ): Promise { - const { files, cleanMessage } = this.parse(message); - - if (files.length === 0) { - return message; - } - - let context = ''; - - for (const file of files) { - const fullPath = path.join(workspaceRoot, file); - - try { - const content = await vscode.workspace.fs.readFile( - vscode.Uri.file(fullPath) - ); - const text = Buffer.from(content).toString('utf8'); - - // 检测语言 - const ext = path.extname(file).slice(1); - const lang = this.getLanguage(ext); - - context += `\n[File: ${file}]\n`; - context += `\`\`\`${lang}\n${text}\n\`\`\`\n`; - } catch (error) { - context += `\n[File: ${file}] - Error: File not found\n`; - } - } - - return context + '\n\nUser: ' + cleanMessage; - } - - private getLanguage(ext: string): string { - const langMap: Record = { - ts: 'typescript', - tsx: 'tsx', - js: 'javascript', - jsx: 'jsx', - py: 'python', - rs: 'rust', - go: 'go', - java: 'java', - cpp: 'cpp', - c: 'c', - md: 'markdown', - json: 'json', - yaml: 'yaml', - yml: 'yaml' - }; - return langMap[ext] || ext; - } -} -```` - -### 方案 3:内联 Diff 预览 - -**交互流程**: - -``` -1. Agent 请求写入文件 - ↓ -2. 读取当前文件内容(oldContent) - ↓ -3. 打开 VSCode Diff 视图 - vscode.diff(oldUri, newUri, title) - ↓ -4. 显示 QuickPick 让用户选择 - ✅ Accept | ❌ Reject | 👁️ Review Later - ↓ -5. 根据选择执行操作 - - Accept: 写入新内容 - - Reject: 保持原样 - - Review: 保留 diff 视图,稍后决定 -``` - -**代码实现**: - -```typescript -// src/extension/services/DiffManager.ts -export class DiffManager { - private pendingDiffs = new Map< - string, - { - oldContent: string; - newContent: string; - } - >(); - - async showDiff( - filePath: string, - oldContent: string, - newContent: string, - ): Promise<'accept' | 'reject' | 'later'> { - // 保存待处理的 diff - this.pendingDiffs.set(filePath, { oldContent, newContent }); - - // 创建虚拟文档 URI - const oldUri = vscode.Uri.parse(`aionui-diff:${filePath}?version=old`).with( - { - query: Buffer.from(oldContent).toString('base64'), - }, - ); - - const newUri = vscode.Uri.parse(`aionui-diff:${filePath}?version=new`).with( - { - query: Buffer.from(newContent).toString('base64'), - }, - ); - - // 打开 diff 视图 - await vscode.commands.executeCommand( - 'vscode.diff', - oldUri, - newUri, - `AI Changes: ${path.basename(filePath)}`, - ); - - // 显示操作选项 - const action = await vscode.window.showQuickPick( - [ - { - label: '$(check) Accept Changes', - description: 'Apply AI modifications', - value: 'accept', - }, - { - label: '$(x) Reject Changes', - description: 'Keep original file', - value: 'reject', - }, - { - label: '$(eye) Review Later', - description: 'Keep diff open for review', - value: 'later', - }, - ], - { - placeHolder: 'Choose an action for AI changes', - }, - ); - - return (action?.value as any) || 'later'; - } - - async applyChanges(filePath: string): Promise { - const diff = this.pendingDiffs.get(filePath); - if (!diff) return; - - await vscode.workspace.fs.writeFile( - vscode.Uri.file(filePath), - Buffer.from(diff.newContent), - ); - - this.pendingDiffs.delete(filePath); - vscode.window.showInformationMessage( - `✅ Applied changes to ${path.basename(filePath)}`, - ); - } - - async rejectChanges(filePath: string): Promise { - this.pendingDiffs.delete(filePath); - vscode.window.showInformationMessage( - `❌ Rejected changes to ${path.basename(filePath)}`, - ); - } -} - -// 注册虚拟文档 provider -vscode.workspace.registerTextDocumentContentProvider('aionui-diff', { - provideTextDocumentContent(uri: vscode.Uri): string { - const content = uri.query; - return Buffer.from(content, 'base64').toString('utf8'); - }, -}); -``` - -### 方案 4:集成到消息发送流程 - -**完整流程**: - -```typescript -// src/extension/WebViewProvider.ts -private async handleSendMessage(text: string): Promise { - // 1. 收集 VSCode 上下文 - const contextCollector = new ContextCollector(); - const context = await contextCollector.collectFullContext(); - const contextStr = contextCollector.formatContext(context); - - // 2. 解析文件引用 - const fileParser = new FileReferenceParser(); - const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath || ''; - const messageWithFiles = await fileParser.injectFileContents(text, workspaceRoot); - - // 3. 构建完整 prompt - const fullPrompt = contextStr + '\n' + messageWithFiles; - - // 4. 创建检查点(如果启用) - if (this.config.enableCheckpoints) { - await this.checkpointManager.createCheckpoint(text); - } - - // 5. 发送给 Agent - await this.agentManager.sendMessage(fullPrompt); -} -``` - ---- - -## 实现时间表 - -### Week 1-2:P0 核心功能 - -- [x] Day 1-2: 自动上下文注入 -- [x] Day 3-5: 文件引用解析 -- [x] Day 6-10: 内联 Diff 预览 -- [x] Day 11-12: 一键接受/拒绝 - -**里程碑**:实现 Claude Code 70% 的核心体验 - -### Week 3-4:P1 增强功能 - -- [x] Day 13-17: Checkpoint 系统 -- [x] Day 18-19: Extended Thinking -- [x] Day 20-22: MCP 配置支持 - -**里程碑**:实现 Claude Code 90% 的功能 - -### Month 2-3:P2 高级功能 - -- [ ] Week 5-6: 多会话并行 -- [ ] Week 7: 图片上传 -- [ ] Week 8: UI/UX 优化 - -**里程碑**:功能完全对标 Claude Code - ---- - -## 成功指标 - -### 功能完整度 - -- ✅ 核心聊天功能:100% -- ⏳ 上下文感知:0% → 目标 100% -- ⏳ 代码修改:0% → 目标 100% -- ⏳ 历史管理:0% → 目标 80% - -### 用户体验 - -- ⏳ 自动化程度:提升 80%(减少手动操作) -- ⏳ 响应速度:< 100ms(上下文注入延迟) -- ⏳ 操作便捷性:接近 Claude Code - -### 技术指标 - -- ⏳ 代码质量:保持 TypeScript 严格模式 -- ⏳ 测试覆盖:核心功能 > 80% -- ⏳ 性能:内存占用 < 50MB - ---- - -## 总结 - -### 与 Claude Code 的差异 - -**Claude Code 的优势**: - -- ✅ 成熟的产品体验 -- ✅ Anthropic 官方支持 -- ✅ 与 Claude 模型深度集成 - -**我们的独特优势**: - -- ✅ 多 Agent 支持(Claude/Qwen/Gemini) -- ✅ 完全开源 -- ✅ 本地模型支持 -- ✅ 企业私有部署 - -### 目标定位 - -**不是替代 Claude Code,而是提供更灵活的选择**: - -- 对标 Claude Code 的功能 -- 保持多 Agent 的灵活性 -- 提供更好的隐私保护 -- 打造开放的生态系统 - ---- - -## 下一步行动 - -1. ✅ **立即开始**:实现自动上下文注入(2 天) -2. ✅ **本周完成**:文件引用解析(3 天) -3. ✅ **两周内完成**:内联 Diff 预览(5 天) -4. ✅ **一个月内**:完成 P0 和 P1 所有功能 - -**让我们开始吧!🚀** diff --git a/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_DEEP_ANALYSIS.md b/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_DEEP_ANALYSIS.md deleted file mode 100644 index 0ec448d7..00000000 --- a/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_DEEP_ANALYSIS.md +++ /dev/null @@ -1,1257 +0,0 @@ -# Claude Code VSCode Extension 深度技术分析报告 - -> **分析目标**: 从 Claude Code v2.0.43 压缩产物中提取可迁移的 UI 和逻辑代码 -> -> **分析日期**: 2025-11-18 -> -> **方法论**: 静态代码分析 + CSS 逆向工程 + package.json 配置推断 - ---- - -## 一、Quick Win 概念解释 - -### 什么是 Quick Win? - -**Quick Win** (快速胜利) 是敏捷开发中的术语,指: - -> **投入小、见效快、风险低的改进措施** - -在本项目中,Quick Win 功能包括: - -| 功能 | 投入时间 | 效果 | 风险 | -| ---------------- | -------- | ------------------ | ---- | -| WebView 固定右侧 | 10 分钟 | 立即改善用户体验 | 无 | -| Header 布局调整 | 2-3 小时 | UI 更符合 IDE 习惯 | 低 | -| 显示当前 Session | 1-2 小时 | 用户知道当前上下文 | 低 | - -**为什么关注 Quick Win?** - -1. 快速验证技术方案 -2. 团队士气提升 -3. 用户可立即感知改进 -4. 为复杂功能铺路 - ---- - -## 二、从压缩代码中提取的可行性评估 - -### 2.1 压缩代码分析结果 - -#### 文件规模 - -``` -extension.js: 155 行 (压缩后) -webview/index.js: 1380 行 (压缩后) -webview/index.css: 完整 CSS (未压缩) -package.json: 配置文件 (可读) -``` - -#### 代码压缩程度 - -```javascript -// 典型代码片段 -var zA = Object.create; -var Pc = Object.defineProperty; -var BA = Object.getOwnPropertyDescriptor; -// ... 变量名已混淆,无法直接读取 -``` - -**关键发现**: - -- ❌ **JavaScript 完全混淆** - 变量名、函数名无意义 -- ✅ **CSS 完全可读** - 类名、样式、布局清晰 -- ✅ **package.json 可读** - 配置、命令、依赖明确 - -### 2.2 可提取内容评估 - -| 内容类型 | 可提取性 | 可用性 | 推荐方案 | -| --------------------- | -------- | ---------- | ---------------- | -| **CSS 样式** | ✅ 100% | ⭐⭐⭐⭐⭐ | 直接复制适配 | -| **HTML 结构** | ⚠️ 50% | ⭐⭐⭐ | 从 CSS 类名推断 | -| **React 组件逻辑** | ❌ 0% | ❌ | 自行实现 | -| **package.json 配置** | ✅ 100% | ⭐⭐⭐⭐ | 参考借鉴 | -| **功能设计思路** | ✅ 80% | ⭐⭐⭐⭐⭐ | CSS 反推 UI 逻辑 | - -**结论**: - -- **可以提取**: CSS 样式、UI 结构设计 -- **无法提取**: 具体业务逻辑、React 代码 -- **最佳策略**: 参考 UI 设计,自行实现逻辑 - ---- - -## 三、Claude Code 核心功能详细分析 - -### 3.1 从 CSS 逆向工程的 UI 结构 - -#### A. 顶部 Header 组件 - -**CSS 类名分析**: - -```css -/* Header 容器 */ -.he { - display: flex; - border-bottom: 1px solid var(--app-primary-border-color); - padding: 6px 10px; - gap: 4px; - background-color: var(--app-header-background); - justify-content: flex-start; /* ← 左对齐 */ - user-select: none; -} - -/* 下拉按钮 (.E 类) */ -.E { - display: flex; - align-items: center; - gap: 6px; - padding: 2px 8px; - background: transparent; - border: none; - border-radius: 4px; - cursor: pointer; - outline: none; - min-width: 0; - max-width: 300px; /* ← 限制最大宽度 */ - overflow: hidden; - font-size: var(--vscode-chat-font-size, 13px); - font-family: var(--vscode-chat-font-family); -} - -/* 下拉按钮悬停/聚焦效果 */ -.E:focus, -.E:hover { - background: var(--app-ghost-button-hover-background); -} - -/* 下拉按钮内容区 (.xe 类) */ -.xe { - display: flex; - align-items: center; - gap: 4px; - max-width: 300px; - overflow: hidden; -} - -/* Session 标题文本 (.fe 类) */ -.fe { - overflow: hidden; - text-overflow: ellipsis; /* ← 长文本截断 */ - white-space: nowrap; - font-weight: 500; -} - -/* 下拉箭头图标 (.ve 类) */ -.ve { - flex-shrink: 0; /* ← 不缩小 */ -} - -/* 图标样式 (.we 类) */ -.we { - width: 16px; - height: 16px; - min-width: 16px; -} - -/* Spacer (.ke 类) */ -.ke { - flex: 1; /* ← 占据剩余空间,推送右侧按钮 */ -} - -/* 图标按钮 (.j 类) */ -.j { - flex: 0 0 auto; - padding: 0; - background: transparent; - border: 1px solid transparent; - border-radius: 4px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - outline: none; - width: 24px; /* ← 固定尺寸 */ - height: 24px; -} - -.j:focus, -.j:hover { - background: var(--app-ghost-button-hover-background); -} -``` - -**推断的 HTML 结构**: - -```html -
- - - - - -
- - - -
-``` - -**关键设计要点**: - -1. ✅ 使用 `flex` 布局,左中右三栏 -2. ✅ Session 按钮在左侧,最大宽度 300px -3. ✅ 使用 `text-overflow: ellipsis` 处理长标题 -4. ✅ Spacer 使用 `flex: 1` 推送右侧按钮 -5. ✅ 图标按钮固定 24x24 尺寸 -6. ✅ 统一的悬停效果 `--app-ghost-button-hover-background` - -#### B. 消息容器组件 - -**CSS 分析**: - -```css -/* 主容器 (.ye 类) */ -.ye { - display: flex; - flex-direction: column; - flex: 1; - overflow: hidden; - position: relative; - line-height: 1.5; -} - -/* 滚动容器 (.M 类) */ -.M { - flex: 1; - overflow-y: auto; - overflow-x: hidden; - padding: 20px 20px 40px; /* ← 底部额外留白 */ - display: flex; - flex-direction: column; - gap: 0; - background-color: var(--app-primary-background); - position: relative; - min-width: 0; -} - -/* 渐变遮罩效果 (.ze 类) */ -.ze { - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 150px; - background: linear-gradient( - to bottom, - transparent 0%, - var(--app-primary-background) 100% - ); /* ← 底部渐变遮罩 */ - pointer-events: none; - z-index: 2; -} - -/* 焦点模式样式 */ -.M.Be > *:not(.T) { - opacity: 0.4; /* ← 非焦点项半透明 */ -} - -.T { - opacity: 1; - position: relative; - z-index: 10; /* ← 焦点项提升层级 */ -} -``` - -**功能推断**: - -1. ✅ **底部渐变效果** - 视觉引导,提示有更多内容 -2. ✅ **焦点模式** - 工具调用时突出显示当前项 -3. ✅ **流畅滚动** - `overflow-y: auto` - -#### C. 消息气泡组件 - -**CSS 分析**: - -```css -/* 消息容器 (.Z 类) */ -.Z { - color: var(--app-primary-foreground); - display: flex; - gap: 0; - align-items: flex-start; - padding: 8px 0; - flex-direction: column; - position: relative; -} - -/* 用户消息 (._ 类) */ -._ { - display: inline-block; - margin: 4px 0; - position: relative; -} - -/* 消息内容气泡 (.Fe 类) */ -.Fe { - white-space: pre-wrap; - border: 1px solid var(--app-input-border); - border-radius: var(--corner-radius-medium); - background-color: var(--app-input-background); - padding: 4px 6px; - display: inline-block; - max-width: 100%; - overflow-x: auto; - overflow-y: hidden; - user-select: text; -} - -/* 代码块样式 (.He 类) */ -.He { - font-family: var(--app-monospace-font-family); - font-size: 0.9em; -} -``` - -#### D. 工具调用组件 (Tool Call) - -**CSS 分析**: - -```css -/* 工具调用容器 (.o 类) */ -.o { - align-items: flex-start; - padding-left: 30px; /* ← 缩进 */ - user-select: text; -} - -/* 状态指示点 */ -.o:before { - content: '\25cf'; /* ● 圆点 */ - position: absolute; - left: 8px; - padding-top: 2px; - font-size: 10px; - color: var(--app-secondary-foreground); - z-index: 1; -} - -/* 不同状态的颜色 */ -.o.Ie:before { - color: #74c991; -} /* 完成 - 绿色 */ -.o.Se:before { - color: #c74e39; -} /* 错误 - 红色 */ -.o.Le:before { - color: #e1c08d; -} /* 警告 - 黄色 */ - -/* 进行中动画 */ -.o.Ee:before { - background-color: var(--app-secondary-background); - animation: eo 1s linear infinite; -} - -@keyframes eo { - 0%, - to { - opacity: 1; - } - 50% { - opacity: 0; - } -} - -/* 连接线 */ -.o:after { - content: ''; - position: absolute; - left: 12px; - top: 0; - bottom: 0; - width: 1px; - background-color: var(--app-primary-border-color); -} - -/* 首尾特殊处理 */ -.o:not(.o + .o):after { - top: 18px; /* ← 第一个元素,线从中间开始 */ -} - -.o:not(:has(+ .o)):after { - height: 18px; /* ← 最后一个元素,线高度限制 */ -} -``` - -**推断的交互逻辑**: - -1. ✅ **状态可视化**: 圆点颜色表示工具调用状态 -2. ✅ **树形结构**: 连接线展示调用层级 -3. ✅ **脉冲动画**: 进行中状态有呼吸效果 - -#### E. 权限请求组件 - -**CSS 分析**: - -```css -/* 权限请求容器 (.t 类) */ -.t { - display: flex; - flex-direction: column; - padding: 8px; - background-color: var(--app-input-secondary-background); - border: 1px solid var(--app-input-border); - border-radius: var(--corner-radius-large); - max-height: 70vh; - outline: 0; - position: relative; - margin-bottom: 6px; -} - -/* 焦点时边框高亮 */ -.t:focus-within { - border-color: color-mix( - in srgb, - var(--app-input-active-border) 65%, - transparent - ); -} - -/* 标题区 (.lo 类) */ -.lo { - font-weight: 700; - color: var(--app-primary-foreground); - margin-bottom: 4px; -} - -/* 代码块区域 (.gr 类) */ -.gr { - font-family: var(--app-monospace-font-family); - font-size: 0.9em; - margin-bottom: 4px; - min-height: 0; - overflow-y: auto; - flex-shrink: 1; -} - -/* 按钮组 (.b 类) */ -.b { - display: flex; - flex-direction: column; - gap: 8px; - min-width: 0; - margin-top: 8px; - z-index: 1; -} - -/* 选项按钮 (.a 类) */ -.a { - color: var(--app-primary-foreground); - font-weight: 500; - cursor: pointer; - background-color: transparent; - padding: 6px 8px; - box-shadow: inset 0 0 0 1px var(--app-transparent-inner-border); - border-width: 0; - text-align: left; - width: 100%; - box-sizing: border-box; - border-radius: 4px; -} - -/* 焦点按钮高亮 */ -.t[data-focused-index='0'] .b .a:nth-child(1):not(:disabled), -.t[data-focused-index='1'] .b .a:nth-child(2):not(:disabled), -.t[data-focused-index='2'] .b .a:nth-child(3):not(:disabled) { - background-color: var(--app-button-background); - border: 0px solid var(--app-button-background); - color: var(--app-button-foreground); - font-weight: 700; - position: relative; -} -``` - -**推断的交互特性**: - -1. ✅ **键盘导航**: `data-focused-index` 属性控制焦点 -2. ✅ **多选项支持**: 动态高亮第 N 个按钮 -3. ✅ **自适应高度**: `max-height: 70vh` 防止过高 -4. ✅ **内容可滚动**: 代码区域独立滚动 - ---- - -### 3.2 从 package.json 推断的功能清单 - -#### 命令列表 - -虽然无法从 package.json 的 grep 结果直接看到命令,但从标准 Claude Code 文档,我们知道有以下命令: - -```json -{ - "commands": [ - { - "command": "claude-code.openEditor", - "title": "Claude Code: Open in Editor" - }, - { - "command": "claude-code.openSidebar", - "title": "Claude Code: Open in Sidebar" - }, - { - "command": "claude-code.newSession", - "title": "Claude Code: New Session" - }, - { - "command": "claude-code.switchSession", - "title": "Claude Code: Switch Session" - }, - { - "command": "claude-code.acceptChange", - "title": "Claude Code: Accept Change" - }, - { - "command": "claude-code.rejectChange", - "title": "Claude Code: Reject Change" - } - ] -} -``` - -#### 配置项推断 - -```json -{ - "configuration": { - "title": "Claude Code", - "properties": { - "claude-code.selectedModel": { - "type": "string", - "default": "claude-3-5-sonnet-20241022", - "description": "Selected Claude model" - }, - "claude-code.permissionMode": { - "type": "string", - "enum": ["ask", "accept", "reject"], - "default": "ask", - "description": "How to handle permission requests" - }, - "claude-code.autoScroll": { - "type": "boolean", - "default": true, - "description": "Auto-scroll to bottom on new messages" - } - } - } -} -``` - ---- - -## 四、可直接复制的 CSS 代码片段 - -### 4.1 Header 组件样式 - -```css -/* ========== Header 样式 ========== */ -.chat-header { - display: flex; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - padding: 6px 10px; - gap: 4px; - background-color: var(--vscode-sideBar-background); - justify-content: flex-start; - user-select: none; -} - -/* Session 下拉按钮 */ -.session-dropdown-button { - display: flex; - align-items: center; - gap: 6px; - padding: 2px 8px; - background: transparent; - border: none; - border-radius: 4px; - cursor: pointer; - outline: none; - min-width: 0; - max-width: 300px; - overflow: hidden; - font-size: var(--vscode-chat-font-size, 13px); - font-family: var(--vscode-chat-font-family); -} - -.session-dropdown-button:focus, -.session-dropdown-button:hover { - background: var(--vscode-toolbar-hoverBackground); -} - -.session-dropdown-content { - display: flex; - align-items: center; - gap: 4px; - max-width: 300px; - overflow: hidden; -} - -.session-title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-weight: 500; -} - -.dropdown-arrow { - flex-shrink: 0; - width: 16px; - height: 16px; -} - -/* Spacer */ -.header-spacer { - flex: 1; -} - -/* 图标按钮 */ -.icon-button { - flex: 0 0 auto; - padding: 0; - background: transparent; - border: 1px solid transparent; - border-radius: 4px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - outline: none; - width: 24px; - height: 24px; -} - -.icon-button:focus, -.icon-button:hover { - background: var(--vscode-toolbar-hoverBackground); -} -``` - -### 4.2 工具调用样式 - -```css -/* ========== Tool Call 样式 ========== */ -.tool-call { - align-items: flex-start; - padding-left: 30px; - user-select: text; - position: relative; -} - -/* 状态指示点 */ -.tool-call:before { - content: '\25cf'; - position: absolute; - left: 8px; - padding-top: 2px; - font-size: 10px; - color: var(--vscode-descriptionForeground); - z-index: 1; -} - -/* 状态颜色 */ -.tool-call.status-completed:before { - color: #74c991; -} - -.tool-call.status-failed:before { - color: #c74e39; -} - -.tool-call.status-warning:before { - color: #e1c08d; -} - -/* 进行中动画 */ -.tool-call.status-in-progress:before { - animation: tool-pulse 1s linear infinite; -} - -@keyframes tool-pulse { - 0%, - 100% { - opacity: 1; - } - 50% { - opacity: 0; - } -} - -/* 连接线 */ -.tool-call:after { - content: ''; - position: absolute; - left: 12px; - top: 0; - bottom: 0; - width: 1px; - background-color: rgba(255, 255, 255, 0.1); -} - -.tool-call:first-child:after { - top: 18px; -} - -.tool-call:last-child:after { - height: 18px; -} - -.tool-call:only-child:after { - display: none; -} -``` - -### 4.3 权限请求样式 - -```css -/* ========== Permission Request 样式 ========== */ -.permission-request { - display: flex; - flex-direction: column; - padding: 8px; - background-color: var(--vscode-menu-background); - border: 1px solid var(--vscode-inlineChatInput-border); - border-radius: 8px; - max-height: 70vh; - outline: 0; - position: relative; - margin-bottom: 6px; -} - -.permission-request:focus-within { - border-color: color-mix( - in srgb, - var(--vscode-inputOption-activeBorder) 65%, - transparent - ); -} - -.permission-title { - font-weight: 700; - color: var(--vscode-foreground); - margin-bottom: 4px; -} - -.permission-code { - font-family: var(--vscode-editor-font-family); - font-size: 0.9em; - margin-bottom: 4px; - min-height: 0; - overflow-y: auto; - flex-shrink: 1; -} - -.permission-options { - display: flex; - flex-direction: column; - gap: 8px; - min-width: 0; - margin-top: 8px; - z-index: 1; -} - -.permission-option { - color: var(--vscode-foreground); - font-weight: 500; - cursor: pointer; - background-color: transparent; - padding: 6px 8px; - box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1); - border: none; - text-align: left; - width: 100%; - box-sizing: border-box; - border-radius: 4px; -} - -.permission-option.focused { - background-color: var(--vscode-button-background); - color: var(--vscode-button-foreground); - font-weight: 700; -} - -.permission-option:disabled { - opacity: 0.5; - cursor: not-allowed; -} -``` - ---- - -## 五、无法从压缩代码提取的内容 - -### 5.1 业务逻辑 - -❌ **完全无法提取**: - -- React 组件状态管理 -- WebView 消息通信逻辑 -- Session 切换逻辑 -- 权限请求流程 - -**原因**: JavaScript 变量名和函数名完全混淆 - -### 5.2 数据结构 - -❌ **无法直接获取**: - -- Session 数据格式 -- Message 数据格式 -- Tool Call 数据格式 - -**解决方案**: 参考 Claude API 文档和 Anthropic 开源工具 - ---- - -## 六、推荐的迁移策略 - -### 策略 A: CSS 优先法 (推荐 ⭐⭐⭐⭐⭐) - -**步骤**: - -1. ✅ **复制 CSS** - 直接使用 Claude Code 的样式 -2. ✅ **重建 HTML** - 根据 CSS 类名推断结构 -3. ✅ **自实现逻辑** - 用 Qwen 的数据模型 - -**优点**: - -- UI 100% 对标 -- 代码可控,可维护 -- 无版权风险 - -**时间**: 2-3 天 - -### 策略 B: 参考设计法 - -**步骤**: - -1. 理解 Claude Code 的设计思路 -2. 自行设计类似的 UI -3. 复用部分 CSS 变量 - -**优点**: - -- 更灵活 -- 可加入创新 - -**缺点**: - -- 时间更长 - -**时间**: 5-7 天 - -### 策略 C: 混合法 (实用主义) - -**步骤**: - -1. **核心组件** - 复制 CSS,自实现逻辑 -2. **非核心组件** - 参考设计,自由发挥 - -**推荐组合**: -| 组件 | 策略 | -|------|------| -| Header | 复制 CSS ✅ | -| Tool Call | 复制 CSS ✅ | -| Permission | 复制 CSS ✅ | -| Message | 参考设计 ⚠️ | -| Input | 自由发挥 ⚠️ | - ---- - -## 七、具体实现指南 - -### 7.1 迁移 Header 组件 - -#### Step 1: 创建 React 组件 - -```tsx -// src/webview/components/ChatHeader.tsx -import React from 'react'; -import './ChatHeader.css'; - -interface ChatHeaderProps { - currentSessionTitle: string; - onSessionClick: () => void; - onNewChatClick: () => void; -} - -export const ChatHeader: React.FC = ({ - currentSessionTitle, - onSessionClick, - onNewChatClick, -}) => { - return ( -
- {/* Session Dropdown */} - - - {/* Spacer */} -
- - {/* New Chat Button */} - -
- ); -}; -``` - -#### Step 2: 添加 CSS (从 Claude Code 复制) - -```css -/* src/webview/components/ChatHeader.css */ -/* 直接复制上面的 "Header 组件样式" */ -``` - -#### Step 3: 集成到 App.tsx - -```tsx -// src/webview/App.tsx -import { ChatHeader } from './components/ChatHeader'; - -export const App: React.FC = () => { - const [currentSessionTitle, setCurrentSessionTitle] = useState(''); - - return ( -
- - {/* 其他组件 */} -
- ); -}; -``` - -### 7.2 迁移 Tool Call 组件 - -```tsx -// src/webview/components/ToolCall.tsx -import React from 'react'; -import './ToolCall.css'; - -type ToolCallStatus = 'pending' | 'in-progress' | 'completed' | 'failed'; - -interface ToolCallProps { - title: string; - status: ToolCallStatus; - content?: React.ReactNode; - isFirst?: boolean; - isLast?: boolean; -} - -export const ToolCall: React.FC = ({ - title, - status, - content, - isFirst = false, - isLast = false, -}) => { - const getStatusClass = () => { - switch (status) { - case 'completed': - return 'status-completed'; - case 'failed': - return 'status-failed'; - case 'in-progress': - return 'status-in-progress'; - default: - return ''; - } - }; - - const className = `tool-call ${getStatusClass()}`; - - return ( -
-
{title}
- {content &&
{content}
} -
- ); -}; -``` - -### 7.3 迁移 Permission Request 组件 - -```tsx -// src/webview/components/PermissionRequest.tsx -import React, { useState, useEffect } from 'react'; -import './PermissionRequest.css'; - -interface PermissionOption { - id: string; - label: string; - description?: string; -} - -interface PermissionRequestProps { - title: string; - code?: string; - options: PermissionOption[]; - onSelect: (optionId: string) => void; -} - -export const PermissionRequest: React.FC = ({ - title, - code, - options, - onSelect, -}) => { - const [focusedIndex, setFocusedIndex] = useState(0); - - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'ArrowDown') { - e.preventDefault(); - setFocusedIndex((prev) => Math.min(prev + 1, options.length - 1)); - } else if (e.key === 'ArrowUp') { - e.preventDefault(); - setFocusedIndex((prev) => Math.max(prev - 1, 0)); - } else if (e.key === 'Enter') { - e.preventDefault(); - onSelect(options[focusedIndex].id); - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, [focusedIndex, options, onSelect]); - - return ( -
-
{title}
- - {code && ( -
-          {code}
-        
- )} - -
- {options.map((option, index) => ( - - ))} -
-
- ); -}; -``` - ---- - -## 八、功能对标清单 - -### 已有功能对比 - -| 功能 | Claude Code | Qwen Code | 差距 | -| ------------------ | ---------------------- | ----------- | ------ | -| **UI 组件** | -| Header 布局 | ✅ 左侧下拉 + 右侧按钮 | ❌ 右侧按钮 | 需迁移 | -| Tool Call 可视化 | ✅ 树形 + 状态颜色 | ❌ 无 | 需实现 | -| Permission Request | ✅ 键盘导航 | ⚠️ 基础版 | 需增强 | -| 消息渐变遮罩 | ✅ | ❌ | 可选 | -| **交互功能** | -| Session 下拉选择 | ✅ | ❌ 模态框 | 需改进 | -| 键盘快捷键 | ✅ | ⚠️ 部分 | 需补全 | -| 焦点模式 | ✅ | ❌ | 可选 | -| **核心功能** | -| 流式响应 | ✅ | ✅ | 已对标 | -| 会话管理 | ✅ | ✅ | 已对标 | -| 工具调用 | ✅ | ✅ | 已对标 | - -### 推荐实现优先级 - -#### P0 - 核心 UI (本周完成) - -- [x] Header 布局迁移 -- [x] Session 下拉选择器 -- [x] 图标按钮样式 -- [x] 基础 CSS 变量 - -#### P1 - 增强体验 (下周��成) - -- [ ] Tool Call 可视化 -- [ ] Permission Request 键盘导航 -- [ ] 消息渐变遮罩 -- [ ] 焦点模式 - -#### P2 - 锦上添花 (可选) - -- [ ] 动画效果优化 -- [ ] 主题切换支持 -- [ ] 响应式布局 - ---- - -## 九、版权和风险评估 - -### CSS 复用的合法性 - -✅ **CSS 样式不受版权保护** (在美国法律下): - -- Lotus v. Borland 案例 - UI 元素属于"操作方法" -- CSS 是公开的样式描述,非创意作品 -- **但**: 完全复制可能构成"外观设计"侵权 - -✅ **推荐做法**: - -1. 参考 CSS 设计思路 -2. 修改类名 -3. 调整部分样式值 -4. 添加自己的创新 - -❌ **避免**: - -- 完全复制粘贴 -- 保留原始类名 -- 逐字复制注释 - -### 推荐的"安全"复用策略 - -```css -/* ❌ 不推荐:完全复制 */ -.E { - display: flex; - align-items: center; - /* ... 100% 一致 */ -} - -/* ✅ 推荐:参考后重写 */ -.session-dropdown-button { - display: flex; - align-items: center; - gap: 6px; /* ← 修改值 */ - padding: 4px 10px; /* ← 调整 */ - /* ... 重新组织 */ -} -``` - ---- - -## 十、总结与建议 - -### 可行性评估 - -| 方面 | 评分 | 说明 | -| ------------ | ---------- | ---------- | -| CSS 提取 | ⭐⭐⭐⭐⭐ | 100% 可用 | -| UI 设计参考 | ⭐⭐⭐⭐⭐ | 思路清晰 | -| 逻辑代码提取 | ⭐ | 几乎不可行 | -| 整体可行性 | ⭐⭐⭐⭐ | 高度可行 | - -### 最终建议 - -#### ✅ 应该做的 - -1. **复制 CSS 设计理念** - 学习布局思路 -2. **参考组件结构** - 从类名推断 HTML -3. **自实现逻辑** - 用 React + TypeScript -4. **适当修改** - 避免完全一致 - -#### ❌ 不应该做的 - -1. ~~直接提取 JS 逻辑~~ - 不可行 -2. ~~完全复制 CSS~~ - 有风险 -3. ~~反编译代码~~ - 违反许可 - -#### 🎯 Quick Win 行动清单 - -**本周可完成** (4-6 小时): - -- [x] 复制 Header CSS -- [x] 创建 ChatHeader 组件 -- [x] 实现 Session 下拉 -- [x] 添加新建按钮 -- [x] WebView 固定右侧 - -**效果**: - -- ✅ UI 立即对标 Claude Code -- ✅ 用户体验显著提升 -- ✅ 为后续功能铺路 - ---- - -## 附录 - -### A. Claude Code CSS 完整提取 - -详见压缩包中的 `webview/index.css` 文件 (已完整保留) - -### B. 关键 CSS 变量映射表 - -| Claude Code 变量 | VSCode 变量 | 用途 | -| ------------------------------------- | ---------------------------------- | ---------- | -| `--app-primary-foreground` | `--vscode-foreground` | 主文本颜色 | -| `--app-primary-background` | `--vscode-sideBar-background` | 主背景色 | -| `--app-input-border` | `--vscode-inlineChatInput-border` | 输入框边框 | -| `--app-button-background` | `--vscode-button-background` | 按钮背景 | -| `--app-ghost-button-hover-background` | `--vscode-toolbar-hoverBackground` | 悬停背景 | - -### C. 参考资源 - -- Claude Code 官方文档: https://docs.anthropic.com/claude-code -- VSCode Extension API: https://code.visualstudio.com/api -- React TypeScript: https://react-typescript-cheatsheet.netlify.app/ - ---- - -**文档版本**: v1.0 -**最后更新**: 2025-11-18 -**作者**: Claude (Sonnet 4.5) -**状态**: 待审核 diff --git a/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_UI_IMPLEMENTATION.md b/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_UI_IMPLEMENTATION.md deleted file mode 100644 index a92b9af9..00000000 --- a/packages/vscode-ide-companion/docs-tmp/CLAUDE_CODE_UI_IMPLEMENTATION.md +++ /dev/null @@ -1,211 +0,0 @@ -# Claude Code UI 还原实现 - -## 概述 - -本文档记录了如何将 Claude Code VSCode 扩展的 Webview UI 设计还原到我们的 Qwen Code VSCode IDE Companion 项目中。 - -## 分析的源 HTML 结构 - -从 Claude Code VSCode 扩展的 webview HTML 中,我们识别出以下关键组件: - -### 1. 顶部导航栏 (`.he`) - -- **Past Conversations** 按钮 (`.E`) - 带下拉箭头的会话列表按钮 -- **New Session** 按钮 (`.j`) - 创建新会话的加号按钮 -- 使用了 ghost button 风格,hover 时有背景色变化 - -### 2. 中间内容区域 - -- **空状态界面** - 当没有消息时显示 - - Qwen Logo (SVG) - - 欢迎文本:"What to do first? Ask about this codebase or we can start writing code." - - 横幅提示:"Prefer the Terminal experience? Switch back in Settings." - -### 3. 底部输入区域 (`.u`) - -- **可编辑的 contenteditable div** - 替代传统的 textarea - - placeholder: "Ask Claude to edit…" - - 支持多行输入 -- **操作按钮行** (`.ri`) - - "Ask before edits" 按钮 (`.l`) - 编辑模式选择 - - Thinking 开关按钮 (`.H.ni`) - - 命令菜单按钮 - - 发送按钮 (`.r`) - -## 实现的组件 - -### 1. EmptyState 组件 - -**文件**: `src/webview/components/EmptyState.tsx`, `EmptyState.css` - -**功能**: - -- 显示 Qwen Logo (使用现有的 SVG) -- 显示欢迎文本 -- 显示横幅提示(可关闭) -- 响应式布局 - -**关键样式**: - -```css -.empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - padding: 40px 20px; -} -``` - -### 2. 更新的 Header - -**改动**: `src/webview/App.tsx`, `App.css` - -**变更**: - -- 将 select 下拉框改为 "Past Conversations" 按钮 -- 按钮样式遵循 Claude Code 的 ghost button 设计 -- 使用 flex 布局,左对齐按钮,右侧 spacer,最右侧新建按钮 - -**类名**: - -- `.header-conversations-button` - 会话列表按钮 -- `.header-spacer` - flex spacer -- `.new-session-header-button` - 新建会话按钮 - -### 3. 重新设计的输入表单 - -**改动**: `src/webview/App.tsx`, `App.css` - -**变更**: - -- 使用 `contenteditable` div 替代 `` 或 `