254 lines
11 KiB
Markdown
254 lines
11 KiB
Markdown
---
|
|
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>
|