9.6 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | user_setup | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 04-gsd-integration | 02 | execute | 1 |
|
true |
|
|
Purpose: Enable key GSD commands that require orchestrator-level logic: pre-creating sessions for new-project and tracking user context for use.
Output: Orchestrator with _handle_new_project and _handle_use_project methods integrated into handle_message routing.
<execution_context> @/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md @/home/starmen1265/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/04-gsd-integration/04-CONTEXT.md @.planning/phases/04-gsd-integration/04-RESEARCH.mdFrom src/gsd_openclaw/orchestrator.py (current implementation):
class Orchestrator:
COMMAND_PATTERN = re.compile(r'^/gsd:(\S+)\s*(.*)$')
MAX_OUTPUT_LENGTH = 2000
def parse_command(self, message: str) -> Optional[Tuple[str, str]]:
"""Parse a message for /gsd:* command pattern."""
# Returns (command, args) or None
def handle_message(self, user_id: str, message: str, channel: str, context: Dict) -> Dict:
"""Main entry point - currently auto-creates session for all commands."""
From src/gsd_openclaw/response_formatter.py:
@dataclass
class CardButton:
"""Interactive button for Feishu Card actions."""
text: str
value: Dict[str, Any]
button_type: str = "primary" # primary, default, danger
From src/gsd_openclaw/tmux_session.py:
class TmuxSessionManager:
def create_session(self, project_name: str, ...) -> TmuxSession:
"""Create a new tmux session for a project."""
def get_session(self, project_name: str) -> Optional[TmuxSession]:
"""Get existing session without creating new one."""
Special command handling requirements (from CONTEXT.md):
- /gsd:new-project: Pre-create session, then pass command to tmux
- /gsd:use: Track user context, show error + "Create New Project" button if not exists
-
Add import: from gsd_openclaw.user_context import UserContextManager
-
Update Orchestrator.init:
- Add: self.user_context_managers: Dict[str, UserContextManager] = {}
- Add helper: _get_user_context_manager(user_id) -> UserContextManager
-
Add LONG_COMMANDS class attribute:
LONG_COMMANDS = {'execute-phase', 'plan-phase', 'discuss-phase', 'new-project'} -
Implement _handle_new_project(user_id: str, project_name: str) -> Dict:
- If project_name is empty, return format_error with "Project name required"
- Create session via tmux_manager.create_session(project_name)
- Execute "/gsd:new-project {project_name}" in the session with timeout=None
- Update user context: user_context.set_current_project(project_name)
- Return formatted result (success or error based on command result)
-
Update handle_message to route 'new-project' to _handle_new_project
-
Add TestSpecialCommands class to tests/test_orchestrator.py with tests for new-project pytest tests/test_orchestrator.py::TestSpecialCommands::test_new_project -x -v Orchestrator has _handle_new_project method that pre-creates session and updates user context
-
Implement _handle_use_project(user_id: str, project_name: str) -> Dict:
- If project_name is empty, return format_error with "Project name required"
- Check if project session exists: tmux_manager.get_session(project_name)
- If session exists:
- Update user context: user_context.set_current_project(project_name)
- Return format_success with "Switched to project '{project_name}'"
- If session doesn't exist:
- Return format_error with:
- title: "Project not found"
- content: "Project '{project_name}' does not exist"
- buttons: [CardButton(text="Create New Project", value={"action": "new-project", "name": project_name})]
- Return format_error with:
-
Update handle_message to route 'use' command to _handle_use_project
-
Add tests for _handle_use_project in TestSpecialCommands class
-
Ensure CardButton import is available from response_formatter pytest tests/test_orchestrator.py::TestSpecialCommands::test_use_project tests/test_orchestrator.py::TestSpecialCommands::test_use_nonexistent -x -v Orchestrator has _handle_use_project method with context tracking and error handling
-
Modify handle_message to get project from user context:
def handle_message(self, user_id, message, channel, context): # Parse command parsed = self.parse_command(message) if not parsed: return format_error(...) command, args = parsed # Special commands if command == 'new-project': return self._handle_new_project(user_id, args) if command == 'use': return self._handle_use_project(user_id, args) # Generic commands - get project from user context user_ctx = self._get_user_context_manager(user_id) project_name = user_ctx.get_current_project() if not project_name: project_name = context.get("project", "default") # Rest of existing logic... -
Ensure existing tests still pass (backward compatibility)
-
Add integration tests in TestIntegrationFlows for:
- Command after /gsd:use goes to correct project
- Context persists across multiple commands pytest tests/test_orchestrator.py -x -v handle_message routes special commands and uses user context for project selection
<success_criteria>
- Orchestrator has _handle_new_project and _handle_use_project methods
- Special commands are routed correctly in handle_message
- User context is used for project selection in generic commands
- Error cards include "Create New Project" button for missing projects </success_criteria>