hangs indefinitely when executed from Node.js `child_process` (subprocess)

### What happened?

Gemini CLI version 0.1.22 hangs indefinitely when executed from Node.js `child_process` (subprocess), while the exact same commands work perfectly when run directly from a terminal. This is a regression that breaks subprocess integration for automation tools and MCP servers.

## Actual Behavior

When executed as a subprocess:
1. ✅ Authenticates successfully
2. ✅ Prints "Data collection is disabled."
3. ❌ **Hangs indefinitely** - no further output or response
4. ❌ Does not respond to stdin input
5. ❌ Must be killed with SIGTERM

The **exact same command works perfectly** when run directly in a terminal.

### What did you expect to happen?

When executed as a subprocess with command-line arguments (e.g., `gemini -y -m gemini-2.5-flash -p "hello"`), the CLI should:
1. Authenticate successfully
2. Process the prompt 
3. Return the response
4. Exit normally


### Client information

- **Gemini CLI Version**: 0.1.22
- **Operating System**: Linux Mint 21.3 (also affects other Linux distributions)
- **Node.js Version**: v20.19.2
- **Authentication**: OAuth (working - not an auth issue)

### Login information

0auth

### Anything else we need to know?


## Reproduction Steps

### Working (Terminal)
```bash
gemini -y -m gemini-2.5-flash -p "can you hear me?"
# Output: Works perfectly, returns response immediately
```

### Broken (Node.js Subprocess)
```javascript
const { spawn } = require('child_process');

const child = spawn('gemini', ['-y', '-m', 'gemini-2.5-flash', '-p', 'can you hear me?'], {
    stdio: ['pipe', 'pipe', 'pipe']
});

child.stdout.on('data', (data) => {
    console.log('[STDOUT]', data.toString());
    // Only outputs: "Data collection is disabled.\n"
    // Then hangs forever
});

child.stderr.on('data', (data) => {
    console.log('[STDERR]', data.toString());
});

// Process never exits, must be killed manually
```

### Testing Commands

You can reproduce this issue with any Node.js subprocess execution:

```bash
# This hangs in subprocess but works in terminal:
CLI_PERSONA_NAME=test GEMINI_LOGGING=/tmp GEMINI_SYSTEM_MD=/tmp/test.md gemini -y -m gemini-2.5-flash --include-directories /home/user -p "hello"

# Simple version that also hangs:
echo "test" | gemini -y -m gemini-2.5-flash -p "hello"  # Works in terminal
node -e "require('child_process').spawn('gemini', ['-y', '-m', 'gemini-2.5-flash', '-p', 'hello'])" # Hangs
```

## Root Cause Analysis

After investigating the code differences between 0.1.20 (working) and 0.1.22 (broken), we identified the regression in `packages/cli/src/gemini.tsx`:

### Version 0.1.20 (Working)
```typescript
if (!process.stdin.isTTY && !input) { // Note the `&& !input` condition
  input += await readStdin();
}
```

### Version 0.1.22 (Broken) 
```typescript
if (!process.stdin.isTTY) { // Condition changed: `&& !input` removed
  const stdinData = await readStdin();
  if (stdinData) {
    input = `${stdinData}\n${input}`;
  }
}
```

## Technical Details

1. **Non-TTY Environment**: Node.js subprocess sets `process.stdin.isTTY = false`
2. **Removed Condition**: The `&& !input` condition was removed in 0.1.22
3. **Blocking Call**: `readStdin()` now always executes in subprocess and waits indefinitely for input
4. **No EOF Signal**: Node.js parent process doesn't send EOF to child stdin by default

## Impact

This regression breaks:
- **Automation tools** that spawn Gemini CLI as subprocess
- **MCP servers** using Gemini CLI backend  
- **CI/CD pipelines** with Gemini CLI integration
- **Any programmatic usage** of Gemini CLI

## Workarounds for Affected Users

### For Node.js Applications

#### Method 1: spawn() with stdin.end() (Recommended)
```javascript
const { spawn } = require('child_process');

function runGeminiWithWorkaround(args, prompt) {
    return new Promise((resolve, reject) => {
        const child = spawn('gemini', ['-y', '-m', 'gemini-2.5-flash', '-p', prompt], {
            stdio: ['pipe', 'pipe', 'pipe']
        });
        
        // CRITICAL: Close stdin immediately to prevent hang
        child.stdin.end();
        
        let stdout = '';
        let stderr = '';
        
        child.stdout.on('data', (data) => {
            stdout += data.toString();
        });
        
        child.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        
        child.on('close', (code) => {
            if (code === 0) {
                resolve(stdout);
            } else {
                reject(new Error(`Gemini failed with code ${code}: ${stderr}`));
            }
        });
    });
}

// Usage
runGeminiWithWorkaround([], "Hello, can you hear me?")
    .then(response => console.log(response))
    .catch(err => console.error(err));
```

#### Method 2: exec() with stdin redirection
```javascript
const { exec } = require('child_process');

function runGeminiExecWorkaround(prompt) {
    return new Promise((resolve, reject) => {
        // Redirect /dev/null to stdin to prevent hang
        const command = `echo "" | gemini -y -m gemini-2.5-flash -p "${prompt.replace(/"/g, '\\"')}"`;
        
        exec(command, (error, stdout, stderr) => {
            if (error) {
                reject(error);
            } else {
                resolve(stdout);
            }
        });
    });
}
```

#### Method 3: Version-aware detection (Advanced)
```javascript
const { exec, spawn } = require('child_process');
const { promisify } = require('util');

