7.7 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 | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-core-infrastructure | 02 | execute | 1 |
|
true |
|
|
Purpose: Each project gets its own isolated workspace with the defined directory structure. This ensures SESS-06 (isolated workspace per project).
Output: Working workspace.py with directory creation, structure validation, and cleanup.
<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/01-core-infrastructure/01-CONTEXT.md @.planning/phases/01-core-infrastructure/01-RESEARCH.mdDirectory layout:
~/gsd-workspaces/{project}/
├── .gsd/
│ ├── state.json # Session state
│ ├── state.json.bak # State backup
│ └── session-dump/ # Session dump
├── code/ # Project code (optional)
└── io-logs/
└── {session-id}.log # I/O logs
Key paths:
- Root:
Path.home() / "gsd-workspaces" / project_name - State:
workspace_root / ".gsd" / "state.json" - I/O logs:
workspace_root / "io-logs"
from dataclasses import dataclass
from pathlib import Path
from typing import Optional
@dataclass
class Workspace:
project_name: str
root: Path = None # Computed property
def __post_init__(self):
if self.root is None:
self.root = Path.home() / "gsd-workspaces" / self.project_name
@property
def gsd_dir(self) -> Path:
return self.root / ".gsd"
@property
def state_path(self) -> Path:
return self.gsd_dir / "state.json"
@property
def state_backup_path(self) -> Path:
return self.gsd_dir / "state.json.bak"
@property
def session_dump_dir(self) -> Path:
return self.gsd_dir / "session-dump"
@property
def code_dir(self) -> Path:
return self.root / "code"
@property
def io_logs_dir(self) -> Path:
return self.root / "io-logs"
def io_log_path(self, session_id: str) -> Path:
return self.io_logs_dir / f"{session_id}.log"
For testing, allow injecting a custom root path (for tmp_path isolation). pytest tests/test_workspace.py::test_workspace_paths -x Workspace dataclass exists with correct path properties for all directories
Task 2: Implement WorkspaceManager with create/destroy operations src/gsd_openclaw/workspace.py, tests/test_workspace.py - Test 1: create() creates all required directories - Test 2: create() is idempotent (calling twice doesn't fail) - Test 3: destroy() removes entire workspace directory - Test 4: exists() returns True after create, False after destroy - Test 5: Two projects have isolated workspaces (different roots) Create WorkspaceManager class:class WorkspaceManager:
WORKSPACES_ROOT = Path.home() / "gsd-workspaces"
def __init__(self, project_name: str, root: Optional[Path] = None):
self.project_name = project_name
self.root = root or self.WORKSPACES_ROOT
self.workspace = Workspace(project_name, self.root / project_name)
def create(self) -> Workspace:
"""Create workspace directory structure. Idempotent."""
# Create all directories
self.workspace.gsd_dir.mkdir(parents=True, exist_ok=True)
self.workspace.session_dump_dir.mkdir(exist_ok=True)
self.workspace.code_dir.mkdir(exist_ok=True)
self.workspace.io_logs_dir.mkdir(exist_ok=True)
return self.workspace
def destroy(self) -> None:
"""Remove entire workspace directory."""
import shutil
if self.workspace.root.exists():
shutil.rmtree(self.workspace.root)
def exists(self) -> bool:
"""Check if workspace exists."""
return self.workspace.root.exists()
def get_workspace(self) -> Workspace:
"""Get workspace object (does not create)."""
return self.workspace
The root parameter allows testing with tmp_path instead of home directory. pytest tests/test_workspace.py::test_workspace_create -x pytest tests/test_workspace.py::test_workspace_destroy -x pytest tests/test_workspace.py::test_workspace_isolation -x WorkspaceManager creates/destroys workspace directories, multiple projects are isolated
Task 3: Create test fixtures for workspace testing tests/conftest.py Add workspace fixtures to conftest.py:import pytest
from pathlib import Path
from gsd_openclaw.workspace import Workspace, WorkspaceManager
@pytest.fixture
def tmp_workspaces_root(tmp_path: Path) -> Path:
"""Temporary root for workspace testing."""
return tmp_path / "gsd-workspaces"
@pytest.fixture
def workspace_manager(tmp_workspaces_root: Path) -> WorkspaceManager:
"""WorkspaceManager with temporary root for isolation."""
manager = WorkspaceManager("test-project", tmp_workspaces_root)
yield manager
# Cleanup
if manager.workspace.root.exists():
import shutil
shutil.rmtree(manager.workspace.root)
This ensures tests don't pollute the real ~/gsd-workspaces directory. pytest tests/test_workspace.py -v Test fixtures exist for isolated workspace testing
Run full test suite: ```bash pytest tests/test_workspace.py -v ```Verify:
- Directory structure created correctly
- Idempotent create (no error on second call)
- Destroy removes all files
- Isolation between projects
<success_criteria>
- Workspace dataclass with all path properties exists
- WorkspaceManager creates directory structure
- WorkspaceManager destroys workspace cleanly
- Multiple projects have isolated workspaces
- All tests pass:
pytest tests/test_workspace.py -v</success_criteria>