( options?: InitBridgeOptions, )
| 108 | } |
| 109 | |
| 110 | export async function initReplBridge( |
| 111 | options?: InitBridgeOptions, |
| 112 | ): Promise<ReplBridgeHandle | null> { |
| 113 | const { |
| 114 | onInboundMessage, |
| 115 | onPermissionResponse, |
| 116 | onInterrupt, |
| 117 | onSetModel, |
| 118 | onSetMaxThinkingTokens, |
| 119 | onSetPermissionMode, |
| 120 | onStateChange, |
| 121 | initialMessages, |
| 122 | getMessages, |
| 123 | previouslyFlushedUUIDs, |
| 124 | initialName, |
| 125 | perpetual, |
| 126 | outboundOnly, |
| 127 | tags, |
| 128 | } = options ?? {} |
| 129 | |
| 130 | // Wire the cse_ shim kill switch so toCompatSessionId respects the |
| 131 | // GrowthBook gate. Daemon/SDK paths skip this — shim defaults to active. |
| 132 | setCseShimGate(isCseShimEnabled) |
| 133 | |
| 134 | // 1. Runtime gate |
| 135 | if (!(await isBridgeEnabledBlocking())) { |
| 136 | logBridgeSkip('not_enabled', '[bridge:repl] Skipping: bridge not enabled') |
| 137 | return null |
| 138 | } |
| 139 | |
| 140 | // 1b. Minimum version check — deferred to after the v1/v2 branch below, |
| 141 | // since each implementation has its own floor (tengu_bridge_min_version |
| 142 | // for v1, tengu_bridge_repl_v2_config.min_version for v2). |
| 143 | |
| 144 | // 2. Check OAuth — must be signed in with claude.ai. Runs before the |
| 145 | // policy check so console-auth users get the actionable "/login" hint |
| 146 | // instead of a misleading policy error from a stale/wrong-org cache. |
| 147 | if (!getBridgeAccessToken()) { |
| 148 | logBridgeSkip('no_oauth', '[bridge:repl] Skipping: no OAuth tokens') |
| 149 | onStateChange?.('failed', '/login') |
| 150 | return null |
| 151 | } |
| 152 | |
| 153 | // 3. Check organization policy — remote control may be disabled |
| 154 | await waitForPolicyLimitsToLoad() |
| 155 | if (!isPolicyAllowed('allow_remote_control')) { |
| 156 | logBridgeSkip( |
| 157 | 'policy_denied', |
| 158 | '[bridge:repl] Skipping: allow_remote_control policy not allowed', |
| 159 | ) |
| 160 | onStateChange?.('failed', "disabled by your organization's policy") |
| 161 | return null |
| 162 | } |
| 163 | |
| 164 | // When CLAUDE_BRIDGE_OAUTH_TOKEN is set (ant-only local dev), the bridge |
| 165 | // uses that token directly via getBridgeAccessToken() — keychain state is |
| 166 | // irrelevant. Skip 2b/2c to preserve that decoupling: an expired keychain |
| 167 | // token shouldn't block a bridge connection that doesn't use it. |
no test coverage detected