Skip to content
源码分析手册

远程与桌面端协同:会话迁移与跨端执行协议

Claude Code 并不局限于本地终端。通过 Web 桥接、远程执行(Remote Execution)和桌面端接力(Desktop Handoff)协议,它支持将会话在不同形态的客户端之间平滑迁移。

本质

跨端协同本质上是 运行时环境与执行控制权(Control Plane)的解耦协议

当你在本地终端启动 Claude Code 并指定 --remote(或进入 Teleported 状态)时,CLI 的角色从“独立执行引擎”转变为“远程环境的种子(Seed)或代理”。它负责将会话元数据、当前代码快照和环境配置打包,传递给更高层级的托管平台。而 /desktop(或 /app)则是这种协议在本地侧的极致应用:利用 Deep Link 将控制权移交给 Claude Desktop,通过本地文件系统进行接力。

实现机制

跨端与迁移逻辑主要分布在 claude-code-opensource/src/bootstrap/state.ts 和各级命令入口中:

  1. 远程模式标志(isRemoteMode): 当环境检测到 CLAUDE_CODE_REMOTE 为真,或通过 --remote 显式启动时,STATE.isRemoteMode 会被激活。此时,CLI 进入“受限态”:

    • 命令治理:通过 filterCommandsForRemoteMode 禁用本地风险命令(如直接修改敏感配置)。
    • 上下文剪裁:在 getSystemContext 中跳过耗时的 Git Status 扫描,因为远程环境通常有自己的仓库管理系统。
  2. 桌面端接力(Desktop Handoff): 执行 /desktop/app 会触发 claude-code-opensource/src/commands/desktop/desktop.tsx 中的逻辑:

    • 版本前哨检查:先通过组件检查 Claude Desktop 是否安装,且版本是否满足最低要求(如 1.1.2396+)。
    • 强制落盘(Sync Flush):在跳转前强制调用 flushSessionStorage(),确保所有 Transcript 状态已写入本地磁盘。这是因为桌面端并非从 CLI 内存接状态,而是基于磁盘持久化 ID 恢复。
    • Deep Link 生成:利用 claude-code-opensource/src/utils/desktopDeepLink.ts 拼装 claude://resume?session=...&cwd=... 的 URL,唤起桌面端并退出 CLI。
  3. 会话传送与接入(Teleporting & Ingress): 当你使用云端迁移功能时,系统会触发 setTeleportedSessionInfo 记录状态。

    • 种子信息打包:系统生成包含会话摘要和临时认证令牌的链接。
    • 接入认证:利用 getSessionIngressAuthToken 确保只有合法发起方能连回执行环境。
    • Web 端模拟层:Web 界面加载一个与本地 CLI 协议兼容的逻辑层,解析并渲染由种子定义的工具集与指令。

别踩这些坑

  • 本地性限制/desktop 仅支持 macOS 与 Windows x64。它依赖本地会话存储,如果你期待的是把任务迁到另一台物理机器或云端后台,/desktop 并非为此设计,你应该使用 --remote
  • 同步与分叉风险:一旦会话被“传送到”Web 或远程端,后续历史通常保存在云端。如果你回到本地再次 --resume 相同 Session,系统会尝试拉取云端 Transcript 进行同步。
  • 代码种子的局限:迁移时通常只传送“初始代码快照”或“变更差异”。如果本地项目包含海量、未被追踪的二进制大文件,远程端可能无法完整复现该环境。
  • 权限与策略治理:远程模式下的权限判定由云端策略(Policy Limits)接管。即便本地允许某些操作,如果云端策略限制了该 Session,执行仍会失败。

延伸阅读

源码锚点

  • claude-code-opensource/src/bootstrap/state.tssetTeleportedSessionInfo 传送状态的定义。
📄 src/bootstrap/state.ts — `setTeleportedSessionInfo` 传送状态的定义。L1477-1485 of 1759
typescript
export function setTeleportedSessionInfo(info: {
  sessionId: string | null
}): void {
  STATE.teleportedSessionInfo = {
    isTeleported: true,
    hasLoggedFirstMessage: false,
    sessionId: info.sessionId,
  }
}
  • claude-code-opensource/src/commands/desktop/desktop.tsx/desktop 命令入口与版本前哨检查。
📄 src/commands/desktop/desktop.tsx — `/desktop` 命令入口与版本前哨检查。L4-8 of 9
tsx
export async function call(onDone: (result?: string, options?: {
  display?: CommandResultDisplay;
}) => void): Promise<React.ReactNode> {
  return <DesktopHandoff onDone={onDone} />;
}
  • claude-code-opensource/src/utils/desktopDeepLink.ts — 生成跨端跳转 Deep Link 的核心工具。
📄 src/utils/desktopDeepLink.ts — 生成跨端跳转 Deep Link 的核心工具。L35-41 of 237
typescript
function buildDesktopDeepLink(sessionId: string): string {
  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-code-opensource/src/utils/sessionIngressAuth.ts — 生成跨端接入凭证与令牌的逻辑。
📄 src/utils/sessionIngressAuth.ts — 生成跨端接入凭证与令牌的逻辑。L18-47 of 141
typescript
function getTokenFromFileDescriptor(): string | null {
  // Check if we've already attempted to read the token
  const cachedToken = getSessionIngressToken()
  if (cachedToken !== undefined) {
    return cachedToken
  }

  const fdEnv = process.env.CLAUDE_CODE_WEBSOCKET_AUTH_FILE_DESCRIPTOR
  if (!fdEnv) {
    // No FD env var — either we're not in CCR, or we're a subprocess whose
    // parent stripped the (useless) FD env var. Try the well-known file.
    const path =
      process.env.CLAUDE_SESSION_INGRESS_TOKEN_FILE ??
      CCR_SESSION_INGRESS_TOKEN_PATH
    const fromFile = readTokenFromWellKnownFile(path, 'session ingress token')
    setSessionIngressToken(fromFile)
    return fromFile
  }

  const fd = parseInt(fdEnv, 10)
  if (Number.isNaN(fd)) {
    logForDebugging(
      `CLAUDE_CODE_WEBSOCKET_AUTH_FILE_DESCRIPTOR must be a valid file descriptor number, got: ${fdEnv}`,
      { level: 'error' },
    )
    setSessionIngressToken(null)
    return null
  }

  try {

基于 Claude Code v2.1.88 开源快照的深度分析