diff --git a/gsd-openclaw/.planning/ROADMAP.md b/gsd-openclaw/.planning/ROADMAP.md index 55039a9..c9227ab 100644 --- a/gsd-openclaw/.planning/ROADMAP.md +++ b/gsd-openclaw/.planning/ROADMAP.md @@ -32,10 +32,10 @@ Decimal phases appear between their surrounding integers in numeric order. **Plans**: 4 plans Plans: -- [ ] 01-01-PLAN.md — State persistence layer with atomic writes and backup rotation -- [ ] 01-02-PLAN.md — Workspace directory management for project isolation -- [ ] 01-03-PLAN.md — tmux session lifecycle management using libtmux -- [ ] 01-04-PLAN.md — CLI entry point with session recovery and orphan cleanup +- [x] 01-01-PLAN.md — State persistence layer with atomic writes and backup rotation +- [x] 01-02-PLAN.md — Workspace directory management for project isolation +- [x] 01-03-PLAN.md — tmux session lifecycle management using libtmux +- [x] 01-04-PLAN.md — CLI entry point with session recovery and orphan cleanup ### Phase 2: Integration Layer **Goal**: OpenClaw can load and invoke the skill with channel-adaptive response formatting @@ -62,7 +62,12 @@ Plans: 3. User can approve/reject GSD workflow gates through chat responses 4. User receives periodic progress updates during long-running operations 5. Skill integrates with OpenClaw's security model (dmPolicy, allowlists) and works across all channels -**Plans**: TBD +**Plans**: 3 plans + +Plans: +- [ ] 03-01-PLAN.md — Command executor with output capture and error detection (BRDG-02, BRDG-03) +- [ ] 03-02-PLAN.md — Approval handler and progress monitor (BRDG-04, BRDG-05) +- [ ] 03-03-PLAN.md — Orchestrator integration with command routing (BRDG-01, OCLW-03, OCLW-05, OCLW-06) ### Phase 4: GSD Integration **Goal**: All GSD slash commands are fully bridged with complete workflow support @@ -82,9 +87,9 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 |-------|----------------|--------|-----------| | 1. Core Infrastructure | 4/4 | Complete | 2026-03-11 | | 2. Integration Layer | 3/3 | Complete | 2026-03-11 | -| 3. Orchestration | 0/TBD | Not started | - | +| 3. Orchestration | 0/3 | Not started | - | | 4. GSD Integration | 0/TBD | Not started | - | --- *Roadmap created: 2026-03-10* -*Last updated: 2026-03-11 - Planned Phase 2 integration layer* +*Last updated: 2026-03-11 - Planned Phase 3 orchestration* diff --git a/gsd-openclaw/.planning/phases/03-orchestration/03-01-PLAN.md b/gsd-openclaw/.planning/phases/03-orchestration/03-01-PLAN.md new file mode 100644 index 0000000..d59ad49 --- /dev/null +++ b/gsd-openclaw/.planning/phases/03-orchestration/03-01-PLAN.md @@ -0,0 +1,198 @@ +--- +phase: 03-orchestration +plan: 01 +type: tdd +wave: 1 +depends_on: [] +files_modified: + - src/gsd_openclaw/command_executor.py + - tests/test_command_executor.py +autonomous: true +requirements: [BRDG-02, BRDG-03] + +must_haves: + truths: + - "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" + artifacts: + - path: "src/gsd_openclaw/command_executor.py" + provides: "Command execution and output capture" + exports: ["CommandExecutor", "CommandResult", "OutputCapture"] + - path: "tests/test_command_executor.py" + provides: "Test coverage for command execution" + min_lines: 150 + key_links: + - from: "CommandExecutor" + to: "TmuxSessionManager" + via: "session.tmux_session.active_pane" + pattern: "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. + + + +@/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 + + + + +From src/gsd_openclaw/tmux_session.py: +```python +@dataclass +class TmuxSession: + session_id: str + project_name: str + tmux_session_name: str + tmux_session: Optional[libtmux.Session] = None + + @property + def exists(self) -> bool: ... + +class TmuxSessionManager: + SESSION_PREFIX = "gsd-" + + def get_session(self, project_name: str) -> Optional[TmuxSession]: ... + def create_session(self, project_name: str, ...) -> TmuxSession: ... + def resume_session(self, project_name: str) -> TmuxSession: ... +``` + +From src/gsd_openclaw/response_formatter.py: +```python +class CardTheme(Enum): + SUCCESS = "green" + ERROR = "red" + INFO = "blue" + +@dataclass +class CardButton: + text: str + value: Dict[str, Any] + button_type: str = "primary" + +class FeishuResponseFormatter: + def format_error(self, title: str, content: str, buttons=None) -> dict: ... + def format_success(self, title: str, content: str, buttons=None) -> dict: ... +``` + + + + + 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. + + + +- 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) + + + +After completion, create `.planning/phases/03-orchestration/03-01-SUMMARY.md` + diff --git a/gsd-openclaw/.planning/phases/03-orchestration/03-02-PLAN.md b/gsd-openclaw/.planning/phases/03-orchestration/03-02-PLAN.md new file mode 100644 index 0000000..625914c --- /dev/null +++ b/gsd-openclaw/.planning/phases/03-orchestration/03-02-PLAN.md @@ -0,0 +1,253 @@ +--- +phase: 03-orchestration +plan: 02 +type: tdd +wave: 2 +depends_on: [03-01] +files_modified: + - src/gsd_openclaw/approval_handler.py + - src/gsd_openclaw/progress_monitor.py + - tests/test_approval_handler.py + - tests/test_progress_monitor.py +autonomous: true +requirements: [BRDG-04, BRDG-05] + +must_haves: + truths: + - "Approval requests in output are detected via pattern matching" + - "Approval card with confirm/reject buttons is created for pending approvals" + - "Approval state is persisted for crash recovery" + - "Progress indicators in output are extracted (percentage, fraction, phase)" + - "Progress updates are throttled to 1 minute intervals" + artifacts: + - path: "src/gsd_openclaw/approval_handler.py" + provides: "Approval workflow state management" + exports: ["ApprovalHandler", "ApprovalState"] + - path: "src/gsd_openclaw/progress_monitor.py" + provides: "Progress detection and update logic" + exports: ["ProgressMonitor", "ProgressInfo"] + - path: "tests/test_approval_handler.py" + provides: "Test coverage for approval handling" + min_lines: 100 + - path: "tests/test_progress_monitor.py" + provides: "Test coverage for progress monitoring" + min_lines: 100 + key_links: + - from: "ApprovalHandler" + to: "FeishuResponseFormatter" + via: "format_info() with CardButton" + pattern: "CardButton.*value.*approval_id" + - from: "ApprovalHandler" + to: "StateManager" + via: "save()/load() for persistence" + pattern: "state_manager\\.save" + - from: "ProgressMonitor" + to: "FeishuResponseFormatter" + via: "format_info() for progress card" + pattern: "format_info.*正在执行" +--- + + +Implement approval workflow handler and progress monitor for interactive GSD operations. + +Purpose: Enable bidirectional chat interaction - users can approve/reject workflow gates and receive periodic progress updates during long-running operations. +Output: ApprovalHandler class for approval workflow, ProgressMonitor class for progress detection and updates. + + + +@/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 + + + + +From src/gsd_openclaw/response_formatter.py: +```python +class CardTheme(Enum): + SUCCESS = "green" + ERROR = "red" + INFO = "blue" + +@dataclass +class CardButton: + text: str + value: Dict[str, Any] + button_type: str = "primary" # primary, default, danger + +class FeishuResponseFormatter: + def format_info(self, title: str, content: str, buttons=None) -> dict: ... + def format_success(self, title: str, content: str, buttons=None) -> dict: ... +``` + +From src/gsd_openclaw/state_manager.py: +```python +@dataclass +class SessionState: + session_id: str + project_name: str + # ... other fields + +class StateManager: + def save(self, state: SessionState) -> None: ... + def load(self) -> Optional[SessionState]: ... +``` + +From src/gsd_openclaw/command_executor.py (Wave 1): +```python +@dataclass +class CommandResult: + output: str + completed: bool + has_error: bool + error_type: Optional[str] +``` + + + + + Approval Handler with Card Callbacks + src/gsd_openclaw/approval_handler.py, tests/test_approval_handler.py + + - Test 1: detect_approval_request returns dict when "AskUserQuestion" found in output + - Test 2: detect_approval_request returns dict when "ExitPlanMode" found in output + - Test 3: detect_approval_request returns dict when "需要确认" found in output + - Test 4: create_approval_card returns Feishu Card JSON with confirm/reject buttons + - Test 5: ApprovalState is persisted to StateManager + - Test 6: handle_callback processes approval action and returns response + - Test 7: Expired approvals return appropriate error message + + + 1. Create ApprovalState dataclass with: approval_id, session_id, project_name, context, created_at + 2. Create ApprovalHandler class with: + - APPROVAL_PATTERNS: ['AskUserQuestion', 'ExitPlanMode', '需要确认', 'Please confirm'] + - __init__(formatter: FeishuResponseFormatter) + - pending_approvals: Dict[str, ApprovalState] (in-memory cache) + - detect_approval_request(output: str) -> Optional[dict] + - create_approval_card(context: dict, session_id: str, project_name: str) -> dict + - handle_callback(callback_data: dict) -> str (returns "approved", "rejected", or error) + - persist_approval(state: StateManager, approval: ApprovalState) -> None + - load_approval(state: StateManager, approval_id: str) -> Optional[ApprovalState] + 3. Use FeishuResponseFormatter.format_info() with CardButton for confirm/reject + 4. Button values: {"action": "approve"|"reject", "approval_id": "...", "project": "..."} + 5. Follow user decision: no timeout limit for approvals (wait for user or session end) + + + + + Progress Monitor with Throttled Updates + src/gsd_openclaw/progress_monitor.py, tests/test_progress_monitor.py + + - Test 1: extract_progress returns {"type": "percentage", "value": 50} for "50%" + - Test 2: extract_progress returns {"type": "fraction", "current": 2, "total": 5} for "[2/5]" + - Test 3: extract_progress returns {"type": "phase", "value": 3} for "Phase 3" + - Test 4: should_send_update returns True only after 60 seconds elapsed + - Test 5: create_progress_card formats percentage progress correctly + - Test 6: create_progress_card formats fraction progress correctly + + + 1. Create ProgressInfo dataclass with: type (str), value, current, total (optional fields) + 2. Create ProgressMonitor class with: + - PROGRESS_PATTERNS: list of (pattern, type) tuples + - (r'(\d+)%', 'percentage') + - (r'\[(\d+)/(\d+)\]', 'fraction') + - (r'Phase\s+(\d+)', 'phase') + - (r'完成|completed|done', 'completion') + - update_interval: float = 60.0 (1 minute from CONTEXT.md) + - last_update_time: float = 0 + - __init__(formatter: FeishuResponseFormatter, update_interval: float = 60.0) + - extract_progress(output: str) -> Optional[ProgressInfo] + - should_send_update() -> bool + - create_progress_card(progress: ProgressInfo, message: str) -> dict + 3. Use FeishuResponseFormatter.format_info() with title "正在执行..." + 4. Progress format: "正在执行...\n\n进度: 50%" or "进度: [2/5]" + + + + + + + Task 1: Create test scaffolds for approval and progress modules + tests/test_approval_handler.py, tests/test_progress_monitor.py + + Approval tests: + - Test 1: detect_approval_request finds AskUserQuestion pattern + - Test 2: create_approval_card has confirm/reject buttons + Progress tests: + - Test 3: extract_progress parses percentage pattern + - Test 4: should_send_update respects interval + + Create two test files with pytest test functions. Mock FeishuResponseFormatter in tests. Follow test patterns from tests/test_response_formatter.py. + + pytest tests/test_approval_handler.py tests/test_progress_monitor.py -v --collect-only 2>&1 | grep -c "test_" | xargs -I{} bash -c 'test {} -ge 4' + + Both test files exist with at least 2 test functions each, all discoverable by pytest + + + + Task 2: Implement ApprovalHandler class + src/gsd_openclaw/approval_handler.py, tests/test_approval_handler.py + + - Test 1: detect_approval_request returns context for "AskUserQuestion" output + - Test 2: detect_approval_request returns context for "需要确认" output + - Test 3: create_approval_card has title "需要确认" + - Test 4: create_approval_card has confirm button with action="approve" + - Test 5: create_approval_card has reject button with action="reject" + - Test 6: handle_callback returns "approved" for approve action + - Test 7: handle_callback returns "rejected" for reject action + - Test 8: handle_callback returns error for unknown approval_id + + Implement ApprovalState dataclass and ApprovalHandler class. Use APPROVAL_PATTERNS for detection. Create CardButton with confirm/reject text (2-4 Chinese characters per CONTEXT.md). Store pending approvals in memory with approval_id as key. Buttons use button_type="primary" for confirm, "danger" for reject. + + pytest tests/test_approval_handler.py -v + + ApprovalHandler implemented with all methods, 8+ tests pass + + + + Task 3: Implement ProgressMonitor class + src/gsd_openclaw/progress_monitor.py, tests/test_progress_monitor.py + + - Test 1: extract_progress returns percentage for "Progress: 75%" + - Test 2: extract_progress returns fraction for "[3/5 tasks]" + - Test 3: extract_progress returns phase for "Phase 2 complete" + - Test 4: should_send_update returns False immediately after creation + - Test 5: should_send_update returns True after 60 seconds + - Test 6: create_progress_card includes progress percentage in content + - Test 7: create_progress_card uses title "正在执行..." + + Implement ProgressInfo dataclass and ProgressMonitor class. Use PROGRESS_PATTERNS with re.search for extraction. Track last_update_time with time.time(). Format progress as "进度: X%" or "进度: [N/M]" per CONTEXT.md format preference. + + pytest tests/test_progress_monitor.py -v + + ProgressMonitor implemented with all methods, 7+ tests pass + + + + + +Run full test suite for both modules: +```bash +pytest tests/test_approval_handler.py tests/test_progress_monitor.py -v --cov=src/gsd_openclaw/approval_handler --cov=src/gsd_openclaw/progress_monitor +``` +All tests must pass with >90% coverage. + + + +- ApprovalHandler detects approval patterns and creates cards with buttons +- Approval callbacks are handled correctly +- ProgressMonitor extracts progress from output patterns +- Progress updates are throttled to 1 minute intervals +- All tests pass with mock-based testing + + + +After completion, create `.planning/phases/03-orchestration/03-02-SUMMARY.md` + diff --git a/gsd-openclaw/.planning/phases/03-orchestration/03-03-PLAN.md b/gsd-openclaw/.planning/phases/03-orchestration/03-03-PLAN.md new file mode 100644 index 0000000..e798850 --- /dev/null +++ b/gsd-openclaw/.planning/phases/03-orchestration/03-03-PLAN.md @@ -0,0 +1,255 @@ +--- +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` +