mirror of
https://github.com/sanbuphy/claude-code-source-code.git
synced 2026-04-07 13:34:55 +08:00
v2.1.88 反编译源码
从 npm 包 @anthropic-ai/claude-code 2.1.88 版本提取的反编译源码 包含 src/ 目录下的 TypeScript 源文件及 vendor/ 原生模块源码 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
202
src/bridge/bridgeEnabled.ts
Normal file
202
src/bridge/bridgeEnabled.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import { feature } from 'bun:bundle'
|
||||
import {
|
||||
checkGate_CACHED_OR_BLOCKING,
|
||||
getDynamicConfig_CACHED_MAY_BE_STALE,
|
||||
getFeatureValue_CACHED_MAY_BE_STALE,
|
||||
} from '../services/analytics/growthbook.js'
|
||||
// Namespace import breaks the bridgeEnabled → auth → config → bridgeEnabled
|
||||
// cycle — authModule.foo is a live binding, so by the time the helpers below
|
||||
// call it, auth.js is fully loaded. Previously used require() for the same
|
||||
// deferral, but require() hits a CJS cache that diverges from the ESM
|
||||
// namespace after mock.module() (daemon/auth.test.ts), breaking spyOn.
|
||||
import * as authModule from '../utils/auth.js'
|
||||
import { isEnvTruthy } from '../utils/envUtils.js'
|
||||
import { lt } from '../utils/semver.js'
|
||||
|
||||
/**
|
||||
* Runtime check for bridge mode entitlement.
|
||||
*
|
||||
* Remote Control requires a claude.ai subscription (the bridge auths to CCR
|
||||
* with the claude.ai OAuth token). isClaudeAISubscriber() excludes
|
||||
* Bedrock/Vertex/Foundry, apiKeyHelper/gateway deployments, env-var API keys,
|
||||
* and Console API logins — none of which have the OAuth token CCR needs.
|
||||
* See github.com/deshaw/anthropic-issues/issues/24.
|
||||
*
|
||||
* The `feature('BRIDGE_MODE')` guard ensures the GrowthBook string literal
|
||||
* is only referenced when bridge mode is enabled at build time.
|
||||
*/
|
||||
export function isBridgeEnabled(): boolean {
|
||||
// Positive ternary pattern — see docs/feature-gating.md.
|
||||
// Negative pattern (if (!feature(...)) return) does not eliminate
|
||||
// inline string literals from external builds.
|
||||
return feature('BRIDGE_MODE')
|
||||
? isClaudeAISubscriber() &&
|
||||
getFeatureValue_CACHED_MAY_BE_STALE('tengu_ccr_bridge', false)
|
||||
: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking entitlement check for Remote Control.
|
||||
*
|
||||
* Returns cached `true` immediately (fast path). If the disk cache says
|
||||
* `false` or is missing, awaits GrowthBook init and fetches the fresh
|
||||
* server value (slow path, max ~5s), then writes it to disk.
|
||||
*
|
||||
* Use at entitlement gates where a stale `false` would unfairly block access.
|
||||
* For user-facing error paths, prefer `getBridgeDisabledReason()` which gives
|
||||
* a specific diagnostic. For render-body UI visibility checks, use
|
||||
* `isBridgeEnabled()` instead.
|
||||
*/
|
||||
export async function isBridgeEnabledBlocking(): Promise<boolean> {
|
||||
return feature('BRIDGE_MODE')
|
||||
? isClaudeAISubscriber() &&
|
||||
(await checkGate_CACHED_OR_BLOCKING('tengu_ccr_bridge'))
|
||||
: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Diagnostic message for why Remote Control is unavailable, or null if
|
||||
* it's enabled. Call this instead of a bare `isBridgeEnabledBlocking()`
|
||||
* check when you need to show the user an actionable error.
|
||||
*
|
||||
* The GrowthBook gate targets on organizationUUID, which comes from
|
||||
* config.oauthAccount — populated by /api/oauth/profile during login.
|
||||
* That endpoint requires the user:profile scope. Tokens without it
|
||||
* (setup-token, CLAUDE_CODE_OAUTH_TOKEN env var, or pre-scope-expansion
|
||||
* logins) leave oauthAccount unpopulated, so the gate falls back to
|
||||
* false and users see a dead-end "not enabled" message with no hint
|
||||
* that re-login would fix it. See CC-1165 / gh-33105.
|
||||
*/
|
||||
export async function getBridgeDisabledReason(): Promise<string | null> {
|
||||
if (feature('BRIDGE_MODE')) {
|
||||
if (!isClaudeAISubscriber()) {
|
||||
return 'Remote Control requires a claude.ai subscription. Run `claude auth login` to sign in with your claude.ai account.'
|
||||
}
|
||||
if (!hasProfileScope()) {
|
||||
return 'Remote Control requires a full-scope login token. Long-lived tokens (from `claude setup-token` or CLAUDE_CODE_OAUTH_TOKEN) are limited to inference-only for security reasons. Run `claude auth login` to use Remote Control.'
|
||||
}
|
||||
if (!getOauthAccountInfo()?.organizationUuid) {
|
||||
return 'Unable to determine your organization for Remote Control eligibility. Run `claude auth login` to refresh your account information.'
|
||||
}
|
||||
if (!(await checkGate_CACHED_OR_BLOCKING('tengu_ccr_bridge'))) {
|
||||
return 'Remote Control is not yet enabled for your account.'
|
||||
}
|
||||
return null
|
||||
}
|
||||
return 'Remote Control is not available in this build.'
|
||||
}
|
||||
|
||||
// try/catch: main.tsx:5698 calls isBridgeEnabled() while defining the Commander
|
||||
// program, before enableConfigs() runs. isClaudeAISubscriber() → getGlobalConfig()
|
||||
// throws "Config accessed before allowed" there. Pre-config, no OAuth token can
|
||||
// exist anyway — false is correct. Same swallow getFeatureValue_CACHED_MAY_BE_STALE
|
||||
// already does at growthbook.ts:775-780.
|
||||
function isClaudeAISubscriber(): boolean {
|
||||
try {
|
||||
return authModule.isClaudeAISubscriber()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
function hasProfileScope(): boolean {
|
||||
try {
|
||||
return authModule.hasProfileScope()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
function getOauthAccountInfo(): ReturnType<
|
||||
typeof authModule.getOauthAccountInfo
|
||||
> {
|
||||
try {
|
||||
return authModule.getOauthAccountInfo()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime check for the env-less (v2) REPL bridge path.
|
||||
* Returns true when the GrowthBook flag `tengu_bridge_repl_v2` is enabled.
|
||||
*
|
||||
* This gates which implementation initReplBridge uses — NOT whether bridge
|
||||
* is available at all (see isBridgeEnabled above). Daemon/print paths stay
|
||||
* on the env-based implementation regardless of this gate.
|
||||
*/
|
||||
export function isEnvLessBridgeEnabled(): boolean {
|
||||
return feature('BRIDGE_MODE')
|
||||
? getFeatureValue_CACHED_MAY_BE_STALE('tengu_bridge_repl_v2', false)
|
||||
: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill-switch for the `cse_*` → `session_*` client-side retag shim.
|
||||
*
|
||||
* The shim exists because compat/convert.go:27 validates TagSession and the
|
||||
* claude.ai frontend routes on `session_*`, while v2 worker endpoints hand out
|
||||
* `cse_*`. Once the server tags by environment_kind and the frontend accepts
|
||||
* `cse_*` directly, flip this to false to make toCompatSessionId a no-op.
|
||||
* Defaults to true — the shim stays active until explicitly disabled.
|
||||
*/
|
||||
export function isCseShimEnabled(): boolean {
|
||||
return feature('BRIDGE_MODE')
|
||||
? getFeatureValue_CACHED_MAY_BE_STALE(
|
||||
'tengu_bridge_repl_v2_cse_shim_enabled',
|
||||
true,
|
||||
)
|
||||
: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an error message if the current CLI version is below the
|
||||
* minimum required for the v1 (env-based) Remote Control path, or null if the
|
||||
* version is fine. The v2 (env-less) path uses checkEnvLessBridgeMinVersion()
|
||||
* in envLessBridgeConfig.ts instead — the two implementations have independent
|
||||
* version floors.
|
||||
*
|
||||
* Uses cached (non-blocking) GrowthBook config. If GrowthBook hasn't
|
||||
* loaded yet, the default '0.0.0' means the check passes — a safe fallback.
|
||||
*/
|
||||
export function checkBridgeMinVersion(): string | null {
|
||||
// Positive pattern — see docs/feature-gating.md.
|
||||
// Negative pattern (if (!feature(...)) return) does not eliminate
|
||||
// inline string literals from external builds.
|
||||
if (feature('BRIDGE_MODE')) {
|
||||
const config = getDynamicConfig_CACHED_MAY_BE_STALE<{
|
||||
minVersion: string
|
||||
}>('tengu_bridge_min_version', { minVersion: '0.0.0' })
|
||||
if (config.minVersion && lt(MACRO.VERSION, config.minVersion)) {
|
||||
return `Your version of Claude Code (${MACRO.VERSION}) is too old for Remote Control.\nVersion ${config.minVersion} or higher is required. Run \`claude update\` to update.`
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Default for remoteControlAtStartup when the user hasn't explicitly set it.
|
||||
* When the CCR_AUTO_CONNECT build flag is present (ant-only) and the
|
||||
* tengu_cobalt_harbor GrowthBook gate is on, all sessions connect to CCR by
|
||||
* default — the user can still opt out by setting remoteControlAtStartup=false
|
||||
* in config (explicit settings always win over this default).
|
||||
*
|
||||
* Defined here rather than in config.ts to avoid a direct
|
||||
* config.ts → growthbook.ts import cycle (growthbook.ts → user.ts → config.ts).
|
||||
*/
|
||||
export function getCcrAutoConnectDefault(): boolean {
|
||||
return feature('CCR_AUTO_CONNECT')
|
||||
? getFeatureValue_CACHED_MAY_BE_STALE('tengu_cobalt_harbor', false)
|
||||
: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Opt-in CCR mirror mode — every local session spawns an outbound-only
|
||||
* Remote Control session that receives forwarded events. Separate from
|
||||
* getCcrAutoConnectDefault (bidirectional Remote Control). Env var wins for
|
||||
* local opt-in; GrowthBook controls rollout.
|
||||
*/
|
||||
export function isCcrMirrorEnabled(): boolean {
|
||||
return feature('CCR_MIRROR')
|
||||
? isEnvTruthy(process.env.CLAUDE_CODE_CCR_MIRROR) ||
|
||||
getFeatureValue_CACHED_MAY_BE_STALE('tengu_ccr_mirror', false)
|
||||
: false
|
||||
}
|
||||
Reference in New Issue
Block a user