()
| 437 | * Call this after the REPL has been rendered. |
| 438 | */ |
| 439 | export function startDeferredPrefetches(): void { |
| 440 | // This function runs after first render, so it doesn't block the initial paint. |
| 441 | // However, the spawned processes and async work still contend for CPU and event |
| 442 | // loop time, which skews startup benchmarks (CPU profiles, time-to-first-render |
| 443 | // measurements). Skip all of it when we're only measuring startup performance. |
| 444 | if (isEnvTruthy(process.env.CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER) || |
| 445 | // --bare: skip ALL prefetches. These are cache-warms for the REPL's |
| 446 | // first-turn responsiveness (initUser, getUserContext, tips, countFiles, |
| 447 | // modelCapabilities, change detectors). Scripted -p calls don't have a |
| 448 | // "user is typing" window to hide this work in — it's pure overhead on |
| 449 | // the critical path. |
| 450 | isBareMode()) { |
| 451 | return; |
| 452 | } |
| 453 | |
| 454 | if (isDeferredHeadlessPluginStartupSurfacesEnabled()) { |
| 455 | logForDebugging('[STARTUP] Skipping deferred prefetches during deferred headless startup'); |
| 456 | return; |
| 457 | } |
| 458 | |
| 459 | // Process-spawning prefetches (consumed at first API call, user is still typing) |
| 460 | void initUser(); |
| 461 | void getUserContext(); |
| 462 | prefetchSystemContextIfSafe(); |
| 463 | void getRelevantTips(); |
| 464 | if (shouldPrefetchAwsCredentialsAtStartup({ |
| 465 | useBedrock: isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK), |
| 466 | skipBedrockAuth: isEnvTruthy(process.env.CLAUDE_CODE_SKIP_BEDROCK_AUTH), |
| 467 | })) { |
| 468 | void prefetchCurrentAwsCredentialsAndBedrockInfoIfSafe(); |
| 469 | } |
| 470 | if (shouldPrefetchGcpCredentialsAtStartup({ |
| 471 | useVertex: isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX), |
| 472 | skipVertexAuth: isEnvTruthy(process.env.CLAUDE_CODE_SKIP_VERTEX_AUTH), |
| 473 | })) { |
| 474 | void prefetchCurrentGcpCredentialsIfSafe(); |
| 475 | } |
| 476 | void countFilesRoundedRg(getCwd(), AbortSignal.timeout(3000), []); |
| 477 | |
| 478 | // Analytics and feature flag initialization |
| 479 | void initializeAnalyticsGates(); |
| 480 | void prefetchOfficialMcpUrls(); |
| 481 | void refreshModelCapabilities(); |
| 482 | |
| 483 | // File change detectors deferred from init() to unblock first render |
| 484 | void settingsChangeDetector.initialize(); |
| 485 | if (!isBareMode()) { |
| 486 | void skillChangeDetector.initialize(); |
| 487 | } |
| 488 | |
| 489 | // Event loop stall detector — logs when the main thread is blocked >500ms |
| 490 | if (isInternalBuild()) { |
| 491 | void import('./utils/eventLoopStallDetector.js').then(m => m.startEventLoopStallDetector()); |
| 492 | } |
| 493 | } |
| 494 | function loadSettingsFromFlag(settingsFile: string): void { |
| 495 | try { |
| 496 | const trimmedSettings = settingsFile.trim(); |
no test coverage detected