diff --git a/CLAUDE.md b/CLAUDE.md index 6dfdb4cb..c3ada076 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,8 +51,8 @@ bun run docs:dev ### Runtime & Build - **Runtime**: Bun (not Node.js). All imports, builds, and execution use Bun APIs. -- **Build**: `build.ts` 执行 `Bun.build()` with `splitting: true`,入口 `src/entrypoints/cli.tsx`,输出 `dist/cli.js` + chunk files。默认启用 `AGENT_TRIGGERS_REMOTE` feature。构建后自动替换 `import.meta.require` 为 Node.js 兼容版本(产物 bun/node 都可运行)。 -- **Dev mode**: `scripts/dev.ts` 通过 Bun `-d` flag 注入 `MACRO.*` defines,运行 `src/entrypoints/cli.tsx`。默认启用 `BUDDY`、`TRANSCRIPT_CLASSIFIER`、`BRIDGE_MODE`、`AGENT_TRIGGERS_REMOTE` 四个 feature。 +- **Build**: `build.ts` 执行 `Bun.build()` with `splitting: true`,入口 `src/entrypoints/cli.tsx`,输出 `dist/cli.js` + chunk files。默认启用 `AGENT_TRIGGERS_REMOTE`、`CHICAGO_MCP`、`VOICE_MODE` feature。构建后自动替换 `import.meta.require` 为 Node.js 兼容版本(产物 bun/node 都可运行)。 +- **Dev mode**: `scripts/dev.ts` 通过 Bun `-d` flag 注入 `MACRO.*` defines,运行 `src/entrypoints/cli.tsx`。默认启用 `BUDDY`、`TRANSCRIPT_CLASSIFIER`、`BRIDGE_MODE`、`AGENT_TRIGGERS_REMOTE`、`CHICAGO_MCP`、`VOICE_MODE` 六个 feature。 - **Module system**: ESM (`"type": "module"`), TSX with `react-jsx` transform. - **Monorepo**: Bun workspaces — internal packages live in `packages/` resolved via `workspace:*`. - **Lint/Format**: Biome (`biome.json`)。`bun run lint` / `bun run lint:fix` / `bun run format`。 @@ -132,8 +132,8 @@ Feature flags control which functionality is enabled at runtime: - **在代码中使用**: 统一通过 `import { feature } from 'bun:bundle'` 导入,调用 `feature('FLAG_NAME')` 返回 `boolean`。**不要**在 `cli.tsx` 或其他文件里自己定义 `feature` 函数或覆盖这个 import。 - **启用方式**: 通过环境变量 `FEATURE_=1`。例如 `FEATURE_BUDDY=1 bun run dev` 启用 BUDDY 功能。 -- **Dev 默认 features**: `BUDDY`、`TRANSCRIPT_CLASSIFIER`、`BRIDGE_MODE`、`AGENT_TRIGGERS_REMOTE`(见 `scripts/dev.ts`)。 -- **Build 默认 features**: `AGENT_TRIGGERS_REMOTE`(见 `build.ts`)。 +- **Dev 默认 features**: `BUDDY`、`TRANSCRIPT_CLASSIFIER`、`BRIDGE_MODE`、`AGENT_TRIGGERS_REMOTE`、`CHICAGO_MCP`、`VOICE_MODE`(见 `scripts/dev.ts`)。 +- **Build 默认 features**: `AGENT_TRIGGERS_REMOTE`、`CHICAGO_MCP`、`VOICE_MODE`(见 `build.ts`)。 - **常见 flag**: `BUDDY`, `DAEMON`, `BRIDGE_MODE`, `BG_SESSIONS`, `PROACTIVE`, `KAIROS`, `VOICE_MODE`, `FORK_SUBAGENT`, `SSH_REMOTE`, `DIRECT_CONNECT`, `TEMPLATES`, `CHICAGO_MCP`, `BYOC_ENVIRONMENT_RUNNER`, `SELF_HOSTED_RUNNER`, `COORDINATOR_MODE`, `UDS_INBOX`, `LODESTONE`, `ABLATION_BASELINE` 等。 - **类型声明**: `src/types/internal-modules.d.ts` 中声明了 `bun:bundle` 模块的 `feature` 函数签名。 @@ -143,13 +143,45 @@ Feature flags control which functionality is enabled at runtime: | Module | Status | |--------|--------| -| Computer Use (`@ant/*`) | Stub packages in `packages/@ant/` | -| `*-napi` packages (audio, image, url, modifiers) | Stubs in `packages/` (except `color-diff-napi` which is fully implemented) | +| Computer Use (`@ant/*`) | Restored — `computer-use-swift`, `computer-use-input`, `computer-use-mcp`, `claude-for-chrome-mcp` 均有完整实现,macOS + Windows 可用,Linux 后端待完成 | +| `*-napi` packages | `audio-capture-napi`、`image-processor-napi` 已恢复实现;`color-diff-napi` 完整实现;`url-handler-napi`、`modifiers-napi` 仍为 stub | +| Voice Mode | Restored — `src/voice/`、`src/hooks/useVoiceIntegration.tsx`、`src/services/voiceStreamSTT.ts` 等,Push-to-Talk 语音输入(需 Anthropic OAuth) | +| OpenAI 兼容层 | Restored — `src/services/api/openai/`,支持 Ollama/DeepSeek/vLLM 等任意 OpenAI 协议端点,通过 `CLAUDE_CODE_USE_OPENAI=1` 启用 | | Analytics / GrowthBook / Sentry | Empty implementations | -| Magic Docs / Voice Mode / LSP Server | Removed | +| Magic Docs / LSP Server | Removed | | Plugins / Marketplace | Removed | | MCP OAuth | Simplified | +### Computer Use + +Feature flag `CHICAGO_MCP`,dev/build 默认启用。实现跨平台屏幕操控(macOS + Windows 可用,Linux 待完成)。 + +- **`packages/@ant/computer-use-mcp/`** — MCP server,注册截图/键鼠/剪贴板/应用管理工具 +- **`packages/@ant/computer-use-input/`** — 键鼠模拟,dispatcher + per-platform backend(`backends/darwin.ts`、`win32.ts`、`linux.ts`) +- **`packages/@ant/computer-use-swift/`** — 截图 + 应用管理,同样 dispatcher + per-platform backend +- **`packages/@ant/claude-for-chrome-mcp/`** — Chrome 浏览器控制(独立于 Computer Use,通过 `--chrome` CLI 参数启用) + +详见 `docs/features/computer-use.md`。 + +### Voice Mode + +Feature flag `VOICE_MODE`,dev/build 默认启用。Push-to-Talk 语音输入,音频通过 WebSocket 流式传输到 Anthropic STT(Nova 3)。需要 Anthropic OAuth(非 API key)。 + +- **`src/voice/voiceModeEnabled.ts`** — 三层门控(feature flag + GrowthBook + OAuth auth) +- **`src/hooks/useVoice.ts`** — React hook 管理录音状态和 WebSocket 连接 +- **`src/services/voiceStreamSTT.ts`** — STT WebSocket 流式传输 + +详见 `docs/features/voice-mode.md`。 + +### OpenAI 兼容层 + +通过 `CLAUDE_CODE_USE_OPENAI=1` 环境变量启用,支持任意 OpenAI Chat Completions 协议端点(Ollama、DeepSeek、vLLM 等)。流适配器模式:在 `queryModel()` 中将 Anthropic 格式请求转为 OpenAI 格式,再将 SSE 流转换回 `BetaRawMessageStreamEvent`,下游代码完全不改。 + +- **`src/services/api/openai/`** — client、消息/工具转换、流适配、模型映射 +- **`src/utils/model/providers.ts`** — 添加 `'openai'` provider 类型(最高优先级) + +关键环境变量:`CLAUDE_CODE_USE_OPENAI`、`OPENAI_API_KEY`、`OPENAI_BASE_URL`、`OPENAI_MODEL`、`OPENAI_MODEL_MAP`。详见 `docs/plans/openai-compatibility.md`。 + ### Key Type Files - **`src/types/global.d.ts`** — Declares `MACRO`, `BUILD_TARGET`, `BUILD_ENV` and internal Anthropic-only identifiers. diff --git a/DEV-LOG.md b/DEV-LOG.md index 349e499a..9d24ec55 100644 --- a/DEV-LOG.md +++ b/DEV-LOG.md @@ -1,5 +1,17 @@ # DEV-LOG +## Computer Use macOS 适配修复 (2026-04-04) + +**分支**: `feature/computer-use/mac-support` + +- **darwin.ts** — 应用枚举改用 Spotlight `mdfind` + `mdls`,获取真实 bundleId(旧方案合成 `com.app.xxx`),覆盖 `/Applications` + `/System/Applications` + CoreServices +- **index.ts** — 新增 `hotkey` backend fallback,非原生模块不崩溃 +- **toolCalls.ts** — `resolveRequestedApps()` 新增子串模糊匹配(`"Chrome"` → `"Google Chrome"`) +- **hostAdapter.ts** — `ensureOsPermissions()` 检查 `cu.tcc` 存在性,跨平台 JS backend 安全降级 +- **测试**: 17 个 MCP 工具中 10 个完全通过,6 个在 full tier 应用上通过(IDE click tier 受限为预期行为),`screenshot` 未返回图片(疑似屏幕录制权限问题) + +--- + ## Computer Use Windows 增强:窗口绑定截图 + UI Automation + OCR (2026-04-03) 在三平台基础实现之上,利用 Windows 原生 API 增强 Computer Use 的 Windows 专属能力。 diff --git a/README.md b/README.md index dc92cdb5..993a1bc2 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,13 @@ - [x] 关闭自动更新; - [x] 添加自定义 sentry 错误上报支持 [文档](https://ccb.agent-aura.top/docs/internals/sentry-setup) - [x] 添加自定义 GrowthBook 支持 (GB 也是开源的, 现在你可以配置一个自定义的遥控平台) [文档](https://ccb.agent-aura.top/docs/internals/growthbook-adapter) - - [x] 自定义 login 模式, 大家可以用这个配置 Claude 的模型! + - [x] 自定义 login 模式, 大家可以用这个配置 Claude 的模型! [文档](https://ccb.agent-aura.top/docs/features/custom-platform-login) + - [x] Remote Control / Bridge Mode 支持 [文档](https://ccb.agent-aura.top/docs/features/bridge-mode) - [x] 修复搜索工具的 rg 缺失问题(需要重新 bun i) - - [x] OpenAI 接口兼容! /login 然后配置 OpenAI 平台即可! - - [x] Chrome use 支持(暂时浏览器插件要订阅权限,万恶的牢 A) 感谢 @amDosion - - [x] Computer use 支持 感谢 @amDosion - - [x] /voice 支持 @amDosion + - [x] OpenAI 接口兼容! /login 然后配置 OpenAI 平台即可! [文档](https://ccb.agent-aura.top/docs/plans/openai-compatibility) + - [x] Chrome use 支持(暂时浏览器插件要订阅权限,万恶的牢 A) 感谢 @amDosion [文档](https://ccb.agent-aura.top/docs/features/claude-in-chrome-mcp) + - [x] Computer use 支持 感谢 @amDosion [文档](https://ccb.agent-aura.top/docs/features/computer-use) + - [x] /voice 支持 @amDosion [文档](https://ccb.agent-aura.top/docs/features/voice-mode) - [ ] V6 大规模重构石山代码, 全面模块分包 - [ ] V6 将会为全新分支, 届时 main 分支将会封存为历史版本 diff --git a/docs/features/claude-in-chrome-mcp.md b/docs/features/claude-in-chrome-mcp.md index 3b668ff5..8fe8c0d9 100644 --- a/docs/features/claude-in-chrome-mcp.md +++ b/docs/features/claude-in-chrome-mcp.md @@ -1,243 +1,137 @@ -# Claude in Chrome MCP — 恢复计划 +# Claude in Chrome — 用户操作指南 -更新时间:2026-04-03 -参考项目:`E:\源码\claude-code-source-main\claude-code-source-main` +## 1. 功能简介 -## 1. 功能概述 +Claude in Chrome 让 Claude Code 直接控制你的 Chrome 浏览器。你可以用自然语言让 Claude 帮你: -Claude in Chrome 让 Claude Code CLI 通过 MCP 协议控制用户的 Chrome 浏览器:导航网页、填写表单、截图、录制 GIF、读取 DOM、执行 JS、监控网络请求和控制台日志。 +- 打开网页、导航、前进后退 +- 填写表单、上传图片 +- 截图、录制 GIF +- 读取页面内容(DOM、纯文本) +- 执行 JavaScript +- 监控网络请求和控制台日志 +- 管理标签页 -通信方式有两种: -- **本地 Socket**:Chrome 扩展通过 Native Messaging Host 与 CLI 建立 Unix socket 连接 -- **Bridge WebSocket**:通过 Anthropic 的 bridge 服务中转,支持远程浏览器 +## 2. 前置条件 -## 2. 完整加载链路 +| 条件 | 说明 | +|------|------| +| Claude Code 订阅 | 需要 Claude Pro、Max 或 Team 订阅,浏览器插件功能不向免费用户开放 | +| Chrome 浏览器 | 需已安装 Google Chrome | +| Claude in Chrome 扩展 | 从 Chrome Web Store 安装(`claude.ai/chrome`) | +| Claude Code CLI | 已通过 `bun run dev` 或构建产物运行 | +## 3. 启用方式 + +### Dev 模式 + +```bash +bun run dev -- --chrome ``` -CLI 启动 - │ - ▼ -src/main.tsx:1003 - .option('--chrome', 'Enable Claude in Chrome integration') - │ - ▼ -src/main.tsx:1522-1527 - setChromeFlagOverride(chromeOpts.chrome) - │ - ▼ -src/utils/claudeInChrome/setup.ts - shouldEnableClaudeInChrome() - ├── --chrome flag → true - ├── --no-chrome flag → false - ├── 非交互模式 → false - ├── 环境变量 CLAUDE_CODE_DISABLE_CHROME → false - ├── 配置 claudeInChromeDefaultEnabled → true/false - └── Chrome 扩展已安装 + GrowthBook tengu_chrome_auto_enable → auto - │ - ▼ -src/utils/claudeInChrome/setup.ts - setupClaudeInChrome() - ├── 生成 MCP server 配置 - └── 返回 mcpConfig + allowedTools - │ - ▼ -src/utils/claudeInChrome/mcpServer.ts - import { createClaudeForChromeMcpServer } from '@ant/claude-for-chrome-mcp' - │ - ▼ -packages/@ant/claude-for-chrome-mcp/src/index.ts ← 当前是 STUB - export function createClaudeForChromeMcpServer() { return null } - export const BROWSER_TOOLS = [] + +启动后 Claude 会自动检测 Chrome 扩展是否已安装,并注册浏览器控制工具。 + +### 构建产物 + +```bash +node dist/cli.js --chrome ``` -## 3. 阻塞点清单 - -| # | 阻塞点 | 位置 | 状态 | -|---|--------|------|------| -| ① | `@ant/claude-for-chrome-mcp` 是 stub | `packages/@ant/claude-for-chrome-mcp/src/index.ts` | **6 行空壳,返回 null** | -| ② | 缺少完整实现(7 个文件,3038 行) | `packages/@ant/claude-for-chrome-mcp/src/` | 只有 1 个 stub 文件 | - -**不需要任何 feature flag** — `/chrome` 命令无条件注册在 `src/commands.ts:264`。 - -**不需要改 `src/` 下任何文件** — 以下文件全部与参考项目 0 行差异: -- `src/utils/claudeInChrome/setup.ts` -- `src/utils/claudeInChrome/mcpServer.ts` -- `src/utils/claudeInChrome/common.ts` -- `src/utils/claudeInChrome/chromeNativeHost.ts` -- `src/utils/claudeInChrome/prompt.ts` -- `src/utils/claudeInChrome/setupPortable.ts` -- `src/utils/claudeInChrome/toolRendering.tsx` -- `src/commands/chrome/index.ts` -- `src/commands/chrome/chrome.tsx`(仅 sourcemap 差异) -- `src/skills/bundled/claudeInChrome.ts` - -## 4. 参考项目完整实现清单 - -参考项目路径:`deps/@ant/claude-for-chrome-mcp/src/` - -| 文件 | 行数 | 职责 | -|------|------|------| -| `index.ts` | 15 | 导出入口:`createBridgeClient`、`BROWSER_TOOLS`、`createChromeSocketClient`、`createClaudeForChromeMcpServer`、`localPlatformLabel` + 类型导出 | -| `types.ts` | 134 | 类型定义:`Logger`、`PermissionMode`、`BridgeConfig`、`ChromeExtensionInfo`、`ClaudeForChromeContext`、`SocketClient`、`BridgePermissionRequest/Response`、`PermissionOverrides` | -| `browserTools.ts` | 546 | 17 个浏览器工具定义(MCP tool schema) | -| `mcpServer.ts` | 96 | MCP Server 创建:注册 `ListTools`/`CallTool` handler,选择 socket/bridge 传输 | -| `mcpSocketClient.ts` | 493 | Unix Socket 客户端:连接 Chrome Native Messaging Host,JSON-RPC 通信 | -| `mcpSocketPool.ts` | 327 | Socket 连接池:多 Chrome profile 支持,按 tabId 路由 | -| `bridgeClient.ts` | 1126 | Bridge WebSocket 客户端:连接 Anthropic bridge 服务,扩展发现、设备配对、权限管理 | -| `toolCalls.ts` | 301 | 工具调用路由:连接状态处理、结果转换、权限模式切换、浏览器切换 | - -### 17 个浏览器工具 - -| 工具名 | 功能 | -|--------|------| -| `javascript_tool` | 在页面上下文执行 JavaScript | -| `read_page` | 获取页面可访问性树(DOM) | -| `find` | 自然语言搜索页面元素 | +### 禁用 + +```bash +bun run dev -- --no-chrome +``` + +或在 REPL 中通过 `/chrome` 命令切换启用/禁用状态。 + +### 通过配置默认启用 + +在 Claude Code 设置中将 `claudeInChromeDefaultEnabled` 设为 `true`,以后启动无需加 `--chrome` 参数。 + +## 4. 使用流程 + +1. **启动 CLI** — 加 `--chrome` 参数启动 Claude Code +2. **确认连接** — REPL 中输入 `/chrome`,查看扩展状态是否显示 "Installed / Connected" +3. **开始对话** — 正常与 Claude 对话,当需要操作浏览器时直接说,例如: + - "打开 https://example.com 并截图" + - "在当前页面搜索关键词 xxx" + - "填写登录表单,用户名 admin" + - "帮我录制当前操作的 GIF" +4. **权限审批** — 首次执行浏览器操作时,Claude 会请求你的确认 +5. **操作完成** — Claude 完成操作后会返回结果(截图、文本、执行结果等) + +## 5. 可用操作 + +### 页面交互 + +| 操作 | 说明 | +|------|------| +| `navigate` | 导航到指定 URL,或前进/后退 | +| `computer` | 鼠标点击、移动、拖拽、键盘输入、截图等(13 种 action) | | `form_input` | 填写表单字段 | -| `computer` | 鼠标键盘操作 + 截图(13 种 action) | -| `navigate` | URL 导航 / 前进后退 | -| `resize_window` | 调整浏览器窗口尺寸 | -| `gif_creator` | GIF 录制和导出 | -| `upload_image` | 图片上传到文件输入框或拖拽区域 | -| `get_page_text` | 提取页面纯文本 | +| `upload_image` | 上传图片到文件输入框或拖拽区域 | +| `javascript_tool` | 在页面上下文执行 JavaScript | + +### 页面读取 + +| 操作 | 说明 | +|------|------| +| `read_page` | 获取页面可访问性树(DOM 结构) | +| `get_page_text` | 提取页面纯文本内容 | +| `find` | 用自然语言搜索页面元素 | + +### 标签页管理 + +| 操作 | 说明 | +|------|------| | `tabs_context_mcp` | 获取当前标签组信息 | | `tabs_create_mcp` | 创建新标签页 | -| `update_plan` | 向用户提交操作计划供审批 | + +### 监控与调试 + +| 操作 | 说明 | +|------|------| | `read_console_messages` | 读取浏览器控制台日志 | -| `read_network_requests` | 读取网络请求 | +| `read_network_requests` | 读取网络请求记录 | + +### 其他 + +| 操作 | 说明 | +|------|------| +| `resize_window` | 调整浏览器窗口尺寸 | +| `gif_creator` | 录制 GIF 并导出 | | `shortcuts_list` | 列出可用快捷方式 | | `shortcuts_execute` | 执行快捷方式 | -| `switch_browser` | 切换到其他 Chrome 浏览器(仅 bridge 模式) | +| `update_plan` | 向你提交操作计划供审批 | +| `switch_browser` | 切换到其他 Chrome 浏览器(仅 Bridge 模式) | -### 外部依赖 +## 6. 通信模式 -| 依赖 | 用途 | 我们项目是否已有 | -|------|------|----------------| -| `ws` | WebSocket 客户端(bridge 模式) | ✅ 有 | -| `@modelcontextprotocol/sdk` | MCP Server + 类型 | ✅ 有 | -| `fs`/`net`/`os`/`path` | Node.js 内置 | ✅ | +Claude in Chrome 支持两种与浏览器通信的方式: -## 5. 修复步骤 +### 本地 Socket(默认) -### 步骤 1:复制完整实现到 stub 包目录 +Chrome 扩展通过 Native Messaging Host 与 CLI 建立 Unix socket 连接。适用于本地开发,无需额外配置。 -```bash -# 从参考项目复制 7 个文件(覆盖现有的 1 个 stub) -cp "E:/源码/claude-code-source-main/claude-code-source-main/deps/@ant/claude-for-chrome-mcp/src/"*.ts \ - "E:/源码/Claude-code-bast/packages/@ant/claude-for-chrome-mcp/src/" -``` +### Bridge WebSocket -复制后 `packages/@ant/claude-for-chrome-mcp/src/` 应包含 8 个文件: +通过 Anthropic 的 bridge 服务中转,支持远程操控浏览器。需要 claude.ai OAuth 登录。 -``` -packages/@ant/claude-for-chrome-mcp/src/ -├── index.ts ← 覆盖 stub(15 行,导出入口) -├── types.ts ← 新增(134 行) -├── browserTools.ts ← 新增(546 行) -├── mcpServer.ts ← 新增(96 行) -├── mcpSocketClient.ts ← 新增(493 行) -├── mcpSocketPool.ts ← 新增(327 行) -├── bridgeClient.ts ← 新增(1126 行) -└── toolCalls.ts ← 新增(301 行) -``` +## 7. 常见问题 -### 步骤 2:验证构建 +### 扩展显示未安装 -```bash -bun run build -``` +确认已从 Chrome Web Store 安装 "Claude in Chrome" 扩展,安装后重启浏览器。 -不需要改 `scripts/dev.ts` 或 `build.ts`(无 feature flag)。 +### 工具未出现在工具列表 -### 步骤 3:功能验证 +检查启动时是否加了 `--chrome` 参数,或通过 `/chrome` 命令确认状态。 -```bash -# 启动(手动启用 chrome) -bun run dev -- --chrome +### 连接超时 -# 在 REPL 中: -# 1. /chrome 命令应显示 Chrome 设置菜单 -# 2. 如果 Chrome 扩展已安装 → 状态显示 "Enabled" -# 3. 如果未安装 → 提示安装扩展链接 -``` +确保 Chrome 浏览器正在运行且扩展已启用。Native Messaging Host 在扩展安装时自动注册,如果重装过扩展需要重启浏览器。 + +### 不使用 Chrome 功能时 -## 6. 验证测试项 - -### 6.1 构建验证 - -| 测试项 | 预期结果 | 验证命令 | -|--------|---------|---------| -| build 成功 | 无报错 | `bun run build` | -| BROWSER_TOOLS 非空 | 产物中包含 17 个工具定义 | `grep "javascript_tool" dist/*.js` | -| createClaudeForChromeMcpServer 非 null | 产物中包含 MCP Server 创建逻辑 | `grep "ListToolsRequestSchema" dist/*.js` | -| Bridge WebSocket 逻辑在产物中 | 包含 bridge 连接代码 | `grep "bridge.claudeusercontent.com" dist/*.js` | - -### 6.2 命令注册验证 - -| 测试项 | 预期结果 | -|--------|---------| -| `/chrome` 命令可见 | REPL 中输入 `/chrome` 显示设置菜单 | -| `--chrome` 参数可用 | `bun run dev -- --chrome` 不报错 | -| `--no-chrome` 参数可用 | `bun run dev -- --no-chrome` 不报错 | - -### 6.3 MCP Server 验证(需要 Chrome 扩展) - -| 测试项 | 预期结果 | -|--------|---------| -| Chrome 扩展检测 | 已安装扩展时 `/chrome` 显示 "Extension: Installed" | -| Socket 连接 | 扩展连接后 MCP tools 可用 | -| BROWSER_TOOLS 注册 | `tabs_context_mcp` 等 17 个工具在 MCP 工具列表中可见 | - -### 6.4 工具功能验证(需要 Chrome 扩展 + 连接) - -| 测试项 | 预期结果 | -|--------|---------| -| `tabs_context_mcp` | 返回当前标签组信息 | -| `navigate` | 能导航到指定 URL | -| `computer` + `screenshot` | 返回页面截图 | -| `read_page` | 返回 DOM 可访问性树 | -| `javascript_tool` | 执行 JS 并返回结果 | - -### 6.5 不影响现有功能 - -| 测试项 | 预期结果 | -|--------|---------| -| 不带 `--chrome` 启动 | 正常运行,无 chrome 相关报错 | -| `/voice` 命令 | 不受影响 | -| `/schedule` 命令 | 不受影响 | -| `bun test` | 现有测试全部通过 | - -## 7. 改动总结 - -| 操作 | 文件 | 说明 | -|------|------|------| -| 覆盖 stub | `packages/@ant/claude-for-chrome-mcp/src/index.ts` | 6 行 stub → 15 行完整导出 | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/types.ts` | 134 行类型定义 | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/browserTools.ts` | 546 行,17 个工具定义 | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/mcpServer.ts` | 96 行 MCP Server | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/mcpSocketClient.ts` | 493 行 Socket 客户端 | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/mcpSocketPool.ts` | 327 行连接池 | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/bridgeClient.ts` | 1126 行 Bridge 客户端 | -| 新增 | `packages/@ant/claude-for-chrome-mcp/src/toolCalls.ts` | 301 行工具调用路由 | - -**不改动**:`src/` 下所有文件(已与参考项目一致)、`scripts/dev.ts`、`build.ts`。 - -## 8. 运行时依赖 - -| 依赖 | 必需? | 说明 | -|------|--------|------| -| Chrome 浏览器 | 是 | 需安装 Chrome | -| Claude in Chrome 扩展 | 是 | 从 https://claude.ai/chrome 安装 | -| claude.ai OAuth 登录 | Bridge 模式需要 | 本地 Socket 模式不需要 | -| Native Messaging Host | 本地 Socket 需要 | 扩展安装时自动注册 | - -## 9. 与 /voice、/schedule 恢复方式对比 - -| 项 | `/schedule` | `/voice` | Claude in Chrome | -|---|---|---|---| -| 编译开关 | `AGENT_TRIGGERS_REMOTE` | `VOICE_MODE` | **无需** | -| 改 dev.ts/build.ts | ✅ | ✅ | **不需要** | -| 缺失的 vendor 二进制 | 无 | `.node` 文件 | 无 | -| 需要替换的 stub | 无 | `audio-capture-napi` | `@ant/claude-for-chrome-mcp`(7 个文件) | -| 改动 src/ 源码 | 无 | 无 | 无 | -| 平台限制 | 无 | 需原生 `.node` | 需 Chrome 浏览器 | +不带 `--chrome` 参数正常启动即可,不会加载任何浏览器相关模块,不影响其他功能。 diff --git a/docs/features/computer-use-mcp-test-report.md b/docs/features/computer-use-mcp-test-report.md new file mode 100644 index 00000000..d8f4df39 --- /dev/null +++ b/docs/features/computer-use-mcp-test-report.md @@ -0,0 +1,277 @@ +# Computer Use MCP 工具测试报告 + +> 测试日期: 2026-04-04 +> 测试环境: macOS Darwin 25.4.0, Cursor (IDE tier: click) +> MCP Server: `@ant/computer-use-mcp` + +## 工具总览 + +共 17 个工具(含 batch 复合操作),分为 5 大类: + +| 类别 | 工具 | 数量 | +|------|------|------| +| 截图/显示 | `screenshot`, `switch_display`, `zoom` | 3 | +| 鼠标操作 | `left_click`, `right_click`, `double_click`, `triple_click`, `middle_click`, `left_click_drag`, `mouse_move` | 7 | +| 键盘操作 | `key`, `type`, `hold_key` | 3 | +| 状态查询 | `cursor_position`, `request_access` | 2 | +| 复合/辅助 | `computer_batch`, `wait` | 2 | + +--- + +## 测试结果 + +### 1. 权限管理 + +#### `request_access` — 请求应用访问权限 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 行为 | 弹出系统对话框请求用户授权,支持批量申请多个应用 | +| 返回 | `{ granted: [...], denied: [...], tierGuidance: "..." }` | +| 权限分级 | `click`(仅点击), `full`(完整控制) | +| 说明 | IDE 类应用(Cursor、VSCode、Terminal)默认授予 `click` tier,限制键盘输入和右键操作;系统应用(System Settings)授予 `full` tier | + +#### 已授权应用 + +| 应用 | Tier | 能力 | +|------|------|------| +| Cursor | click | 可见 + 纯左键点击(无键盘输入、右键、修饰键点击、拖拽) | +| Terminal | click | 同上 | +| System Settings | full | 完整控制(键鼠、拖拽等) | +| Finder | — | 已授权 | + +--- + +### 2. 截图与显示 + +#### `screenshot` — 截取屏幕截图 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 部分通过 | +| 执行 | 工具成功执行,返回 `ok: true` | +| 图片 | **未返回可视图片内容**(output 为空字符串) | +| `save_to_disk` | 设置后仍无输出 | +| 分析 | 可能原因:(1) macOS 屏幕录制权限未授予;(2) 当前前台应用未被过滤导致截图为空;(3) MCP 传输层未正确编码图片数据 | +| 建议 | 检查 **系统设置 → 隐私与安全性 → 屏幕录制** 是否授权给运行 Claude Code 的应用 | + +#### `switch_display` — 切换显示器 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 行为 | 接受显示器名称或 `"auto"`(自动选择) | +| 返回 | 确认消息 | + +#### `zoom` — 区域放大截图 + +| 项目 | 结果 | +|------|------| +| 状态 | ⏭️ 跳过 | +| 原因 | 依赖 `screenshot` 返回的图片坐标,截图未返回图片无法测试 | + +--- + +### 3. 鼠标操作 + +> 以下测试在 Cursor 窗口上执行(tier: click) + +#### `mouse_move` — 移动鼠标 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 输入 | `coordinate: [500, 500]` | +| 返回 | `"Moved."` | + +#### `left_click` — 左键单击 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 输入 | `coordinate: [500, 500]` | +| 返回 | `"Clicked."` | + +#### `double_click` — 双击 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 输入 | `coordinate: [500, 500]` | +| 返回 | `"Clicked."` | + +#### `triple_click` — 三击 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 输入 | `coordinate: [500, 500]` | +| 返回 | `"Clicked."` | + +#### `right_click` — 右键点击 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 受 tier 限制 | +| Cursor (click tier) | ❌ 被拒绝 — `"Code" is granted at tier "click" — right-click, middle-click, and clicks with modifier keys require tier "full"` | +| Finder (full tier) | ✅ 通过 — 返回 `"Clicked."` | +| 结论 | 功能正常,IDE 安全限制符合预期 | + +#### `middle_click` — 中键点击 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 受 tier 限制 | +| Cursor (click tier) | ❌ 被拒绝 — 同 `right_click`,需要 full tier | +| Finder (full tier) | ✅ 通过 — 返回 `"Clicked."` | +| 结论 | 功能正常,IDE 安全限制符合预期 | + +#### `left_click_drag` — 拖拽 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 受 tier 限制 | +| Cursor (click tier) | ❌ 被拒绝 — 拖拽被视为修饰键点击,需要 full tier | +| Finder (full tier) | ✅ 通过 — 返回 `"Dragged."` | +| 结论 | 功能正常,IDE 安全限制符合预期 | + +#### `scroll` — 滚轮滚动 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 输入 | `coordinate: [500, 500]`, `scroll_direction: "down"`, `scroll_amount: 3` | +| 返回 | `"Scrolled."` | +| 反向 | ✅ `scroll_direction: "up"` 也通过 | + +--- + +### 4. 键盘操作 + +> 以下测试在 Cursor 窗口上执行(tier: click)— 所有键盘操作均被拒绝 + +#### `key` — 按键/快捷键 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 受 tier 限制 | +| Cursor (click tier) | ❌ 被拒绝 — IDE tier 限制键盘输入 | +| Finder (full tier) | ✅ 通过 — `escape` 按键成功,返回 `"Key pressed."` | +| 结论 | 功能正常,IDE 安全限制符合预期 | + +#### `type` — 输入文本 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 受 tier 限制 | +| Cursor (click tier) | ❌ 被拒绝 — IDE tier 限制文本输入 | +| Finder (full tier) | ✅ 通过 — 输入 `"hello"` 成功,返回 `"Typed 5 grapheme(s)."` | +| 结论 | 功能正常,IDE 安全限制符合预期 | + +#### `hold_key` — 按住按键 + +| 项目 | 结果 | +|------|------| +| 状态 | ⚠️ 受 tier 限制 | +| Cursor (click tier) | ❌ 被拒绝 — IDE tier 限制键盘输入 | +| Finder (full tier) | ✅ 通过 — 按住 `shift` 1 秒成功,返回 `"Key held."` | +| 结论 | 功能正常,IDE 安全限制符合预期 | + +--- + +### 5. 状态查询 + +#### `cursor_position` — 获取鼠标位置 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 返回 | `{"x": null, "y": null, "coordinateSpace": "image_pixels"}` | +| 说明 | 坐标为 null 是因为没有成功截图,无参考坐标系 | + +--- + +### 6. 复合/辅助操作 + +#### `computer_batch` — 批量执行操作 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 行为 | 按顺序执行操作列表,遇到失败则停止后续操作 | +| 返回 | `{ completed: [...], failed: {...}, remaining: N }` | +| 特点 | 单次 API 调用执行多个操作,减少往返延迟 | +| 错误处理 | 失败的操作会中断后续操作,返回已完成和剩余数量 | + +#### `wait` — 等待 + +| 项目 | 结果 | +|------|------| +| 状态 | ✅ 通过 | +| 输入 | `duration: 1` (秒) | +| 返回 | `"Waited 1s."` | +| 最大值 | 100 秒 | + +--- + +## 汇总统计 + +| 状态 | 数量 | 工具 | +|------|------|------| +| ✅ 通过 | 10 | `request_access`, `switch_display`, `mouse_move`, `left_click`, `double_click`, `triple_click`, `scroll`, `cursor_position`, `computer_batch`, `wait` | +| ⚠️ 部分通过 | 7 | `screenshot`(执行成功但无图片返回), `right_click`, `middle_click`, `left_click_drag`, `key`, `type`, `hold_key`(均在 full tier 应用上通过,IDE click tier 限制是预期行为) | +| ❌ 被拒绝 | 0 | — | +| ⏭️ 跳过 | 1 | `zoom`(依赖截图) | + +--- + +## 已知问题 + +### P0: 截图无图片返回 + +`screenshot` 工具执行成功但未返回图片内容,导致: +- 无法获取屏幕坐标参考 +- `cursor_position` 返回 null 坐标 +- `zoom` 无法使用 +- 所有点击操作只能盲点(无截图验证) + +**可能原因**: +1. macOS 屏幕录制权限未授予 +2. MCP 图片传输/编码问题 +3. 截图内容被安全过滤机制过滤 + +**建议排查**: 检查 `系统设置 → 隐私与安全性 → 屏幕录制` 权限。 + +### P1: IDE 应用键盘操作受限 — ✅ 已确认功能正常 + +IDE 类应用(Cursor、VSCode、Terminal)被限制在 `click` tier,无法执行: +- 键盘输入(`key`, `type`, `hold_key`) +- 右键/中键点击(`right_click`, `middle_click`) +- 拖拽操作(`left_click_drag`) + +这是安全设计,防止 AI 操控 IDE 终端。**在 full tier 应用(Finder、System Settings)上,以上 6 个操作均测试通过,功能完全正常。** + +--- + +## 权限模型说明 + +Computer Use MCP 采用分级权限模型: + +``` +┌─────────────────────────────────────────┐ +│ Tier: full │ +│ - 所有鼠标操作(左键、右键、中键、拖拽) │ +│ - 键盘输入(type, key, hold_key) │ +│ - 适用于: 系统应用、Finder 等 │ +├─────────────────────────────────────────┤ +│ Tier: click │ +│ - 仅纯左键点击 │ +│ - 滚轮滚动 │ +│ - 适用于: IDE、Terminal 等 │ +├─────────────────────────────────────────┤ +│ 未授权 │ +│ - 所有操作被拒绝 │ +│ - 需通过 request_access 申请 │ +└─────────────────────────────────────────┘ +``` diff --git a/docs/features/computer-use.md b/docs/features/computer-use.md index 2ae3cc77..2cfd54d8 100644 --- a/docs/features/computer-use.md +++ b/docs/features/computer-use.md @@ -1,197 +1,136 @@ -# Computer Use — macOS / Windows / Linux 跨平台实施计划 +# Computer Use 用户指南 -更新时间:2026-04-03 -参考项目:`E:\源码\claude-code-source-main\claude-code-source-main` +Computer Use 让 Claude 直接操控你的电脑——移动鼠标、点击、输入文字、截图,就像一个远程助手坐在你面前操作一样。 -## 1. 现状 +## 支持平台 -参考项目的 Computer Use **仅支持 macOS**——从入口到底层全部写死 darwin。我们的项目在 Phase 1-3 中已经完成了: - -- ✅ `@ant/computer-use-mcp` stub 替换为完整实现(12 文件) -- ✅ `@ant/computer-use-input` 拆为 dispatcher + backends(darwin + win32) -- ✅ `@ant/computer-use-swift` 拆为 dispatcher + backends(darwin + win32) -- ✅ `CHICAGO_MCP` 编译开关已开 -- ❌ `src/` 层有 6 处 macOS 硬编码阻塞 - -## 2. 阻塞点全景 - -### 2.1 入口层 - -| # | 文件:行号 | 阻塞代码 | 影响 | -|---|----------|---------|------| -| 1 | `src/main.tsx:1605` | `getPlatform() === 'macos'` | 整个 CU 初始化被跳过 | - -### 2.2 加载层 - -| # | 文件:行号 | 阻塞代码 | 影响 | -|---|----------|---------|------| -| 2 | `src/utils/computerUse/swiftLoader.ts:16` | `process.platform !== 'darwin'` → throw | 截图、应用管理全部不可用 | -| 3 | `src/utils/computerUse/executor.ts:263` | `process.platform !== 'darwin'` → throw | 整个 executor 工厂函数不可用 | - -### 2.3 macOS 特有依赖 - -| # | 文件:行号 | 依赖 | macOS 实现 | 需要替代方案 | -|---|----------|------|-----------|------------| -| 4 | `executor.ts:70-88` | 剪贴板 | `pbcopy`/`pbpaste` | Win: PowerShell `Get/Set-Clipboard`;Linux: `xclip`/`wl-copy` | -| 5 | `drainRunLoop.ts:21` | CFRunLoop pump | `cu._drainMainRunLoop()` | 非 darwin:直接执行 fn(),不需要 pump | -| 6 | `escHotkey.ts:28` | ESC 热键 | CGEventTap | 非 darwin:返回 false(已有 Ctrl+C fallback) | -| 7 | `hostAdapter.ts:48-54` | 系统权限 | TCC accessibility + screenRecording | Win:直接 granted;Linux:检查 xdotool | -| 8 | `common.ts:56` | 平台标识 | `platform: 'darwin'` 硬编码 | 动态获取 | -| 9 | `executor.ts:180` | 粘贴快捷键 | `command+v` | Win/Linux:`ctrl+v` | - -### 2.4 缺失的 Linux 后端 - -| 包 | macOS | Windows | Linux | -|---|-------|---------|-------| -| `computer-use-input/backends/` | ✅ darwin.ts | ✅ win32.ts | ❌ 需新建 linux.ts | -| `computer-use-swift/backends/` | ✅ darwin.ts | ✅ win32.ts | ❌ 需新建 linux.ts | - -## 3. 每个平台的能力依赖 - -### 3.1 computer-use-input(键鼠) - -| 功能 | macOS | Windows | Linux | -|------|-------|---------|-------| -| 鼠标移动 | CGEvent JXA | SetCursorPos P/Invoke | xdotool mousemove | -| 鼠标点击 | CGEvent JXA | SendInput P/Invoke | xdotool click | -| 鼠标滚轮 | CGEvent JXA | SendInput MOUSEEVENTF_WHEEL | xdotool scroll | -| 键盘按键 | System Events osascript | keybd_event P/Invoke | xdotool key | -| 组合键 | System Events osascript | keybd_event 组合 | xdotool key combo | -| 文本输入 | System Events keystroke | SendKeys.SendWait | xdotool type | -| 前台应用 | System Events osascript | GetForegroundWindow P/Invoke | xdotool getactivewindow + /proc | -| 工具依赖 | osascript(内置) | powershell(内置) | xdotool(需安装) | - -### 3.2 computer-use-swift(截图 + 应用管理) - -| 功能 | macOS | Windows | Linux | -|------|-------|---------|-------| -| 全屏截图 | screencapture | CopyFromScreen | gnome-screenshot / scrot / grim | -| 区域截图 | screencapture -R | CopyFromScreen(rect) | gnome-screenshot -a / scrot -a / grim -g | -| 显示器列表 | CGGetActiveDisplayList JXA | Screen.AllScreens | xrandr --query | -| 运行中应用 | System Events JXA | Get-Process | wmctrl -l / ps | -| 打开应用 | osascript activate | Start-Process | xdg-open / gtk-launch | -| 隐藏/显示 | System Events visibility | ShowWindow/SetForegroundWindow | wmctrl -c / xdotool | -| 工具依赖 | screencapture + osascript | powershell | xdotool + scrot/grim + wmctrl | - -### 3.3 executor 层 - -| 功能 | macOS | Windows | Linux | -|------|-------|---------|-------| -| drainRunLoop | CFRunLoop pump | 不需要 | 不需要 | -| ESC 热键 | CGEventTap | 跳过(Ctrl+C fallback) | 跳过(Ctrl+C fallback) | -| 剪贴板读 | pbpaste | `powershell Get-Clipboard` | xclip -o / wl-paste | -| 剪贴板写 | pbcopy | `powershell Set-Clipboard` | xclip / wl-copy | -| 粘贴快捷键 | command+v | ctrl+v | ctrl+v | -| 终端检测 | __CFBundleIdentifier | WT_SESSION / TERM_PROGRAM | TERM_PROGRAM | -| 系统权限 | TCC check | 直接 granted | 检查 xdotool 安装 | - -## 4. 执行步骤 - -### Phase 1:已完成 ✅ - -- [x] `@ant/computer-use-mcp` stub → 完整实现 -- [x] `@ant/computer-use-input` dispatcher + darwin/win32 backends -- [x] `@ant/computer-use-swift` dispatcher + darwin/win32 backends -- [x] `CHICAGO_MCP` 编译开关 - -### Phase 2:移除 6 处 macOS 硬编码(解锁 macOS + Windows) - -**改动原则:macOS 代码路径不变,只在每处 darwin 守卫后加 win32/linux 分支。** - -| 步骤 | 文件 | 改动 | -|------|------|------| -| 2.1 | `src/main.tsx:1605` | `getPlatform() === 'macos'` → 去掉平台限制,或改为 `!== 'unknown'` | -| 2.2 | `src/utils/computerUse/swiftLoader.ts:16-18` | 移除 `process.platform !== 'darwin'` throw。`@ant/computer-use-swift/index.ts` 已有跨平台 dispatch | -| 2.3 | `src/utils/computerUse/executor.ts:263-267` | 移除 `process.platform !== 'darwin'` throw。改为检查 input/swift isSupported | -| 2.4 | `src/utils/computerUse/executor.ts:70-88` | 剪贴板函数按平台分发:darwin→pbcopy/pbpaste,win32→PowerShell Get/Set-Clipboard,linux→xclip | -| 2.5 | `src/utils/computerUse/executor.ts:180` | `typeViaClipboard` 中 `command+v` → 非 darwin 时用 `ctrl+v` | -| 2.6 | `src/utils/computerUse/executor.ts:273` | `const cu = requireComputerUseSwift()` → 改为 `new ComputerUseAPI()`(从 package 直接实例化,不走 swiftLoader throw) | -| 2.7 | `src/utils/computerUse/drainRunLoop.ts` | 开头加 `if (process.platform !== 'darwin') return fn()` | -| 2.8 | `src/utils/computerUse/escHotkey.ts` | `registerEscHotkey` 非 darwin 返回 false(已有 Ctrl+C fallback) | -| 2.9 | `src/utils/computerUse/hostAdapter.ts:48-54` | `ensureOsPermissions` 非 darwin 返回 `{ granted: true }` | -| 2.10 | `src/utils/computerUse/common.ts:56` | `platform: 'darwin'` → `platform: process.platform === 'win32' ? 'windows' : process.platform === 'linux' ? 'linux' : 'darwin'` | -| 2.11 | `src/utils/computerUse/common.ts:55` | `screenshotFiltering: 'native'` → 非 darwin 时 `'none'`(Windows/Linux 截图不支持 per-app 过滤) | -| 2.12 | `src/utils/computerUse/gates.ts:13` | `enabled: false` → `enabled: true`(无 GrowthBook 时默认可用) | -| 2.13 | `src/utils/computerUse/gates.ts:39-43` | `hasRequiredSubscription()` → 直接返回 `true` | - -### Phase 3:新增 Linux 后端 - -| 步骤 | 文件 | 内容 | -|------|------|------| -| 3.1 | `packages/@ant/computer-use-input/src/backends/linux.ts` | xdotool 键鼠(mousemove/click/key/type/getactivewindow) | -| 3.2 | `packages/@ant/computer-use-swift/src/backends/linux.ts` | scrot/grim 截图 + xrandr 显示器 + wmctrl 窗口管理 | -| 3.3 | `packages/@ant/computer-use-input/src/index.ts` | dispatcher 加 `case 'linux'` | -| 3.4 | `packages/@ant/computer-use-swift/src/index.ts` | dispatcher 加 `case 'linux'` | - -### Phase 4:验证 - -| 测试项 | macOS | Windows | Linux | -|--------|-------|---------|-------| -| build 成功 | ✅ | 验证 | 验证 | -| MCP 工具列表非空 | 验证 | 验证 | 验证 | -| 鼠标移动 | 验证 | ✅ 已通过 | 验证 | -| 截图 | 验证 | ✅ 已通过 | 验证 | -| 键盘输入 | 验证 | 验证 | 验证 | -| 前台窗口 | 验证 | ✅ 已通过 | 验证 | -| 剪贴板 | 验证 | 验证 | 验证 | - -## 5. 文件改动总览 - -### 不动的文件(14 个) - -`cleanup.ts`、`computerUseLock.ts`、`wrapper.tsx`、`toolRendering.tsx`、`mcpServer.ts`、`setup.ts`、`appNames.ts`、`inputLoader.ts`、`src/services/mcp/client.ts`、`@ant/computer-use-mcp/src/*`(Phase 1 已完成)、`backends/darwin.ts`(两个包都不动) - -### 改 src/ 的文件(8 个) - -| 文件 | 改动量 | 风险 | -|------|--------|------| -| `main.tsx` | 1 行 | 低 | -| `swiftLoader.ts` | 2 行 | 低 | -| `executor.ts` | ~40 行(剪贴板分发 + 平台守卫 + paste 快捷键) | **中** | -| `drainRunLoop.ts` | 1 行 | 低 | -| `escHotkey.ts` | 3 行 | 低 | -| `hostAdapter.ts` | 5 行 | 低 | -| `common.ts` | 3 行 | 低 | -| `gates.ts` | 3 行 | 低 | - -### 新增文件(2 个) - -| 文件 | 行数估算 | -|------|---------| -| `packages/@ant/computer-use-input/src/backends/linux.ts` | ~150 行 | -| `packages/@ant/computer-use-swift/src/backends/linux.ts` | ~200 行 | - -## 6. Linux 依赖工具 - -| 工具 | 用途 | 安装命令(Ubuntu) | -|------|------|-------------------| -| `xdotool` | 键鼠模拟 + 窗口管理 | `sudo apt install xdotool` | -| `scrot` 或 `gnome-screenshot` | 截图 | `sudo apt install scrot` | -| `xrandr` | 显示器信息 | 通常已预装 | -| `xclip` | 剪贴板 | `sudo apt install xclip` | -| `wmctrl` | 窗口列表/切换 | `sudo apt install wmctrl` | - -Wayland 环境需要替代工具:`ydotool`(替代 xdotool)、`grim`(替代 scrot)、`wl-clipboard`(替代 xclip)。初期可先只支持 X11,Wayland 标记为 todo。 - -## 7. 执行顺序建议 +| 平台 | 状态 | 额外配置 | +|------|------|---------| +| macOS | 可用 | 需授予辅助功能 + 屏幕录制权限 | +| Windows | 可用 | 无需额外配置 | +| Linux | 不可用 | 后端待开发 | +## 快速开始 + +1. 启动 Claude Code: + + ```bash + bun run dev + ``` + + Computer Use 默认已开启,无需额外参数。 + +2. 在对话中告诉 Claude 你想做什么,例如: + - "帮我打开系统设置" + - "截个屏看看当前桌面" + - "在 Finder 里点击那个文件" + +3. 首次操控某个应用时,会弹出权限对话框让你确认。 + +4. 操作过程中随时按 **Esc**(macOS)或 **Ctrl+C**(Windows)中止。 + +## 权限说明 + +Computer Use 采用分级权限模型,保护你的安全: + +| 级别 | 能力 | 适用场景 | +|------|------|---------| +| **full** | 所有操作:鼠标点击(左/右/中键)、拖拽、键盘输入、组合键 | 系统设置、Finder 等系统应用 | +| **click** | 仅左键点击和滚轮滚动 | IDE(VS Code、Cursor)、终端 | +| 未授权 | 所有操作被拒绝 | 需要通过 `request_access` 申请 | + +IDE 类应用默认只有 click 权限,这是安全设计——防止 AI 在你的终端或编辑器中执行危险操作。如需完整控制,可以在权限对话框中手动提升。 + +## 可用操作 + +### 鼠标 + +| 操作 | 说明 | +|------|------| +| 移动鼠标 | 移动到指定坐标 | +| 左键点击 | 单击、双击、三击 | +| 右键点击 | 需要 full 权限 | +| 中键点击 | 需要 full 权限 | +| 拖拽 | 从 A 点拖到 B 点,需要 full 权限 | +| 滚轮 | 向上或向下滚动 | + +### 键盘 + +| 操作 | 说明 | +|------|------| +| 按键 | 单个按键或组合键(如 Ctrl+C) | +| 输入文字 | 逐字符输入文本,需要 full 权限 | +| 长按 | 按住某个键一段时间,需要 full 权限 | + +### 屏幕 + +| 操作 | 说明 | +|------|------| +| 截图 | 截取当前屏幕 | +| 切换显示器 | 多显示器环境下切换目标屏幕 | +| 缩放 | 放大屏幕某个区域 | + +### 其他 + +| 操作 | 说明 | +|------|------| +| 获取鼠标位置 | 查询当前鼠标坐标 | +| 批量操作 | 一次执行多个操作,减少等待 | +| 等待 | 暂停指定秒数(最长 100 秒) | + +## macOS 权限配置 + +首次使用前,需要授予两项系统权限。缺少任一项都会导致功能异常(见下方说明)。 + +### 辅助功能(Accessibility) + +允许 Claude 控制鼠标和键盘。 + +1. 打开 **系统设置 → 隐私与安全性 → 辅助功能** +2. 点击左下角锁图标解锁(需要管理员密码) +3. 将运行 Claude Code 的应用添加到允许列表: + - Terminal → `Terminal.app` + - iTerm → `iTerm.app` + - Cursor → `Cursor.app` + - VS Code 终端 → `Electron` 或 `Visual Studio Code.app` +4. 确保应用旁边的开关已打开 + +**未授予时的现象**:鼠标移动、点击、键盘输入均无反应,工具执行成功但屏幕没有任何变化。 + +### 屏幕录制(Screen Recording) + +允许 Claude 截取屏幕内容。 + +1. 打开 **系统设置 → 隐私与安全性 → 屏幕录制** +2. 将同一个应用添加到允许列表并开启开关 +3. **需要重启该应用**才能生效(系统会提示 "xxx 需要重新打开") + +**未授予时的现象**:截图工具执行成功但返回空白图片,Claude 无法看到你的屏幕,所有点击操作变成"盲点"。 + +### 验证权限 + +授予两项权限后,重启 Claude Code,在对话中让 Claude 截一张图即可验证是否配置成功。如果截图内容正常显示,说明权限配置完成。 + +## Linux 依赖(暂不可用) + +Linux 后端尚未开发。完成后需要安装以下工具: + +```bash +sudo apt install xdotool scrot xclip wmctrl ``` -Phase 2(解锁 macOS + Windows) - ├── 2.1-2.3 移除 3 处硬编码 throw/skip - ├── 2.4-2.5 剪贴板 + 粘贴快捷键平台分发 - ├── 2.6 swiftLoader → 直接实例化 - ├── 2.7-2.9 drainRunLoop / escHotkey / permissions 平台分支 - ├── 2.10-2.11 common.ts 平台标识动态化 - ├── 2.12-2.13 gates.ts 默认值 - └── 验证 Windows - -Phase 3(Linux 后端) - ├── 3.1 input/backends/linux.ts - ├── 3.2 swift/backends/linux.ts - ├── 3.3-3.4 dispatcher 加 linux case - └── 验证 Linux - -Phase 4(集成验证 + PR) -``` -每个 Phase 可独立验证、独立提交。Phase 2 完成后 macOS + Windows 可用,Phase 3 完成后三平台全部可用。 +仅支持 X11,Wayland 不支持。 + +## 常见问题 + +### 截图成功但看不到图片 + +检查 **系统设置 → 隐私与安全性 → 屏幕录制** 是否已授权。未授权时截图工具会执行成功但返回空白内容。 + +### IDE 中无法输入文字或右键 + +这是正常行为。IDE 类应用只有 click 权限,无法执行键盘输入、右键、拖拽等操作。如需完整控制,请在系统应用(如 Finder)中操作。 + +### 操作中途想停止 + +按 **Esc**(macOS)或 **Ctrl+C** 即可立即中止。 diff --git a/packages/@ant/computer-use-mcp/src/toolCalls.ts b/packages/@ant/computer-use-mcp/src/toolCalls.ts index 557eab9f..5fcb2b59 100644 --- a/packages/@ant/computer-use-mcp/src/toolCalls.ts +++ b/packages/@ant/computer-use-mcp/src/toolCalls.ts @@ -796,6 +796,17 @@ function resolveRequestedApps( if (!resolved) { resolved = byLowerDisplayName.get(requested.toLowerCase()); } + // Fuzzy fallback: match requested name as substring of display name + // e.g. "Chrome" matches "Google Chrome", "Code" matches "Visual Studio Code" + if (!resolved) { + const lower = requested.toLowerCase(); + for (const app of installed) { + if (app.displayName.toLowerCase().includes(lower)) { + resolved = app; + break; + } + } + } const bundleId = resolved?.bundleId; // When unresolved AND the requested string looks like a bundle ID, use it // directly for tier lookup (e.g. "company.thebrowser.Browser" with Arc not diff --git a/packages/@ant/computer-use-swift/src/backends/darwin.ts b/packages/@ant/computer-use-swift/src/backends/darwin.ts index 620f162a..c11e381a 100644 --- a/packages/@ant/computer-use-swift/src/backends/darwin.ts +++ b/packages/@ant/computer-use-swift/src/backends/darwin.ts @@ -159,23 +159,28 @@ export const apps: AppsAPI = { async listInstalled() { try { - const result = await osascript(` - tell application "System Events" - set appList to "" - repeat with appFile in (every file of folder "Applications" of startup disk whose name ends with ".app") - set appPath to POSIX path of (appFile as alias) - set appName to name of appFile - set appList to appList & appPath & "|" & appName & "\\n" - end repeat - return appList - end tell - `) - return result.split('\n').filter(Boolean).map(line => { - const [path, name] = line.split('|', 2) - const displayName = (name ?? '').replace(/\.app$/, '') + // Use Spotlight (mdfind) to enumerate .app bundles and mdls to get real bundle IDs. + // Searches /Applications, /System/Applications, and /System/Applications/Utilities + // so that system apps (Terminal, Chess, etc.) and core services (Finder) are found. + const proc = Bun.spawn([ + 'bash', '-c', + `for dir in /Applications /System/Applications /System/Applications/Utilities /System/Library/CoreServices; do +mdfind 'kMDItemContentType == "com.apple.application-bundle"' -onlyin "$dir" 2>/dev/null +done | sort -u | while read -r appPath; do +bundleId=$(mdls -raw -name kMDItemCFBundleIdentifier "$appPath" 2>/dev/null) +if [ -n "$bundleId" ] && [ "$bundleId" != "(null)" ]; then + displayName=$(basename "$appPath" .app) + echo "$bundleId|$displayName|$appPath" +fi +done`, + ], { stdout: 'pipe', stderr: 'pipe' }) + const text = await new Response(proc.stdout).text() + await proc.exited + return text.split('\n').filter(Boolean).map(line => { + const [bundleId, displayName, path] = line.split('|', 3) return { - bundleId: `com.app.${displayName.toLowerCase().replace(/\s+/g, '-')}`, - displayName, + bundleId: bundleId ?? '', + displayName: displayName ?? '', path: path ?? '', } }) diff --git a/packages/@ant/computer-use-swift/src/index.ts b/packages/@ant/computer-use-swift/src/index.ts index cae20642..e3daf6e4 100644 --- a/packages/@ant/computer-use-swift/src/index.ts +++ b/packages/@ant/computer-use-swift/src/index.ts @@ -80,6 +80,12 @@ export class ComputerUseAPI { async captureRegion() { throw new Error('computer-use-swift: no backend for this platform') }, } + hotkey = (backend as any)?.hotkey ?? { + registerEscape(_cb: () => void): boolean { return false }, + unregister() {}, + notifyExpectedEscape() {}, + } + async resolvePrepareCapture( allowedBundleIds: string[], _surrogateHost: string, diff --git a/src/utils/computerUse/hostAdapter.ts b/src/utils/computerUse/hostAdapter.ts index acefbaa3..6b494ec6 100644 --- a/src/utils/computerUse/hostAdapter.ts +++ b/src/utils/computerUse/hostAdapter.ts @@ -46,9 +46,16 @@ export function getComputerUseHostAdapter(): ComputerUseHostAdapter { }), ensureOsPermissions: async () => { if (process.platform !== 'darwin') return { granted: true } - const cu = requireComputerUseSwift() - const accessibility = (cu as any).tcc.checkAccessibility() - const screenRecording = (cu as any).tcc.checkScreenRecording() + const cu = requireComputerUseSwift() as any + // Native .node module exposes tcc; cross-platform JS backend does not. + // When tcc is absent (JS backend on macOS), we cannot programmatically + // check TCC status — returning granted:false would create a deadlock + // (recheck also fails, user can never pass). The JS backend uses + // osascript/screencapture which trigger OS-level permission prompts + // themselves, so the OS provides the safety net instead. + if (!cu.tcc) return { granted: true } + const accessibility = cu.tcc.checkAccessibility() + const screenRecording = cu.tcc.checkScreenRecording() return accessibility && screenRecording ? { granted: true } : { granted: false, accessibility, screenRecording }