桌面应用
Claude Code 如何将终端桥接到 Claude Desktop、与 IDE 集成、通过本机消息传递与浏览器对话以及获取计算机使用功能 — 所有这些都来自一个 CLI 二进制文件。
Claude Code 是一个终端应用程序,但它具有令人惊讶的桌面集成深度:它可以将正在运行的会话移交给 Claude Desktop,自动检测从其启动的 IDE(VS Code、Cursor、JetBrains 系列),通过本机消息传递主机连接 Chrome 扩展,并公开完整的计算机使用 MCP 服务器。 所有这些都是作为不共享全局状态的离散子系统实现的——每个子系统仅在满足其条件时才激活。
commands/desktop/index.ts ·
commands/desktop/desktop.tsx ·
components/DesktopHandoff.tsx ·
components/DesktopUpsell/DesktopUpsellStartup.tsx ·
utils/desktopDeepLink.ts ·
utils/claudeDesktop.ts ·
utils/ide.ts ·
utils/claudeInChrome/ ·
utils/computerUse/ ·
entrypoints/cli.tsx
有四个不同的集成层,每个层都有自己的检测逻辑、激活路径和后备行为:
克劳德桌面切换
The /desktop 命令刷新会话并通过深层链接 URL 在桌面应用程序中打开它。
IDE集成
通过读取以下文件中的锁定文件自动检测 VS Code、Cursor、Windsurf 和 14+ JetBrains IDE ~/.claude/ide/.
克劳德在 Chrome 中
安装本机消息传递主机清单,以便浏览器扩展可以直接调用 Claude Code 工具。
计算机使用 MCP
由 Max/Pro 订阅和 GrowthBook 标志控制; 生成一个单独的 MCP 服务器来驱动操作系统。
/desktop 命令和深层链接命令注册
The /desktop 命令(别名 /app)住在
commands/desktop/index.ts。 其可用性被锁定
claude-ai 产品 — 它不会出现在 SDK 或企业控制台版本中。 该命令还在运行时对平台进行门控检查:
// commands/desktop/index.ts
function isSupportedPlatform(): boolean {
if (process.platform === 'darwin') return true
if (process.platform === 'win32' && process.arch === 'x64') return true
return false
}
const desktop = {
type: 'local-jsx',
name: 'desktop',
aliases: ['app'],
description: 'Continue the current session in Claude Desktop',
availability: ['claude-ai'],
isEnabled: isSupportedPlatform,
get isHidden() { return !isSupportedPlatform() },
load: () => import('./desktop.js'),
}
启用后,该命令将呈现 DesktopHandoff 反应/墨水组件。 在 Windows 上仅支持 x64; ARM Windows 和 Linux 被排除。
切换状态机
DesktopHandoff in components/DesktopHandoff.tsx 是一个具有六个状态的小型状态机:
所需的最低桌面版本被硬编码为 MIN_DESKTOP_VERSION = '1.1.2396'
in utils/desktopDeepLink.ts。 较旧的安装会被捕获,并在移交继续之前提示用户进行更新。
深层链接建设
启动切换的实际 URL 是由 buildDesktopDeepLink:
// utils/desktopDeepLink.ts
function buildDesktopDeepLink(sessionId: string): string {
// dev builds use 'claude-dev://', prod uses 'claude://'
const protocol = isDevMode() ? 'claude-dev' : 'claude'
const url = new URL(`${protocol}://resume`)
url.searchParams.set('session', sessionId)
url.searchParams.set('cwd', getCwd())
return url.toString()
}
网址格式为 claude://resume?session=<uuid>&cwd=<path>。 克劳德桌面注册 claude:// 通过 Electron 的协议处理程序
setAsDefaultProtocolClient。 在开发中,使用AppleScript代替
open 因为 dev Electron 二进制文件注册的是它自己而不是应用程序包:
// macOS dev mode workaround
const { code } = await execFileNoThrow('osascript', [
'-e',
`tell application "Electron" to open location "${deepLinkUrl}"`,
])
特定于平台的安装检测
在打开深层链接之前,代码会验证应用程序是否确实使用适合操作系统的方法安装:
路径检查
Checks /Applications/Claude.app 存在。 版本读取方式 defaults read …/Info.plist CFBundleShortVersionString.
xdg-mime 查询
Runs xdg-mime query default x-scheme-handler/claude 并检查标准输出是否为非空(单独的退出代码是不可靠的)。
注册表查询
Queries HKEY_CLASSES_ROOT\claude via reg query。 版本发现于 %LOCALAPPDATA%\AnthropicClaude\app-*\.
会话刷新:秘密成分
在打开深层链接之前, flushing 国家呼吁
flushSessionStorage()。 这会强制将所有缓冲的对话写入磁盘 ~/.claude/projects/ 以便 Claude Desktop 在打开时可以读取完整的会话记录 claude://resume 网址。 如果没有刷新,桌面应用程序将打开一个不完整的会话。
与显式分开 /desktop 命令,Claude Code 可以在启动时主动建议迁移到桌面应用程序。 逻辑存在于
components/DesktopUpsell/DesktopUpsellStartup.tsx.
当对话框出现时
功能 shouldShowDesktopUpsellStartup() 控制对话框:
export function shouldShowDesktopUpsellStartup(): boolean {
if (!isSupportedPlatform()) return false
// Requires GrowthBook flag 'tengu_desktop_upsell'.enable_startup_dialog
if (!getDesktopUpsellConfig().enable_startup_dialog) return false
const config = getGlobalConfig()
if (config.desktopUpsellDismissed) return false // "Never" was chosen
if ((config.desktopUpsellSeenCount ?? 0) >= 3) return false // capped at 3 showings
return true
}
该对话框提供三个选项: 在 Claude Code 桌面中打开 (触发完整的切换流程), 现在不要 (增加看到的计数器),并且
永远不要再问 (sets desktopUpsellDismissed: true in
~/.claude/config.json via saveGlobalConfig)。 该功能由控制 tengu_desktop_upsell GrowthBook 实验,默认情况下处于禁用状态。
desktopUpsellDismissed and desktopUpsellSeenCount 存储在全局配置中 ~/.claude/config.json。 删除该文件会重置抑制状态。
Claude Code 可以从 Claude Desktop 读取 MCP 服务器配置并将其导入。 该实用程序位于 utils/claudeDesktop.ts,它知道每个平台上的配置文件位置:
// utils/claudeDesktop.ts
export async function getClaudeDesktopConfigPath(): Promise<string> {
if (platform === 'macos') {
return join(homedir(), 'Library', 'Application Support', 'Claude',
'claude_desktop_config.json')
}
// WSL: tries USERPROFILE, then scans /mnt/c/Users/* for AppData/Roaming/Claude/
}
解析该文件以提取 mcpServers 地图。 每个条目均经过验证
McpStdioServerConfigSchema() (Zod)在被接受之前。 这
MCPServerDesktopImportDialog 组件呈现一个多选列表,以便用户可以选择将哪些服务器复制到其 Claude Code 配置中。
C:\Users\moiz\AppData\Roaming\Claude 被转换为 /mnt/c/Users/moiz/AppData/Roaming/Claude 通过剥离驱动器盘符并预先添加 /mnt/c.
当 Claude Code 在嵌入 IDE 的终端内运行时,它会检测 IDE 并调整行为 - 例如,使用 IDE 的文件打开 API 而不是系统编辑器,或通过更快的通道路由“辅助查询”(快速问题)。 检测发生在
utils/ide.ts.
支持的 IDE
The supportedIdeConfigs 映射到 ide.ts 涵盖两个家庭,由 ideKind field:
光标、风帆冲浪、vscode
通过进程名称检测,例如 Cursor Helper, Code Helper。 传输:HTTP/WebSocket 到本地端口。
intellij、pycharm、webstorm、phpstorm、rubymine、clion、goland、rider、datagrip、appcode、dataspell、aqua、网关、舰队、androidstudio
总共 15 个 IDE。 传输:通过锁定文件通告的端口进行 SSE 或 WebSocket。
基于锁定文件的发现
IDE 插件将锁定文件写入 ~/.claude/ide/<port>.lock 当他们开始时。 Claude Code 读取这些内容以查找哪些 IDE 正在运行以及它们打开了哪些工作区文件夹:
// utils/ide.ts — lockfile JSON schema
type LockfileJsonContent = {
workspaceFolders?: string[]
pid?: number
ideName?: string
transport?: 'ws' | 'sse'
runningInWindows?: boolean
authToken?: string
}
锁定文件按修改时间排序(最新的在前),因此优先选择最近关注的 IDE。 过时的锁会被跳过——代码调用 isProcessRunning(pid)
via process.kill(pid, 0) 在信任锁文件之前验证 PID 是否仍然存在。
终端检测快捷方式
在扫描锁定文件之前,代码会检查 TERM_PROGRAM 环境变量(存储在 env.terminal)。 如果它与已知的 IDE 进程名称匹配(例如,
vscode, cursor), isSupportedTerminal() returns
true 立即执行,无需任何文件系统 I/O。
Windows-in-WSL 路径转换
当 IDE 在本机 Windows 中运行但 Claude Code 在 WSL 中运行时,文件路径需要转换。 utils/idePathConversion.ts provides
WindowsToWSLConverter 这改变了
C:\Users\moiz\project into /mnt/c/Users/moiz/project, 和
checkWSLDistroMatch 在接受跨界连接之前验证两个进程是否都针对相同的 WSL 分布。
Claude Code 可以充当 Chrome(或 Chromium)扩展程序的本机消息传递主机。 这允许浏览器扩展从网页调用 Claude Code 工具。 该子系统位于 utils/claudeInChrome/.
入口点标志
两个特殊的 CLI 标志在最顶部处理 entrypoints/cli.tsx,在任何正常启动之前:
// entrypoints/cli.tsx
if (process.argv[2] === '--claude-in-chrome-mcp') {
// Runs the MCP server that the Chrome extension connects to
await runClaudeInChromeMcpServer()
return
} else if (process.argv[2] === '--chrome-native-host') {
// Acts as the Chrome native messaging host (stdin/stdout protocol)
await runChromeNativeHost()
return
}
本机消息传递主机清单
Chrome 需要一个 JSON 清单文件,将主机标识符映射到二进制路径。 Claude Code 在启动时自动安装此清单 shouldEnableClaudeInChrome()
返回真:
const NATIVE_HOST_IDENTIFIER = 'com.anthropic.claude_code_browser_extension'
// In bundled (native binary) mode, a wrapper script is created that calls:
// `"${process.execPath}" --chrome-native-host`
// because native host manifests cannot contain CLI arguments directly.
const execCommand = `"${process.execPath}" --chrome-native-host`
void createWrapperScript(execCommand)
.then(manifestBinaryPath => installChromeNativeHostManifest(manifestBinaryPath))
支持的浏览器
The CHROMIUM_BROWSERS 映射到 utils/claudeInChrome/common.ts 涵盖多个基于 Chromium 的浏览器,每个浏览器都具有特定于平台的数据路径和本机消息传递主机目录:
export const CHROMIUM_BROWSERS: Record<ChromiumBrowser, BrowserConfig> = {
chrome: { macos: { nativeMessagingPath: ['Library', 'Application Support',
'Google', 'Chrome', 'NativeMessagingHosts'] }, ... },
// Also: chromium, brave, edge, opera, vivaldi, arc ...
}
激活条件
shouldEnableClaudeInChrome() 按优先顺序检查:
- 默认情况下在非交互式 (SDK/CI) 会话中禁用
--chrome/--no-chromeCLI 标志覆盖所有内容CLAUDE_CODE_ENABLE_CFC环境变量claudeInChromeDefaultEnabled领域在~/.claude/config.json- 自动启用:交互式会话 + 已安装扩展 +
tengu_chrome_auto_enable成长书旗帜
最强大(也是最封闭)的桌面集成是计算机的使用——截取屏幕截图、移动鼠标、敲击键盘以及与任意桌面应用程序交互的能力。 它作为一个单独的 MCP 服务器公开,代号为“Chicago”/“Malort”。
入口点标志
// entrypoints/cli.tsx
if (feature('CHICAGO_MCP') && process.argv[2] === '--computer-use-mcp') {
await runComputerUseMcpServer()
return
}
The feature('CHICAGO_MCP') call 是构建时死代码消除门:整个分支将从不启用该标志的外部构建中删除。
出入闸门
utils/computerUse/gates.ts 实现分层门检查:
export function getChicagoEnabled(): boolean {
// Ant employees with monorepo access are excluded unless ALLOW_ANT_COMPUTER_USE_MCP=1
if (process.env.USER_TYPE === 'ant' && process.env.MONOREPO_ROOT_DIR
&& !isEnvTruthy(process.env.ALLOW_ANT_COMPUTER_USE_MCP)) {
return false
}
// External users need Max or Pro subscription + GrowthBook gate
return hasRequiredSubscription() && readConfig().enabled
}
GrowthBook实验的关键是 tengu_malort_pedway。 它运送一个
ChicagoConfig 包含细粒度子门的对象:
type ChicagoConfig = CuSubGates & {
enabled: boolean
coordinateMode: 'pixels' | 'normalized'
pixelValidation: boolean
clipboardPasteMultiline: boolean
mouseAnimation: boolean
hideBeforeAction: boolean // hide terminal before screenshot
autoTargetDisplay: boolean
clipboardGuard: boolean
}
终端捆绑ID感知
由于 Claude Code 是一个没有窗口的终端应用程序,因此计算机使用包需要知道哪个终端模拟器正在托管它,以便它可以从屏幕截图中排除该窗口,并避免意外阻止其自己的键盘输入。 utils/computerUse/common.ts 通过解决这个问题 __CFBundleIdentifier (由 macOS LaunchServices 设置),具有知名终端的静态后备表:
const TERMINAL_BUNDLE_ID_FALLBACK = {
'iTerm.app': 'com.googlecode.iterm2',
'Apple_Terminal': 'com.apple.Terminal',
'ghostty': 'com.mitchellh.ghostty',
'WarpTerminal': 'dev.warp.Warp-Stable',
'vscode': 'com.microsoft.VSCode',
// ...
}
坐标模式(pixels vs normalized)在第一次读取时被冻结 - 否则,实时的 GrowthBook 翻转会导致模型在一个坐标空间中思考,而执行器在另一个坐标空间中进行转换。
所有与桌面相关的子系统都通过最顶部的特殊参数检查挂接到 CLI 中。 entrypoints/cli.tsx,在任何模块加载或配置初始化之前。 这使本机主机模式的代码路径保持精简:
feature CHICAGO_MCP required] B -->|--daemon-worker| F[runDaemonWorker] B -->|remote-control / rc| G[bridgeMain] B -->|normal| H[full CLI boot] C --> Z[exit] D --> Z E --> Z F --> Z G --> Z
每个快速路径在其处理程序完成后立即返回,因此主机/服务器模式下的正常引导管道的开销为零。 这对于 Chrome 原生消息传递很重要 - Chrome 按需生成主机二进制文件,并期望它在几毫秒内做出响应。
Claude Code 提供两种分发模式:npm 安装的 JavaScript 捆绑包和预编译的本机二进制文件。 本机安装程序位于 utils/nativeInstaller/
与 npm 安装一起管理本机二进制文件的生命周期。
目录布局
# XDG-compliant layout
~/.local/share/claude/versions/ # permanent — one dir per installed version
~/.cache/claude/staging/ # temporary — download target before atomic rename
~/.local/state/claude/locks/ # PID-based lock files for update coordination
~/.local/bin/claude # symlink → active version
安装程序保留 VERSION_RETENTION_COUNT = 2 磁盘上的版本,成功更新后删除旧版本。 通过基于 PID 的锁定文件,更新是多进程安全的,具有 7 天的过时超时(足够长的时间以保证笔记本电脑睡眠)。
平台定位
getPlatform() 在安装程序模块中生成类似的字符串
darwin-arm64, linux-x64, linux-x64-musl,
win32-x64。 musl 变体是通过以下方式自动检测的
envDynamic.isMuslEnvironment() 适用于 Alpine Linux / Docker 环境。
utils/sessionStoragePortable.ts 包含故意不含内部依赖性的纯Node.js实用程序。 该文件与 VS Code 扩展包逐字共享,位于
packages/claude-vscode/src/common-host/sessionStorage.ts — 相同的代码读取 CLI 和 IDE 插件中的会话记录。
(terminal)"] subgraph Desktop["Claude Desktop (Electron)"] DP["claude://resume
deep link handler"] DS["Session reader
(~/.claude/projects/)"] end subgraph IDE["IDE Plugin (VS Code / JetBrains)"] LF["~/.claude/ide/*.lock"] RP["Local HTTP/WS
RPC server"] end subgraph Browser["Chrome Extension"] NM["Native Messaging
com.anthropic.claude_code_browser_extension"] MCP["MCP Server
(--claude-in-chrome-mcp)"] end subgraph OS["OS (macOS)"] CU["Computer Use MCP
(--computer-use-mcp)
screenshots, mouse, keyboard"] end CLI -->|"/desktop command\nflushSession + open URL"| DP DP --> DS CLI -->|"reads lockfiles\nauto-detects"| LF LF --> RP CLI -->|"installs manifest\nspawns on demand"| NM NM --> MCP CLI -->|"Max/Pro + GB flag"| CU
要点
- The
/desktop命令是一个 6 状态 React 机器,它刷新会话记录,构建一个claude://resume?session=…&cwd=…URL,然后通过操作系统本机 URL 打开将其交给桌面应用程序。 - 桌面安装检测特定于操作系统:macOS 上的路径检查,
xdg-mime在 Linux 上,在 Windows 上进行注册表查询。 - IDE检测用途
~/.claude/ide/<port>.lock由 VS Code 和 JetBrains 插件编写的文件,并由TERM_PROGRAM环境变量。 - Chrome 中的 Claude 通过 Chrome 的本机消息传递协议进行工作 — JSON 清单映射标识符
com.anthropic.claude_code_browser_extension到调用 CLI 的包装器脚本--chrome-native-host. - 计算机的使用是三重门控的:构建时功能标志(
CHICAGO_MCP)、Max/Pro 订阅检查和 GrowthBook 实验密钥tengu_malort_pedway. - 所有桌面模式快速路径(
--chrome-native-host,--claude-in-chrome-mcp,--computer-use-mcp)在任何配置或分析初始化之前进行处理,以将启动开销降至最低。 utils/sessionStoragePortable.ts有意无依赖关系,因此可以与 VS Code 扩展包共享,而无需引入 CLI-only 模块。
知识检查
/desktop 切换继续吗?DesktopHandoff 组件调用 flushSessionStorage() 在打开深层链接之前?openDeepLink 使用AppleScript代替 open 命令?