Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 25 additions & 14 deletions scripts/cli-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,40 @@
/**
* Production bin entry wrapper.
*
* Launches dist/cli.js with --expose-gc so that global.gc() is available
* for the memory-pressure monitor's critical-tier cleanup.
* For most commands: launches dist/cli.js with --expose-gc so that
* global.gc() is available for the memory-pressure monitor's critical-tier
* cleanup.
*
* --expose-gc only exposes the function; it has zero runtime cost.
* global.gc() is called only when RSS hits the critical threshold (0.80),
* where the 10-200 ms pause is acceptable to avoid an OOM kill.
* For `qwen serve`: imports cli.js directly in-process, skipping the
* spawnSync overhead (~370ms on EDR-instrumented hosts). The daemon host
* process never calls global.gc() — only its ACP children do, and they
* independently add --expose-gc via spawnChannel.ts.
*/

import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { dirname, join } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const cliPath = join(__dirname, '..', 'dist', 'cli.js');

const result = spawnSync(
process.execPath,
['--expose-gc', cliPath, ...process.argv.slice(2)],
{ stdio: 'inherit' },
);
function isServeCommand() {
return process.argv[2] === 'serve';
}

if (result.signal) {
process.kill(process.pid, result.signal);
if (isServeCommand()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The new fast path is only exercised by the production bin wrapper, but the current tests still invoke dist/cli.js or packages/cli/dist/index.js directly. That leaves this wrapper branch untested, so a regression where serve still takes the spawn path, process.argv[1] is not rewritten for ACP children, or the generated package wrapper drifts from this checked-in wrapper would not fail the serve integration suite.

A focused script/package test that runs a temporary wrapper for both serve and a non-serve argv shape, plus an assertion on the preparePackage()-generated dist/cli-entry.js, would cover the behavior changed here.

— GPT-5 via Qwen Code /review

process.argv[1] = cliPath;
await import(pathToFileURL(cliPath).href);
} else {
process.exit(result.status ?? 1);
const result = spawnSync(
process.execPath,
['--expose-gc', cliPath, ...process.argv.slice(2)],
{ stdio: 'inherit' },
);

if (result.signal) {
process.kill(process.pid, result.signal);
} else {
process.exit(result.status ?? 1);
}
}
27 changes: 18 additions & 9 deletions scripts/prepare-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,31 @@ function writeDistPackageJson(

const cliEntryContent = `#!/usr/bin/env node
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { dirname, join } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const cliPath = join(__dirname, 'cli.js');

const result = spawnSync(
process.execPath,
['--expose-gc', cliPath, ...process.argv.slice(2)],
{ stdio: 'inherit' },
);
function isServeCommand() {
return process.argv[2] === 'serve';
}

if (result.signal) {
process.kill(process.pid, result.signal);
if (isServeCommand()) {
process.argv[1] = cliPath;
await import(pathToFileURL(cliPath).href);
} else {
process.exit(result.status ?? 1);
const result = spawnSync(
process.execPath,
['--expose-gc', cliPath, ...process.argv.slice(2)],
{ stdio: 'inherit' },
);

if (result.signal) {
process.kill(process.pid, result.signal);
} else {
process.exit(result.status ?? 1);
}
}
`;

Expand Down
Loading