docs(03-orchestration): create phase 3 plans

This commit is contained in:
2026-03-11 15:37:32 +08:00
parent 409bfbe5b5
commit cb4e1c48a7
4 changed files with 718 additions and 7 deletions
+12 -7
View File
@@ -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*
@@ -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"
---
<objective>
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.
</objective>
<execution_context>
@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md
@/home/starmen1265/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-orchestration/03-CONTEXT.md
@.planning/phases/03-orchestration/03-RESEARCH.md
<interfaces>
<!-- Key types and contracts from existing codebase -->
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: ...
```
</interfaces>
</context>
<feature>
<name>Command Execution with Output Capture</name>
<files>src/gsd_openclaw/command_executor.py, tests/test_command_executor.py</files>
<behavior>
- 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
</behavior>
<implementation>
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)
</implementation>
</feature>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Create test scaffold for command executor</name>
<files>tests/test_command_executor.py</files>
<behavior>
- 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
</behavior>
<action>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.</action>
<verify>
<automated>pytest tests/test_command_executor.py -v --collect-only 2>&1 | grep -c "test_" | xargs -I{} bash -c 'test {} -ge 4'</automated>
</verify>
<done>Test file exists with at least 4 test functions, all tests are discoverable by pytest</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Implement OutputCapture class</name>
<files>src/gsd_openclaw/command_executor.py, tests/test_command_executor.py</files>
<behavior>
- 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
</behavior>
<action>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.</action>
<verify>
<automated>pytest tests/test_command_executor.py::test_is_prompt -v && pytest tests/test_command_executor.py::test_capture_until_complete -v</automated>
</verify>
<done>OutputCapture class implemented, all related tests pass</done>
</task>
<task type="auto" tdd="true">
<name>Task 3: Implement CommandExecutor class</name>
<files>src/gsd_openclaw/command_executor.py, tests/test_command_executor.py</files>
<behavior>
- 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)
</behavior>
<action>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).</action>
<verify>
<automated>pytest tests/test_command_executor.py -v</automated>
</verify>
<done>CommandExecutor class implemented with all methods, all tests pass (7+ tests)</done>
</task>
</tasks>
<verification>
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.
</verification>
<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>
<output>
After completion, create `.planning/phases/03-orchestration/03-01-SUMMARY.md`
</output>
@@ -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.*正在执行"
---
<objective>
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.
</objective>
<execution_context>
@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md
@/home/starmen1265/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-orchestration/03-CONTEXT.md
@.planning/phases/03-orchestration/03-RESEARCH.md
<interfaces>
<!-- Key types and contracts from existing codebase -->
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]
```
</interfaces>
</context>
<feature>
<name>Approval Handler with Card Callbacks</name>
<files>src/gsd_openclaw/approval_handler.py, tests/test_approval_handler.py</files>
<behavior>
- 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
</behavior>
<implementation>
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)
</implementation>
</feature>
<feature>
<name>Progress Monitor with Throttled Updates</name>
<files>src/gsd_openclaw/progress_monitor.py, tests/test_progress_monitor.py</files>
<behavior>
- 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
</behavior>
<implementation>
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]"
</implementation>
</feature>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Create test scaffolds for approval and progress modules</name>
<files>tests/test_approval_handler.py, tests/test_progress_monitor.py</files>
<behavior>
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
</behavior>
<action>Create two test files with pytest test functions. Mock FeishuResponseFormatter in tests. Follow test patterns from tests/test_response_formatter.py.</action>
<verify>
<automated>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'</automated>
</verify>
<done>Both test files exist with at least 2 test functions each, all discoverable by pytest</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Implement ApprovalHandler class</name>
<files>src/gsd_openclaw/approval_handler.py, tests/test_approval_handler.py</files>
<behavior>
- 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
</behavior>
<action>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.</action>
<verify>
<automated>pytest tests/test_approval_handler.py -v</automated>
</verify>
<done>ApprovalHandler implemented with all methods, 8+ tests pass</done>
</task>
<task type="auto" tdd="true">
<name>Task 3: Implement ProgressMonitor class</name>
<files>src/gsd_openclaw/progress_monitor.py, tests/test_progress_monitor.py</files>
<behavior>
- 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 "正在执行..."
</behavior>
<action>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.</action>
<verify>
<automated>pytest tests/test_progress_monitor.py -v</automated>
</verify>
<done>ProgressMonitor implemented with all methods, 7+ tests pass</done>
</task>
</tasks>
<verification>
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.
</verification>
<success_criteria>
- 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
</success_criteria>
<output>
After completion, create `.planning/phases/03-orchestration/03-02-SUMMARY.md`
</output>
@@ -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)"
---
<objective>
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.
</objective>
<execution_context>
@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md
@/home/starmen1265/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.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
<interfaces>
<!-- Key types and contracts from Waves 1 and 2 -->
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: ...
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Create test scaffold for orchestrator</name>
<files>tests/test_orchestrator.py</files>
<behavior>
- 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
</behavior>
<action>Create test file with pytest test functions. Mock all dependencies (TmuxSessionManager, CommandExecutor, ApprovalHandler, ProgressMonitor). Follow mock patterns from tests/test_tmux_session.py.</action>
<verify>
<automated>pytest tests/test_orchestrator.py -v --collect-only 2>&1 | grep -c "test_" | xargs -I{} bash -c 'test {} -ge 6'</automated>
</verify>
<done>Test file exists with at least 6 test functions, all discoverable by pytest</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Implement Orchestrator class</name>
<files>src/gsd_openclaw/orchestrator.py, tests/test_orchestrator.py</files>
<behavior>
- 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
</behavior>
<action>
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
</action>
<verify>
<automated>pytest tests/test_orchestrator.py -v</automated>
</verify>
<done>Orchestrator class implemented with handle_message() and handle_callback(), 8+ tests pass</done>
</task>
<task type="auto">
<name>Task 3: Update SKILL.md and __init__.py exports</name>
<files>skill/SKILL.md, src/gsd_openclaw/__init__.py</files>
<action>
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
</action>
<verify>
<automated>python -c "from gsd_openclaw import Orchestrator, CommandExecutor, ApprovalHandler, ProgressMonitor; print('OK')"</automated>
</verify>
<done>SKILL.md updated with orchestrator documentation, __init__.py exports all new classes</done>
</task>
<task type="auto">
<name>Task 4: Integration test with all components</name>
<files>tests/test_orchestrator.py</files>
<action>
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.
</action>
<verify>
<automated>pytest tests/test_orchestrator.py -v --cov=src/gsd_openclaw/orchestrator</automated>
</verify>
<done>Integration tests added and passing, orchestrator coverage >90%</done>
</task>
</tasks>
<verification>
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%.
</verification>
<success_criteria>
- 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
</success_criteria>
<output>
After completion, create `.planning/phases/03-orchestration/03-03-SUMMARY.md`
</output>