codev / docs /remote-bridge /overview.md
chenbhao's picture
docs: document standalone AskUserQuestion channel and CCR forwarding
0f215fe
|
Raw
History Blame Contribute Delete
8.01 kB

远程桥接 / Remote Control

概述

Bridge(桥接)模式将本地 CLI 连接到 Anthropic 的远程会话基础设施(CCR, Claude Code Remote),使用户可以通过 claude.ai/code 从浏览器控制本地终端。


两种传输模式

1. 基于环境 (env-based)

通过 Environments API 进行 poll/dispatch:

  1. CLI 注册为一个 "环境"(environment)到 Anthropic 服务器
  2. 服务器通过 pollForWork API 分发工作
  3. 客户端领取(acknowledge)工作、执行、发送心跳、返回结果

核心 API(src/bridge/bridgeApi.ts

端点 方法 用途
POST /v1/environments/bridge registerBridgeEnvironment 注册当前终端为可用的执行环境
GET .../work/poll pollForWork 轮询待处理的工作
POST .../work/{id}/ack acknowledgeWork 确认领取工作
POST .../work/{id}/heartbeat heartbeatWork 发送心跳(延长租约)
POST .../work/{id}/stop stopWork 停止工作
DELETE .../environments/bridge/{id} deregisterEnvironment 注销环境

认证:使用 OAuth token 或 Bridge Access Token。

2. 无环境 (env-less)

直接通过 OAuth → Worker JWT 交换来连接远程会话:

  1. 通过 OAuth 获取访问令牌
  2. 直接连接到远程会话 WebSocket(/v1/sessions/ws/{sessionId}/subscribe
  3. 使用 SDK 消息格式进行双向通信

核心组件(src/remote/

文件 路径 用途
SessionsWebSocket.ts src/remote/SessionsWebSocket.ts WebSocket 客户端
sdkMessageAdapter.ts src/remote/sdkMessageAdapter.ts SDK 消息转换适配器

核心组件

bridgeApi.ts(src/bridge/bridgeApi.ts

HTTP 客户端,封装了所有 Bridge API 调用:

  • OAuth 认证:自动 401 重试 + token 刷新(通过 onAuth401 回调)
  • BridgeFatalError:不可重试的错误(认证失败、权限不足、会话过期)
  • ID 验证validateBridgeId() 防止路径遍历攻击
  • 错误处理:对 401/403/404/410/429 状态码分别处理
export class BridgeFatalError extends Error {
  readonly status: number
  readonly errorType: string | undefined
}

bridgeMain.ts(src/bridge/bridgeMain.ts

主桥接逻辑,约 3000 行。负责:

  • 环境注册与生命周期管理
  • 工作(work)的 poll/dispatch 循环
  • 会话(session)的创建、运行、恢复
  • 多会话支持(--spawn, --capacity, --create-session-in-dir
  • 优雅关闭(SIGTERM → SIGKILL 宽限期)
  • 退避策略(连接退避、通用退避、stopWork 退避)
export type BackoffConfig = {
  connInitialMs: number      // 连接初始延迟
  connCapMs: number           // 连接最大延迟 (2min)
  connGiveUpMs: number        // 连接放弃时间 (10min)
  generalInitialMs: number    // 通用初始延迟
  generalCapMs: number        // 通用最大延迟 (30s)
  generalGiveUpMs: number     // 通用放弃时间 (10min)
  shutdownGraceMs?: number    // SIGTERM→SIGKILL 宽限期
}

replBridge.ts(src/bridge/replBridge.ts

REPL 集成桥接,约 2400 行。在 REPL(交互式终端)模式下将 CLI 连接到远程会话:

  • 通过 HybridTransport 实现消息转发
  • 支持 CCR v1/v2 协议(createV1ReplTransport / createV2ReplTransport
  • 消息入口(ingress)处理
  • 控制请求/响应(SDKControlRequest / SDKControlResponse
  • 容量唤醒(capacity wake)信号
export type ReplBridgeHandle = {
  bridgeSessionId: string
  environmentId: string
  sessionIngressUrl: string
  writeMessages(messages: Message[]): void
  writeSdkMessages(messages: SDKMessage[]): void
  sendControlRequest(request: SDKControlRequest): void
  sendControlResponse(response: SDKControlResponse): void
  sendControlCancelRequest(requestId: string): void
  sendResult(): void
  teardown(): Promise<void>
}

SessionsWebSocket.ts(src/remote/SessionsWebSocket.ts

WebSocket 客户端,用于直接连接远程会话:

协议

  1. 连接到 wss://api.anthropic.com/v1/sessions/ws/{sessionId}/subscribe?organization_uuid=...
  2. 发送认证消息:{ type: 'auth', credential: { type: 'oauth', token: '...' } }
  3. 接收 SDK 消息流

重连机制

  • RECONNECT_DELAY_MS = 2000:重连延迟 2 秒
  • MAX_RECONNECT_ATTEMPTS = 5:最大重连次数
  • PING_INTERVAL_MS = 30000:30 秒心跳间隔
  • PERMANENT_CLOSE_CODES = new Set([4003]):4003(未授权)为永久关闭,不重连
  • MAX_SESSION_NOT_FOUND_RETRIES = 3:4001(会话未找到)有限重试(压缩期间可能短暂出现)
type SessionsWebSocketCallbacks = {
  onMessage: (message: SessionsMessage) => void
  onClose?: () => void
  onError?: (error: Error) => void
  onConnected?: () => void
  onReconnecting?: () => void
}

sdkMessageAdapter.ts(src/remote/sdkMessageAdapter.ts

SDK 消息格式转换器。将 CCR 发送的 SDK 格式消息(SDKMessage)转换为 CLI 内部的消息类型(Message):

  • convertAssistantMessage(): SDKAssistantMessageAssistantMessage
  • convertStreamEvent(): SDKPartialAssistantMessageStreamEvent
  • 处理多种消息类型:assistant、system、compact_boundary、status、tool_progress、result 等

remotePermissionBridge.ts

在远程会话中处理权限请求桥接(位于 src/hooks/useSSHSession.tsuseRemoteSession.tsuseDirectConnect.ts),将远程权限提示通过 WebSocket 转发给用户。

AskUserQuestion 远程转发

AskUserQuestion 走独立问答通道(详见 docs/architecture/safety-and-permissions.md 附录),桥接连接时会把问题作为 can_use_tool control_request 转发给远程用户(claude.ai),与本地 overlay 竞速应答:

  • 远程 allow + updatedInput.answers → 按题映射回填;通用 allow 降级为每题首个选项。
  • 远程 deny → 拒绝该问题。
  • 任一端先应答即 cancelRequest 另一端,避免残留 prompt。

实现位于 src/screens/REPL.tsxquestionService 事件(asked / replied / rejected)的订阅。


认证机制

机制 说明
OAuth Token 通过 OAuth 2.0 流程获取的访问令牌
Bridge Access Token 桥接模式专用的访问令牌,通过 workSecret.ts 中的 decodeWorkSecret() 解码
Trusted Device Token X-Trusted-Device-Token 头部,用于权限提升
Token 刷新 handleOAuth401Error 在 401 时自动刷新

WebSocket 协议(CCR v1/v2)

认证流程

Client → Server: { type: "auth", credential: { type: "oauth", token: "..." } }
Server → Client: { type: "auth_ok" }  或  { type: "auth_error" }

消息格式

  • CCR v1:通过 replBridgeTransport.tscreateV1ReplTransport 处理
  • CCR v2:通过 createV2ReplTransport 处理,使用 buildCCRv2SdkUrl() 构建 URL

心跳保活

  • 标准 WebSocket ping:30 秒间隔
  • 会话活动信号(sendSessionActivitySignal())在压缩等长时间操作期间发送,防止 WebSocket 因 idle 超时被断开

其他组件

文件 路径 用途
bridgeConfig.ts src/bridge/bridgeConfig.ts 桥接配置管理
bridgeMessaging.ts src/bridge/bridgeMessaging.ts 桥接消息处理逻辑
capacityWake.ts src/bridge/capacityWake.ts 容量唤醒信号
codeSessionApi.ts src/bridge/codeSessionApi.ts 代码会话 API
trustedDevice.ts src/bridge/trustedDevice.ts 受信任设备管理
workSecret.ts src/bridge/workSecret.ts Work Secret 编解码
sessionIdCompat.ts src/bridge/sessionIdCompat.ts 会话 ID 兼容性转换
pollConfig.ts src/bridge/pollConfig.ts 轮询间隔配置
types.ts src/bridge/types.ts 桥接模块类型定义