--- phase: 03-orchestration plan: 03 type: execute wave: 3 depends_on: [03-01, 03-02] files_modified: - src/gsd_openclaw/orchestrator.py - src/gsd_openclaw/__init__.py - skill/SKILL.md - tests/test_orchestrator.py autonomous: true requirements: [BRDG-01, OCLW-03, OCLW-05, OCLW-06] must_haves: truths: - "User can send /gsd:* command through chat and receive output" - "Session is auto-created if it doesn't exist" - "Error messages are formatted as red cards when commands fail" - "Approval requests trigger interactive card with buttons" - "Orchestrator routes commands through appropriate handlers" artifacts: - path: "src/gsd_openclaw/orchestrator.py" provides: "Main command router and OpenClaw skill handler" exports: ["Orchestrator", "handle_message", "handle_callback"] - path: "skill/SKILL.md" provides: "OpenClaw skill definition with orchestrator reference" contains: "orchestrator.py" - path: "tests/test_orchestrator.py" provides: "Test coverage for orchestration" min_lines: 200 key_links: - from: "Orchestrator.handle_message" to: "TmuxSessionManager" via: "get_session()/create_session()" pattern: "tmux_manager\\.(get|create)_session" - from: "Orchestrator.handle_message" to: "CommandExecutor" via: "execute(session, command)" pattern: "executor\\.execute" - from: "Orchestrator.handle_message" to: "ApprovalHandler" via: "detect_approval_request()" pattern: "approval_handler\\.detect" - from: "Orchestrator.handle_message" to: "FeishuResponseFormatter" via: "format_success()/format_error()" pattern: "formatter\\.format_(success|error)" --- Implement the main orchestrator that integrates all components into a cohesive command routing system for OpenClaw skill invocation. Purpose: Create the central command router that receives chat messages, routes them through session management and command execution, handles approvals and progress, and returns formatted responses. Output: Orchestrator class with handle_message() entry point, SKILL.md update with orchestrator reference. @/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md @/home/starmen1265/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-orchestration/03-CONTEXT.md @.planning/phases/03-orchestration/03-RESEARCH.md @.planning/phases/03-orchestration/03-01-PLAN.md @.planning/phases/03-orchestration/03-02-PLAN.md From src/gsd_openclaw/command_executor.py (Wave 1): ```python @dataclass class CommandResult: output: str completed: bool has_error: bool error_type: Optional[str] class CommandExecutor: DEFAULT_TIMEOUT: float = 60.0 def execute(self, session: TmuxSession, command: str, timeout: float = None) -> CommandResult: ... ``` From src/gsd_openclaw/approval_handler.py (Wave 2): ```python @dataclass class ApprovalState: approval_id: str session_id: str project_name: str context: dict created_at: float class ApprovalHandler: def detect_approval_request(self, output: str) -> Optional[dict]: ... def create_approval_card(self, context: dict, session_id: str, project_name: str) -> dict: ... def handle_callback(self, callback_data: dict) -> str: ... ``` From src/gsd_openclaw/progress_monitor.py (Wave 2): ```python @dataclass class ProgressInfo: type: str # percentage, fraction, phase, completion value: Optional[int] = None current: Optional[int] = None total: Optional[int] = None class ProgressMonitor: def extract_progress(self, output: str) -> Optional[ProgressInfo]: ... def should_send_update(self) -> bool: ... def create_progress_card(self, progress: ProgressInfo, message: str) -> dict: ... ``` From src/gsd_openclaw/tmux_session.py: ```python class TmuxSessionManager: def get_session(self, project_name: str) -> Optional[TmuxSession]: ... def create_session(self, project_name: str, ...) -> TmuxSession: ... ``` From src/gsd_openclaw/response_formatter.py: ```python class FeishuResponseFormatter: def format_success(self, title: str, content: str, buttons=None) -> dict: ... def format_error(self, title: str, content: str, buttons=None) -> dict: ... def format_info(self, title: str, content: str, buttons=None) -> dict: ... ``` Task 1: Create test scaffold for orchestrator tests/test_orchestrator.py - Test 1: handle_message routes to session creation when no session exists - Test 2: handle_message executes command and returns success card - Test 3: handle_message returns error card when command fails - Test 4: handle_message returns approval card when approval detected - Test 5: handle_callback routes approval response correctly - Test 6: Command parsing extracts /gsd:* pattern Create test file with pytest test functions. Mock all dependencies (TmuxSessionManager, CommandExecutor, ApprovalHandler, ProgressMonitor). Follow mock patterns from tests/test_tmux_session.py. pytest tests/test_orchestrator.py -v --collect-only 2>&1 | grep -c "test_" | xargs -I{} bash -c 'test {} -ge 6' Test file exists with at least 6 test functions, all discoverable by pytest Task 2: Implement Orchestrator class src/gsd_openclaw/orchestrator.py, tests/test_orchestrator.py - Test 1: Orchestrator initializes with all required components - Test 2: handle_message creates session if not exists (auto-create per CONTEXT.md) - Test 3: handle_message executes command via CommandExecutor - Test 4: handle_message returns format_success() for successful commands - Test 5: handle_message returns format_error() for failed commands - Test 6: handle_message returns approval card when approval detected - Test 7: handle_message truncates output to 2000 chars for card limits - Test 8: handle_callback processes approval/reject actions Implement Orchestrator class with: 1. __init__(self, tmux_manager=None, formatter=None) - inject dependencies for testing 2. Command routing via regex: r'^/gsd:(\S+)\s*(.*)$' extracts command and args 3. handle_message(user_id, message, channel, context) -> dict - Extract project_name from context.get('project', 'default') - Get or create session via TmuxSessionManager - Execute command via CommandExecutor.execute() - Check for approval request via ApprovalHandler.detect_approval_request() - Return appropriate card (success/error/approval) 4. handle_callback(callback_data) -> dict - Route to ApprovalHandler.handle_callback() - Send approval/rejection to tmux session - Return confirmation card 5. Error handling with try/except, return format_error() on exceptions 6. Use format_error(title="命令执行失败", content=output[-2000:]) for errors pytest tests/test_orchestrator.py -v Orchestrator class implemented with handle_message() and handle_callback(), 8+ tests pass Task 3: Update SKILL.md and __init__.py exports skill/SKILL.md, src/gsd_openclaw/__init__.py 1. Update skill/SKILL.md to add orchestrator integration notes: - Add section "## How It Works" explaining orchestrator.py entry point - Document that the skill calls orchestrator.handle_message() for each message - Keep existing command documentation 2. Update src/gsd_openclaw/__init__.py to export: - from gsd_openclaw.orchestrator import Orchestrator - from gsd_openclaw.command_executor import CommandExecutor, CommandResult - from gsd_openclaw.approval_handler import ApprovalHandler, ApprovalState - from gsd_openclaw.progress_monitor import ProgressMonitor, ProgressInfo - Add to __all__ list python -c "from gsd_openclaw import Orchestrator, CommandExecutor, ApprovalHandler, ProgressMonitor; print('OK')" SKILL.md updated with orchestrator documentation, __init__.py exports all new classes Task 4: Integration test with all components tests/test_orchestrator.py Add integration-style tests to test_orchestrator.py: 1. Test full flow: handle_message -> session creation -> command execution -> success card 2. Test error flow: handle_message -> command fails -> error card 3. Test approval flow: handle_message -> approval detected -> approval card 4. Test callback flow: handle_callback -> approval processed -> confirmation Use real component instances where possible, mock only tmux server. Ensure all tests pass with full coverage of integration paths. pytest tests/test_orchestrator.py -v --cov=src/gsd_openclaw/orchestrator Integration tests added and passing, orchestrator coverage >90% Run full test suite for Phase 3: ```bash pytest tests/test_command_executor.py tests/test_approval_handler.py tests/test_progress_monitor.py tests/test_orchestrator.py -v --cov=src/gsd_openclaw ``` All tests must pass. Phase 3 coverage should be >85%. - Orchestrator integrates all Phase 3 components - handle_message() provides complete command routing flow - Auto-session-creation works per CONTEXT.md decision - Error handling returns formatted error cards - Approval workflow integrates with callback handling - All exports added to __init__.py - SKILL.md documents orchestrator integration After completion, create `.planning/phases/03-orchestration/03-03-SUMMARY.md`