From ddb776cd5fbe19ac06ac12c2d4e75b6344555095 Mon Sep 17 00:00:00 2001 From: y574444354 <574444354@qq.com> Date: Mon, 20 Apr 2026 17:55:09 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20Windows=20TTY?= =?UTF-8?q?=20=E5=A4=84=E7=90=86=E5=92=8C=E4=BB=A3=E7=A0=81=E9=A3=8E?= =?UTF-8?q?=E6=A0=BC=E7=BB=9F=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/dev.ts: 添加 CLAUDE_CODE_FORCE_INTERACTIVE 环境变量处理,优化 Windows 嵌套 Bun 启动时的交互模式检测 - cli.tsx: 统一代码风格(分号、引号),添加 ref/unref/setRawMode polyfill 以支持 Windows 环境 - model.ts: 优化模型选择逻辑,仅对 Anthropic 相关 provider 使用 ANTHROPIC_MODEL 环境变量 - sideQuery.ts: 更新导入路径,使用 @ant/model-provider 包 - README.md: 添加分隔线 --- README.md | 4 +- scripts/dev.ts | 14 +- src/entrypoints/cli.tsx | 358 +++++++++++++++++++-------------------- src/utils/model/model.ts | 11 +- src/utils/sideQuery.ts | 4 +- 5 files changed, 198 insertions(+), 193 deletions(-) diff --git a/README.md b/README.md index 1f5f58ac6..07d26e8d6 100644 --- a/README.md +++ b/README.md @@ -393,4 +393,6 @@ bun run dev:inspect # → ws://localhost:8888/xxx ```bash /teach-me CoStrict 架构 /teach-me Tool 系统 --level beginner --resume -``` \ No newline at end of file +``` + +--- \ No newline at end of file diff --git a/scripts/dev.ts b/scripts/dev.ts index fffd3f714..5f79bb6bb 100644 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -65,6 +65,14 @@ const envFeatures = Object.entries(process.env) const allFeatures = [...new Set([...DEFAULT_FEATURES, ...envFeatures])]; const featureArgs = allFeatures.flatMap((name) => ["--feature", name]); +// Dev mode should stay interactive for real terminal launches. Nested Bun +// launches on Windows can lose TTY metadata, but we should not force +// interactive mode when stdin is piped because that breaks headless usage like +// `"hello" | bun run dev`. +if (process.stdin.isTTY) { + process.env.CLAUDE_CODE_FORCE_INTERACTIVE ??= "1"; +} + // If BUN_INSPECT is set, pass --inspect-wait to the child process const inspectArgs = process.env.BUN_INSPECT ? ["--inspect-wait=" + process.env.BUN_INSPECT] @@ -77,7 +85,11 @@ const bunCmd = process.execPath; const result = Bun.spawnSync( [bunCmd, ...inspectArgs, "run", ...defineArgs, ...featureArgs, cliPath, ...process.argv.slice(2)], - { stdio: ["inherit", "inherit", "inherit"], cwd: projectRoot }, + { + stdio: ["inherit", "inherit", "inherit"], + cwd: projectRoot, + env: process.env, + }, ); process.exit(result.exitCode ?? 0); diff --git a/src/entrypoints/cli.tsx b/src/entrypoints/cli.tsx index f6a311d92..3931c229e 100644 --- a/src/entrypoints/cli.tsx +++ b/src/entrypoints/cli.tsx @@ -1,11 +1,11 @@ #!/usr/bin/env bun -import { feature } from 'bun:bundle' -import { isEnvTruthy } from '../utils/envUtils.js' +import { feature } from 'bun:bundle'; +import { isEnvTruthy } from '../utils/envUtils.js'; // Runtime fallback for MACRO.* when not injected by build/dev defines. // This happens when running cli.tsx directly (not via `bun run dev` or built dist/). if (typeof globalThis.MACRO === 'undefined') { - ;(globalThis as any).MACRO = { + (globalThis as any).MACRO = { VERSION: process.env.CLAUDE_CODE_VERSION || '2.1.888', BUILD_TIME: new Date().toISOString(), FEEDBACK_CHANNEL: '', @@ -13,14 +13,14 @@ if (typeof globalThis.MACRO === 'undefined') { NATIVE_PACKAGE_URL: '', PACKAGE_URL: '', VERSION_CHANGELOG: '', - } + }; } // Default to disabling nonessential traffic to api.anthropic.com // (telemetry, GrowthBook, metrics, MCP registry, etc.) // Users can opt back in by setting CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=0 // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level -process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC ??= '1' +process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC ??= '1'; if (isEnvTruthy(process.env.CLAUDE_CODE_FORCE_INTERACTIVE)) { for (const stream of [process.stdin, process.stdout, process.stderr]) { @@ -29,27 +29,56 @@ if (isEnvTruthy(process.env.CLAUDE_CODE_FORCE_INTERACTIVE)) { Object.defineProperty(stream, 'isTTY', { value: true, configurable: true, - }) + }); } catch { // Best-effort dev-only override for nested bun launch on Windows. } } + + for (const methodName of ['ref', 'unref'] as const) { + const maybeStream = stream as NodeJS.ReadStream & { + ref?: () => void; + unref?: () => void; + }; + if (typeof maybeStream[methodName] !== 'function') { + try { + Object.defineProperty(maybeStream, methodName, { + value: () => {}, + configurable: true, + }); + } catch { + // Best-effort dev-only override for nested bun launch on Windows. + } + } + } + } + + const stdin = process.stdin as NodeJS.ReadStream & { + setRawMode?: (mode: boolean) => void; + }; + if (typeof stdin.setRawMode !== 'function') { + try { + Object.defineProperty(stdin, 'setRawMode', { + value: () => {}, + configurable: true, + }); + } catch { + // Best-effort dev-only override for nested bun launch on Windows. + } } } // Bugfix for corepack auto-pinning, which adds yarnpkg to peoples' package.jsons // eslint-disable-next-line custom-rules/no-top-level-side-effects -process.env.COREPACK_ENABLE_AUTO_PIN = '0' +process.env.COREPACK_ENABLE_AUTO_PIN = '0'; // Set max heap size for child processes in CCR environments (containers have 16GB) // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level, custom-rules/safe-env-boolean-check if (process.env.CLAUDE_CODE_REMOTE === 'true') { // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level - const existing = process.env.NODE_OPTIONS || '' + const existing = process.env.NODE_OPTIONS || ''; // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level - process.env.NODE_OPTIONS = existing - ? `${existing} --max-old-space-size=8192` - : '--max-old-space-size=8192' + process.env.NODE_OPTIONS = existing ? `${existing} --max-old-space-size=8192` : '--max-old-space-size=8192'; } // Harness-science L0 ablation baseline. Inlined here (not init.ts) because @@ -68,7 +97,7 @@ if (feature('ABLATION_BASELINE') && process.env.CLAUDE_CODE_ABLATION_BASELINE) { 'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS', ]) { // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level - process.env[k] ??= '1' + process.env[k] ??= '1'; } } @@ -78,72 +107,60 @@ if (feature('ABLATION_BASELINE') && process.env.CLAUDE_CODE_ABLATION_BASELINE) { * Fast-path for --version has zero imports beyond this file. */ async function main(): Promise { - const args = process.argv.slice(2) + const args = process.argv.slice(2); // Fast-path for --version/-v: zero module loading needed - if ( - args.length === 1 && - (args[0] === '--version' || args[0] === '-v' || args[0] === '-V') - ) { + if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) { // MACRO.VERSION is inlined at build time // biome-ignore lint/suspicious/noConsole:: intentional console output - console.log(`${MACRO.VERSION} (CoStrict)`) - return + console.log(`${MACRO.VERSION} (CoStrict)`); + return; } // For all other paths, load the startup profiler - const { profileCheckpoint } = await import('../utils/startupProfiler.js') - profileCheckpoint('cli_entry') + const { profileCheckpoint } = await import('../utils/startupProfiler.js'); + profileCheckpoint('cli_entry'); // Fast-path for --dump-system-prompt: output the rendered system prompt and exit. // Used by prompt sensitivity evals to extract the system prompt at a specific commit. // Ant-only: eliminated from external builds via feature flag. if (feature('DUMP_SYSTEM_PROMPT') && args[0] === '--dump-system-prompt') { - profileCheckpoint('cli_dump_system_prompt_path') - const { enableConfigs } = await import('../utils/config.js') - enableConfigs() - const { getMainLoopModel } = await import('../utils/model/model.js') - const modelIdx = args.indexOf('--model') - const model = (modelIdx !== -1 && args[modelIdx + 1]) || getMainLoopModel() - const { getSystemPrompt } = await import('../constants/prompts.js') - const prompt = await getSystemPrompt([], model) + profileCheckpoint('cli_dump_system_prompt_path'); + const { enableConfigs } = await import('../utils/config.js'); + enableConfigs(); + const { getMainLoopModel } = await import('../utils/model/model.js'); + const modelIdx = args.indexOf('--model'); + const model = (modelIdx !== -1 && args[modelIdx + 1]) || getMainLoopModel(); + const { getSystemPrompt } = await import('../constants/prompts.js'); + const prompt = await getSystemPrompt([], model); // biome-ignore lint/suspicious/noConsole:: intentional console output - console.log(prompt.join('\n')) - return + console.log(prompt.join('\n')); + return; } if (process.argv[2] === '--claude-in-chrome-mcp') { - profileCheckpoint('cli_claude_in_chrome_mcp_path') - const { runClaudeInChromeMcpServer } = await import( - '../utils/claudeInChrome/mcpServer.js' - ) - await runClaudeInChromeMcpServer() - return + profileCheckpoint('cli_claude_in_chrome_mcp_path'); + const { runClaudeInChromeMcpServer } = await import('../utils/claudeInChrome/mcpServer.js'); + await runClaudeInChromeMcpServer(); + return; } else if (process.argv[2] === '--chrome-native-host') { - profileCheckpoint('cli_chrome_native_host_path') - const { runChromeNativeHost } = await import( - '../utils/claudeInChrome/chromeNativeHost.js' - ) - await runChromeNativeHost() - return - } else if ( - feature('CHICAGO_MCP') && - process.argv[2] === '--computer-use-mcp' - ) { - profileCheckpoint('cli_computer_use_mcp_path') - const { runComputerUseMcpServer } = await import( - '../utils/computerUse/mcpServer.js' - ) - await runComputerUseMcpServer() - return + profileCheckpoint('cli_chrome_native_host_path'); + const { runChromeNativeHost } = await import('../utils/claudeInChrome/chromeNativeHost.js'); + await runChromeNativeHost(); + return; + } else if (feature('CHICAGO_MCP') && process.argv[2] === '--computer-use-mcp') { + profileCheckpoint('cli_computer_use_mcp_path'); + const { runComputerUseMcpServer } = await import('../utils/computerUse/mcpServer.js'); + await runComputerUseMcpServer(); + return; } // Fast-path for `--acp` — ACP (Agent Client Protocol) agent mode over stdio. if (feature('ACP') && process.argv[2] === '--acp') { - profileCheckpoint('cli_acp_path') - const { runAcpAgent } = await import('../services/acp/entry.js') - await runAcpAgent() - return + profileCheckpoint('cli_acp_path'); + const { runAcpAgent } = await import('../services/acp/entry.js'); + await runAcpAgent(); + return; } // Fast-path for `--daemon-worker=` (internal — supervisor spawns this). @@ -152,10 +169,10 @@ async function main(): Promise { // workers are lean. If a worker kind needs configs/auth (assistant will), // it calls them inside its run() fn. if (feature('DAEMON') && (args[0] === '--daemon-worker' || args[0]?.startsWith('--daemon-worker='))) { - const kind = args[0] === '--daemon-worker' ? args[1] : args[0].split('=')[1] - const { runDaemonWorker } = await import('../daemon/workerRegistry.js') - await runDaemonWorker(kind) - return + const kind = args[0] === '--daemon-worker' ? args[1] : args[0].split('=')[1]; + const { runDaemonWorker } = await import('../daemon/workerRegistry.js'); + await runDaemonWorker(kind); + return; } // Fast-path for `claude remote-control` (also accepts legacy `claude remote` / `claude sync` / `claude bridge`): @@ -170,210 +187,175 @@ async function main(): Promise { args[0] === 'sync' || args[0] === 'bridge') ) { - profileCheckpoint('cli_bridge_path') - const { enableConfigs } = await import('../utils/config.js') - enableConfigs() + profileCheckpoint('cli_bridge_path'); + const { enableConfigs } = await import('../utils/config.js'); + enableConfigs(); - const { getBridgeDisabledReason, checkBridgeMinVersion } = await import( - '../bridge/bridgeEnabled.js' - ) - const { BRIDGE_LOGIN_ERROR } = await import('../bridge/types.js') - const { bridgeMain } = await import('../bridge/bridgeMain.js') - const { exitWithError } = await import('../utils/process.js') + const { getBridgeDisabledReason, checkBridgeMinVersion } = await import('../bridge/bridgeEnabled.js'); + const { BRIDGE_LOGIN_ERROR } = await import('../bridge/types.js'); + const { bridgeMain } = await import('../bridge/bridgeMain.js'); + const { exitWithError } = await import('../utils/process.js'); // Auth check must come before the GrowthBook gate check — without auth, // GrowthBook has no user context and would return a stale/default false. // getBridgeDisabledReason awaits GB init, so the returned value is fresh // (not the stale disk cache), but init still needs auth headers to work. - const { getClaudeAIOAuthTokens } = await import('../utils/auth.js') - const { getBridgeAccessToken } = await import('../bridge/bridgeConfig.js') + const { getClaudeAIOAuthTokens } = await import('../utils/auth.js'); + const { getBridgeAccessToken } = await import('../bridge/bridgeConfig.js'); if (!getClaudeAIOAuthTokens()?.accessToken && !getBridgeAccessToken()) { - exitWithError(BRIDGE_LOGIN_ERROR) + exitWithError(BRIDGE_LOGIN_ERROR); } - const disabledReason = await getBridgeDisabledReason() + const disabledReason = await getBridgeDisabledReason(); if (disabledReason) { - exitWithError(`Error: ${disabledReason}`) + exitWithError(`Error: ${disabledReason}`); } - const versionError = checkBridgeMinVersion() + const versionError = checkBridgeMinVersion(); if (versionError) { - exitWithError(versionError) + exitWithError(versionError); } // Bridge is a remote control feature - check policy limits - const { waitForPolicyLimitsToLoad, isPolicyAllowed } = await import( - '../services/policyLimits/index.js' - ) - await waitForPolicyLimitsToLoad() + const { waitForPolicyLimitsToLoad, isPolicyAllowed } = await import('../services/policyLimits/index.js'); + await waitForPolicyLimitsToLoad(); if (!isPolicyAllowed('allow_remote_control')) { - exitWithError( - "Error: Remote Control is disabled by your organization's policy.", - ) + exitWithError("Error: Remote Control is disabled by your organization's policy."); } - await bridgeMain(args.slice(1)) - return + await bridgeMain(args.slice(1)); + return; } // Fast-path for `claude daemon [subcommand]`: unified daemon + session management. // Handles both supervisor (start/stop) and background session (bg/attach/logs/kill) // subcommands under one namespace. - if ( - (feature('DAEMON') || feature('BG_SESSIONS')) && - args[0] === 'daemon' - ) { - profileCheckpoint('cli_daemon_path') - const { enableConfigs } = await import('../utils/config.js') - enableConfigs() - const { setShellIfWindows } = await import('../utils/windowsPaths.js') - setShellIfWindows() - const { initSinks } = await import('../utils/sinks.js') - initSinks() - const { daemonMain } = await import('../daemon/main.js') - await daemonMain(args.slice(1)) - return + if ((feature('DAEMON') || feature('BG_SESSIONS')) && args[0] === 'daemon') { + profileCheckpoint('cli_daemon_path'); + const { enableConfigs } = await import('../utils/config.js'); + enableConfigs(); + const { setShellIfWindows } = await import('../utils/windowsPaths.js'); + setShellIfWindows(); + const { initSinks } = await import('../utils/sinks.js'); + initSinks(); + const { daemonMain } = await import('../daemon/main.js'); + await daemonMain(args.slice(1)); + return; } // Fast-path for `--bg`/`--background` shortcut → daemon bg. - if ( - feature('BG_SESSIONS') && - (args.includes('--bg') || args.includes('--background')) - ) { - profileCheckpoint('cli_daemon_path') - const { enableConfigs } = await import('../utils/config.js') - enableConfigs() - const { setShellIfWindows } = await import('../utils/windowsPaths.js') - setShellIfWindows() - const bg = await import('../cli/bg.js') - await bg.handleBgStart( - args.filter(a => a !== '--bg' && a !== '--background'), - ) - return + if (feature('BG_SESSIONS') && (args.includes('--bg') || args.includes('--background'))) { + profileCheckpoint('cli_daemon_path'); + const { enableConfigs } = await import('../utils/config.js'); + enableConfigs(); + const { setShellIfWindows } = await import('../utils/windowsPaths.js'); + setShellIfWindows(); + const bg = await import('../cli/bg.js'); + await bg.handleBgStart(args.filter(a => a !== '--bg' && a !== '--background')); + return; } // Backward-compat: ps/logs/attach/kill → daemon (deprecated) if ( feature('BG_SESSIONS') && - (args[0] === 'ps' || - args[0] === 'logs' || - args[0] === 'attach' || - args[0] === 'kill') + (args[0] === 'ps' || args[0] === 'logs' || args[0] === 'attach' || args[0] === 'kill') ) { - const mapped = args[0] === 'ps' ? 'status' : args[0] - console.error( - `[deprecated] Use: claude daemon ${mapped}${args[1] ? ' ' + args[1] : ''}`, - ) - profileCheckpoint('cli_daemon_path') - const { enableConfigs } = await import('../utils/config.js') - enableConfigs() - const { setShellIfWindows } = await import('../utils/windowsPaths.js') - setShellIfWindows() - const { initSinks } = await import('../utils/sinks.js') - initSinks() - const { daemonMain } = await import('../daemon/main.js') - await daemonMain([args[0] === 'ps' ? 'status' : args[0]!, ...args.slice(1)]) - return + const mapped = args[0] === 'ps' ? 'status' : args[0]; + console.error(`[deprecated] Use: claude daemon ${mapped}${args[1] ? ' ' + args[1] : ''}`); + profileCheckpoint('cli_daemon_path'); + const { enableConfigs } = await import('../utils/config.js'); + enableConfigs(); + const { setShellIfWindows } = await import('../utils/windowsPaths.js'); + setShellIfWindows(); + const { initSinks } = await import('../utils/sinks.js'); + initSinks(); + const { daemonMain } = await import('../daemon/main.js'); + await daemonMain([args[0] === 'ps' ? 'status' : args[0]!, ...args.slice(1)]); + return; } // Fast-path for `claude job `: template jobs. if (feature('TEMPLATES') && args[0] === 'job') { - profileCheckpoint('cli_templates_path') - const { templatesMain } = await import('../cli/handlers/templateJobs.js') - await templatesMain(args.slice(1)) + profileCheckpoint('cli_templates_path'); + const { templatesMain } = await import('../cli/handlers/templateJobs.js'); + await templatesMain(args.slice(1)); // process.exit (not return) — mountFleetView's Ink TUI can leave event // loop handles that prevent natural exit. // eslint-disable-next-line custom-rules/no-process-exit - process.exit(0) + process.exit(0); } // Backward-compat: new/list/reply → job (deprecated) - if ( - feature('TEMPLATES') && - (args[0] === 'new' || args[0] === 'list' || args[0] === 'reply') - ) { - console.error( - `[deprecated] Use: claude job ${args[0]} ${args.slice(1).join(' ')}`.trim(), - ) - profileCheckpoint('cli_templates_path') - const { templatesMain } = await import('../cli/handlers/templateJobs.js') - await templatesMain(args) + if (feature('TEMPLATES') && (args[0] === 'new' || args[0] === 'list' || args[0] === 'reply')) { + console.error(`[deprecated] Use: claude job ${args[0]} ${args.slice(1).join(' ')}`.trim()); + profileCheckpoint('cli_templates_path'); + const { templatesMain } = await import('../cli/handlers/templateJobs.js'); + await templatesMain(args); // eslint-disable-next-line custom-rules/no-process-exit - process.exit(0) + process.exit(0); } // Fast-path for `claude environment-runner`: headless BYOC runner. // feature() must stay inline for build-time dead code elimination. if (feature('BYOC_ENVIRONMENT_RUNNER') && args[0] === 'environment-runner') { - profileCheckpoint('cli_environment_runner_path') - const { environmentRunnerMain } = await import( - '../environment-runner/main.js' - ) - await environmentRunnerMain(args.slice(1)) - return + profileCheckpoint('cli_environment_runner_path'); + const { environmentRunnerMain } = await import('../environment-runner/main.js'); + await environmentRunnerMain(args.slice(1)); + return; } // Fast-path for `claude self-hosted-runner`: headless self-hosted-runner // targeting the SelfHostedRunnerWorkerService API (register + poll; poll IS // heartbeat). feature() must stay inline for build-time dead code elimination. if (feature('SELF_HOSTED_RUNNER') && args[0] === 'self-hosted-runner') { - profileCheckpoint('cli_self_hosted_runner_path') - const { selfHostedRunnerMain } = await import( - '../self-hosted-runner/main.js' - ) - await selfHostedRunnerMain(args.slice(1)) - return + profileCheckpoint('cli_self_hosted_runner_path'); + const { selfHostedRunnerMain } = await import('../self-hosted-runner/main.js'); + await selfHostedRunnerMain(args.slice(1)); + return; } // Fast-path for --worktree --tmux: exec into tmux before loading full CLI - const hasTmuxFlag = args.includes('--tmux') || args.includes('--tmux=classic') + const hasTmuxFlag = args.includes('--tmux') || args.includes('--tmux=classic'); if ( hasTmuxFlag && - (args.includes('-w') || - args.includes('--worktree') || - args.some(a => a.startsWith('--worktree='))) + (args.includes('-w') || args.includes('--worktree') || args.some(a => a.startsWith('--worktree='))) ) { - profileCheckpoint('cli_tmux_worktree_fast_path') - const { enableConfigs } = await import('../utils/config.js') - enableConfigs() - const { isWorktreeModeEnabled } = await import( - '../utils/worktreeModeEnabled.js' - ) + profileCheckpoint('cli_tmux_worktree_fast_path'); + const { enableConfigs } = await import('../utils/config.js'); + enableConfigs(); + const { isWorktreeModeEnabled } = await import('../utils/worktreeModeEnabled.js'); if (isWorktreeModeEnabled()) { - const { execIntoTmuxWorktree } = await import('../utils/worktree.js') - const result = await execIntoTmuxWorktree(args) + const { execIntoTmuxWorktree } = await import('../utils/worktree.js'); + const result = await execIntoTmuxWorktree(args); if (result.handled) { - return + return; } // If not handled (e.g., error), fall through to normal CLI if (result.error) { - const { exitWithError } = await import('../utils/process.js') - exitWithError(result.error) + const { exitWithError } = await import('../utils/process.js'); + exitWithError(result.error); } } } // Redirect common update flag mistakes to the update subcommand - if ( - args.length === 1 && - (args[0] === '--update' || args[0] === '--upgrade') - ) { - process.argv = [process.argv[0]!, process.argv[1]!, 'update'] + if (args.length === 1 && (args[0] === '--update' || args[0] === '--upgrade')) { + process.argv = [process.argv[0]!, process.argv[1]!, 'update']; } // --bare: set SIMPLE early so gates fire during module eval / commander // option building (not just inside the action handler). if (args.includes('--bare')) { - process.env.CLAUDE_CODE_SIMPLE = '1' + process.env.CLAUDE_CODE_SIMPLE = '1'; } // No special flags detected, load and run the full CLI - const { startCapturingEarlyInput } = await import('../utils/earlyInput.js') - startCapturingEarlyInput() - profileCheckpoint('cli_before_main_import') - const { main: cliMain } = await import('../main.jsx') - profileCheckpoint('cli_after_main_import') - await cliMain() - profileCheckpoint('cli_after_main_complete') + const { startCapturingEarlyInput } = await import('../utils/earlyInput.js'); + startCapturingEarlyInput(); + profileCheckpoint('cli_before_main_import'); + const { main: cliMain } = await import('../main.jsx'); + profileCheckpoint('cli_after_main_import'); + await cliMain(); + profileCheckpoint('cli_after_main_complete'); } // eslint-disable-next-line custom-rules/no-top-level-side-effects -void main() +void main(); diff --git a/src/utils/model/model.ts b/src/utils/model/model.ts index 5ca967777..61cccbcf9 100644 --- a/src/utils/model/model.ts +++ b/src/utils/model/model.ts @@ -76,9 +76,18 @@ export function getUserSpecifiedModelSetting(): ModelSetting | undefined { specifiedModel = modelOverride } else { const settings = getSettings_DEPRECATED() || {} + const provider = getAPIProvider() // Settings.model takes precedence over ANTHROPIC_MODEL env var // This ensures user's explicit model selection via /login is respected - specifiedModel = settings.model || process.env.ANTHROPIC_MODEL || undefined + specifiedModel = + settings.model || + (provider === 'firstParty' || + provider === 'bedrock' || + provider === 'vertex' || + provider === 'foundry' + ? process.env.ANTHROPIC_MODEL + : undefined) || + undefined } // Ignore the user-specified model if it's not in the availableModels allowlist. diff --git a/src/utils/sideQuery.ts b/src/utils/sideQuery.ts index 2f510dc50..bae6fdf57 100644 --- a/src/utils/sideQuery.ts +++ b/src/utils/sideQuery.ts @@ -16,8 +16,8 @@ import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from import { getAPIMetadata } from '../services/api/claude.js' import { getAnthropicClient } from '../services/api/client.js' import { getOpenAIClient } from '../services/api/openai/client.js' -import { resolveOpenAIModel } from '../services/api/openai/modelMapping.js' -import { anthropicMessagesToOpenAI } from '../services/api/openai/convertMessages.js' +import { resolveOpenAIModel } from '@ant/model-provider' +import { anthropicMessagesToOpenAI } from '@ant/model-provider' import { createCoStrictFetch } from '../costrict/provider/fetch.js' import { loadCoStrictCredentials } from '../costrict/provider/credentials.js' import { getCoStrictBaseURL } from '../costrict/provider/auth.js'