feat(04-02): implement _handle_new_project with UserContextManager
- Add UserContextManager for per-user project tracking - Add _handle_new_project method that pre-creates sessions - Update user context after new-project creation - Route new-project command in handle_message - Add LONG_COMMANDS class attribute for timeout control Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,8 @@ from gsd_openclaw.tmux_session import TmuxSession, TmuxSessionManager
|
||||
from gsd_openclaw.command_executor import CommandExecutor, CommandResult
|
||||
from gsd_openclaw.approval_handler import ApprovalHandler
|
||||
from gsd_openclaw.progress_monitor import ProgressMonitor
|
||||
from gsd_openclaw.response_formatter import FeishuResponseFormatter
|
||||
from gsd_openclaw.response_formatter import FeishuResponseFormatter, CardButton
|
||||
from gsd_openclaw.user_context import UserContextManager
|
||||
|
||||
|
||||
class Orchestrator:
|
||||
@@ -40,6 +41,9 @@ class Orchestrator:
|
||||
# Maximum characters for card content (Feishu limit)
|
||||
MAX_OUTPUT_LENGTH = 2000
|
||||
|
||||
# Commands that require long-running sessions (no timeout)
|
||||
LONG_COMMANDS = {'execute-phase', 'plan-phase', 'discuss-phase', 'new-project'}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tmux_manager: Optional[TmuxSessionManager] = None,
|
||||
@@ -58,6 +62,79 @@ class Orchestrator:
|
||||
self.executor = CommandExecutor()
|
||||
self.approval_handler = ApprovalHandler(self.formatter)
|
||||
self.progress_monitor = ProgressMonitor(self.formatter)
|
||||
self.user_context_managers: Dict[str, UserContextManager] = {}
|
||||
|
||||
def _get_user_context_manager(self, user_id: str) -> UserContextManager:
|
||||
"""Get or create UserContextManager for a user.
|
||||
|
||||
Args:
|
||||
user_id: The user identifier.
|
||||
|
||||
Returns:
|
||||
UserContextManager instance for the user.
|
||||
"""
|
||||
if user_id not in self.user_context_managers:
|
||||
self.user_context_managers[user_id] = UserContextManager(user_id)
|
||||
return self.user_context_managers[user_id]
|
||||
|
||||
def _handle_new_project(self, user_id: str, project_name: str) -> Dict[str, Any]:
|
||||
"""Handle /gsd:new-project command.
|
||||
|
||||
Pre-creates a tmux session before executing the command,
|
||||
then updates user context to track the new project.
|
||||
|
||||
Args:
|
||||
user_id: ID of the user sending the command.
|
||||
project_name: Name of the project to create.
|
||||
|
||||
Returns:
|
||||
Feishu Card JSON dict as response.
|
||||
"""
|
||||
# Validate project name
|
||||
if not project_name or not project_name.strip():
|
||||
return self.formatter.format_error(
|
||||
title="Project name required",
|
||||
content="Please provide a project name: /gsd:new-project <name>"
|
||||
)
|
||||
|
||||
project_name = project_name.strip()
|
||||
|
||||
try:
|
||||
# Create session first
|
||||
session = self.tmux_manager.create_session(project_name)
|
||||
|
||||
# Build and execute the new-project command
|
||||
full_command = f"/gsd:new-project {project_name}"
|
||||
|
||||
# Execute with no timeout for long-running commands
|
||||
result = self.executor.execute(session, full_command, timeout=None)
|
||||
|
||||
# Update user context
|
||||
user_ctx = self._get_user_context_manager(user_id)
|
||||
user_ctx.set_current_project(project_name)
|
||||
|
||||
# Truncate output if needed
|
||||
output = result.output
|
||||
if len(output) > self.MAX_OUTPUT_LENGTH:
|
||||
output = output[-self.MAX_OUTPUT_LENGTH:]
|
||||
|
||||
# Return appropriate response
|
||||
if result.has_error:
|
||||
return self.formatter.format_error(
|
||||
title="Project creation failed",
|
||||
content=output
|
||||
)
|
||||
else:
|
||||
return self.formatter.format_success(
|
||||
title="Project created",
|
||||
content=f"Project '{project_name}' created successfully.\n\n{output}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return self.formatter.format_error(
|
||||
title="Project creation failed",
|
||||
content=str(e)[-self.MAX_OUTPUT_LENGTH:]
|
||||
)
|
||||
|
||||
def parse_command(self, message: str) -> Optional[Tuple[str, str]]:
|
||||
"""Parse a message for /gsd:* command pattern.
|
||||
@@ -112,6 +189,10 @@ class Orchestrator:
|
||||
|
||||
command, args = parsed
|
||||
|
||||
# Route special commands
|
||||
if command == 'new-project':
|
||||
return self._handle_new_project(user_id, args)
|
||||
|
||||
# Get project name from context
|
||||
project_name = context.get("project", "default")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user