Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第11章:Bridge 桥接层

本章介绍 Claude Code 的 Bridge 桥接层实现,包括远程控制(Remote Control)功能的架构设计和通信机制。

11.1 Bridge 目录结构

Bridge 模块位于 src/bridge/ 目录,包含约 30 个 TypeScript 文件:

src/bridge/
├── types.ts              # 类型定义和常量
├── bridgeApi.ts          # Bridge API 客户端
├── bridgeConfig.ts       # Bridge 配置解析
├── bridgeMain.ts         # Bridge 主入口
├── bridgeMessaging.ts    # 消息处理
├── createSession.ts      # Session 创建
├── sessionRunner.ts      # Session 运行器
├── replBridge.ts         # REPL Bridge 实现
├── replBridgeTransport.ts # 传输层抽象
├── jwtUtils.ts           # JWT 工具和 Token 刷新
├── bridgeEnabled.ts      # Bridge 启用检测
├── bridgeDebug.ts        # 调试工具
├── bridgeStatusUtil.ts   # 状态管理
├── bridgeUI.ts           # UI 层集成
├── initReplBridge.ts     # Bridge 初始化
├── inboundMessages.ts    # 入站消息处理
├── inboundAttachments.ts # 入站附件处理
├── flushGate.ts          # 输出缓冲控制
├── capacityWake.ts       # 能力唤醒
├── pollConfig.ts         # 配置轮询
├── sessionIdCompat.ts    # Session ID 兼容性
├── trustedDevice.ts      # 可信设备管理
├── workSecret.ts         # 工作密钥解析
└── ...

Note

Bridge 模块是 Claude Code 实现远程控制功能的核心,允许用户通过 claude.ai 网站远程控制本地运行的 Claude Code CLI。

11.2 核心类型定义

11.2.1 Session 相关类型

// Session 超时常量(24小时)
export const DEFAULT_SESSION_TIMEOUT_MS = 24 * 60 * 60 * 1000

// Session 完成状态
export type SessionDoneStatus = 'completed' | 'failed' | 'interrupted'

// Session 活动类型
export type SessionActivityType = 'tool_start' | 'text' | 'result' | 'error'

// Session 活动记录
export type SessionActivity = {
  type: SessionActivityType
  summary: string    // 如 "Editing src/foo.ts"
  timestamp: number
}

11.2.2 工作密钥类型

// 工作密钥(Session 启动参数)
export type WorkSecret = {
  version: number
  session_ingress_token: string   // Session 入口 Token
  api_base_url: string            // API 基础 URL
  sources: Array<{
    type: string
    git_info?: { type: string; repo: string; ref?: string; token?: string }
  }>
  auth: Array<{ type: string; token: string }>
  claude_code_args?: Record<string, string> | null
  mcp_config?: unknown | null
  environment_variables?: Record<string, string> | null
  use_code_sessions?: boolean     // CCR v2 兼容标识
}

11.2.3 启动模式

// Bridge Session 工作目录选择模式
export type SpawnMode =
  | 'single-session'  // 单 Session,Session 结束后 Bridge 退出
  | 'worktree'        // 持久服务,每个 Session 独立 git worktree
  | 'same-dir'        // 持久服务,所有 Session 共享 cwd

11.3 Session 创建流程

Session 创建通过 createBridgeSession 函数实现,用于 claude remote-control 命令和 /remote-control 斜杠命令:

sequenceDiagram
    participant User as 用户
    participant Bridge as Bridge
    participant OAuth as OAuth 服务
    participant API as claude.ai API

    User->>Bridge: 发起 remote-control
    Bridge->>OAuth: 获取 Access Token
    OAuth-->>Bridge: accessToken
    Bridge->>OAuth: 获取 Organization UUID
    OAuth-->>Bridge: orgUUID
    Bridge->>API: POST /v1/sessions
    API-->>Bridge: sessionId
    Bridge->>Bridge: 启动 sessionRunner
    Bridge-->>User: 返回 sessionId

11.3.1 createBridgeSession 函数

export async function createBridgeSession({
  environmentId,
  title,
  events,
  gitRepoUrl,
  branch,
  signal,
  baseUrl,
  getAccessToken,
  permissionMode,
}): Promise<string | null> {
  // 1. 获取 OAuth Token
  const accessToken = getAccessToken?.() ?? getClaudeAIOAuthTokens()?.accessToken
  if (!accessToken) return null

  // 2. 获取 Organization UUID
  const orgUUID = await getOrganizationUUID()
  if (!orgUUID) return null

  // 3. 构建 Git 源信息
  let gitSource = null
  let gitOutcome = null
  if (gitRepoUrl) {
    const parsed = parseGitRemote(gitRepoUrl)
    if (parsed) {
      gitSource = {
        type: 'git_repository',
        url: `https://${parsed.host}/${parsed.owner}/${parsed.name}`,
        revision: branch,
      }
      gitOutcome = {
        type: 'git_repository',
        git_info: {
          type: 'github',
          repo: `${parsed.owner}/${parsed.name}`,
          branches: [`claude/${branch || 'task'}`],
        },
      }
    }
  }

  // 4. 发送创建请求
  const response = await axios.post(`${baseUrl}/v1/sessions`, {
    environment_id: environmentId,
    title,
    events,
    source: gitSource,
    expected_outcome: gitOutcome,
    permission_mode: permissionMode,
  })

  return response.data.id
}

11.4 JWT 认证与 Token 刷新

11.4.1 JWT 解码

