Back to all docs

Command Execution Design Analysis - v0

Date: 2025-11-20 Codebase: AhaiaApp/ide/web Purpose: Document how command execution currently works and its limitations


Architecture Overview

Backend Implementation (server.js:139-182)

const { stdout, stderr } = await execAsync(command, {
  cwd: actualPath,
  timeout: 10000,        // 10 second timeout
  maxBuffer: 1024 * 1024 // 1MB max output
});

Key Components:


How Different Command Types Are Handled

1. Quick Commands ✅ Work Well

Examples: ls, git status, gh -h, pwd, echo "hello"

Behavior:

Example Flow:

User types: ls -la
→ Frontend sends POST to /api/execute
→ Backend runs: exec('ls -la', { cwd: repoPath, timeout: 10000 })
→ stdout returned in ~50-200ms
→ Displayed in chat as monospace code block

Status: ✅ Works perfectly for commands that complete quickly


2. Long-Running Commands ⚠️ TIMEOUT ISSUE

Examples: brew install, npm install, docker build, pytest, cargo build

Current Behavior:

Problems:

  1. ❌ Commands taking >10s fail
  2. ❌ No progress updates (can't see what's happening)
  3. ❌ Output buffer limit (1MB) - truncates large outputs
  4. ❌ User has no idea command is still running vs. frozen

What happens:

User types: npm install
→ Command starts executing
→ At 10 seconds: KILLED
→ stderr: "Error: Command failed: npm install\nkilled"
→ Package installation incomplete

Root Cause: Using exec() which buffers all output and enforces timeout


3. Interactive Commands ❌ COMPLETELY BROKEN

Examples: vim, nano, python (REPL), claude, ssh, top, less, man

Current Behavior:

Why They Fail:

  1. exec() provides no stdin interaction
  2. No pseudo-TTY (PTY) allocation
  3. No way to send keyboard input (arrows, Ctrl+C, etc.)
  4. Commands detect non-interactive shell and may behave differently

What happens:

User types: vim myfile.txt
→ vim starts but expects interactive terminal
→ Waits for input that never comes
→ Hangs for 10 seconds
→ Killed by timeout
→ Error returned

Root Cause: HTTP request/response model has no mechanism for bidirectional communication


Current Limitations Summary

Command Type Status Issue
Quick commands (<10s) ✅ Works None
Long commands (>10s) ⚠️ Broken Timeout kills process
Commands with large output ⚠️ Truncated 1MB buffer limit
Interactive commands ❌ Broken No stdin/TTY support
Background processes ❌ Broken Can't run in background
Streaming output ❌ Missing No real-time updates
Job management ❌ Missing Can't list/cancel/resume

Technical Root Causes

1. Using exec() instead of spawn()

2. No Process Management

3. No PTY (Pseudo-Terminal)

4. Request/Response Model


Security Considerations (Current)

Implemented:

Missing:


Potential Improvements

Option A: Increase Timeout (Quick Fix)

Pros:

Cons:

Implementation:

timeout: 300000, // 5 minutes instead of 10 seconds

Option B: Add Streaming Output

Pros:

Cons:

Stack:


Option C: Full Terminal Emulator

Pros:

Cons:

Stack:


Option D: Background Job Queue

Pros:

Cons:

Stack:


Phase 1: Quick Wins (1-2 hours)

  1. Increase timeout to 5-10 minutes
  2. Increase buffer to 10MB
  3. Add timeout indicator in UI

Phase 2: Streaming (1-2 days)

  1. Add WebSocket support
  2. Switch to spawn() for streaming
  3. Real-time output in chat bubbles
  4. Job management (cancel, status)

Phase 3: Interactive (1-2 weeks)

  1. Implement PTY support with node-pty
  2. Add xterm.js terminal emulator
  3. Bidirectional WebSocket communication
  4. Session persistence

Code Locations

Command Execution:

Key Lines:


Notes


References