Command output is captured from tmux pane and returned as string
Command completion is detected when prompt reappears or output stabilizes
Error keywords in output are detected and flagged
Timeout is enforced during output capture
path
provides
exports
src/gsd_openclaw/command_executor.py
Command execution and output capture
CommandExecutor
CommandResult
OutputCapture
path
provides
min_lines
tests/test_command_executor.py
Test coverage for command execution
150
from
to
via
pattern
CommandExecutor
TmuxSessionManager
session.tmux_session.active_pane
active_pane.send_keys|capture_pane
Implement command execution layer that sends commands to tmux sessions and captures output with completion detection.
Purpose: Provide the foundational I/O layer for all GSD command bridging - send commands to tmux, capture output, detect completion, identify errors.
Output: CommandExecutor class with send_command(), capture_output(), and error detection.
Command Execution with Output Capture
src/gsd_openclaw/command_executor.py, tests/test_command_executor.py
- Test 1: send_command sends text to tmux pane via send_keys with enter=True
- Test 2: capture_output returns pane content until prompt appears or timeout
- Test 3: Output stabilizes (no changes for 3 polls) is detected as completion
- Test 4: Error keywords (error, failed, exception, traceback, 错误, 失败) are detected
- Test 5: Timeout (default 60s) is enforced during capture
- Test 6: CommandResult dataclass contains output, completed, has_error, error_type
1. Create CommandResult dataclass with: output (str), completed (bool), has_error (bool), error_type (Optional[str])
2. Create OutputCapture class with:
- PROMPT_PATTERNS: list of regex patterns for shell prompts (^\$\s*$, ^❯\s*$, ^➜\s*$)
- capture_until_complete(pane, timeout, poll_interval) -> tuple[str, bool]
- _is_prompt(line) -> bool
- Use stable output detection (no changes for 3 consecutive polls)
3. Create CommandExecutor class with:
- ERROR_KEYWORDS: ['error', 'failed', 'exception', 'traceback', '错误', '失败']
- DEFAULT_TIMEOUT: 60.0 (from CONTEXT.md user decision)
- send_command(pane, command) -> None (calls pane.send_keys)
- execute(session, command, timeout) -> CommandResult
- _detect_errors(output) -> tuple[bool, Optional[str]]
4. All classes use type hints and docstrings following Phase 1 patterns
5. Mock-based testing - no real tmux server required (follow Phase 1 test patterns)
Task 1: Create test scaffold for command executor
tests/test_command_executor.py
- Test 1: OutputCapture._is_prompt detects common prompt patterns
- Test 2: OutputCapture.capture_until_complete returns output and completion flag
- Test 3: CommandExecutor._detect_errors identifies error keywords
- Test 4: CommandExecutor.execute returns CommandResult with all fields
Create test file with pytest test functions for CommandExecutor and OutputCapture. Use mock objects for tmux pane (no real tmux). Follow test patterns from tests/test_tmux_session.py.
pytest tests/test_command_executor.py -v --collect-only 2>&1 | grep -c "test_" | xargs -I{} bash -c 'test {} -ge 4'
Test file exists with at least 4 test functions, all tests are discoverable by pytest
Task 2: Implement OutputCapture class
src/gsd_openclaw/command_executor.py, tests/test_command_executor.py
- Test 1: _is_prompt returns True for "$ ", "❯ ", "➜ " prompts
- Test 2: _is_prompt returns False for non-prompt lines
- Test 3: capture_until_complete returns (output, True) when prompt detected
- Test 4: capture_until_complete returns (output, True) when output stabilizes
- Test 5: capture_until_complete returns (output, False) on timeout
Implement OutputCapture class with PROMPT_PATTERNS constant, _is_prompt() method, and capture_until_complete() method. Use re module for pattern matching. Implement stable output detection (3 consecutive polls with same line count). Mock pane.capture_pane() in tests.
pytest tests/test_command_executor.py::test_is_prompt -v && pytest tests/test_command_executor.py::test_capture_until_complete -v
OutputCapture class implemented, all related tests pass
Task 3: Implement CommandExecutor class
src/gsd_openclaw/command_executor.py, tests/test_command_executor.py
- Test 1: send_command calls pane.send_keys with enter=True
- Test 2: _detect_errors returns (True, "error") for "Error: something"
- Test 3: _detect_errors returns (True, "failed") for "Process failed"
- Test 4: _detect_errors returns (False, None) for normal output
- Test 5: execute returns CommandResult with captured output
- Test 6: execute sets has_error=True when error keywords detected
- Test 7: execute respects timeout parameter (default 60s)
Implement CommandResult dataclass and CommandExecutor class with ERROR_KEYWORDS constant, DEFAULT_TIMEOUT=60.0, send_command(), _detect_errors(), and execute() methods. Use OutputCapture for output capture. Integrate with TmuxSession (session.tmux_session.active_pane).
pytest tests/test_command_executor.py -v
CommandExecutor class implemented with all methods, all tests pass (7+ tests)
Run full test suite for command executor module:
```bash
pytest tests/test_command_executor.py -v --cov=src/gsd_openclaw/command_executor
```
All tests must pass with >90% coverage.
<success_criteria>
OutputCapture class correctly detects prompt patterns and output stabilization
CommandExecutor sends commands and captures output with timeout enforcement
Error detection identifies error keywords in output
All tests pass with mock-based testing (no real tmux required)
Code follows Phase 1 patterns (dataclasses, type hints, docstrings)
</success_criteria>
After completion, create `.planning/phases/03-orchestration/03-01-SUMMARY.md`