jwtUtils.ts 提供了 JWT Token 解码功能,无需验证签名:

// 解码 JWT payload(不验证签名)
export function decodeJwtPayload(token: string): unknown | null {
  // 去除 sk-ant-si- 前缀
  const jwt = token.startsWith('sk-ant-si-')
    ? token.slice('sk-ant-si-'.length)
    : token

  const parts = jwt.split('.')
  if (parts.length !== 3 || !parts[1]) return null

  return jsonParse(Buffer.from(parts[1], 'base64url').toString('utf8'))
}

// 解码 JWT expiry
export function decodeJwtExpiry(token: string): number | null {
  const payload = decodeJwtPayload(token)
  if (payload && typeof payload === 'object' && 'exp' in payload) {
    return payload.exp
  }
  return null
}

11.4.2 Token 刷新调度器

flowchart TD
    A[schedule] --> B[计算刷新时间]
    B --> C[设置定时器]
    C --> D{Token 即将过期?}
    D -->|Yes| E[调用 onRefresh]
    E --> F[获取新 Token]
    F --> G{成功?}
    G -->|Yes| H[重新 schedule]
    G -->|No| I[失败计数 +1]
    I --> J{超过 MAX_FAILURES?}
    J -->|Yes| K[停止刷新]
    J -->|No| L[延迟重试]
// 刷新缓冲时间:提前 5 分钟刷新
const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000

// 备用刷新间隔:30 分钟
const FALLBACK_REFRESH_INTERVAL_MS = 30 * 60 * 1000

// 最大连续失败次数
const MAX_REFRESH_FAILURES = 3

export function createTokenRefreshScheduler({
  getAccessToken,
  onRefresh,
  label,
  refreshBufferMs,
}): {
  schedule: (sessionId: string, token: string) => void
  scheduleFromExpiresIn: (sessionId: string, expiresInSeconds: number) => void
  cancel: (sessionId: string) => void
  cancelAll: () => void
} {
  const timers = new Map<string, ReturnType<typeof setTimeout>>()
  const failureCounts = new Map<string, number>()
  const generations = new Map<string, number>()

  // 调度刷新
  function schedule(sessionId: string, token: string) {
    const expiry = decodeJwtExpiry(token)
    if (!expiry) {
      // 无法解析过期时间,使用备用间隔
      scheduleFromExpiresIn(sessionId, FALLBACK_REFRESH_INTERVAL_MS / 1000)
      return
    }

    const nowMs = Date.now()
    const expiryMs = expiry * 1000
    const delayMs = expiryMs - nowMs - refreshBufferMs

    if (delayMs <= 0) {
      // 已过期或即将过期,立即刷新
      doRefresh(sessionId)
    } else {
      setTimer(sessionId, delayMs)
    }
  }

  return { schedule, scheduleFromExpiresIn, cancel, cancelAll }
}

11.5 传输层架构

Bridge 支持两种传输协议版本:

11.5.1 V1 协议(WebSocket)

graph LR
    A[claude.ai] --> B[WebSocket]
    B --> C[replBridgeTransport]
    C --> D[Session Runner]
    D --> E[Claude Code REPL]

11.5.2 V2 协议(CCR)

graph LR
    A[claude.ai] --> B[CCR API]
    B --> C[codeSessionApi]
    C --> D[Session Runner]
    D --> E[Claude Code REPL]

Tip

V2 协议通过 CCR (Claude Code Runtime) 兼容层支持 Code Sessions,提供更好的隔离性和扩展性。

11.6 消息协议

11.6.1 入站消息类型

inboundMessages.ts 处理来自远程客户端的消息:

// 消息类型定义
type InboundMessage =
  | { type: 'text'; content: string }
  | { type: 'attachment'; data: Attachment }
  | { type: 'permission_response'; decision: 'allow' | 'deny' }
  | { type: 'interrupt' }
  | { type: 'ping' }

11.6.2 消息处理流程

sequenceDiagram
    participant Client as 远程客户端
    participant Transport as 传输层
    participant Messaging as bridgeMessaging
    participant Runner as sessionRunner
    participant REPL as Claude Code

    Client->>Transport: 发送消息
    Transport->>Messaging: 解析消息
    Messaging->>Messaging: 验证权限
    Messaging->>Runner: 分发消息
    Runner->>REPL: 注入到对话
    REPL-->>Runner: 处理结果
    Runner-->>Messaging: 输出事件
    Messaging-->>Transport: 编码响应
    Transport-->>Client: 发送响应

11.7 认证配置参数

// Bridge 配置
export type BridgeConfig = {
  dir: string              // 工作目录
  machineName: string      // 机器名称
  branch: string           // Git 分支
  gitRepoUrl: string | null
  maxSessions: number      // 最大 Session 数
  spawnMode: SpawnMode     // 启动模式
  verbose: boolean         // 详细日志
  sandbox: boolean         // 沙箱模式
  bridgeId: string         // Bridge 实例 UUID
  workerType: string       // 工作类型
  environmentId: string    // 环境注册 ID
}

本章小结

Bridge 模块是 Claude Code 远程控制功能的核心实现,主要特点:

  1. 双协议支持:V1 WebSocket 和 V2 CCR 兼容
  2. JWT Token 管理:自动刷新机制确保长连接稳定
  3. 多种启动模式:single-session、worktree、same-dir
  4. 完整消息协议:支持文本、附件、权限响应等多种消息类型

下一章将介绍 Services 服务层的详细设计。