Complete architectural separation of concerns implementing clean layered design: • Services Layer: Pure business logic isolated from presentation - WorkspaceService: TDD workspace operations - IssueService: Issue management and creation - ProjectService: Project management and milestones - ExportService: Unix-friendly data export • CLI Layer: Clean presentation with command/presenter separation - Commands delegate to services for all business operations - Presenters handle formatted output and error messaging - Framework provides unified interface • Benefits: - Eliminates mixed concerns in 943-line CLI monolith - Enables easier testing and maintenance - Preserves all existing functionality and Unix pipeline compatibility - Provides foundation for future CLI development Resolves issue #20: CLI separation from core logic 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
99 lines
3.9 KiB
Python
99 lines
3.9 KiB
Python
"""
|
|
Workspace CLI commands.
|
|
"""
|
|
|
|
from tddai import TddaiError
|
|
from services import WorkspaceService
|
|
from cli.presenters import OutputFormatter, WorkspaceView
|
|
|
|
|
|
class WorkspaceCommands:
|
|
"""Commands for workspace operations."""
|
|
|
|
def __init__(self):
|
|
self.service = WorkspaceService()
|
|
|
|
def status(self) -> None:
|
|
"""Show current workspace status."""
|
|
try:
|
|
summary = self.service.get_workspace_summary()
|
|
WorkspaceView.show_status(summary)
|
|
except TddaiError as e:
|
|
OutputFormatter.exit_with_error(str(e))
|
|
|
|
def start_issue(self, issue_number: int) -> None:
|
|
"""Start working on an issue."""
|
|
try:
|
|
OutputFormatter.info(f"Starting work on issue #{issue_number}...")
|
|
OutputFormatter.info(f"Fetching issue #{issue_number} details...")
|
|
|
|
workspace_info = self.service.start_issue_workspace(issue_number)
|
|
summary = self.service.get_workspace_summary()
|
|
WorkspaceView.show_start_success(summary)
|
|
|
|
except TddaiError as e:
|
|
if "Already working on" in str(e):
|
|
OutputFormatter.warning(str(e))
|
|
print(" Run 'make tdd-finish' first or 'make tdd-status' to see details")
|
|
OutputFormatter.exit_with_error("Cannot start new workspace", 1)
|
|
else:
|
|
OutputFormatter.exit_with_error(str(e))
|
|
|
|
def finish_issue(self) -> None:
|
|
"""Finish current issue workspace."""
|
|
try:
|
|
issue_number = self.service.finish_current_workspace()
|
|
if issue_number is None:
|
|
OutputFormatter.error("No active issue workspace")
|
|
print(" Nothing to finish")
|
|
OutputFormatter.exit_with_error("", 1)
|
|
|
|
# Get test count before finishing
|
|
summary = self.service.get_workspace_summary()
|
|
test_count = summary.get('test_count', 0)
|
|
|
|
WorkspaceView.show_finish_success(issue_number, test_count)
|
|
|
|
except TddaiError as e:
|
|
OutputFormatter.exit_with_error(str(e))
|
|
|
|
def add_test_guidance(self) -> None:
|
|
"""Show guidance for adding tests."""
|
|
try:
|
|
summary = self.service.get_workspace_summary()
|
|
if not summary['active']:
|
|
OutputFormatter.error("No active issue workspace")
|
|
print(" Run 'make tdd-start NUM=X' first")
|
|
OutputFormatter.exit_with_error("", 1)
|
|
|
|
issue_num = summary['issue_number']
|
|
issue_title = summary['issue_title']
|
|
workspace_dir = summary['workspace_dir']
|
|
|
|
print(f"🧪 Adding test to issue #{issue_num} workspace")
|
|
OutputFormatter.empty_line()
|
|
OutputFormatter.key_value("Issue", f"#{issue_num}: {issue_title}")
|
|
OutputFormatter.key_value("Workspace", f"{workspace_dir}/issue_{issue_num}/")
|
|
OutputFormatter.empty_line()
|
|
|
|
print("🤖 Please ask Claude Code to generate a test:")
|
|
OutputFormatter.empty_line()
|
|
print(" Command: 'Generate a test for the current workspace issue'")
|
|
OutputFormatter.empty_line()
|
|
|
|
print("📝 Test Requirements:")
|
|
print(f" - Save test in: {workspace_dir}/issue_{issue_num}/tests/")
|
|
print(f" - Name format: test_issue_{issue_num}_<scenario>.py")
|
|
print(f" - Include docstring referencing issue #{issue_num}")
|
|
print(" - Follow TDD principles (test should fail initially)")
|
|
print(" - Review requirements.md and test_plan.md for context")
|
|
OutputFormatter.empty_line()
|
|
|
|
print("📋 Issue Details:")
|
|
OutputFormatter.key_value("Title", issue_title)
|
|
# Note: Could fetch full issue details if needed
|
|
OutputFormatter.empty_line()
|
|
print("💡 After generation: Use 'make tdd-status' to see all tests")
|
|
|
|
except TddaiError as e:
|
|
OutputFormatter.exit_with_error(str(e)) |