Files
claude-code-mirror/claude-code源码-中文注释/src/bridge/sessionIdCompat.ts
2026-04-03 13:01:19 +08:00

90 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Session ID tag translation helpers for the CCR v2 compat layer.
*
* Lives in its own file (rather than workSecret.ts) so that sessionHandle.ts
* and replBridgeTransport.ts (bridge.mjs entry points) can import from
* workSecret.ts without pulling in these retag functions.
*
* The isCseShimEnabled kill switch is injected via setCseShimGate() to avoid
* a static import of bridgeEnabled.ts → growthbook.ts → config.ts — all
* banned from the sdk.mjs bundle (scripts/build-agent-sdk.sh). Callers that
* already import bridgeEnabled.ts register the gate; the SDK path never does,
* so the shim defaults to active (matching isCseShimEnabled()'s own default).
* CCR v2 compat 层的会话 ID 标签转换辅助函数。
*
* 生活在自己的文件中(而非 workSecret.ts以便 sessionHandle.ts
* 和 replBridgeTransport.tsbridge.mjs 入口点)可以从 workSecret.ts 导入,
* 而无需引入这些 retag 函数。
*
* isCseShimEnabled kill switch 通过 setCseShimGate() 注入,以避免
* bridgeEnabled.ts → growthbook.ts → config.ts 的静态导入 — 所有这些
* 都从 sdk.mjs bundle 中禁止scripts/build-agent-sdk.sh。已经导入
* bridgeEnabled.ts 的调用者注册门禁SDK 路径从不这样做,
* 因此 shim 默认为 active匹配 isCseShimEnabled() 自身的默认值)。
*/
let _isCseShimEnabled: (() => boolean) | undefined
/**
* Register the GrowthBook gate for the cse_ shim. Called from bridge
* init code that already imports bridgeEnabled.ts.
* 为 cse_ shim 注册 GrowthBook 门禁。从已经导入 bridgeEnabled.ts 的
* bridge init 代码调用。
*/
export function setCseShimGate(gate: () => boolean): void {
_isCseShimEnabled = gate
}
/**
* Re-tag a `cse_*` session ID to `session_*` for use with the v1 compat API.
*
* Worker endpoints (/v1/code/sessions/{id}/worker/*) want `cse_*`; that's
* what the work poll delivers. Client-facing compat endpoints
* (/v1/sessions/{id}, /v1/sessions/{id}/archive, /v1/sessions/{id}/events)
* want `session_*` — compat/convert.go:27 validates TagSession. Same UUID,
* different costume. No-op for IDs that aren't `cse_*`.
*
* bridgeMain holds one sessionId variable for both worker registration and
* session-management calls. It arrives as `cse_*` from the work poll under
* the compat gate, so archiveSession/fetchSessionTitle need this re-tag.
* 将 `cse_*` session ID 重新标记为 `session_*`,用于 v1 compat API。
*
* Worker endpoints/v1/code/sessions/{id}/worker/*)需要 `cse_*`
* 这是 work poll 提供的内容。面向客户端的 compat endpoints
*/v1/sessions/{id}, /v1/sessions/{id}/archive, /v1/sessions/{id}/events
* 需要 `session_*` — compat/convert.go:27 验证 TagSession。同一个 UUID
* 不同的 costume。对于不是 `cse_*` 的 ID 无操作。
*
* bridgeMain 为 worker 注册和会话管理调用持有一个 sessionId 变量。
* 在 compat 门禁下,它作为 `cse_*` 从 work poll 到达,
* 因此 archiveSession/fetchSessionTitle 需要这个重新标记。
*/
export function toCompatSessionId(id: string): string {
if (!id.startsWith('cse_')) return id
if (_isCseShimEnabled && !_isCseShimEnabled()) return id
return 'session_' + id.slice('cse_'.length)
}
/**
* Re-tag a `session_*` session ID to `cse_*` for infrastructure-layer calls.
*
* Inverse of toCompatSessionId. POST /v1/environments/{id}/bridge/reconnect
* lives below the compat layer: once ccr_v2_compat_enabled is on server-side,
* it looks sessions up by their infra tag (`cse_*`). createBridgeSession still
* returns `session_*` (compat/convert.go:41) and that's what bridge-pointer
* stores — so perpetual reconnect passes the wrong costume and gets "Session
* not found" back. Same UUID, wrong tag. No-op for IDs that aren't `session_*`.
* 将 `session_*` session ID 重新标记为 `cse_*`,用于基础设施层调用。
*
* toCompatSessionId 的反向。POST /v1/environments/{id}/bridge/reconnect
* 位于 compat 层之下:一旦 ccr_v2_compat_enabled 在服务器端开启,
* 它通过 infra tag`cse_*`查找会话。createBridgeSession 仍然返回
* `session_*`compat/convert.go:41这是 bridge-pointer 存储的 —
* 因此永久 reconnect 传递了错误的 costume 并得到"Session not found"。
* 同一个 UUID错误的标签。对于不是 `session_*` 的 ID 无操作。
*/
export function toInfraSessionId(id: string): string {
if (!id.startsWith('session_')) return id
return 'cse_' + id.slice('session_'.length)
}