first commit
This commit is contained in:
659
claude-code-中文Wiki/06-桥接系统.md
Normal file
659
claude-code-中文Wiki/06-桥接系统.md
Normal file
@@ -0,0 +1,659 @@
|
||||
# Claude Code 桥接系统详解
|
||||
|
||||
## 概述
|
||||
|
||||
桥接系统(Bridge)是 Claude Code CLI 与 IDE 扩展(VS Code, JetBrains)之间的双向通信层。它使 IDE 能够:
|
||||
1. 在远程设备上启动 Claude Code 会话
|
||||
2. 将用户输入转发到 Claude Code
|
||||
3. 显示 Claude Code 的输出和工具执行结果
|
||||
4. 处理权限请求和响应
|
||||
|
||||
---
|
||||
|
||||
## 核心架构
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ IDE Extension (VS Code / JetBrains) │
|
||||
│ - 用户界面 │
|
||||
│ - 输入处理 │
|
||||
│ - 输出展示 │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ WebSocket / HTTP
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Bridge Layer │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ bridgeMain.ts │ │
|
||||
│ │ 入口点,管理桥接生命周期 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ bridgeMessaging.ts │ │
|
||||
│ │ 消息处理、入口路由、流量控制 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ replBridge.ts │ │
|
||||
│ │ REPL 会话桥接 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ sessionRunner.ts │ │
|
||||
│ │ 会话执行管理 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ jwtUtils.ts │ │
|
||||
│ │ JWT 认证工具 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ bridgePermissionCallbacks.ts │ │
|
||||
│ │ 权限回调处理 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Claude Code CLI (子进程) │
|
||||
│ - 命令处理 │
|
||||
│ - 工具执行 │
|
||||
│ - API 调用 │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. bridgeMain.ts - 桥接主入口
|
||||
|
||||
**文件位置**: `src/bridge/bridgeMain.ts`
|
||||
|
||||
### 核心类型
|
||||
|
||||
```typescript
|
||||
export type BridgeState = 'ready' | 'connected' | 'reconnecting' | 'failed'
|
||||
|
||||
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>
|
||||
}
|
||||
```
|
||||
|
||||
### 核心函数
|
||||
|
||||
```typescript
|
||||
export async function initBridgeCore(
|
||||
params: BridgeCoreParams
|
||||
): Promise<BridgeCoreHandle | null>
|
||||
```
|
||||
|
||||
**BridgeCoreParams 输入参数**:
|
||||
|
||||
```typescript
|
||||
type BridgeCoreParams = {
|
||||
dir: string // 工作目录
|
||||
machineName: string // 机器名称
|
||||
branch: string // Git 分支
|
||||
gitRepoUrl: string | null // Git 仓库 URL
|
||||
title: string // 会话标题
|
||||
baseUrl: string // API 基础 URL
|
||||
sessionIngressUrl: string // 会话入口 URL
|
||||
workerType: string // 工作器类型
|
||||
getAccessToken: () => string | undefined
|
||||
createSession: (opts: {...}) => Promise<string | null>
|
||||
archiveSession: (sessionId: string) => Promise<void>
|
||||
toSDKMessages?: (messages: Message[]) => SDKMessage[]
|
||||
onAuth401?: (staleAccessToken: string) => Promise<boolean>
|
||||
getPollIntervalConfig?: () => PollIntervalConfig
|
||||
initialMessages?: Message[]
|
||||
previouslyFlushedUUIDs?: Set<string>
|
||||
onInboundMessage?: (msg: SDKMessage) => void
|
||||
onPermissionResponse?: (response: SDKControlResponse) => void
|
||||
onInterrupt?: () => void
|
||||
onSetModel?: (model: string | undefined) => void
|
||||
onSetMaxThinkingTokens?: (maxTokens: number | null) => void
|
||||
onSetPermissionMode?: (mode: PermissionMode) => {...}
|
||||
onStateChange?: (state: BridgeState, detail?: string) => void
|
||||
onUserMessage?: (text: string, sessionId: string) => boolean
|
||||
perpetual?: boolean
|
||||
initialSSESequenceNum?: number
|
||||
}
|
||||
```
|
||||
|
||||
### 桥接生命周期
|
||||
|
||||
1. **注册桥接环境**
|
||||
```typescript
|
||||
const reg = await api.registerBridgeEnvironment(bridgeConfig)
|
||||
environmentId = reg.environment_id
|
||||
environmentSecret = reg.environment_secret
|
||||
```
|
||||
|
||||
2. **创建会话**
|
||||
```typescript
|
||||
const createdSessionId = await createSession({...})
|
||||
currentSessionId = createdSessionId
|
||||
```
|
||||
|
||||
3. **启动工作轮询循环**
|
||||
```typescript
|
||||
void startWorkPollLoop(pollOpts)
|
||||
```
|
||||
|
||||
4. **处理入口消息**
|
||||
```typescript
|
||||
transport.onData(data => {
|
||||
handleIngressMessage(data, recentPostedUUIDs, recentInboundUUIDs, ...)
|
||||
})
|
||||
```
|
||||
|
||||
5. **清理**
|
||||
```typescript
|
||||
await doTeardownImpl()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. bridgeMessaging.ts - 消息处理
|
||||
|
||||
**文件位置**: `src/bridge/bridgeMessaging.ts`
|
||||
|
||||
### 消息入口处理
|
||||
|
||||
```typescript
|
||||
export function handleIngressMessage(
|
||||
data: string,
|
||||
recentPostedUUIDs: BoundedUUIDSet,
|
||||
recentInboundUUIDs: BoundedUUIDSet,
|
||||
onInboundMessage: ((msg: SDKMessage) => void | Promise<void>) | undefined,
|
||||
onPermissionResponse?: ((response: SDKControlResponse) => void) | undefined,
|
||||
onControlRequest?: ((request: SDKControlRequest) => void) | undefined,
|
||||
): void
|
||||
```
|
||||
|
||||
**消息类型判断**:
|
||||
|
||||
```typescript
|
||||
export function isSDKMessage(value: unknown): value is SDKMessage
|
||||
export function isSDKControlResponse(value: unknown): value is SDKControlResponse
|
||||
export function isSDKControlRequest(value: unknown): value is SDKControlRequest
|
||||
```
|
||||
|
||||
### 可桥接消息过滤
|
||||
|
||||
```typescript
|
||||
export function isEligibleBridgeMessage(m: Message): boolean {
|
||||
// 排除虚拟消息
|
||||
if ((m.type === 'user' || m.type === 'assistant') && m.isVirtual) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
m.type === 'user' ||
|
||||
m.type === 'assistant' ||
|
||||
(m.type === 'system' && m.subtype === 'local_command')
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 服务器控制请求处理
|
||||
|
||||
```typescript
|
||||
export function handleServerControlRequest(
|
||||
request: SDKControlRequest,
|
||||
handlers: ServerControlRequestHandlers,
|
||||
): void
|
||||
```
|
||||
|
||||
**支持的请求类型**:
|
||||
- `initialize` - 初始化
|
||||
- `set_model` - 设置模型
|
||||
- `set_max_thinking_tokens` - 设置最大思考 token
|
||||
- `set_permission_mode` - 设置权限模式
|
||||
- `interrupt` - 中断
|
||||
|
||||
### 标题文本提取
|
||||
|
||||
```typescript
|
||||
export function extractTitleText(m: Message): string | undefined
|
||||
// 从用户消息中提取标题
|
||||
```
|
||||
|
||||
### BoundedUUIDSet - UUID 环形缓冲区
|
||||
|
||||
```typescript
|
||||
export class BoundedUUIDSet {
|
||||
constructor(capacity: number)
|
||||
add(uuid: string): void
|
||||
has(uuid: string): boolean
|
||||
clear(): void
|
||||
}
|
||||
```
|
||||
|
||||
**用途**:
|
||||
- 消息回音过滤
|
||||
- 重复消息去重
|
||||
|
||||
---
|
||||
|
||||
## 3. replBridge.ts - REPL 会话桥接
|
||||
|
||||
**文件位置**: `src/bridge/replBridge.ts`
|
||||
|
||||
### 核心接口
|
||||
|
||||
```typescript
|
||||
export type ReplBridgeTransport = {
|
||||
setOnConnect(callback: () => void): void
|
||||
setOnData(callback: (data: string) => void): void
|
||||
setOnClose(callback: (code: number | undefined) => void): void
|
||||
connect(): void
|
||||
write(message: object): Promise<void>
|
||||
writeBatch(messages: object[]): Promise<void>
|
||||
close(): void
|
||||
getStateLabel(): string
|
||||
getLastSequenceNum(): number
|
||||
isConnectedStatus(): boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 传输类型
|
||||
|
||||
#### 1. HybridTransport (v1)
|
||||
- WebSocket 读取
|
||||
- HTTP POST 写入
|
||||
- 目标: Session-Ingress
|
||||
|
||||
#### 2. SSETransport (v2)
|
||||
- Server-Sent Events 读取
|
||||
- HTTP POST 写入
|
||||
- 目标: CCR (/worker/*)
|
||||
|
||||
### 初始化流程
|
||||
|
||||
```typescript
|
||||
export async function initReplBridge(
|
||||
params: InitBridgeOptions
|
||||
): Promise<ReplBridgeHandle | null>
|
||||
```
|
||||
|
||||
### 消息写入
|
||||
|
||||
```typescript
|
||||
writeMessages(messages: Message[]) {
|
||||
// 过滤可桥接消息
|
||||
const filtered = messages.filter(m =>
|
||||
isEligibleBridgeMessage(m) &&
|
||||
!initialMessageUUIDs.has(m.uuid) &&
|
||||
!recentPostedUUIDs.has(m.uuid)
|
||||
)
|
||||
|
||||
// 转换并发送
|
||||
const sdkMessages = toSDKMessages(filtered)
|
||||
void transport.writeBatch(events)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. jwtUtils.ts - JWT 认证
|
||||
|
||||
**文件位置**: `src/bridge/jwtUtils.ts`
|
||||
|
||||
### JWT 解析
|
||||
|
||||
```typescript
|
||||
export function decodeJwtPayload(token: string): unknown | null {
|
||||
// 剥离 sk-ant-si- 前缀
|
||||
const jwt = token.startsWith('sk-ant-si-')
|
||||
? token.slice('sk-ant-si-'.length)
|
||||
: token
|
||||
|
||||
// 解析 payload (不验证签名)
|
||||
const parts = jwt.split('.')
|
||||
if (parts.length !== 3 || !parts[1]) return null
|
||||
return jsonParse(Buffer.from(parts[1], 'base64url').toString('utf8'))
|
||||
}
|
||||
```
|
||||
|
||||
### Token 刷新调度器
|
||||
|
||||
```typescript
|
||||
export function createTokenRefreshScheduler({
|
||||
getAccessToken,
|
||||
onRefresh,
|
||||
label,
|
||||
refreshBufferMs = 5 * 60 * 1000, // 5 分钟
|
||||
}): {
|
||||
schedule: (sessionId: string, token: string) => void
|
||||
scheduleFromExpiresIn: (sessionId: string, expiresInSeconds: number) => void
|
||||
cancel: (sessionId: string) => void
|
||||
cancelAll: () => void
|
||||
}
|
||||
```
|
||||
|
||||
**刷新策略**:
|
||||
- 过期前 5 分钟刷新(默认)
|
||||
- 指数退避重试
|
||||
- 最多 3 次连续失败
|
||||
|
||||
---
|
||||
|
||||
## 5. sessionRunner.ts - 会话执行管理
|
||||
|
||||
**文件位置**: `src/bridge/sessionRunner.ts`
|
||||
|
||||
### 核心类型
|
||||
|
||||
```typescript
|
||||
type SessionSpawnerDeps = {
|
||||
execPath: string
|
||||
scriptArgs: string[]
|
||||
env: NodeJS.ProcessEnv
|
||||
verbose: boolean
|
||||
sandbox: boolean
|
||||
debugFile?: string
|
||||
permissionMode?: string
|
||||
onDebug: (msg: string) => void
|
||||
onActivity?: (sessionId: string, activity: SessionActivity) => void
|
||||
onPermissionRequest?: (sessionId: string, request: PermissionRequest, accessToken: string) => void
|
||||
}
|
||||
|
||||
export function createSessionSpawner(deps: SessionSpawnerDeps): SessionSpawner
|
||||
```
|
||||
|
||||
### 会话句柄
|
||||
|
||||
```typescript
|
||||
export type SessionHandle = {
|
||||
sessionId: string
|
||||
done: Promise<SessionDoneStatus>
|
||||
activities: SessionActivity[]
|
||||
accessToken: string
|
||||
lastStderr: string[]
|
||||
currentActivity: SessionActivity | null
|
||||
kill(): void
|
||||
forceKill(): void
|
||||
writeStdin(data: string): void
|
||||
updateAccessToken(token: string): void
|
||||
}
|
||||
```
|
||||
|
||||
### 活动提取
|
||||
|
||||
```typescript
|
||||
function extractActivities(
|
||||
line: string,
|
||||
sessionId: string,
|
||||
onDebug: (msg: string) => void
|
||||
): SessionActivity[]
|
||||
```
|
||||
|
||||
**活动类型**:
|
||||
```typescript
|
||||
type SessionActivity =
|
||||
| { type: 'tool_start'; summary: string; timestamp: number }
|
||||
| { type: 'text'; summary: string; timestamp: number }
|
||||
| { type: 'result'; summary: string; timestamp: number }
|
||||
| { type: 'error'; summary: string; timestamp: number }
|
||||
```
|
||||
|
||||
### 子进程管理
|
||||
|
||||
```typescript
|
||||
const child: ChildProcess = spawn(deps.execPath, args, {
|
||||
cwd: dir,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
env,
|
||||
windowsHide: true,
|
||||
})
|
||||
```
|
||||
|
||||
**环境变量设置**:
|
||||
```typescript
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
...deps.env,
|
||||
CLAUDE_CODE_OAUTH_TOKEN: undefined,
|
||||
CLAUDE_CODE_ENVIRONMENT_KIND: 'bridge',
|
||||
CLAUDE_CODE_SESSION_ACCESS_TOKEN: opts.accessToken,
|
||||
CLAUDE_CODE_USE_CCR_V2: opts.useCcrV2 ? '1' : undefined,
|
||||
CLAUDE_CODE_WORKER_EPOCH: String(opts.workerEpoch),
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. bridgePermissionCallbacks.ts - 权限回调
|
||||
|
||||
**文件位置**: `src/bridge/bridgePermissionCallbacks.ts`
|
||||
|
||||
### 权限响应类型
|
||||
|
||||
```typescript
|
||||
type BridgePermissionResponse = {
|
||||
behavior: 'allow' | 'deny'
|
||||
updatedInput?: Record<string, unknown>
|
||||
updatedPermissions?: PermissionUpdate[]
|
||||
message?: string
|
||||
}
|
||||
```
|
||||
|
||||
### 回调接口
|
||||
|
||||
```typescript
|
||||
type BridgePermissionCallbacks = {
|
||||
sendRequest(
|
||||
requestId: string,
|
||||
toolName: string,
|
||||
input: Record<string, unknown>,
|
||||
toolUseId: string,
|
||||
description: string,
|
||||
permissionSuggestions?: PermissionUpdate[],
|
||||
blockedPath?: string
|
||||
): void
|
||||
|
||||
sendResponse(requestId: string, response: BridgePermissionResponse): void
|
||||
|
||||
cancelRequest(requestId: string): void
|
||||
|
||||
onResponse(
|
||||
requestId: string,
|
||||
handler: (response: BridgePermissionResponse) => void
|
||||
): () => void // 返回取消订阅函数
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. replBridgeHandle.ts - REPL 桥接句柄
|
||||
|
||||
**文件位置**: `src/bridge/replBridgeHandle.ts`
|
||||
|
||||
### 句柄类型
|
||||
|
||||
```typescript
|
||||
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>
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. replBridgeTransport.ts - 传输层实现
|
||||
|
||||
**文件位置**: `src/bridge/replBridgeTransport.ts`
|
||||
|
||||
### 工厂函数
|
||||
|
||||
```typescript
|
||||
export function createV1ReplTransport(
|
||||
transport: HybridTransport
|
||||
): ReplBridgeTransport
|
||||
|
||||
export function createV2ReplTransport(opts: {
|
||||
sessionUrl: string
|
||||
ingressToken: string
|
||||
sessionId: string
|
||||
initialSequenceNum: number
|
||||
}): Promise<ReplBridgeTransport>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 入口消息处理流程
|
||||
|
||||
```
|
||||
IDE Extension
|
||||
│
|
||||
│ 1. 用户输入
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ WS 连接 │
|
||||
└─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ handleIngressMessage() │
|
||||
│ │
|
||||
│ 1. 解析 JSON │
|
||||
│ 2. 检查 UUID (回音/重复过滤) │
|
||||
│ 3. 分发消息类型 │
|
||||
│ - user → onInboundMessage │
|
||||
│ - control_response → onPermission │
|
||||
│ - control_request → onControlRequest │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Claude Code CLI (子进程) │
|
||||
│ │
|
||||
│ - 执行工具 │
|
||||
│ - AI 推理 │
|
||||
│ - 返回结果 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ writeMessages() / writeSdkMessages() │
|
||||
│ │
|
||||
│ 1. 过滤消息 │
|
||||
│ 2. 转换为 SDK 格式 │
|
||||
│ 3. 通过 transport.writeBatch() 发送 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
IDE Extension (WebSocket 订阅)
|
||||
│
|
||||
▼
|
||||
显示输出
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 权限请求流程
|
||||
|
||||
```
|
||||
Claude Code CLI
|
||||
│
|
||||
▼ (can_use_tool 请求)
|
||||
┌─────────────────────────────────────────┐
|
||||
│ BridgePermissionCallbacks │
|
||||
│ │
|
||||
│ sendRequest(requestId, toolName, input) │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
│ WebSocket / HTTP
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ IDE Extension │
|
||||
│ │
|
||||
│ 显示权限对话框 │
|
||||
│ 用户允许/拒绝 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ sendResponse(requestId, response) │
|
||||
│ │
|
||||
│ response: { │
|
||||
│ behavior: 'allow' | 'deny', │
|
||||
│ updatedInput?, │
|
||||
│ updatedPermissions? │
|
||||
│ } │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
onResponse() 回调
|
||||
│
|
||||
▼
|
||||
CLI 继续执行或中止
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 关键配置
|
||||
|
||||
### 轮询配置
|
||||
|
||||
```typescript
|
||||
const DEFAULT_POLL_CONFIG = {
|
||||
poll_interval_ms_not_at_capacity: 5000, // 5 秒
|
||||
poll_interval_ms_at_capacity: 120000, // 2 分钟
|
||||
reclaim_older_than_ms: 5 * 60 * 1000, // 5 分钟
|
||||
non_exclusive_heartbeat_interval_ms: 30000, // 30 秒
|
||||
session_keepalive_interval_v2_ms: 120000, // 2 分钟
|
||||
}
|
||||
```
|
||||
|
||||
### 重连策略
|
||||
|
||||
```typescript
|
||||
const MAX_RECONNECT_ATTEMPTS = 5
|
||||
const INITIAL_BACKOFF_MS = 1000
|
||||
const MAX_BACKOFF_MS = 30000
|
||||
```
|
||||
|
||||
### UUID 缓冲区容量
|
||||
|
||||
```typescript
|
||||
const recentPostedUUIDs = new BoundedUUIDSet(2000)
|
||||
const recentInboundUUIDs = new BoundedUUIDSet(2000)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关源码文件
|
||||
|
||||
| 文件 | 功能 |
|
||||
|------|------|
|
||||
| `bridgeMain.ts` | 桥接主入口和生命周期管理 |
|
||||
| `bridgeMessaging.ts` | 消息处理、路由、流量控制 |
|
||||
| `replBridge.ts` | REPL 会话桥接 |
|
||||
| `replBridgeTransport.ts` | 传输层实现 |
|
||||
| `sessionRunner.ts` | 子进程会话管理 |
|
||||
| `jwtUtils.ts` | JWT 解析和刷新调度 |
|
||||
| `bridgePermissionCallbacks.ts` | 权限回调接口 |
|
||||
| `replBridgeHandle.ts` | 句柄类型定义 |
|
||||
| `bridgeApi.ts` | 桥接 API 客户端 |
|
||||
| `pollConfig.ts` | 轮询配置 |
|
||||
| `flushGate.ts` | 刷新门控 |
|
||||
| `capacityWake.ts` | 容量唤醒机制 |
|
||||
Reference in New Issue
Block a user