Skip to content

fix(cli): scrub CI env vars in dev mode to prevent interactive hang#25260

Open
KeWang0622 wants to merge 2 commits intogoogle-gemini:mainfrom
KeWang0622:fix/ci-env-scrub-dev-mode
Open

fix(cli): scrub CI env vars in dev mode to prevent interactive hang#25260
KeWang0622 wants to merge 2 commits intogoogle-gemini:mainfrom
KeWang0622:fix/ci-env-scrub-dev-mode

Conversation

@KeWang0622
Copy link
Copy Markdown

Summary

Fixes #22452

The bundled build patches is-in-ci via an esbuild alias (see esbuild.config.js line 104) so that ink stays in interactive mode regardless of CI env vars. However, npm run start (the dev server) bypasses esbuild and runs TypeScript directly, so the alias never applies.

When CI or CONTINUOUS_INTEGRATION is set in the developer's shell — common for contributors working in CI-adjacent environments like GitLab runners, Jenkins, or any tool that sets CI=trueink switches to non-interactive mode and the CLI hangs indefinitely after displaying the ASCII art header, with no error message.

Changes

  • scripts/scrub-ci-env.js — New utility that removes CI and CONTINUOUS_INTEGRATION from an env object in-place, respecting the same falsy-value semantics ('0', 'false') that is-in-ci v2 uses.
  • scripts/start.js — Import and call scrubCiEnv(env) before spawning the child process; print a warning to stderr when vars are scrubbed so developers know why their vars are missing.
  • scripts/tests/scrub-ci-env.test.js — 7 unit tests covering truthy values, falsy values ('0', 'false'), empty string, both vars set, and no vars present.

Why not just delete the env vars inline?

Extracting to a separate module makes the scrubbing logic independently testable and keeps start.js readable. The utility mirrors the exact check that is-in-ci v2 performs (key in env && env[key] !== '0' && env[key] !== 'false'), so it stays correct even if the detection logic evolves.

Test plan

  • 7 new unit tests in scripts/tests/scrub-ci-env.test.js — all pass
  • Full scripts test suite (npx vitest run --config scripts/tests/vitest.config.ts) — 50/50 pass
  • Full unit test suite (npm run test) — all pass
  • Lint (npm run lint) — clean
  • Pre-commit hooks — clean
  • Manual verification: CI=true npm run start now shows the interactive prompt instead of hanging

The bundled build patches `is-in-ci` via an esbuild alias so that `ink`
stays in interactive mode regardless of CI env vars. However, `npm run
start` (the dev server) bypasses esbuild and runs TypeScript directly,
so the alias never applies. When `CI` or `CONTINUOUS_INTEGRATION` is
set in the shell (common for contributors working in CI-adjacent
environments), `ink` switches to non-interactive mode and the CLI hangs
after the ASCII art header.

Extract a `scrubCiEnv` utility that strips these vars from the child
process environment, print a warning to stderr when scrubbing occurs,
and add 7 unit tests covering the truthy/falsy/absent cases.

Fixes google-gemini#22452
@KeWang0622 KeWang0622 requested a review from a team as a code owner April 13, 2026 08:20
@google-cla
Copy link
Copy Markdown

google-cla bot commented Apr 13, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@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 the development server would hang indefinitely when running in environments where CI-related environment variables are set. By stripping these variables before spawning the child process, the CLI is prevented from incorrectly switching to non-interactive mode, thereby restoring expected functionality for contributors.

Highlights

  • CI Environment Variable Scrubbing: Introduced a new utility, scrubCiEnv, to remove CI and CONTINUOUS_INTEGRATION environment variables from the development server process.
  • Dev Server Fix: Updated scripts/start.js to utilize the new utility, ensuring the CLI remains in interactive mode even when CI-related environment variables are present in the host shell.
  • Comprehensive Testing: Added a new test suite in scripts/tests/scrub-ci-env.test.js covering various scenarios, including truthy/falsy values and empty strings.
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 introduces a utility to scrub CI-related environment variables when running the development server to ensure the terminal remains interactive. A review comment points out that the environment variables should be deleted even if they are set to "0" or "false" because the mere presence of these keys can still trigger non-interactive mode in some libraries.

Comment thread scripts/scrub-ci-env.js Outdated
Comment on lines +34 to +37
if (key in env && env[key] !== '0' && env[key] !== 'false') {
scrubbed.push(key);
delete env[key];
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The logic to preserve '0' and 'false' values is likely incorrect and will not prevent the interactive hang in most environments.

Most common implementations of is-in-ci (including the one used by ink via is-interactive) check for the existence of the key ('CI' in env) or its truthiness as a string (!!env.CI). In Node.js, process.env values are always strings, and both '0' and 'false' are truthy strings. Consequently, if these variables are left in the environment, is-in-ci will still return true, and the CLI will continue to hang.

To ensure interactive mode is enabled while still allowing users to suppress the warning as intended by the message in start.js, the variables should be removed from the environment regardless of their value, but only added to the scrubbed list if they are not '0' or 'false'.

    if (key in env) {
      const value = env[key];
      if (value !== '0' && value !== 'false') {
        scrubbed.push(key);
      }
      delete env[key];
    }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch — you're absolutely right. is-in-ci checks key existence ('CI' in env), so '0' and 'false' still trigger CI detection since they're truthy strings in Node.js.

Fixed in 92bf17c: we now always delete env[key], but only push to the scrubbed warning list when the value is meaningful (not '0' or 'false'). Tests updated accordingly — all 7 pass.

`is-in-ci` checks key existence (`'CI' in env`), not the value.
In Node.js, `'0'` and `'false'` are truthy strings, so leaving
them in the environment still triggers CI detection and causes
the interactive CLI to hang.

Now we always delete CI/CONTINUOUS_INTEGRATION from the env, but
only add to the scrubbed warning list when the value was meaningful
(not '0' or 'false'), so callers can still suppress the warning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gemini-cli gemini-cli bot added area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels Apr 13, 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 help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: CI_* env var scrub not applied in dev mode (npm run start) — interactive mode hangs

2 participants