Skip to content

fix(cli): pass node arguments via NODE_OPTIONS during relaunch to support SEA#26130

Merged
cocosheng-g merged 1 commit intogoogle-gemini:mainfrom
cocosheng-g:sea-arg
Apr 28, 2026
Merged

fix(cli): pass node arguments via NODE_OPTIONS during relaunch to support SEA#26130
cocosheng-g merged 1 commit intogoogle-gemini:mainfrom
cocosheng-g:sea-arg

Conversation

@cocosheng-g
Copy link
Copy Markdown
Contributor

@cocosheng-g cocosheng-g commented Apr 28, 2026

Summary

Fixes the issue where Node.js arguments (like --max-old-space-size) were incorrectly parsed as application arguments when running the CLI as a Single Executable Application (SEA).

Details

When Node.js is run as a SEA, process.execPath is the binary itself. Passing Node.js flags as command-line arguments to the binary causes them to be passed to the application's argument parser (yargs), which fails with an "Unknown argument" error.

This PR implements a robust, simplified design to address this and subsequent architectural findings:

  • Moved Node.js flags to NODE_OPTIONS (SEA only): When relaunching in SEA mode, newly calculated Node.js flags (like memory auto-config) are appended to the NODE_OPTIONS environment variable instead of being passed as command-line arguments. This ensures they are consumed by the runtime and never reach yargs.
  • Fixed Compounding Argument Duplication: A critical bug was identified where consecutive relaunches caused arguments to compound indefinitely (e.g., gemini start start start). This was fixed by explicitly injecting process.execPath as the argv[1] placeholder for the child process, guaranteeing the argv[0] === argv[1] invariant and breaking the cycle.
  • Robust SEA Detection: SEA detection was refined to accurately handle both the initial standard SEA execution (where user args start at argv[1]) and subsequent relaunches. It safely falls back to Node.js's native process.isSea?.() and argv[0] === argv[1].
  • Strict Argument Validation: Because the CLI only dynamically adds simple flags (e.g., --max-old-space-size=X), the relaunch logic now explicitly throws a clear error if a flag contains a space, single quote, double quote, or backslash. This guarantees we never encounter a silent NODE_OPTIONS parsing failure in production and avoids fragile string-escaping logic.
  • Centralized Logic: Extracted and DRY'd up isStandardSea, getScriptArgs, and getSpawnConfig into the shared processUtils.ts utility. The ProcessWithSea interface was also exported to eliminate any casting.
  • Reliable Testing: Completely refactored the test environment to use vi.stubEnv instead of directly mutating process.env. NODE_OPTIONS is also explicitly stubbed to prevent test failures on Windows CI runners that inject their own global memory flags.

Related Issues

Fixes #24591

How to Validate

  1. Build the binary using npm run build:binary
  2. Run the binary from the output directory (e.g., ./dist/darwin-arm64/gemini --version). It should execute successfully without an unknown argument error.
  3. Validate standard node execution via npm run start -- --version.
  4. Validate manual relaunch by running the CLI interactively (npm run start), opening /settings, toggling a setting (e.g., UI -> "Show Line Numbers"), and exiting the settings menu. The CLI should successfully restart without duplicating the executed command.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@cocosheng-g cocosheng-g requested a review from a team as a code owner April 28, 2026 17:12
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where Node.js flags were being incorrectly interpreted as application arguments when running as a Single Executable Application. By shifting the responsibility of passing these flags to the NODE_OPTIONS environment variable, the application ensures that the underlying Node.js runtime receives the necessary configuration without interfering with the application's own argument parsing logic.

Highlights

  • Node.js Argument Handling: Modified the relaunch logic to pass Node.js flags via the NODE_OPTIONS environment variable instead of command-line arguments.
  • SEA Compatibility: Ensured that Single Executable Applications (SEA) do not incorrectly parse Node.js flags as application arguments, preventing 'Unknown argument' errors.
  • Test Updates: Updated existing tests in relaunch.test.ts to reflect the new environment-based argument passing mechanism.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request modifies the mechanism for passing additional Node.js arguments during process relaunch. Instead of appending arguments like memory settings directly to the command-line array, they are now injected into the NODE_OPTIONS environment variable, ensuring existing options are preserved. These changes are implemented in the CLI entry point and the relaunch utility, with comprehensive updates to the test suite to verify the correct environment configuration. I have no feedback to provide as no review comments were submitted.

@gemini-cli gemini-cli Bot added the area/core Issues related to User Interface, OS Support, Core Functionality label Apr 28, 2026
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

@cocosheng-g cocosheng-g self-assigned this Apr 28, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the CLI relaunch logic to support a standalone binary (SEA) mode by moving Node.js flags into the NODE_OPTIONS environment variable, while maintaining standard command-line argument passing for non-binary execution. Corresponding updates were made to the test suite to validate both modes. I have identified a potential issue where joining arguments with a space in NODE_OPTIONS will fail if any argument contains a space; I have provided a suggestion to escape these spaces correctly.

