refactor: 优化 Windows TTY 处理和代码风格统一
- 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: 添加分隔线
This commit is contained in:
parent
98a1ce35e4
commit
ddb776cd5f
|
|
@ -394,3 +394,5 @@ bun run dev:inspect # → ws://localhost:8888/xxx
|
||||||
/teach-me CoStrict 架构
|
/teach-me CoStrict 架构
|
||||||
/teach-me Tool 系统 --level beginner --resume
|
/teach-me Tool 系统 --level beginner --resume
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
@ -65,6 +65,14 @@ const envFeatures = Object.entries(process.env)
|
||||||
const allFeatures = [...new Set([...DEFAULT_FEATURES, ...envFeatures])];
|
const allFeatures = [...new Set([...DEFAULT_FEATURES, ...envFeatures])];
|
||||||
const featureArgs = allFeatures.flatMap((name) => ["--feature", name]);
|
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
|
// If BUN_INSPECT is set, pass --inspect-wait to the child process
|
||||||
const inspectArgs = process.env.BUN_INSPECT
|
const inspectArgs = process.env.BUN_INSPECT
|
||||||
? ["--inspect-wait=" + process.env.BUN_INSPECT]
|
? ["--inspect-wait=" + process.env.BUN_INSPECT]
|
||||||
|
|
@ -77,7 +85,11 @@ const bunCmd = process.execPath;
|
||||||
|
|
||||||
const result = Bun.spawnSync(
|
const result = Bun.spawnSync(
|
||||||
[bunCmd, ...inspectArgs, "run", ...defineArgs, ...featureArgs, cliPath, ...process.argv.slice(2)],
|
[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);
|
process.exit(result.exitCode ?? 0);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
#!/usr/bin/env bun
|
#!/usr/bin/env bun
|
||||||
import { feature } from 'bun:bundle'
|
import { feature } from 'bun:bundle';
|
||||||
import { isEnvTruthy } from '../utils/envUtils.js'
|
import { isEnvTruthy } from '../utils/envUtils.js';
|
||||||
|
|
||||||
// Runtime fallback for MACRO.* when not injected by build/dev defines.
|
// 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/).
|
// This happens when running cli.tsx directly (not via `bun run dev` or built dist/).
|
||||||
if (typeof globalThis.MACRO === 'undefined') {
|
if (typeof globalThis.MACRO === 'undefined') {
|
||||||
;(globalThis as any).MACRO = {
|
(globalThis as any).MACRO = {
|
||||||
VERSION: process.env.CLAUDE_CODE_VERSION || '2.1.888',
|
VERSION: process.env.CLAUDE_CODE_VERSION || '2.1.888',
|
||||||
BUILD_TIME: new Date().toISOString(),
|
BUILD_TIME: new Date().toISOString(),
|
||||||
FEEDBACK_CHANNEL: '',
|
FEEDBACK_CHANNEL: '',
|
||||||
|
|
@ -13,14 +13,14 @@ if (typeof globalThis.MACRO === 'undefined') {
|
||||||
NATIVE_PACKAGE_URL: '',
|
NATIVE_PACKAGE_URL: '',
|
||||||
PACKAGE_URL: '',
|
PACKAGE_URL: '',
|
||||||
VERSION_CHANGELOG: '',
|
VERSION_CHANGELOG: '',
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to disabling nonessential traffic to api.anthropic.com
|
// Default to disabling nonessential traffic to api.anthropic.com
|
||||||
// (telemetry, GrowthBook, metrics, MCP registry, etc.)
|
// (telemetry, GrowthBook, metrics, MCP registry, etc.)
|
||||||
// Users can opt back in by setting CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=0
|
// 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
|
// 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)) {
|
if (isEnvTruthy(process.env.CLAUDE_CODE_FORCE_INTERACTIVE)) {
|
||||||
for (const stream of [process.stdin, process.stdout, process.stderr]) {
|
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', {
|
Object.defineProperty(stream, 'isTTY', {
|
||||||
value: true,
|
value: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
})
|
});
|
||||||
} catch {
|
} catch {
|
||||||
// Best-effort dev-only override for nested bun launch on Windows.
|
// 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
|
// Bugfix for corepack auto-pinning, which adds yarnpkg to peoples' package.jsons
|
||||||
// eslint-disable-next-line custom-rules/no-top-level-side-effects
|
// 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)
|
// 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
|
// 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') {
|
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
|
// 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
|
// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
|
||||||
process.env.NODE_OPTIONS = existing
|
process.env.NODE_OPTIONS = existing ? `${existing} --max-old-space-size=8192` : '--max-old-space-size=8192';
|
||||||
? `${existing} --max-old-space-size=8192`
|
|
||||||
: '--max-old-space-size=8192'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Harness-science L0 ablation baseline. Inlined here (not init.ts) because
|
// 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',
|
'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS',
|
||||||
]) {
|
]) {
|
||||||
// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
|
// 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.
|
* Fast-path for --version has zero imports beyond this file.
|
||||||
*/
|
*/
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
const args = process.argv.slice(2)
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
// Fast-path for --version/-v: zero module loading needed
|
// Fast-path for --version/-v: zero module loading needed
|
||||||
if (
|
if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {
|
||||||
args.length === 1 &&
|
|
||||||
(args[0] === '--version' || args[0] === '-v' || args[0] === '-V')
|
|
||||||
) {
|
|
||||||
// MACRO.VERSION is inlined at build time
|
// MACRO.VERSION is inlined at build time
|
||||||
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
||||||
console.log(`${MACRO.VERSION} (CoStrict)`)
|
console.log(`${MACRO.VERSION} (CoStrict)`);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all other paths, load the startup profiler
|
// For all other paths, load the startup profiler
|
||||||
const { profileCheckpoint } = await import('../utils/startupProfiler.js')
|
const { profileCheckpoint } = await import('../utils/startupProfiler.js');
|
||||||
profileCheckpoint('cli_entry')
|
profileCheckpoint('cli_entry');
|
||||||
|
|
||||||
// Fast-path for --dump-system-prompt: output the rendered system prompt and exit.
|
// 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.
|
// Used by prompt sensitivity evals to extract the system prompt at a specific commit.
|
||||||
// Ant-only: eliminated from external builds via feature flag.
|
// Ant-only: eliminated from external builds via feature flag.
|
||||||
if (feature('DUMP_SYSTEM_PROMPT') && args[0] === '--dump-system-prompt') {
|
if (feature('DUMP_SYSTEM_PROMPT') && args[0] === '--dump-system-prompt') {
|
||||||
profileCheckpoint('cli_dump_system_prompt_path')
|
profileCheckpoint('cli_dump_system_prompt_path');
|
||||||
const { enableConfigs } = await import('../utils/config.js')
|
const { enableConfigs } = await import('../utils/config.js');
|
||||||
enableConfigs()
|
enableConfigs();
|
||||||
const { getMainLoopModel } = await import('../utils/model/model.js')
|
const { getMainLoopModel } = await import('../utils/model/model.js');
|
||||||
const modelIdx = args.indexOf('--model')
|
const modelIdx = args.indexOf('--model');
|
||||||
const model = (modelIdx !== -1 && args[modelIdx + 1]) || getMainLoopModel()
|
const model = (modelIdx !== -1 && args[modelIdx + 1]) || getMainLoopModel();
|
||||||
const { getSystemPrompt } = await import('../constants/prompts.js')
|
const { getSystemPrompt } = await import('../constants/prompts.js');
|
||||||
const prompt = await getSystemPrompt([], model)
|
const prompt = await getSystemPrompt([], model);
|
||||||
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
||||||
console.log(prompt.join('\n'))
|
console.log(prompt.join('\n'));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.argv[2] === '--claude-in-chrome-mcp') {
|
if (process.argv[2] === '--claude-in-chrome-mcp') {
|
||||||
profileCheckpoint('cli_claude_in_chrome_mcp_path')
|
profileCheckpoint('cli_claude_in_chrome_mcp_path');
|
||||||
const { runClaudeInChromeMcpServer } = await import(
|
const { runClaudeInChromeMcpServer } = await import('../utils/claudeInChrome/mcpServer.js');
|
||||||
'../utils/claudeInChrome/mcpServer.js'
|
await runClaudeInChromeMcpServer();
|
||||||
)
|
return;
|
||||||
await runClaudeInChromeMcpServer()
|
|
||||||
return
|
|
||||||
} else if (process.argv[2] === '--chrome-native-host') {
|
} else if (process.argv[2] === '--chrome-native-host') {
|
||||||
profileCheckpoint('cli_chrome_native_host_path')
|
profileCheckpoint('cli_chrome_native_host_path');
|
||||||
const { runChromeNativeHost } = await import(
|
const { runChromeNativeHost } = await import('../utils/claudeInChrome/chromeNativeHost.js');
|
||||||
'../utils/claudeInChrome/chromeNativeHost.js'
|
await runChromeNativeHost();
|
||||||
)
|
return;
|
||||||
await runChromeNativeHost()
|
} else if (feature('CHICAGO_MCP') && process.argv[2] === '--computer-use-mcp') {
|
||||||
return
|
profileCheckpoint('cli_computer_use_mcp_path');
|
||||||
} else if (
|
const { runComputerUseMcpServer } = await import('../utils/computerUse/mcpServer.js');
|
||||||
feature('CHICAGO_MCP') &&
|
await runComputerUseMcpServer();
|
||||||
process.argv[2] === '--computer-use-mcp'
|
return;
|
||||||
) {
|
|
||||||
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.
|
// Fast-path for `--acp` — ACP (Agent Client Protocol) agent mode over stdio.
|
||||||
if (feature('ACP') && process.argv[2] === '--acp') {
|
if (feature('ACP') && process.argv[2] === '--acp') {
|
||||||
profileCheckpoint('cli_acp_path')
|
profileCheckpoint('cli_acp_path');
|
||||||
const { runAcpAgent } = await import('../services/acp/entry.js')
|
const { runAcpAgent } = await import('../services/acp/entry.js');
|
||||||
await runAcpAgent()
|
await runAcpAgent();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `--daemon-worker=<kind>` (internal — supervisor spawns this).
|
// Fast-path for `--daemon-worker=<kind>` (internal — supervisor spawns this).
|
||||||
|
|
@ -152,10 +169,10 @@ async function main(): Promise<void> {
|
||||||
// workers are lean. If a worker kind needs configs/auth (assistant will),
|
// workers are lean. If a worker kind needs configs/auth (assistant will),
|
||||||
// it calls them inside its run() fn.
|
// it calls them inside its run() fn.
|
||||||
if (feature('DAEMON') && (args[0] === '--daemon-worker' || args[0]?.startsWith('--daemon-worker='))) {
|
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 kind = args[0] === '--daemon-worker' ? args[1] : args[0].split('=')[1];
|
||||||
const { runDaemonWorker } = await import('../daemon/workerRegistry.js')
|
const { runDaemonWorker } = await import('../daemon/workerRegistry.js');
|
||||||
await runDaemonWorker(kind)
|
await runDaemonWorker(kind);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `claude remote-control` (also accepts legacy `claude remote` / `claude sync` / `claude bridge`):
|
// Fast-path for `claude remote-control` (also accepts legacy `claude remote` / `claude sync` / `claude bridge`):
|
||||||
|
|
@ -170,210 +187,175 @@ async function main(): Promise<void> {
|
||||||
args[0] === 'sync' ||
|
args[0] === 'sync' ||
|
||||||
args[0] === 'bridge')
|
args[0] === 'bridge')
|
||||||
) {
|
) {
|
||||||
profileCheckpoint('cli_bridge_path')
|
profileCheckpoint('cli_bridge_path');
|
||||||
const { enableConfigs } = await import('../utils/config.js')
|
const { enableConfigs } = await import('../utils/config.js');
|
||||||
enableConfigs()
|
enableConfigs();
|
||||||
|
|
||||||
const { getBridgeDisabledReason, checkBridgeMinVersion } = await import(
|
const { getBridgeDisabledReason, checkBridgeMinVersion } = await import('../bridge/bridgeEnabled.js');
|
||||||
'../bridge/bridgeEnabled.js'
|
const { BRIDGE_LOGIN_ERROR } = await import('../bridge/types.js');
|
||||||
)
|
const { bridgeMain } = await import('../bridge/bridgeMain.js');
|
||||||
const { BRIDGE_LOGIN_ERROR } = await import('../bridge/types.js')
|
const { exitWithError } = await import('../utils/process.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,
|
// Auth check must come before the GrowthBook gate check — without auth,
|
||||||
// GrowthBook has no user context and would return a stale/default false.
|
// GrowthBook has no user context and would return a stale/default false.
|
||||||
// getBridgeDisabledReason awaits GB init, so the returned value is fresh
|
// getBridgeDisabledReason awaits GB init, so the returned value is fresh
|
||||||
// (not the stale disk cache), but init still needs auth headers to work.
|
// (not the stale disk cache), but init still needs auth headers to work.
|
||||||
const { getClaudeAIOAuthTokens } = await import('../utils/auth.js')
|
const { getClaudeAIOAuthTokens } = await import('../utils/auth.js');
|
||||||
const { getBridgeAccessToken } = await import('../bridge/bridgeConfig.js')
|
const { getBridgeAccessToken } = await import('../bridge/bridgeConfig.js');
|
||||||
if (!getClaudeAIOAuthTokens()?.accessToken && !getBridgeAccessToken()) {
|
if (!getClaudeAIOAuthTokens()?.accessToken && !getBridgeAccessToken()) {
|
||||||
exitWithError(BRIDGE_LOGIN_ERROR)
|
exitWithError(BRIDGE_LOGIN_ERROR);
|
||||||
}
|
}
|
||||||
const disabledReason = await getBridgeDisabledReason()
|
const disabledReason = await getBridgeDisabledReason();
|
||||||
if (disabledReason) {
|
if (disabledReason) {
|
||||||
exitWithError(`Error: ${disabledReason}`)
|
exitWithError(`Error: ${disabledReason}`);
|
||||||
}
|
}
|
||||||
const versionError = checkBridgeMinVersion()
|
const versionError = checkBridgeMinVersion();
|
||||||
if (versionError) {
|
if (versionError) {
|
||||||
exitWithError(versionError)
|
exitWithError(versionError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bridge is a remote control feature - check policy limits
|
// Bridge is a remote control feature - check policy limits
|
||||||
const { waitForPolicyLimitsToLoad, isPolicyAllowed } = await import(
|
const { waitForPolicyLimitsToLoad, isPolicyAllowed } = await import('../services/policyLimits/index.js');
|
||||||
'../services/policyLimits/index.js'
|
await waitForPolicyLimitsToLoad();
|
||||||
)
|
|
||||||
await waitForPolicyLimitsToLoad()
|
|
||||||
if (!isPolicyAllowed('allow_remote_control')) {
|
if (!isPolicyAllowed('allow_remote_control')) {
|
||||||
exitWithError(
|
exitWithError("Error: Remote Control is disabled by your organization's policy.");
|
||||||
"Error: Remote Control is disabled by your organization's policy.",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await bridgeMain(args.slice(1))
|
await bridgeMain(args.slice(1));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `claude daemon [subcommand]`: unified daemon + session management.
|
// Fast-path for `claude daemon [subcommand]`: unified daemon + session management.
|
||||||
// Handles both supervisor (start/stop) and background session (bg/attach/logs/kill)
|
// Handles both supervisor (start/stop) and background session (bg/attach/logs/kill)
|
||||||
// subcommands under one namespace.
|
// subcommands under one namespace.
|
||||||
if (
|
if ((feature('DAEMON') || feature('BG_SESSIONS')) && args[0] === 'daemon') {
|
||||||
(feature('DAEMON') || feature('BG_SESSIONS')) &&
|
profileCheckpoint('cli_daemon_path');
|
||||||
args[0] === 'daemon'
|
const { enableConfigs } = await import('../utils/config.js');
|
||||||
) {
|
enableConfigs();
|
||||||
profileCheckpoint('cli_daemon_path')
|
const { setShellIfWindows } = await import('../utils/windowsPaths.js');
|
||||||
const { enableConfigs } = await import('../utils/config.js')
|
setShellIfWindows();
|
||||||
enableConfigs()
|
const { initSinks } = await import('../utils/sinks.js');
|
||||||
const { setShellIfWindows } = await import('../utils/windowsPaths.js')
|
initSinks();
|
||||||
setShellIfWindows()
|
const { daemonMain } = await import('../daemon/main.js');
|
||||||
const { initSinks } = await import('../utils/sinks.js')
|
await daemonMain(args.slice(1));
|
||||||
initSinks()
|
return;
|
||||||
const { daemonMain } = await import('../daemon/main.js')
|
|
||||||
await daemonMain(args.slice(1))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `--bg`/`--background` shortcut → daemon bg.
|
// Fast-path for `--bg`/`--background` shortcut → daemon bg.
|
||||||
if (
|
if (feature('BG_SESSIONS') && (args.includes('--bg') || args.includes('--background'))) {
|
||||||
feature('BG_SESSIONS') &&
|
profileCheckpoint('cli_daemon_path');
|
||||||
(args.includes('--bg') || args.includes('--background'))
|
const { enableConfigs } = await import('../utils/config.js');
|
||||||
) {
|
enableConfigs();
|
||||||
profileCheckpoint('cli_daemon_path')
|
const { setShellIfWindows } = await import('../utils/windowsPaths.js');
|
||||||
const { enableConfigs } = await import('../utils/config.js')
|
setShellIfWindows();
|
||||||
enableConfigs()
|
const bg = await import('../cli/bg.js');
|
||||||
const { setShellIfWindows } = await import('../utils/windowsPaths.js')
|
await bg.handleBgStart(args.filter(a => a !== '--bg' && a !== '--background'));
|
||||||
setShellIfWindows()
|
return;
|
||||||
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 <sub> (deprecated)
|
// Backward-compat: ps/logs/attach/kill → daemon <sub> (deprecated)
|
||||||
if (
|
if (
|
||||||
feature('BG_SESSIONS') &&
|
feature('BG_SESSIONS') &&
|
||||||
(args[0] === 'ps' ||
|
(args[0] === 'ps' || args[0] === 'logs' || args[0] === 'attach' || args[0] === 'kill')
|
||||||
args[0] === 'logs' ||
|
|
||||||
args[0] === 'attach' ||
|
|
||||||
args[0] === 'kill')
|
|
||||||
) {
|
) {
|
||||||
const mapped = args[0] === 'ps' ? 'status' : args[0]
|
const mapped = args[0] === 'ps' ? 'status' : args[0];
|
||||||
console.error(
|
console.error(`[deprecated] Use: claude daemon ${mapped}${args[1] ? ' ' + args[1] : ''}`);
|
||||||
`[deprecated] Use: claude daemon ${mapped}${args[1] ? ' ' + args[1] : ''}`,
|
profileCheckpoint('cli_daemon_path');
|
||||||
)
|
const { enableConfigs } = await import('../utils/config.js');
|
||||||
profileCheckpoint('cli_daemon_path')
|
enableConfigs();
|
||||||
const { enableConfigs } = await import('../utils/config.js')
|
const { setShellIfWindows } = await import('../utils/windowsPaths.js');
|
||||||
enableConfigs()
|
setShellIfWindows();
|
||||||
const { setShellIfWindows } = await import('../utils/windowsPaths.js')
|
const { initSinks } = await import('../utils/sinks.js');
|
||||||
setShellIfWindows()
|
initSinks();
|
||||||
const { initSinks } = await import('../utils/sinks.js')
|
const { daemonMain } = await import('../daemon/main.js');
|
||||||
initSinks()
|
await daemonMain([args[0] === 'ps' ? 'status' : args[0]!, ...args.slice(1)]);
|
||||||
const { daemonMain } = await import('../daemon/main.js')
|
return;
|
||||||
await daemonMain([args[0] === 'ps' ? 'status' : args[0]!, ...args.slice(1)])
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `claude job <subcommand>`: template jobs.
|
// Fast-path for `claude job <subcommand>`: template jobs.
|
||||||
if (feature('TEMPLATES') && args[0] === 'job') {
|
if (feature('TEMPLATES') && args[0] === 'job') {
|
||||||
profileCheckpoint('cli_templates_path')
|
profileCheckpoint('cli_templates_path');
|
||||||
const { templatesMain } = await import('../cli/handlers/templateJobs.js')
|
const { templatesMain } = await import('../cli/handlers/templateJobs.js');
|
||||||
await templatesMain(args.slice(1))
|
await templatesMain(args.slice(1));
|
||||||
// process.exit (not return) — mountFleetView's Ink TUI can leave event
|
// process.exit (not return) — mountFleetView's Ink TUI can leave event
|
||||||
// loop handles that prevent natural exit.
|
// loop handles that prevent natural exit.
|
||||||
// eslint-disable-next-line custom-rules/no-process-exit
|
// eslint-disable-next-line custom-rules/no-process-exit
|
||||||
process.exit(0)
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backward-compat: new/list/reply → job <sub> (deprecated)
|
// Backward-compat: new/list/reply → job <sub> (deprecated)
|
||||||
if (
|
if (feature('TEMPLATES') && (args[0] === 'new' || args[0] === 'list' || args[0] === 'reply')) {
|
||||||
feature('TEMPLATES') &&
|
console.error(`[deprecated] Use: claude job ${args[0]} ${args.slice(1).join(' ')}`.trim());
|
||||||
(args[0] === 'new' || args[0] === 'list' || args[0] === 'reply')
|
profileCheckpoint('cli_templates_path');
|
||||||
) {
|
const { templatesMain } = await import('../cli/handlers/templateJobs.js');
|
||||||
console.error(
|
await templatesMain(args);
|
||||||
`[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
|
// eslint-disable-next-line custom-rules/no-process-exit
|
||||||
process.exit(0)
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `claude environment-runner`: headless BYOC runner.
|
// Fast-path for `claude environment-runner`: headless BYOC runner.
|
||||||
// feature() must stay inline for build-time dead code elimination.
|
// feature() must stay inline for build-time dead code elimination.
|
||||||
if (feature('BYOC_ENVIRONMENT_RUNNER') && args[0] === 'environment-runner') {
|
if (feature('BYOC_ENVIRONMENT_RUNNER') && args[0] === 'environment-runner') {
|
||||||
profileCheckpoint('cli_environment_runner_path')
|
profileCheckpoint('cli_environment_runner_path');
|
||||||
const { environmentRunnerMain } = await import(
|
const { environmentRunnerMain } = await import('../environment-runner/main.js');
|
||||||
'../environment-runner/main.js'
|
await environmentRunnerMain(args.slice(1));
|
||||||
)
|
return;
|
||||||
await environmentRunnerMain(args.slice(1))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for `claude self-hosted-runner`: headless self-hosted-runner
|
// Fast-path for `claude self-hosted-runner`: headless self-hosted-runner
|
||||||
// targeting the SelfHostedRunnerWorkerService API (register + poll; poll IS
|
// targeting the SelfHostedRunnerWorkerService API (register + poll; poll IS
|
||||||
// heartbeat). feature() must stay inline for build-time dead code elimination.
|
// heartbeat). feature() must stay inline for build-time dead code elimination.
|
||||||
if (feature('SELF_HOSTED_RUNNER') && args[0] === 'self-hosted-runner') {
|
if (feature('SELF_HOSTED_RUNNER') && args[0] === 'self-hosted-runner') {
|
||||||
profileCheckpoint('cli_self_hosted_runner_path')
|
profileCheckpoint('cli_self_hosted_runner_path');
|
||||||
const { selfHostedRunnerMain } = await import(
|
const { selfHostedRunnerMain } = await import('../self-hosted-runner/main.js');
|
||||||
'../self-hosted-runner/main.js'
|
await selfHostedRunnerMain(args.slice(1));
|
||||||
)
|
return;
|
||||||
await selfHostedRunnerMain(args.slice(1))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-path for --worktree --tmux: exec into tmux before loading full CLI
|
// 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 (
|
if (
|
||||||
hasTmuxFlag &&
|
hasTmuxFlag &&
|
||||||
(args.includes('-w') ||
|
(args.includes('-w') || args.includes('--worktree') || args.some(a => a.startsWith('--worktree=')))
|
||||||
args.includes('--worktree') ||
|
|
||||||
args.some(a => a.startsWith('--worktree=')))
|
|
||||||
) {
|
) {
|
||||||
profileCheckpoint('cli_tmux_worktree_fast_path')
|
profileCheckpoint('cli_tmux_worktree_fast_path');
|
||||||
const { enableConfigs } = await import('../utils/config.js')
|
const { enableConfigs } = await import('../utils/config.js');
|
||||||
enableConfigs()
|
enableConfigs();
|
||||||
const { isWorktreeModeEnabled } = await import(
|
const { isWorktreeModeEnabled } = await import('../utils/worktreeModeEnabled.js');
|
||||||
'../utils/worktreeModeEnabled.js'
|
|
||||||
)
|
|
||||||
if (isWorktreeModeEnabled()) {
|
if (isWorktreeModeEnabled()) {
|
||||||
const { execIntoTmuxWorktree } = await import('../utils/worktree.js')
|
const { execIntoTmuxWorktree } = await import('../utils/worktree.js');
|
||||||
const result = await execIntoTmuxWorktree(args)
|
const result = await execIntoTmuxWorktree(args);
|
||||||
if (result.handled) {
|
if (result.handled) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
// If not handled (e.g., error), fall through to normal CLI
|
// If not handled (e.g., error), fall through to normal CLI
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
const { exitWithError } = await import('../utils/process.js')
|
const { exitWithError } = await import('../utils/process.js');
|
||||||
exitWithError(result.error)
|
exitWithError(result.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect common update flag mistakes to the update subcommand
|
// Redirect common update flag mistakes to the update subcommand
|
||||||
if (
|
if (args.length === 1 && (args[0] === '--update' || args[0] === '--upgrade')) {
|
||||||
args.length === 1 &&
|
process.argv = [process.argv[0]!, process.argv[1]!, 'update'];
|
||||||
(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
|
// --bare: set SIMPLE early so gates fire during module eval / commander
|
||||||
// option building (not just inside the action handler).
|
// option building (not just inside the action handler).
|
||||||
if (args.includes('--bare')) {
|
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
|
// No special flags detected, load and run the full CLI
|
||||||
const { startCapturingEarlyInput } = await import('../utils/earlyInput.js')
|
const { startCapturingEarlyInput } = await import('../utils/earlyInput.js');
|
||||||
startCapturingEarlyInput()
|
startCapturingEarlyInput();
|
||||||
profileCheckpoint('cli_before_main_import')
|
profileCheckpoint('cli_before_main_import');
|
||||||
const { main: cliMain } = await import('../main.jsx')
|
const { main: cliMain } = await import('../main.jsx');
|
||||||
profileCheckpoint('cli_after_main_import')
|
profileCheckpoint('cli_after_main_import');
|
||||||
await cliMain()
|
await cliMain();
|
||||||
profileCheckpoint('cli_after_main_complete')
|
profileCheckpoint('cli_after_main_complete');
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line custom-rules/no-top-level-side-effects
|
// eslint-disable-next-line custom-rules/no-top-level-side-effects
|
||||||
void main()
|
void main();
|
||||||
|
|
|
||||||
|
|
@ -76,9 +76,18 @@ export function getUserSpecifiedModelSetting(): ModelSetting | undefined {
|
||||||
specifiedModel = modelOverride
|
specifiedModel = modelOverride
|
||||||
} else {
|
} else {
|
||||||
const settings = getSettings_DEPRECATED() || {}
|
const settings = getSettings_DEPRECATED() || {}
|
||||||
|
const provider = getAPIProvider()
|
||||||
// Settings.model takes precedence over ANTHROPIC_MODEL env var
|
// Settings.model takes precedence over ANTHROPIC_MODEL env var
|
||||||
// This ensures user's explicit model selection via /login is respected
|
// 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.
|
// Ignore the user-specified model if it's not in the availableModels allowlist.
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from
|
||||||
import { getAPIMetadata } from '../services/api/claude.js'
|
import { getAPIMetadata } from '../services/api/claude.js'
|
||||||
import { getAnthropicClient } from '../services/api/client.js'
|
import { getAnthropicClient } from '../services/api/client.js'
|
||||||
import { getOpenAIClient } from '../services/api/openai/client.js'
|
import { getOpenAIClient } from '../services/api/openai/client.js'
|
||||||
import { resolveOpenAIModel } from '../services/api/openai/modelMapping.js'
|
import { resolveOpenAIModel } from '@ant/model-provider'
|
||||||
import { anthropicMessagesToOpenAI } from '../services/api/openai/convertMessages.js'
|
import { anthropicMessagesToOpenAI } from '@ant/model-provider'
|
||||||
import { createCoStrictFetch } from '../costrict/provider/fetch.js'
|
import { createCoStrictFetch } from '../costrict/provider/fetch.js'
|
||||||
import { loadCoStrictCredentials } from '../costrict/provider/credentials.js'
|
import { loadCoStrictCredentials } from '../costrict/provider/credentials.js'
|
||||||
import { getCoStrictBaseURL } from '../costrict/provider/auth.js'
|
import { getCoStrictBaseURL } from '../costrict/provider/auth.js'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user