google-gemini / google-gemini/gemini-cli
Blocking Synchronous I/O on the Main Thread Causes UI Stutter
- Dominant language
- TypeScript
- Stars
- 107k
- Forks
- 14.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 45
Description
# Performance: Replace blocking filesystem operations in `shell.execute` with asynchronous APIs
**Category:** Performance
**Priority:** High
## Affected Components
- `packages/core/src/tools/shell.ts`
- `packages/cli` (React Ink UI)
## Summary
The shell tool performs synchronous filesystem operations (`fs.mkdtempSync`) on the main Node.js event loop immediately before spawning shell processes. Since the CLI UI is rendered using React Ink on the same event loop, these synchronous operations can briefly block rendering, resulting in input latency, dropped frames, and less responsive streaming output.
## Current Behavior
The temporary directory used for shell execution is created synchronously:
```ts
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gemini-shell-'));
```
Although this operation is typically fast, it can become noticeably slower on busy systems, network-mounted filesystems (e.g. WSL/NFS), or under heavy concurrent tool execution.
## Expected Behavior
Filesystem operations in the shell execution path should be non-blocking so the React Ink UI remains responsive during tool execution and streaming.
## Steps to Reproduce
1. Run multiple shell tool invocations in quick succession.
2. While commands are executing, type into the CLI input.
3. Observe occasional input lag or UI stuttering.
## Impact
- Reduced UI responsiveness during shell execution.
- Increased input latency while the agent is running commands.
- Brief interruptions in streamed terminal output.
## Suggested Solution
Replace synchronous filesystem operations in the shell execution path with their asynchronous equivalents.
A minimal implementation would:
- Replace `fs.mkdtempSync(...)` with `await fsPromises.mkdtemp(...)`.
- Audit the same execution path for other `*Sync` filesystem calls and replace them where appropriate.
Since `execute()` is already asynchronous, this change should integrate naturally without affecting behavior.
## Testing
- Verify all existing shell execution tests continue to pass.
- Add or update performance tests to ensure concurrent shell executions do not introduce unnecessary event loop blocking.
- Manually verify the CLI remains responsive while multiple shell commands are executing.
## Acceptance Criteria
- [ ] No synchronous filesystem operations remain in `shell.execute`.
- [ ] Existing functionality is preserved.
- [ ] CLI responsiveness is maintained during concurrent shell executions.
- [ ] All related tests pass.
Contributor guide
Research direction
Start in packages/core/src/tools/shell.ts, inspect execute() and identify all synchronous filesystem calls in its shell-execution path. Review the related shell execution tests and packages/cli React Ink integration before changing the async flow. Done means no synchronous filesystem operations remain in shell.execute, existing behavior and tests are preserved, and concurrent commands do not block CLI responsiveness.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- cli, performance
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100