fix(cli): route SEA relaunch flags through NODE_OPTIONS

This commit is contained in:
lawrence3699 2026-04-17 18:58:13 +10:00
parent 22fb83320e
commit f590a2c55e
No known key found for this signature in database
4 changed files with 132 additions and 24 deletions

View file

@ -9,6 +9,7 @@
import { spawn } from 'node:child_process';
import os from 'node:os';
import v8 from 'node:v8';
import { buildRelaunchSpawnSpec } from './src/utils/relaunchSpawnSpec.js';
// --- Global Entry Point ---
@ -74,17 +75,14 @@ async function run() {
// --- Lightweight Parent Process / Daemon ---
// We avoid importing heavy dependencies here to save ~1.5s of startup time.
const nodeArgs: string[] = [...process.execArgv];
const scriptArgs = process.argv.slice(2);
const memoryArgs = await getMemoryNodeArgs();
nodeArgs.push(...memoryArgs);
const script = process.argv[1];
nodeArgs.push(script);
nodeArgs.push(...scriptArgs);
const newEnv = { ...process.env, GEMINI_CLI_NO_RELAUNCH: 'true' };
const { args: relaunchArgs, env: newEnv } = buildRelaunchSpawnSpec({
additionalNodeArgs: memoryArgs,
additionalScriptArgs: [],
argv: process.argv,
env: process.env,
execArgv: process.execArgv,
});
const RELAUNCH_EXIT_CODE = 199;
let latestAdminSettings: unknown = undefined;
@ -97,7 +95,7 @@ async function run() {
const runner = () => {
process.stdin.pause();
const child = spawn(process.execPath, nodeArgs, {
const child = spawn(process.execPath, relaunchArgs, {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
env: newEnv,
});

View file

@ -10,6 +10,7 @@ import {
writeToStderr,
type AdminControlsSettings,
} from '@google/gemini-cli-core';
import { buildRelaunchSpawnSpec } from './relaunchSpawnSpec.js';
export async function relaunchOnExitCode(runner: () => Promise<number>) {
while (true) {
@ -43,19 +44,13 @@ export async function relaunchAppInChildProcess(
let latestAdminSettings = remoteAdminSettings;
const runner = () => {
// process.argv is [node, script, ...args]
// We want to construct [ ...nodeArgs, script, ...scriptArgs]
const script = process.argv[1];
const scriptArgs = process.argv.slice(2);
const nodeArgs = [
...process.execArgv,
...additionalNodeArgs,
script,
...additionalScriptArgs,
...scriptArgs,
];
const newEnv = { ...process.env, GEMINI_CLI_NO_RELAUNCH: 'true' };
const { args: nodeArgs, env: newEnv } = buildRelaunchSpawnSpec({
additionalNodeArgs,
additionalScriptArgs,
argv: process.argv,
env: process.env,
execArgv: process.execArgv,
});
// The parent process should not be reading from stdin while the child is running.
process.stdin.pause();

View file

@ -0,0 +1,57 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, expect, it } from 'vitest';
import { buildRelaunchSpawnSpec } from './relaunchSpawnSpec.js';
describe('buildRelaunchSpawnSpec', () => {
it('preserves node-style relaunch arguments for source installs', () => {
const { args, env } = buildRelaunchSpawnSpec({
additionalNodeArgs: ['--max-old-space-size=4096'],
additionalScriptArgs: ['--model', 'gemini-2.5-pro'],
argv: ['/usr/bin/node', '/app/cli.js', 'command', '--verbose'],
env: { PATH: '/usr/bin' },
execArgv: ['--inspect=9229'],
});
expect(args).toEqual([
'--inspect=9229',
'--max-old-space-size=4096',
'/app/cli.js',
'--model',
'gemini-2.5-pro',
'command',
'--verbose',
]);
expect(env).toMatchObject({
GEMINI_CLI_NO_RELAUNCH: 'true',
PATH: '/usr/bin',
});
expect(env['NODE_OPTIONS']).toBeUndefined();
});
it('moves node flags into NODE_OPTIONS for standalone binaries', () => {
const { args, env } = buildRelaunchSpawnSpec({
additionalNodeArgs: ['--max-old-space-size=4096'],
additionalScriptArgs: ['--model', 'gemini-2.5-pro'],
argv: ['/tmp/gemini', '/tmp/gemini', '--verbose'],
env: {
IS_BINARY: 'true',
NODE_OPTIONS: '--trace-warnings',
PATH: '/usr/bin',
},
execArgv: ['--inspect=9229'],
});
expect(args).toEqual(['--model', 'gemini-2.5-pro', '--verbose']);
expect(env).toMatchObject({
GEMINI_CLI_NO_RELAUNCH: 'true',
IS_BINARY: 'true',
NODE_OPTIONS: '--trace-warnings --max-old-space-size=4096',
PATH: '/usr/bin',
});
});
});

View file

@ -0,0 +1,58 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
export interface BuildRelaunchSpawnSpecParams {
additionalNodeArgs: string[];
additionalScriptArgs: string[];
argv: string[];
env: NodeJS.ProcessEnv;
execArgv: string[];
}
export interface RelaunchSpawnSpec {
args: string[];
env: NodeJS.ProcessEnv;
}
export function buildRelaunchSpawnSpec({
additionalNodeArgs,
additionalScriptArgs,
argv,
env,
execArgv,
}: BuildRelaunchSpawnSpecParams): RelaunchSpawnSpec {
const scriptArgs = argv.slice(2);
const newEnv: NodeJS.ProcessEnv = {
...env,
GEMINI_CLI_NO_RELAUNCH: 'true',
};
if (env['IS_BINARY'] === 'true') {
if (additionalNodeArgs.length > 0) {
newEnv['NODE_OPTIONS'] = [newEnv['NODE_OPTIONS'], ...additionalNodeArgs]
.filter(Boolean)
.join(' ');
}
return {
args: [...additionalScriptArgs, ...scriptArgs],
env: newEnv,
};
}
const script = argv[1];
return {
args: [
...execArgv,
...additionalNodeArgs,
script,
...additionalScriptArgs,
...scriptArgs,
],
env: newEnv,
};
}