const execAsync = promisify(exec);

async function getGeminiVersion() {
    try {
        const { stdout } = await execAsync('gemini -v', { timeout: 5000 });
        const versionMatch = stdout.match(/(\d+\.\d+\.\d+)/);
        return versionMatch ? versionMatch[1] : 'unknown';
    } catch (error) {
        return 'unknown';
    }
}

async function runGeminiSmart(prompt) {
    const version = await getGeminiVersion();
    const needsWorkaround = version === '0.1.22';
    
    if (needsWorkaround) {
        console.log('Detected Gemini 0.1.22 - applying stdin workaround');
        return runGeminiWithWorkaround([], prompt);
    } else {
        // Use normal subprocess for other versions
        return runGeminiNormal(prompt);
    }
}
```

### For Shell Scripts

#### Method 1: Redirect /dev/null to stdin
```bash
#!/bin/bash

# Instead of this (hangs):
# gemini -y -m gemini-2.5-flash -p "hello"

# Use this (works):
gemini -y -m gemini-2.5-flash -p "hello" < /dev/null
```

#### Method 2: Pipe empty string
```bash
#!/bin/bash

# Alternative workaround:
echo "" | gemini -y -m gemini-2.5-flash -p "hello"
```

#### Method 3: Version detection in bash
```bash
#!/bin/bash

check_gemini_version() {
    local version=$(gemini -v 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
    if [[ "$version" == "0.1.22" ]]; then
        echo "true"
    else
        echo "false"
    fi
}

run_gemini_safe() {
    local prompt="$1"
    
    if [[ $(check_gemini_version) == "true" ]]; then
        echo "Applying 0.1.22 workaround..."
        echo "" | gemini -y -m gemini-2.5-flash -p "$prompt"
    else
        gemini -y -m gemini-2.5-flash -p "$prompt"
    fi
}

# Usage
run_gemini_safe "Hello, can you hear me?"
```

### For Python Applications

```python
import subprocess
import sys

def run_gemini_with_workaround(prompt):
    """Run Gemini CLI with 0.1.22 subprocess workaround"""
    try:
        # Use subprocess.run with stdin=subprocess.DEVNULL
        result = subprocess.run([
            'gemini', '-y', '-m', 'gemini-2.5-flash', '-p', prompt
        ], 
        capture_output=True, 
        text=True, 
        stdin=subprocess.DEVNULL,  # This prevents the hang
        timeout=30
        )
        
        if result.returncode == 0:
            return result.stdout
        else:
            raise Exception(f"Gemini failed: {result.stderr}")
            
    except subprocess.TimeoutExpired:
        raise Exception("Gemini CLI hanged - likely 0.1.22 subprocess bug")

# Usage
try:
    response = run_gemini_with_workaround("Hello, can you hear me?")
    print(response)
except Exception as e:
    print(f"Error: {e}")
```

### For Docker/CI Environments

```dockerfile
# In Dockerfile or CI script
RUN echo "" | gemini -y -m gemini-2.5-flash -p "test prompt"

# Or use stdin redirection
RUN gemini -y -m gemini-2.5-flash -p "test prompt" < /dev/null
```

### For Automation Tools (GitHub Actions, etc.)

```yaml
# GitHub Actions example
- name: Run Gemini CLI with workaround
  run: |
    echo "" | gemini -y -m gemini-2.5-flash -p "Analyze this code"
    
# Or with stdin redirection
- name: Run Gemini CLI (alternative)
  run: |
    gemini -y -m gemini-2.5-flash -p "Analyze this code" < /dev/null
```

### Temporary Downgrade Option

If workarounds are not feasible, consider temporarily downgrading:

```bash
# Uninstall current version
npm uninstall -g @google/gemini-cli

# Install working version
npm install -g @google/gemini-cli@0.1.21

# Verify version
gemini -v  # Should show 0.1.21
```

**Note**: Remember to upgrade once Google fixes the issue in a future release.

### Testing Your Workaround

Verify your workaround with this test:

```bash
# This should work without hanging:
timeout 10s bash -c 'echo "" | gemini -y -m gemini-2.5-flash -p "test"'

# If it times out, the workaround failed
# If it returns a response, the workaround succeeded
```

## Suggested Fix

Restore the original condition in `packages/cli/src/gemini.tsx`:

```typescript
// Revert to 0.1.20 behavior
if (!process.stdin.isTTY && !input) { // Re-add the `&& !input` condition
  input += await readStdin();
}
```

This ensures that `readStdin()` is only called when:
1. Running in non-TTY environment (subprocess) **AND**
2. No command-line input was provided

## Additional Information

- **Network Traffic**: Minimal network activity observed during hang (indicating it's not a network timeout)
- **Authentication**: Successful (confirmed by "Data collection is disabled." message)
- **Version Comparison**: 0.1.20 works perfectly, 0.1.22 exhibits this regression
- **Cross-Platform**: Issue confirmed on multiple Linux distributions

## Priority

**High** - This is a breaking regression that prevents any subprocess usage of Gemini CLI 0.1.22, forcing users to either:
1. Downgrade to 0.1.21 or earlier
2. Implement complex workarounds
3. Switch to alternative tools

Thank you for your attention to this critical subprocess compatibility regression.

Labels: priority/p2, area/core
State: closed