Comment thread packages/cli/index.ts Outdated
Comment thread packages/cli/src/utils/relaunch.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Comment thread packages/cli/index.ts Fixed
Comment thread packages/cli/src/utils/relaunch.test.ts Fixed
Comment thread packages/cli/src/utils/relaunch.ts Fixed
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements support for Single Executable Application (SEA) mode by transitioning Node.js flags to the NODE_OPTIONS environment variable when the IS_BINARY flag is enabled. Review feedback identifies that the current escaping logic for spaces in NODE_OPTIONS using backslashes is incorrect for the Node.js runtime and should be replaced with double quotes. Additionally, the test suite requires refactoring to avoid re-implementing production logic within test cases, which currently results in fragile change-detector tests and inconsistencies between the test simulations and the actual implementation.

Comment thread packages/cli/index.ts Outdated
Comment thread packages/cli/src/utils/relaunch.ts Outdated
Comment thread packages/cli/src/utils/relaunch.test.ts Outdated
Comment thread packages/cli/src/utils/relaunch.test.ts Outdated
Comment thread packages/cli/index.ts Fixed
Comment thread packages/cli/src/utils/relaunch.ts Fixed
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for Single Executable Application (SEA) mode by moving Node.js arguments into the NODE_OPTIONS environment variable when the IS_BINARY environment variable is set. This logic is implemented in both the main CLI entry point and the relaunch utility, with corresponding updates to the test suite. Review feedback highlighted a bug in the NODE_OPTIONS escaping logic where backslashes are incorrectly escaped in unquoted strings, which could break Windows paths. Additionally, it was recommended to extract this duplicated escaping logic into a shared utility to improve maintainability.

Comment thread packages/cli/index.ts Outdated
Comment thread packages/cli/src/utils/relaunch.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for Single Executable Application (SEA) mode by routing Node.js flags through the NODE_OPTIONS environment variable when the IS_BINARY flag is set. Review feedback identifies a bug in the formatNodeOptions utility, which incorrectly doubles backslashes that the Node.js runtime does not unescape. Additionally, the reviewer recommends encapsulating duplicated relaunch logic found in both index.ts and relaunch.ts, replacing hardcoded exit codes with imported constants, and correcting test expectations to ensure proper argument formatting.

Comment thread packages/cli/src/utils/processUtils.ts Outdated
Comment thread packages/cli/index.ts Outdated
Comment thread packages/cli/index.ts Outdated
Comment thread packages/cli/index.ts Outdated
Comment thread packages/cli/src/utils/relaunch.test.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Comment thread packages/cli/src/utils/processUtils.ts Fixed
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the CLI's process relaunch mechanism by introducing a centralized getSpawnConfig utility that handles environment and argument construction for both standard Node.js and Single Executable Application (SEA) modes. It also includes a new formatNodeOptions helper for escaping arguments within the NODE_OPTIONS environment variable. Review feedback identified a bug in formatNodeOptions where trailing backslashes could break quote escaping and suggested avoiding the duplication of inherited flags in SEA mode to prevent exceeding environment variable length limits.

Comment thread packages/cli/src/utils/processUtils.ts Outdated
Comment thread packages/cli/src/utils/processUtils.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Comment thread packages/cli/src/utils/processUtils.ts Fixed
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the process relaunch logic to support Single Executable Application (SEA) binary mode. It introduces getSpawnConfig and formatNodeOptions in processUtils.ts to handle argument construction and environment variable configuration differently for standard Node and binary modes. In binary mode, node arguments are now passed via the NODE_OPTIONS environment variable with proper escaping and quoting, while standard mode continues to use command-line arguments. I have no feedback to provide.

@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a getSpawnConfig utility to handle process relaunching logic, specifically addressing differences between standard Node.js execution and Single Executable Application (SEA) binary mode. The changes refactor the argument construction in relaunchAppInChildProcess to use this new utility and include updated tests. The reviewer highlighted concerns regarding the fragility of joining nodeArgs with spaces in NODE_OPTIONS and the reliability of using an environment variable (IS_BINARY) for environment detection, suggesting more robust alternatives.

Comment thread packages/cli/src/utils/processUtils.ts
Comment thread packages/cli/src/utils/processUtils.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the process relaunch logic by introducing a centralized getSpawnConfig utility to handle both standard Node.js and Single Executable Application (SEA) binary modes. The changes ensure that Node arguments are correctly passed via NODE_OPTIONS in SEA mode. Feedback was provided to strengthen the validation of unsupported characters in nodeArgs to prevent injection and to adhere to the project's style guide by using vi.stubEnv instead of direct process.env modification in tests.

Comment thread packages/cli/src/utils/processUtils.ts Outdated
Comment thread packages/cli/src/utils/relaunch.test.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the process relaunch logic into a centralized getSpawnConfig utility to support Single Executable Application (SEA) binary modes. It also updates the test suite to use Vitest's environment stubbing utilities as per the style guide. Review feedback highlights the need for more robust SEA detection using process.isSea(), maintaining a consistent argv structure (preserving the slice(2) expectation) when spawning child processes in binary mode, and correctly handling argument slicing in the main entry point for standard SEA binaries.

