qwen-code/scripts/cli-entry.js
jinye 86ecbe04a1
perf(cli): Propagate compile cache to ACP children (#7594)
* perf(cli): propagate compile cache to ACP children

Publish the serve process compile-cache directory so spawned ACP processes can reuse it while preserving user overrides and disabled or unsupported runtimes.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(cli): handle compile cache enable failures

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* codex: address PR review feedback (#7594)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-24 04:06:14 +00:00

383 lines
13 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* @license
* Copyright 2025 Qwen Code
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Production bin entry wrapper.
*
* For most commands: launches the bundled CLI with --expose-gc so that
* global.gc() is available for the memory-pressure monitor's critical-tier
* cleanup.
*
* For bootstrap fast paths: imports cli.js directly in-process, skipping the
* spawnSync overhead. These paths do not need global.gc(); the normal
* interactive path still relaunches with --expose-gc for the memory-pressure
* monitor.
*/
const relaunchArgs = process.env['QWEN_CODE_RELAUNCH_ARGS'];
let cliArgs = process.argv.slice(2);
try {
cliArgs = relaunchArgs ? JSON.parse(relaunchArgs) : cliArgs;
} catch {
// Ignore stale or user-provided junk; normal argv is still usable.
}
delete process.env['QWEN_CODE_RELAUNCH_ARGS'];
delete process.env['QWEN_CODE_PENDING_COMPILE_CACHE'];
function hasFlag(flag, alias) {
for (const arg of cliArgs) {
if (arg === '--') {
return false;
}
if (arg === flag || arg === alias) {
return true;
}
}
return false;
}
function isInProcessFastPath() {
const first = cliArgs[0];
if (first === 'serve' || first === 'mcp') {
return true;
}
if (first === undefined || first.startsWith('-')) {
return hasFlag('--help', '-h') || hasFlag('--version', '-v');
}
return false;
}
const isTopLevelVersion =
(cliArgs[0] === undefined || cliArgs[0].startsWith('-')) &&
hasFlag('--version', '-v');
if (isTopLevelVersion && process.env['CLI_VERSION']) {
process.stdout.write(`${process.env['CLI_VERSION']}\n`);
process.exit(0);
}
const { existsSync, readFileSync, realpathSync, statSync } = await import(
'node:fs'
);
const { createHash } = await import('node:crypto');
const { homedir, tmpdir } = await import('node:os');
const { parseEnv } = await import('node:util');
const { fileURLToPath, pathToFileURL } = await import('node:url');
const { delimiter, dirname, join, parse, resolve, sep } = await import(
'node:path'
);
const __dirname = dirname(fileURLToPath(import.meta.url));
const currentEntryPath = realpathSync(fileURLToPath(import.meta.url));
function getHomeDir() {
try {
return homedir() || tmpdir();
} catch {
return tmpdir();
}
}
function resolveQwenHome() {
const configured = process.env['QWEN_HOME'];
if (!configured) return join(getHomeDir(), '.qwen');
if (configured === '~') return getHomeDir();
if (configured.startsWith('~/') || configured.startsWith('~\\')) {
return join(
getHomeDir(),
...configured
.slice(2)
.split(/[/\\]+/)
.filter(Boolean),
);
}
return resolve(configured);
}
function preResolveQwenHome() {
if (Object.hasOwn(process.env, 'QWEN_HOME')) return;
const home = getHomeDir();
for (const candidate of [join(home, '.qwen', '.env'), join(home, '.env')]) {
try {
const source = readFileSync(candidate, 'utf8')
.replace(/^\uFEFF/, '')
.replace(/^(\s*(?:export\s+)?QWEN_HOME):[^\S\r\n]+/gm, '$1=');
const configured = parseEnv(source)['QWEN_HOME'];
if (configured) {
process.env['QWEN_HOME'] = configured;
return;
}
} catch {
// Match the CLI's quiet handling of missing or invalid home env files.
}
}
}
delete process.env['QWEN_CODE_MANAGED_NPM_UPDATE'];
preResolveQwenHome();
function getManagedNpmPin() {
try {
const pin = JSON.parse(process.env['QWEN_CODE_MANAGED_NPM_PIN'] ?? '');
if (pin.bootstrap !== currentEntryPath) return undefined;
if (
typeof pin.updateRoot !== 'string' ||
resolve(pin.updateRoot) !== pin.updateRoot
) {
return undefined;
}
if (pin.version === null) {
return { version: null, updateRoot: pin.updateRoot };
}
return typeof pin.version === 'string' &&
/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(
pin.version,
)
? { version: pin.version, updateRoot: pin.updateRoot }
: undefined;
} catch {
return undefined;
}
}
const managedNpmPin = getManagedNpmPin();
const managedNpmUpdateRoot =
managedNpmPin?.updateRoot ?? join(resolveQwenHome(), 'updates', 'npm');
function getManagedNpmInstallation() {
try {
if (managedNpmPin?.version === null) return undefined;
const launcherRoot = join(
managedNpmUpdateRoot,
createHash('sha256').update(currentEntryPath).digest('hex').slice(0, 16),
);
let version = managedNpmPin?.version;
if (version === undefined) {
const active = JSON.parse(
readFileSync(join(launcherRoot, 'active.json'), 'utf8'),
);
const basePackageJsonPath = [
join(__dirname, 'package.json'),
join(__dirname, '..', 'package.json'),
].find((candidate) => existsSync(candidate));
if (!basePackageJsonPath) return undefined;
const basePackage = JSON.parse(readFileSync(basePackageJsonPath, 'utf8'));
if (
typeof active.version !== 'string' ||
!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(
active.version,
) ||
typeof active.bootstrap !== 'string' ||
realpathSync(active.bootstrap) !== currentEntryPath ||
active.baseVersion !== basePackage.version ||
active.bootstrapCtimeMs !== statSync(currentEntryPath).ctimeMs
) {
return undefined;
}
version = active.version;
}
const packageRoot = join(
launcherRoot,
'versions',
version,
'node_modules',
'@qwen-code',
'qwen-code',
);
const packageJsonPath = join(packageRoot, 'package.json');
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
const cliPath = join(packageRoot, 'cli.js');
if (
pkg.name !== '@qwen-code/qwen-code' ||
pkg.version !== version ||
!existsSync(cliPath)
) {
return undefined;
}
process.env['QWEN_CODE_MANAGED_NPM_UPDATE'] = 'true';
return { cliPath, packageJsonPath, version };
} catch {
return undefined;
}
}
// The entry a subprocess should call to reach THIS build.
//
// A skill that shells out to `qwen …` gets whatever `qwen` PATH resolves to, which
// is not necessarily the code that launched it: with an older global install on the
// machine, a current-source daemon's `qwen review agent-prompt --role 0` landed in a
// v0.19.10 binary whose `agent-prompt` predates `--role`, and the run died on
// "Missing required argument: chunk". This file is the executable entry and the one
// thing that knows its own path, so it publishes it; `getShellContextEnvVars` passes
// it to every shell subprocess, and a caller prefers it over a bare `qwen`.
//
// Assignment, not `||=`: an inherited value is another session's CLI — an outer
// qwen shelling out to this one — and honouring it re-creates the exact skew above,
// one level up. Each entry stamps itself, so nested sessions each call their own
// build. The managed-version pin keeps nested calls on the running session's build
// even if a background update changes the active pointer. A post-update relaunch
// clears that pin so the launcher's wrapper selects the newly active build.
//
// One exception, and it points the SAME way: the standalone package launches this
// file through a shim (`bin/qwen`) that selects the BUNDLED Node — the host may
// have none — and announces itself via QWEN_CODE_LAUNCHER_PATH. There, "the entry
// that reaches this build" is the shim: stamping this file instead would hand
// subprocesses a `#!/usr/bin/env node` script on a machine where that resolves to
// nothing. Read before the spawn path deletes the variable below.
// Captured AND deleted here, not just read: the serve/mcp fast path below never
// reaches the spawn branch that used to delete it, so the hint leaked into every
// child of a standalone daemon — and a child qwen from a DIFFERENT checkout
// would read the outer shim and republish it as its own entry: the wrong build,
// wearing this one's stamp.
const standaloneShim = process.env['QWEN_CODE_LAUNCHER_PATH'];
delete process.env['QWEN_CODE_LAUNCHER_PATH'];
const managedNpmInstallation = getManagedNpmInstallation();
const validStandaloneShim =
standaloneShim && existsSync(standaloneShim) ? standaloneShim : undefined;
process.env['QWEN_CODE_CLI'] =
validStandaloneShim ?? fileURLToPath(import.meta.url);
if (validStandaloneShim) {
delete process.env['QWEN_CODE_MANAGED_NPM_PIN'];
delete process.env['QWEN_CODE_MANAGED_NPM_ROOT'];
} else {
process.env['QWEN_CODE_MANAGED_NPM_ROOT'] = managedNpmUpdateRoot;
process.env['QWEN_CODE_MANAGED_NPM_PIN'] = JSON.stringify({
bootstrap: currentEntryPath,
version: managedNpmInstallation?.version ?? null,
updateRoot: managedNpmUpdateRoot,
});
}
const cliPathCandidates = [
managedNpmInstallation?.cliPath,
join(__dirname, 'cli.js'),
join(__dirname, '..', 'dist', 'cli.js'),
].filter(Boolean);
const packageJsonPathCandidates = [
managedNpmInstallation?.packageJsonPath,
join(__dirname, 'package.json'),
join(__dirname, '..', 'package.json'),
].filter(Boolean);
const cliPath =
cliPathCandidates.find((candidate) => existsSync(candidate)) ??
cliPathCandidates[0];
const packageJsonPath =
packageJsonPathCandidates.find((candidate) => existsSync(candidate)) ??
packageJsonPathCandidates[0];
if (isTopLevelVersion) {
try {
const { readFileSync } = await import('node:fs');
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
process.stdout.write(`${pkg.version || 'unknown'}\n`);
process.exit(0);
} catch {
// Fall through to cli.js, which has its own version fallback.
}
}
if (isInProcessFastPath()) {
const { default: module } = await import('node:module');
const compileCache = module.enableCompileCache?.();
if (
cliArgs[0] === 'serve' &&
!process.env['NODE_COMPILE_CACHE'] &&
compileCache?.status === module.constants?.compileCacheStatus?.ENABLED &&
compileCache?.directory
) {
process.env['QWEN_CODE_PENDING_COMPILE_CACHE'] = compileCache.directory;
}
process.argv[1] = cliPath;
await import(pathToFileURL(cliPath).href);
} else {
const { spawnSync } = await import('node:child_process');
const UPDATE_COMPLETE_EXIT_CODE = 44;
const launcherNames =
process.platform === 'win32' ? ['qwen.cmd', 'qwen.exe', 'qwen'] : ['qwen'];
const entryPath = resolve(process.argv[1]);
const entryRootLength = parse(entryPath).root.length;
const launcherFromEnv = standaloneShim;
delete process.env['QWEN_CODE_LAUNCHER_PID'];
const launcherCandidates = process.env['PATH']
?.split(delimiter)
.flatMap((dir) => launcherNames.map((name) => join(dir, name)))
.filter((candidate) => existsSync(candidate));
const launcher =
launcherFromEnv && existsSync(launcherFromEnv)
? launcherFromEnv
: launcherCandidates
?.map((candidate) => {
if (resolve(candidate) === entryPath) {
return { candidate, score: Number.MAX_SAFE_INTEGER };
}
try {
if (realpathSync(candidate) === realpathSync(entryPath)) {
return { candidate, score: Number.MAX_SAFE_INTEGER };
}
} catch {
// Fall back to matching the installation prefix.
}
let parent = resolve(dirname(candidate));
while (
parent.length > entryRootLength &&
entryPath !== parent &&
!entryPath.startsWith(`${parent}${sep}`)
) {
const next = dirname(parent);
if (next === parent) break;
parent = next;
}
return { candidate, score: parent.length };
})
.filter(({ score }) => score > entryRootLength)
.sort((a, b) => b.score - a.score)[0]?.candidate;
const env = {
...process.env,
QWEN_CODE_LAUNCHER_PID: String(process.pid),
};
const result = spawnSync(
process.execPath,
['--expose-gc', cliPath, ...cliArgs],
{ stdio: 'inherit', env },
);
if (result.signal) {
process.kill(process.pid, result.signal);
} else if (result.status !== UPDATE_COMPLETE_EXIT_CODE) {
process.exit(result.status ?? 1);
} else {
if (!launcher) {
process.stderr.write(
'Update successful! The new version will be used on your next run.\n',
);
process.exit(0);
}
const relaunchEnv = {
...process.env,
QWEN_CODE_RELAUNCH_ARGS: JSON.stringify(cliArgs),
QWEN_CODE_SKIP_UPDATE_CHECK_ONCE: 'true',
};
delete relaunchEnv['QWEN_CODE_MANAGED_NPM_PIN'];
const relaunchResult =
process.platform === 'win32' && launcher.endsWith('.cmd')
? spawnSync(
process.env['ComSpec'] ?? 'cmd.exe',
['/d', '/s', '/c', `""${launcher}""`],
{ stdio: 'inherit', env: relaunchEnv },
)
: spawnSync(launcher, [], {
stdio: 'inherit',
env: relaunchEnv,
});
if (relaunchResult.signal) {
process.kill(process.pid, relaunchResult.signal);
} else {
process.exit(relaunchResult.status ?? 1);
}
}
}