chore: initialize recovered claude workspace
This commit is contained in:
71
src/utils/apiPreconnect.ts
Normal file
71
src/utils/apiPreconnect.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Preconnect to the Anthropic API to overlap TCP+TLS handshake with startup.
|
||||
*
|
||||
* The TCP+TLS handshake is ~100-200ms that normally blocks inside the first
|
||||
* API call. Kicking a fire-and-forget fetch during init lets the handshake
|
||||
* happen in parallel with action-handler work (~100ms of setup/commands/mcp
|
||||
* before the API request in -p mode; unbounded "user is typing" window in
|
||||
* interactive mode).
|
||||
*
|
||||
* Bun's fetch shares a keep-alive connection pool globally, so the real API
|
||||
* request reuses the warmed connection.
|
||||
*
|
||||
* Called from init.ts AFTER applyExtraCACertsFromConfig() + configureGlobalAgents()
|
||||
* so settings.json env vars are applied and the TLS cert store is finalized.
|
||||
* The early cli.tsx call site was removed — it ran before settings.json loaded,
|
||||
* so ANTHROPIC_BASE_URL/proxy/mTLS in settings would be invisible and preconnect
|
||||
* would warm the wrong pool (or worse, lock BoringSSL's cert store before
|
||||
* NODE_EXTRA_CA_CERTS was applied).
|
||||
*
|
||||
* Skipped when:
|
||||
* - proxy/mTLS/unix socket configured (preconnect would use wrong transport —
|
||||
* the SDK passes a custom dispatcher/agent that doesn't share the global pool)
|
||||
* - Bedrock/Vertex/Foundry (different endpoints, different auth)
|
||||
*/
|
||||
|
||||
import { getOauthConfig } from '../constants/oauth.js'
|
||||
import { isEnvTruthy } from './envUtils.js'
|
||||
|
||||
let fired = false
|
||||
|
||||
export function preconnectAnthropicApi(): void {
|
||||
if (fired) return
|
||||
fired = true
|
||||
|
||||
// Skip if using a cloud provider — different endpoint + auth
|
||||
if (
|
||||
isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) ||
|
||||
isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX) ||
|
||||
isEnvTruthy(process.env.CLAUDE_CODE_USE_FOUNDRY)
|
||||
) {
|
||||
return
|
||||
}
|
||||
// Skip if proxy/mTLS/unix — SDK's custom dispatcher won't reuse this pool
|
||||
if (
|
||||
process.env.HTTPS_PROXY ||
|
||||
process.env.https_proxy ||
|
||||
process.env.HTTP_PROXY ||
|
||||
process.env.http_proxy ||
|
||||
process.env.ANTHROPIC_UNIX_SOCKET ||
|
||||
process.env.CLAUDE_CODE_CLIENT_CERT ||
|
||||
process.env.CLAUDE_CODE_CLIENT_KEY
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Use configured base URL (staging, local, or custom gateway). Covers
|
||||
// ANTHROPIC_BASE_URL env + USE_STAGING_OAUTH + USE_LOCAL_OAUTH in one lookup.
|
||||
// NODE_EXTRA_CA_CERTS no longer a skip — init.ts applied it before this fires.
|
||||
const baseUrl =
|
||||
process.env.ANTHROPIC_BASE_URL || getOauthConfig().BASE_API_URL
|
||||
|
||||
// Fire and forget. HEAD means no response body — the connection is eligible
|
||||
// for keep-alive pool reuse immediately after headers arrive. 10s timeout
|
||||
// so a slow network doesn't hang the process; abort is fine since the real
|
||||
// request will handshake fresh if needed.
|
||||
// eslint-disable-next-line eslint-plugin-n/no-unsupported-features/node-builtins
|
||||
void fetch(baseUrl, {
|
||||
method: 'HEAD',
|
||||
signal: AbortSignal.timeout(10_000),
|
||||
}).catch(() => {})
|
||||
}
|
||||
Reference in New Issue
Block a user