Comment thread packages/cli/src/utils/processUtils.ts Outdated
Comment thread packages/cli/src/utils/processUtils.ts Outdated
Comment thread packages/cli/index.ts Outdated
@cocosheng-g
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for Single Executable Application (SEA) binary mode by centralizing process spawning logic into a new getSpawnConfig utility. In SEA mode, Node-specific arguments are now correctly passed via the NODE_OPTIONS environment variable to ensure they are processed by the runtime. Additionally, the test suite has been refactored to adhere to the repository style guide by using vi.stubEnv and vi.unstubAllEnvs for environment variable management. I have no feedback to provide as there were no review comments to assess.

@cocosheng-g cocosheng-g force-pushed the sea-arg branch 2 times, most recently from c78f60c to 749a73e Compare April 28, 2026 20:07
Copy link
Copy Markdown
Contributor

@devr0306 devr0306 left a comment

Choose a reason for hiding this comment

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

from /review-frontend

Review Summary

The PR successfully addresses the issue by appropriately routing Node arguments through the NODE_OPTIONS environment variable when running in SEA (Single Executable Application) mode. The implementation also includes solid validation to prevent injection vulnerabilities by blocking complex arguments with spaces or quotes.

However, there is a critical logic flaw in how script arguments are passed to the child process that will cause compounding argument duplication upon consecutive relaunches.

Findings

Critical: Compounding Argument Duplication

The interaction between isStandardSea and the script placeholder in getSpawnConfig can create a compounding argument duplication bug if the app is relaunched more than once (e.g., a restart triggered from within the application).

The Scenario:

  1. A user runs gemini my-cmd. process.argv is ['/bin/gemini', 'my-cmd'].
  2. isStandardSea evaluates to true, so scriptArgs is parsed as ['my-cmd'].
  3. In getSpawnConfig, it uses process.argv[1] ?? process.execPath as the placeholder. Because process.argv[1] is 'my-cmd', finalSpawnArgs becomes ['my-cmd', 'my-cmd'].
  4. The spawned child process receives process.argv = ['/bin/gemini', 'my-cmd', 'my-cmd']. The CLI parser works fine here because it ignores the first two elements (slice(2)).
  5. The Bug: If that child process needs to relaunch again, it will check argv[0] !== argv[1] ('/bin/gemini' !== 'my-cmd'), which means isStandardSea evaluates to true again! It will incorrectly slice from index 1, capturing ['my-cmd', 'my-cmd'] as the scriptArgs, and pass those forward. The arguments will compound indefinitely on each relaunch.

Suggested Fixes:

  1. In packages/cli/src/utils/processUtils.ts, always use process.execPath as the explicit placeholder instead of dynamically using process.argv[1]. This guarantees argv[0] === argv[1] in the child process, breaking the cycle.
    // Change:
    // finalSpawnArgs.push(process.argv[1] ?? process.execPath, ...scriptArgs);
    
    // To:
    finalSpawnArgs.push(process.execPath, ...scriptArgs);
  2. In index.ts and relaunch.ts, group the argv[0] !== argv[1] check so that it applies to both IS_BINARY and isSea(). This ensures the child properly identifies the injected placeholder even if Node native process.isSea() is true.
    const isStandardSea =
      process.argv[0] !== process.argv[1] &&
      (process.env['IS_BINARY'] === 'true' || (process as ProcessWithSea).isSea?.() === true);

Improvement: DRY up SEA Detection

The ProcessWithSea interface and the SEA detection logic (isStandardSea / isBinary) are currently duplicated across index.ts, relaunch.ts, and processUtils.ts. Consider extracting a shared helper function (e.g., getScriptArgs and isStandardSea) into processUtils.ts to consolidate this logic.

Conclusion

Status: Request Changes
The core strategy of utilizing NODE_OPTIONS is solid, but the script argument passing logic needs to be corrected to prevent the compounding argument bug.

@cocosheng-g cocosheng-g force-pushed the sea-arg branch 2 times, most recently from fd51f4c to 1e9a59e Compare April 28, 2026 20:42
Copy link
Copy Markdown
Contributor

@devr0306 devr0306 left a comment

Choose a reason for hiding this comment

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

minor nit but approving

Comment thread packages/cli/src/utils/processUtils.ts Outdated
…port SEA

This fixes the issue where Node.js arguments like --max-old-space-size were incorrectly parsed as application arguments when running as a Single Executable Application (SEA).

Fixes google-gemini#24591
@cocosheng-g cocosheng-g enabled auto-merge April 28, 2026 21:02
@cocosheng-g cocosheng-g added this pull request to the merge queue Apr 28, 2026
Merged via the queue into google-gemini:main with commit 12a77da Apr 28, 2026
28 checks passed
@cocosheng-g cocosheng-g deleted the sea-arg branch April 28, 2026 21:30
TirthNaik-99 pushed a commit to TirthNaik-99/gemini-cli that referenced this pull request May 4, 2026
kimjune01 pushed a commit to kimjune01/gemini-cli-claude that referenced this pull request May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] SEA - Unknown arguments: max-old-space-size, maxOldSpaceSize

3 participants