feat: complete working-copies workspace-first cleanup
- Remove clone_mode/branch/new_branch from frontend create session flow. - Add workspace picker to CreateSessionForm; auto-create default workspace when repo selected. - Fix tool-starter.tsx and use-start-tool.ts createInstance signatures after API change. - Remove clone mode badge from SessionCard. - Delete stale backend unit tests referencing removed clone_mode schema fields. - Update OpenSpec working-copies tasks and mark change completed. - Regenerate project maps. Quality gates: npm run typecheck, npm run lint, npm test -- --run (82 passed), python3 -m py_compile on changed backend files.
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@ dir: .
|
||||
Trust boundary: index routes, map orients, source decides.
|
||||
|
||||
## role
|
||||
Infrastructure and deployment configuration for a self-hosted project management platform with OAuth2 authentication, providing Docker Compose orchestration, environment templates, and development tooling.
|
||||
Infrastructure and deployment configuration package for a self-hosted project management platform with OAuth2 authentication, providing Docker orchestration, environment templates, and development tooling.
|
||||
## parent
|
||||
-
|
||||
## children
|
||||
|
||||
+3
-3
@@ -18,10 +18,10 @@ index: ./.pi-map.index.md
|
||||
Trust boundary: index routes, map orients, source decides.
|
||||
|
||||
## role
|
||||
Infrastructure and deployment configuration for a self-hosted project management platform with OAuth2 authentication, providing Docker Compose orchestration, environment templates, and development tooling.
|
||||
Infrastructure and deployment configuration package for a self-hosted project management platform with OAuth2 authentication, providing Docker orchestration, environment templates, and development tooling.
|
||||
## files
|
||||
- .env.example | Provides a template of environment variables for configuring a Headquarter application with PostgreSQL, Redis, Authentik SSO, and Docker/Traefik deployment
|
||||
- .gitignore | Specifies files and directories for Git to ignore across a multi-language project with Python, Node, and various tooling | dep: git
|
||||
- .gitignore | Specifies files and directories for Git to ignore across a multi-language project with Python, Node, and custom tooling | dep: Git
|
||||
- AGENTS.md | Defines operational rules, workflows, and constraints for AI agents working within an OpenSpec-driven software development project. | dep: OpenSpec, superpowers, git, docker compose, conventional commits
|
||||
- CHANGELOG.md | Documents version history and notable changes for a Git-based project management web application
|
||||
- Makefile | Provides standard development commands for containerized web application lifecycle management via Docker Compose | dep: docker compose, alembic, pytest, ruff, mypy, playwright, npm, postgres, redis
|
||||
@@ -31,7 +31,7 @@ Infrastructure and deployment configuration for a self-hosted project management
|
||||
- progress.md | Tracks completed and remaining tasks for a backend-frontend code refactoring project organized in 7 phases
|
||||
- swap-pane | Empty file with no functionality
|
||||
## arch
|
||||
Containerized microservices architecture using Docker Compose with separate frontend/API/PostgreSQL/Redis services, Traefik reverse proxy integration, and environment-driven configuration; includes AI agent governance via OpenSpec and Makefile-driven development workflows.
|
||||
Containerized microservices architecture using Docker Compose with PostgreSQL/Redis data layer, Traefik reverse proxy for TLS/ingress, and environment-driven configuration; includes Python/Node multi-language backend-frontend split with Makefile-driven lifecycle management.
|
||||
## tags
|
||||
docker, redis, git, application, postgresql, compose, traefik, project
|
||||
## symbols
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps
|
||||
|
||||
## role
|
||||
Contains the main application entry points and executable modules for the project.
|
||||
Contains the top-level application entry points and executable binaries for the project.
|
||||
## parent
|
||||
index: ./.pi-map.index.md
|
||||
map: ./.pi-map.md
|
||||
|
||||
+2
-2
@@ -4,10 +4,10 @@ dir: apps
|
||||
index: apps/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Contains the main application entry points and executable modules for the project.
|
||||
Contains the top-level application entry points and executable binaries for the project.
|
||||
## files
|
||||
## arch
|
||||
Typically follows a modular architecture where each subdirectory represents a separate deployable application sharing common domain libraries.
|
||||
Follows a workspace/monorepo pattern where each subdirectory is a distinct deployable application sharing common libraries.
|
||||
## tags
|
||||
-
|
||||
## symbols
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
"""Tests for session creation with branch selection and new branch creation."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
|
||||
from src.api.tool_instances import CreateInstanceRequest
|
||||
|
||||
|
||||
class TestCreateInstanceRequest:
|
||||
"""Tests for CreateInstanceRequest model."""
|
||||
|
||||
def test_default_values(self):
|
||||
"""Test default values for CreateInstanceRequest."""
|
||||
request = CreateInstanceRequest(tool_type_id="123")
|
||||
assert request.clone_mode == "mount"
|
||||
assert request.branch == "main"
|
||||
assert request.new_branch is None
|
||||
assert request.display_name is None
|
||||
|
||||
def test_clone_mode_with_branch(self):
|
||||
"""Test CreateInstanceRequest with clone mode and branch."""
|
||||
request = CreateInstanceRequest(
|
||||
tool_type_id="123",
|
||||
clone_mode="clone",
|
||||
branch="dev",
|
||||
)
|
||||
assert request.clone_mode == "clone"
|
||||
assert request.branch == "dev"
|
||||
|
||||
def test_new_branch_field(self):
|
||||
"""Test CreateInstanceRequest with new_branch field."""
|
||||
request = CreateInstanceRequest(
|
||||
tool_type_id="123",
|
||||
clone_mode="clone",
|
||||
branch="main",
|
||||
new_branch="feature/test",
|
||||
)
|
||||
assert request.new_branch == "feature/test"
|
||||
|
||||
|
||||
class TestBranchCreationInClone:
|
||||
"""Tests for branch creation logic in clone process."""
|
||||
|
||||
def test_create_local_branch_success(self):
|
||||
"""Test successful local branch creation."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Initialize repo
|
||||
subprocess.run(
|
||||
["git", "init", tmpdir],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "config", "user.email", "test@test.com"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "config", "user.name", "Test User"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Create initial commit
|
||||
readme = os.path.join(tmpdir, "README.md")
|
||||
with open(readme, "w") as f:
|
||||
f.write("# Test\n")
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "add", "README.md"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "commit", "-m", "Initial commit"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Create new branch
|
||||
result = subprocess.run(
|
||||
["git", "-C", tmpdir, "checkout", "-b", "feature/new-branch"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert result.returncode == 0
|
||||
|
||||
# Verify branch exists
|
||||
branches_result = subprocess.run(
|
||||
["git", "-C", tmpdir, "branch", "--show-current"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert branches_result.stdout.strip() == "feature/new-branch"
|
||||
|
||||
def test_create_local_branch_invalid_name(self):
|
||||
"""Test local branch creation with invalid name fails."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Initialize repo
|
||||
subprocess.run(
|
||||
["git", "init", tmpdir],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "config", "user.email", "test@test.com"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "config", "user.name", "Test User"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Create initial commit
|
||||
readme = os.path.join(tmpdir, "README.md")
|
||||
with open(readme, "w") as f:
|
||||
f.write("# Test\n")
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "add", "README.md"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", tmpdir, "commit", "-m", "Initial commit"],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Try to create branch with invalid name (contains spaces)
|
||||
result = subprocess.run(
|
||||
["git", "-C", tmpdir, "checkout", "-b", "invalid branch name"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
# Git accepts branch names with spaces but it's not recommended
|
||||
# This test verifies the command structure
|
||||
assert result.returncode == 0 or "fatal" in result.stderr
|
||||
|
||||
|
||||
class TestCreateInstanceAPI:
|
||||
"""Tests for create instance API endpoint with branch options."""
|
||||
|
||||
def test_create_instance_request_validation(self):
|
||||
"""Test that CreateInstanceRequest validates correctly."""
|
||||
# Valid request with new_branch
|
||||
request = CreateInstanceRequest(
|
||||
tool_type_id="550e8400-e29b-41d4-a716-446655440000",
|
||||
clone_mode="clone",
|
||||
branch="main",
|
||||
new_branch="feature/test",
|
||||
)
|
||||
assert request.new_branch == "feature/test"
|
||||
|
||||
# Valid request without new_branch
|
||||
request2 = CreateInstanceRequest(
|
||||
tool_type_id="550e8400-e29b-41d4-a716-446655440000",
|
||||
clone_mode="clone",
|
||||
branch="dev",
|
||||
)
|
||||
assert request2.new_branch is None
|
||||
|
||||
def test_create_instance_with_new_branch_sets_instance_branch(self):
|
||||
"""Test that instance branch is set to new_branch when provided."""
|
||||
# This tests the logic: data.new_branch if data.new_branch else data.branch
|
||||
new_branch = "feature/test"
|
||||
base_branch = "main"
|
||||
|
||||
# Simulate the logic from create_instance
|
||||
stored_branch = new_branch if new_branch else base_branch
|
||||
assert stored_branch == "feature/test"
|
||||
|
||||
# Without new_branch
|
||||
stored_branch2 = None if None else base_branch
|
||||
assert stored_branch2 == "main"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
dir: apps/web
|
||||
|
||||
## role
|
||||
Browser-based web frontend providing the user-facing React application for code editing, terminal access, and routing functionality.
|
||||
Frontend web application providing a React-based UI with code editing, terminal, and routing capabilities for the "headquarter" project.
|
||||
## parent
|
||||
index: apps/.pi-map.index.md
|
||||
map: apps/.pi-map.md
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ dir: apps/web
|
||||
index: apps/web/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Browser-based web frontend providing the user-facing React application for code editing, terminal access, and routing functionality.
|
||||
Frontend web application providing a React-based UI with code editing, terminal, and routing capabilities for the "headquarter" project.
|
||||
## files
|
||||
- .env.example | Template file defining example environment variables for frontend API and application URL configuration
|
||||
- .eslintrc.cjs | Configures ESLint for a TypeScript browser project with modern ECMAScript module support | dep: @typescript-eslint/parser, @typescript-eslint/eslint-plugin, eslint
|
||||
@@ -16,7 +16,7 @@ Browser-based web frontend providing the user-facing React application for code
|
||||
- tsconfig.json | TypeScript configuration file for a React project using Vite with modern ES2020 target and bundler module resolution | dep: typescript, react, vite
|
||||
- vite.config.ts | Configures Vite build tool for a React project with custom dev server port and Vitest test settings. | dep: vite, @vitejs/plugin-react
|
||||
## arch
|
||||
Modern React SPA built with Vite and TypeScript, containerized via multi-stage Docker/nginx deployment with client-side routing and optimized static asset delivery.
|
||||
Modern React SPA built with Vite and TypeScript, containerized via multi-stage Docker with nginx serving, featuring client-side routing, optimized static asset delivery, and development tooling (ESLint, Vitest).
|
||||
## tags
|
||||
react, eslint, vite, typescript, dom, application, nginx, web
|
||||
## symbols
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps/web/src
|
||||
|
||||
## role
|
||||
Frontend web application entry point and core infrastructure for a React-based single-page application with authentication, routing, and domain type definitions.
|
||||
Frontend web application entry point and core infrastructure for a React single-page application with authentication, routing, and domain type definitions.
|
||||
## parent
|
||||
index: apps/web/.pi-map.index.md
|
||||
map: apps/web/.pi-map.md
|
||||
|
||||
@@ -4,13 +4,13 @@ dir: apps/web/src
|
||||
index: apps/web/src/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Frontend web application entry point and core infrastructure for a React-based single-page application with authentication, routing, and domain type definitions.
|
||||
Frontend web application entry point and core infrastructure for a React single-page application with authentication, routing, and domain type definitions.
|
||||
## files
|
||||
- main.tsx | Entry point that bootstraps a React SPA with routing, authentication, and session management context providers. | dep: react, react-dom/client, react-router-dom, ./router, ./state/auth, ./state/sessions, ./styles/tokens.css, ./styles/global.css, ./styles/utilities.css, ./styles/syntax-highlight.css, ./styles/pages/git-history.css, ./styles/pages/repo-workspace.css, ./styles/pages/projects.css, ./styles/pages/sessions.css, ./styles/pages/ssh-keys.css, ./styles/pages/workspace-detail.css, ./styles/pages/workspaces.css, react-dom, ./styles/*
|
||||
- router.tsx | Defines the React Router configuration for a web application with protected routes, nested layouts, and redirects. | exp: AppRouter | dep: react-router-dom, ./components/app-shell, ./components/protected-route, ./pages/DashboardPage, ./pages/PlaceholderPage, ./pages/ProfilePage, ./pages/ProjectsPage, ./pages/GitRepositoriesPage, ./pages/GitHistoryPage, ./pages/ProjectSettingsPage, ./pages/SettingsPage, ./pages/TerminalPage, ./pages/ToolWorkshopPage, ./pages/SshKeysPage, ./pages/ConfigProfilesPage, ./pages/SessionsPage, ./pages/WorkspacesPage, ./pages/WorkspaceDetailPage
|
||||
- types.ts | Defines TypeScript type definitions for user sessions, projects, repositories, and workspaces in an application. | exp: SessionUser, SessionPayload, Project, WorkspaceSummary, RepositorySummary, ProjectWithRepos
|
||||
## arch
|
||||
Layered React SPA architecture using context providers for cross-cutting concerns (auth/session), declarative routing with protected route guards and nested layouts, and centralized TypeScript type definitions for domain models.
|
||||
Layered React SPA architecture using context providers for cross-cutting concerns (auth/session), declarative routing with nested layouts and route guards, and centralized TypeScript type definitions for domain models.
|
||||
## tags
|
||||
pages, styles, css, router, react, session, dom, workspace
|
||||
## symbols
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps/web/src/components
|
||||
|
||||
## role
|
||||
Provides reusable, foundational React UI components and utilities for the web application, including layout shell, data visualization, navigation guards, and user feedback systems.
|
||||
Provides foundational, reusable UI components and utilities for the web application, including layout shell, data states, icon system, code display, routing guards, and toast notification rules.
|
||||
## parent
|
||||
index: apps/web/src/.pi-map.index.md
|
||||
map: apps/web/src/.pi-map.md
|
||||
|
||||
@@ -4,7 +4,7 @@ dir: apps/web/src/components
|
||||
index: apps/web/src/components/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Provides reusable, foundational React UI components and utilities for the web application, including layout shell, data visualization, navigation guards, and user feedback systems.
|
||||
Provides foundational, reusable UI components and utilities for the web application, including layout shell, data states, icon system, code display, routing guards, and toast notification rules.
|
||||
## files
|
||||
- app-shell.tsx | Renders the main application shell layout with navigation, session management, and responsive mobile/desktop views for a React Router-based app. | exp: AppShell | dep: react-router-dom, ../api/sessions, ../hooks/use-theme, ../state/auth, ../state/sessions, ../hooks/use-mobile-viewport, ../state/events, ../state/toast, ../state/notifications, ../state/session-operations, ./features/notification/event-toast-bridge, ./features/notification/notification-center, ./features/session/session-progress-panel, ./icon, ./features/mobile/mobile-nav, ./features/tool/start-tool-fab, ../utils/icons
|
||||
- code-editor.tsx | A React component that renders a syntax-highlighted code editor with line numbers using react-simple-code-editor. | exp: CodeEditor | dep: react, react-simple-code-editor, ../utils/language
|
||||
@@ -16,7 +16,7 @@ Provides reusable, foundational React UI components and utilities for the web ap
|
||||
- toast-rules.test.ts | Unit tests for mapping instance events to toast notification categories and severities | dep: vitest, ./toast-rules, ../types/events
|
||||
- toast-rules.ts | Maps instance events to toast notifications with deduplication logic to prevent spam | exp: func:mapEventToCategory(event: InstanceEventPayload) → string, call:event.event.startsWith, func:mapEventToSeverity(event: InstanceEventPayload) → "info" | "warning" | "error" | "success", func:handleEventToast(event: InstanceEventPayload) → void, call:shouldShowToast, call:toast.info, call:toast.success, call:toast.warning, call:toast.error, func:clearToastDedup() → void, call:lastToastTime.clear | dep: ../state/toast, ../types/events, toast state module, InstanceEventPayload type
|
||||
## arch
|
||||
Component-based architecture with functional React patterns, composition of specialized sub-components (icon, editor, syntax highlighter), separation of concerns via dedicated state-management components (data states, protected routes), and utility modules with pure logic for cross-cutting concerns (toast rules with deduplication).
|
||||
Follows a component-based React architecture with separation of concerns between presentational components (icon, data-states, code-editor), layout/app-shell orchestration, auth-guarded routing (protected-route), and domain-specific utility modules (toast-rules) with colocated unit tests.
|
||||
## tags
|
||||
toast, state, react, icon, code, event, editor, protected
|
||||
## symbols
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps/web/src/components/features
|
||||
|
||||
## role
|
||||
Contains reusable React components that implement specific product features and business logic for the web application.
|
||||
Contains specialized UI components for major feature areas of the web application, organizing components by business domain rather than by atomic design level.
|
||||
## parent
|
||||
index: apps/web/src/components/.pi-map.index.md
|
||||
map: apps/web/src/components/.pi-map.md
|
||||
|
||||
@@ -4,10 +4,10 @@ dir: apps/web/src/components/features
|
||||
index: apps/web/src/components/features/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Contains reusable React components that implement specific product features and business logic for the web application.
|
||||
Contains specialized UI components for major feature areas of the web application, organizing components by business domain rather than by atomic design level.
|
||||
## files
|
||||
## arch
|
||||
Feature-based component organization with domain-specific UI building blocks, likely composed of atomic design elements (from components/ui) and consumed by page-level routes.
|
||||
Feature-based colocation pattern where components are grouped by product functionality (e.g., checkout, dashboard, settings) rather than by component type, typically combining multiple atomic components with domain-specific logic and data fetching.
|
||||
## tags
|
||||
-
|
||||
## symbols
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps/web/src/components/features/session
|
||||
|
||||
## role
|
||||
Provides UI components for managing development environment sessions including creation, listing, monitoring progress, and interacting with individual sessions.
|
||||
Provides UI components for managing development sessions including creation, listing, monitoring progress, and interacting with individual sessions.
|
||||
## parent
|
||||
index: apps/web/src/components/features/.pi-map.index.md
|
||||
map: apps/web/src/components/features/.pi-map.md
|
||||
|
||||
@@ -4,16 +4,16 @@ dir: apps/web/src/components/features/session
|
||||
index: apps/web/src/components/features/session/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Provides UI components for managing development environment sessions including creation, listing, monitoring progress, and interacting with individual sessions.
|
||||
Provides UI components for managing development sessions including creation, listing, monitoring progress, and interacting with individual sessions.
|
||||
## files
|
||||
- create-session-form.tsx | React form component for creating development sessions with configurable project, repository, tool type, branch, SSH keys, and config profile options | exp: CreateSessionForm | dep: react, ../../icon, ../../../api/sessions, ../../../types, ../../../api/git-repositories, ../../../api/tool-types, ../../../api/ssh-keys, ../../../api/config-profiles, icon component, sessions API, git-repositories API, ssh-keys API, config-profiles API, tool-types API, types
|
||||
- session-card.tsx | Renders a React card component displaying session information with status badges, inline editing, action buttons, and responsive mobile/desktop layouts. | exp: SessionCardProps, func:SessionCard({ session, onOpen, onStart, onStop, onDelete, onRecreateTunnel, onRename, isBusy = false, tunnelHealth = null, }: SessionCardProps), call:useState, call:useRef, call:useMobileViewport, call:session.tool_type_interfaces?.includes, call:[ "running", "building", "starting", "probing", "pending", "unhealthy", ].includes, call:useEffect, call:optionsRef.current.contains, call:setOptionsOpen, call:document.addEventListener, call:document.removeEventListener, call:window.confirm, call:onDelete, call:setEditName, call:onRename, call:setIsEditingName, call:editName.trim, call:onOpen, call:new Date(session.created_at).toLocaleString, call:setShowActionSheet, call:onStart, call:onStop, call:onRecreateTunnel | dep: react, ../../../api/sessions, ../../icon, ../../../hooks/use-mobile-viewport, ../mobile/mobile-action-sheet, icon, use-mobile-viewport, mobile-action-sheet, sessions api types
|
||||
- create-session-form.tsx | A React form component for creating and starting a new development session with configurable project, repository, workspace, tool type, config profile, and SSH key options. | exp: CreateSessionForm | dep: react, ../../icon, ../../../api/sessions, ../../../types, ../../../api/git-repositories, ../../../api/tool-types, ../../../api/ssh-keys, ../../../api/config-profiles, ../../../api/workspaces, ../../../types/workspace, icon, sessions API, git-repositories API, tool-types API, ssh-keys API, config-profiles API, workspaces API, types
|
||||
- session-card.tsx | Renders a card component displaying session information with status badges, inline rename editing, action buttons, and responsive mobile/desktop layouts including a dropdown options menu and mobile action sheet. | exp: SessionCardProps, func:SessionCard({ session, onOpen, onStart, onStop, onDelete, onRecreateTunnel, onRename, isBusy = false, tunnelHealth = null, }: SessionCardProps), call:useState, call:useRef, call:useMobileViewport, call:session.tool_type_interfaces?.includes, call:[ "running", "building", "starting", "probing", "pending", "unhealthy", ].includes, call:useEffect, call:optionsRef.current.contains, call:setOptionsOpen, call:document.addEventListener, call:document.removeEventListener, call:window.confirm, call:onDelete, call:setEditName, call:onRename, call:setIsEditingName, call:editName.trim, call:onOpen, call:new Date(session.created_at).toLocaleString, call:setShowActionSheet, call:onStart, call:onStop, call:onRecreateTunnel | dep: react, ../../../api/sessions, ../../icon, ../../../hooks/use-mobile-viewport, ../mobile/mobile-action-sheet
|
||||
- session-list.tsx | Renders a list of sessions grouped by active/recent status or as a flat grid, delegating to SessionCard for individual session display. | exp: SessionListProps, func:SessionList({ sessions, onOpen, onStart, onStop, onDelete, onRecreateTunnel, onRename, actionBusyId = null, tunnelHealth = {}, showGrouping = true, activeTitle = "Active Sessions", recentTitle = "Recent Sessions", maxRecent = 5, emptyMessage = "No sessions", }: SessionListProps), call:sessions.filter, call:activeStatuses.includes, call:sessions .filter((s) => recentStatuses.includes(s.status)) .slice, call:recentStatuses.includes, call:sessions.map, call:activeSessions.map, call:recentSessions.map | dep: ../../../api/sessions, ./session-card, Session, SessionCard, InstanceHealth
|
||||
- session-progress-panel.tsx | Renders a panel displaying active and recently completed session operations with step-by-step progress indicators and dismissible notifications. | exp: func:SessionProgressPanel(), call:useSessionOperations, call:useEventContext, call:useEffect, call:updateOperationFromEvent, call:operations.filter, call:Date.now, call:visibleOperations.map, call:dismissOperation | dep: react, ../../../state/session-operations, ../../../state/events, ../../icon, useSessionOperations, useEventContext, Icon
|
||||
## arch
|
||||
Feature-based component composition with presentational components following a container/presenter pattern, using status-driven conditional rendering and responsive layout adaptations.
|
||||
React component composition with feature-specific grouping, responsive design patterns (mobile/desktop layouts), and status-driven conditional rendering with delegated sub-components.
|
||||
## tags
|
||||
session, call:use, call:on, card, mobile, call:set, event, api
|
||||
session, call:use, call:on, api, card, call:set, event, mobile
|
||||
## symbols
|
||||
- SessionCard
|
||||
- SessionList
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
listConfigProfiles,
|
||||
type ConfigProfile,
|
||||
} from "../../../api/config-profiles";
|
||||
import { listWorkspaces, createWorkspace } from "../../../api/workspaces";
|
||||
import type { Workspace } from "../../../types/workspace";
|
||||
|
||||
interface CreateSessionFormProps {
|
||||
projects: Project[];
|
||||
@@ -54,6 +56,10 @@ export const CreateSessionForm = ({
|
||||
const [selectedConfigProfile, setSelectedConfigProfile] = useState("");
|
||||
const [selectedSshKeyIds, setSelectedSshKeyIds] = useState<string[]>([]);
|
||||
|
||||
const [workspaces, setWorkspaces] = useState<Workspace[]>([]);
|
||||
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState("");
|
||||
const [isLoadingWorkspaces, setIsLoadingWorkspaces] = useState(false);
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -94,6 +100,50 @@ export const CreateSessionForm = ({
|
||||
void loadProfiles();
|
||||
}, [selectedToolType, selectedProject, fixedProjectId]);
|
||||
|
||||
// Load workspaces when repository is selected
|
||||
useEffect(() => {
|
||||
const projectId = fixedProjectId || selectedProject;
|
||||
const repoId = fixedRepoId || selectedRepo;
|
||||
if (!projectId || !repoId) {
|
||||
setWorkspaces([]);
|
||||
setSelectedWorkspaceId("");
|
||||
return;
|
||||
}
|
||||
const loadWorkspaces = async () => {
|
||||
setIsLoadingWorkspaces(true);
|
||||
try {
|
||||
const data = await listWorkspaces(projectId, repoId);
|
||||
setWorkspaces(data);
|
||||
if (data.length > 0) {
|
||||
setSelectedWorkspaceId(data[0].id);
|
||||
} else {
|
||||
// Auto-create a default workspace so the user can start a tool
|
||||
const workspace = await createWorkspace(projectId, repoId, {
|
||||
name: "default",
|
||||
branch: "main",
|
||||
});
|
||||
setWorkspaces([workspace]);
|
||||
setSelectedWorkspaceId(workspace.id);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Failed to load workspaces",
|
||||
);
|
||||
setWorkspaces([]);
|
||||
setSelectedWorkspaceId("");
|
||||
} finally {
|
||||
setIsLoadingWorkspaces(false);
|
||||
}
|
||||
};
|
||||
void loadWorkspaces();
|
||||
}, [
|
||||
fixedProjectId,
|
||||
selectedProject,
|
||||
fixedRepoId,
|
||||
selectedRepo,
|
||||
repositories,
|
||||
]);
|
||||
|
||||
// Filter repositories by selected project
|
||||
const availableRepos = selectedProject
|
||||
? repositories.filter((r) => r.project_id === selectedProject)
|
||||
@@ -106,6 +156,8 @@ export const CreateSessionForm = ({
|
||||
setDisplayName("");
|
||||
setSelectedSshKeyIds([]);
|
||||
setSelectedConfigProfile("");
|
||||
setWorkspaces([]);
|
||||
setSelectedWorkspaceId("");
|
||||
};
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent) => {
|
||||
@@ -123,12 +175,19 @@ export const CreateSessionForm = ({
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const workspaceId = selectedWorkspaceId || undefined;
|
||||
if (!workspaceId) {
|
||||
setError("No workspace available for the selected repository");
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const instance = await createInstance(
|
||||
projectId,
|
||||
repoId,
|
||||
selectedToolType,
|
||||
displayName || undefined,
|
||||
undefined,
|
||||
workspaceId,
|
||||
selectedConfigProfile || undefined,
|
||||
selectedSshKeyIds.length > 0 ? selectedSshKeyIds : undefined,
|
||||
);
|
||||
@@ -214,6 +273,7 @@ export const CreateSessionForm = ({
|
||||
onChange={(e) => {
|
||||
setSelectedRepo(e.target.value);
|
||||
setSelectedToolType("");
|
||||
setSelectedWorkspaceId("");
|
||||
}}
|
||||
disabled={!hasProject || isSubmitting}
|
||||
>
|
||||
@@ -228,6 +288,30 @@ export const CreateSessionForm = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Workspace */}
|
||||
{hasRepo && (
|
||||
<div className="form-field">
|
||||
<label>Workspace</label>
|
||||
{isLoadingWorkspaces ? (
|
||||
<span className="muted">Loading workspaces...</span>
|
||||
) : workspaces.length === 0 ? (
|
||||
<span className="muted">No workspace available</span>
|
||||
) : (
|
||||
<select
|
||||
value={selectedWorkspaceId}
|
||||
onChange={(e) => setSelectedWorkspaceId(e.target.value)}
|
||||
disabled={!hasRepo || isSubmitting || isLoadingWorkspaces}
|
||||
>
|
||||
{workspaces.map((w) => (
|
||||
<option key={w.id} value={w.id}>
|
||||
{w.name} ({w.branch})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Tool Type */}
|
||||
{hasRepo && (
|
||||
<div className="form-field">
|
||||
|
||||
@@ -176,14 +176,6 @@ export function SessionCard({
|
||||
)}{" "}
|
||||
· {session.tool_type_name}
|
||||
</p>
|
||||
{session.clone_mode && (
|
||||
<p className="muted session-card-meta">
|
||||
<Icon name="branch" size="sm" />
|
||||
{session.clone_mode === "clone"
|
||||
? `Clone${session.branch ? ` (${session.branch})` : ""}`
|
||||
: "Mount"}
|
||||
</p>
|
||||
)}
|
||||
{session.url && (
|
||||
<p className="session-card-url">
|
||||
<button
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps/web/src/components/features/tool
|
||||
|
||||
## role
|
||||
Provides UI components for managing container-based development tools, including instance lifecycle operations, manifest editing, and workspace-integrated tool launching.
|
||||
Provides UI components for managing containerized development tools, including instance lifecycle operations, manifest editing, and workspace-integrated tool launching.
|
||||
## parent
|
||||
index: apps/web/src/components/features/.pi-map.index.md
|
||||
map: apps/web/src/components/features/.pi-map.md
|
||||
|
||||
@@ -4,16 +4,16 @@ dir: apps/web/src/components/features/tool
|
||||
index: apps/web/src/components/features/tool/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Provides UI components for managing container-based development tools, including instance lifecycle operations, manifest editing, and workspace-integrated tool launching.
|
||||
Provides UI components for managing containerized development tools, including instance lifecycle operations, manifest editing, and workspace-integrated tool launching.
|
||||
## files
|
||||
- instance-list.tsx | Displays and manages a list of tool instances with CRUD operations, real-time status updates, and configuration profile selection. | exp: InstanceList | dep: react, react-router-dom, ../../icon, ../../../api/sessions, ../../../api/tool-types, ../session/create-session-form, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/events, ../../../state/sessions, icon, api/sessions, api/tool-types, api/config-profiles, api/ssh-keys, state/events, state/sessions
|
||||
- manifest-editor.tsx | A React component that provides a form-based UI for editing container tool definition manifests with fields for base images, packages, user config, environment variables, scripts, mounts, and runtime settings, including compilation preview functionality. | exp: ManifestEditor | dep: react, ../../icon, ../../../utils/errors, ../../../api/tool-definitions, icon, errors, tool-definitions
|
||||
- start-tool-fab.tsx | A floating action button component that opens a modal to select a workspace and start a tool. | exp: func:StartToolFAB(), call:useState, call:setOpen, call:setWorkspacesLoading, call:listAllWorkspaces, call:setWorkspaces, call:setSelectedWorkspace, call:e.stopPropagation, call:workspaces.find, call:workspaces.map | dep: react, ../../icon, ./tool-starter, ../../../types/workspace, ../../../api/workspaces, icon, tool-starter, workspaces api, workspace types
|
||||
- start-tool-modal.tsx | Renders a modal dialog for selecting a tool type and optional config profile to start on a workspace. | exp: StartToolModalProps, func:StartToolModal({ workspace, onClose, onStart, }: StartToolModalProps), call:useState, call:useAsyncData, call:e.preventDefault, call:setError, call:setSubmitting, call:onStart, call:onClose, call:e.stopPropagation, call:setToolTypeId, call:toolTypes?.map, call:setConfigProfileId | dep: react, ../../icon, ../../../api/tool-types, ../../../hooks/use-async-data, ../../../types/workspace, icon, tool-types, use-async-data, workspace
|
||||
- tool-starter.tsx | React component that provides a workspace-first form for starting a new tool instance, fetching tool types, config profiles, and SSH keys dynamically. | exp: ToolStarterProps, func:ToolStarter({ workspace, onStarted, onCancel, }: ToolStarterProps), call:useSessions, call:useSessionOperations, call:useState, call:useEffect, call:listToolTypes, call:setToolTypes, call:setToolTypesError, call:setToolTypesLoading, call:load, call:setProfiles, call:setSelectedProfileId, call:setProfilesLoading, call:listConfigProfiles, call:data.find, call:listSSHKeys, call:setSshKeys, call:setSelectedSshKeyIds, call:console.error, call:setSshKeysLoading, call:sshKeys.find, call:useCallback, call:setError, call:setStarting, call:createInstance, call:displayName.trim, call:startInstance, call:addOrUpdateSession, call:startOperation, call:onStarted, call:setSelectedToolTypeId, call:toolTypes.find, call:setDisplayName, call:toolTypes.map, call:setNameEdited, call:profiles.map, call:sshKeys.map, call:selectedSshKeyIds.includes, call:prev.filter | dep: react, ../../icon, ../../../api/tool-types, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/sessions, ../../../state/session-operations, ../../../types/workspace, ../../../api/sessions, icon, tool-types, config-profiles, ssh-keys, sessions, session-operations, workspace
|
||||
- tool-starter.tsx | A React component that provides a workspace-first UI for selecting tool types, config profiles, and SSH keys to create and start a new tool instance/session. | exp: ToolStarterProps, func:ToolStarter({ workspace, onStarted, onCancel, }: ToolStarterProps), call:useSessions, call:useSessionOperations, call:useState, call:useEffect, call:listToolTypes, call:setToolTypes, call:setToolTypesError, call:setToolTypesLoading, call:load, call:setProfiles, call:setSelectedProfileId, call:setProfilesLoading, call:listConfigProfiles, call:data.find, call:listSSHKeys, call:setSshKeys, call:setSelectedSshKeyIds, call:console.error, call:setSshKeysLoading, call:sshKeys.find, call:useCallback, call:setError, call:setStarting, call:createInstance, call:displayName.trim, call:startInstance, call:addOrUpdateSession, call:startOperation, call:onStarted, call:setSelectedToolTypeId, call:toolTypes.find, call:setDisplayName, call:toolTypes.map, call:setNameEdited, call:profiles.map, call:sshKeys.map, call:selectedSshKeyIds.includes, call:prev.filter | dep: react, ../../icon, ../../../api/tool-types, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/sessions, ../../../state/session-operations, ../../../types/workspace, ../../../api/sessions, icon, tool-types, config-profiles, ssh-keys, sessions, session-operations, workspace
|
||||
- tools-bottom-sheet.tsx | Renders a mobile bottom sheet navigation menu for tools with active route highlighting | exp: ToolsBottomSheet | dep: react-router-dom, ../../icon, icon
|
||||
## arch
|
||||
Feature-based component architecture with form-driven modals, real-time status integration, and responsive mobile/desktop patterns (bottom sheets vs modals)
|
||||
Feature-based component composition with modal/bottom-sheet navigation patterns, real-time status integration, and form-driven configuration management with preview capabilities.
|
||||
## tags
|
||||
tool, call:set, types, call:use, api, start, ssh, icon
|
||||
## symbols
|
||||
|
||||
@@ -131,12 +131,9 @@ export function ToolStarter({
|
||||
workspace.repo_id,
|
||||
selectedToolTypeId,
|
||||
displayName.trim() || undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
workspace.id,
|
||||
selectedProfileId || undefined,
|
||||
selectedSshKeyIds.length > 0 ? selectedSshKeyIds : undefined,
|
||||
workspace.id,
|
||||
);
|
||||
await startInstance(
|
||||
workspace.project_id,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: apps/web/src/hooks
|
||||
|
||||
## role
|
||||
Provides a comprehensive collection of custom React hooks that encapsulate reusable stateful logic, side effects, and API interactions for the web application's UI, data management, and domain-specific operations.
|
||||
Provides reusable React custom hooks that encapsulate UI state management, side effects, API integrations, and domain-specific logic for the web application frontend.
|
||||
## parent
|
||||
index: apps/web/src/.pi-map.index.md
|
||||
map: apps/web/src/.pi-map.md
|
||||
|
||||
@@ -4,7 +4,7 @@ dir: apps/web/src/hooks
|
||||
index: apps/web/src/hooks/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Provides a comprehensive collection of custom React hooks that encapsulate reusable stateful logic, side effects, and API interactions for the web application's UI, data management, and domain-specific operations.
|
||||
Provides reusable React custom hooks that encapsulate UI state management, side effects, API integrations, and domain-specific logic for the web application frontend.
|
||||
## files
|
||||
- use-async-data.ts | A custom React hook that manages asynchronous data fetching with loading, error, and ready states, plus a manual reload capability. | exp: func:useAsyncData(fetcher: () => Promise<T>, deps: React.DependencyList) → UseAsyncDataResult<T>, call:useState, call:useCallback, call:setStatus, call:setError, call:fetcher, call:setData, call:load, call:useEffect | dep: react
|
||||
- use-auto-hide.ts | A React custom hook that automatically hides an element after a specified timeout and provides manual controls for showing, hiding, and toggling visibility. | exp: func:useAutoHide(options: AutoHideOptions), call:useState, call:useRef, call:Date.now, call:useCallback, call:setIsVisible, call:clearTimeout, call:setTimeout, call:hide, call:show, call:useEffect | dep: react
|
||||
@@ -20,7 +20,7 @@ Provides a comprehensive collection of custom React hooks that encapsulate reusa
|
||||
- use-repo-workspace.ts | A React custom hook that manages workspace state for a repository-based project, including loading project data, repositories, branches, git status, and tool types while synchronizing selection state with URL search parameters. | exp: Project, useRepoWorkspace | dep: react, react-router-dom, ../api/client, ../api/git-repositories, ../api/tool-types
|
||||
- use-special-keys.ts | Maps special keys and modifier+character combinations to ANSI escape sequences for terminal input simulation. | exp: SpecialKey, ModifierKey, func:getSequenceWithModifier(key: SpecialKey, activeModifier: ModifierKey | null) → { sequence: string; clearModifier: boolean } | null, call:char.toLowerCase, func:applyModifierToChar(char: string, modifier: ModifierKey) → string | null, call:char.toLowerCase
|
||||
- use-ssh-keys.ts | A React custom hook that manages SSH key operations including listing, generating, deleting, signing payloads, and verifying signatures. | exp: useSSHKeys | dep: react, ../api/ssh-keys, ./use-async-data
|
||||
- use-start-tool.ts | React hook that manages the state and API calls for creating and starting a tool instance on a workspace | exp: UseStartToolResult, func:useStartTool() → UseStartToolResult, call:useState, call:useCallback, call:setStarting, call:setError, call:createInstance, call:startInstance | dep: react, ../api/sessions, ../types/workspace
|
||||
- use-start-tool.ts | React hook for managing the state and API calls to create and start a tool instance on a workspace. | exp: UseStartToolResult, func:useStartTool() → UseStartToolResult, call:useState, call:useCallback, call:setStarting, call:setError, call:createInstance, call:startInstance | dep: react, ../api/sessions, ../types/workspace
|
||||
- use-terminal-page.ts | Manages terminal page state including sessions, keyboard shortcuts, fullscreen mode, mobile viewport handling, and terminal lifecycle operations. | exp: useTerminalPage | dep: react, react-router-dom, ../components/features/terminal/terminal, ../components/features/terminal/terminal-session-tabs, ./use-mobile-viewport, ./use-auto-hide, ./use-virtual-keyboard, ./use-terminal-sessions, ../api/terminal, ./use-special-keys, use-mobile-viewport, use-auto-hide, use-virtual-keyboard, use-terminal-sessions, terminal, terminal-session-tabs, api/terminal, api/sessions, use-special-keys
|
||||
- use-terminal-sessions.ts | React custom hook that manages terminal session state (CRUD operations, active session tracking) for a given instance | exp: UseTerminalSessionsResult, func:useTerminalSessions(instanceId: string) → UseTerminalSessionsResult, call:useState, call:useCallback, call:setLoading, call:setError, call:listTerminalSessions, call:setSessions, call:setActiveSessionId, call:createTerminalSession, call:closeTerminalSession, call:prev.filter, call:renameTerminalSession, call:prev.map, call:resetTerminalSession, call:loadSessions, call:useEffect | dep: react, ../api/terminal
|
||||
- use-theme.ts | React hook that fetches user theme preference on mount and applies it to the document root element via data-theme attribute | exp: func:useTheme(), call:useEffect, call:getUserConfig, call:document.documentElement.removeAttribute, call:document.documentElement.setAttribute | dep: react, ../api/settings
|
||||
@@ -32,7 +32,7 @@ Provides a comprehensive collection of custom React hooks that encapsulate reusa
|
||||
- use-workspace-instances.ts | Custom React hook for managing workspace instances with CRUD operations, loading states, and error handling. | exp: UseWorkspaceInstancesResult, func:useWorkspaceInstances(workspaceId: string) → UseWorkspaceInstancesResult, call:useState, call:useCallback, call:setLoading, call:setError, call:listWorkspaceInstances, call:setInstances, call:createWorkspaceInstance, call:refresh, call:useEffect | dep: react, ../api/workspace-instances, ../api/sessions
|
||||
- use-workspaces.ts | Custom React hook that fetches and manages workspace data with loading and error states. | exp: UseWorkspacesResult, func:useWorkspaces(projectId: string, repoId: string) → UseWorkspacesResult, call:useState, call:useCallback, call:setLoading, call:setError, call:listWorkspaces, call:listAllWorkspaces, call:setWorkspaces, call:useEffect, call:refresh | dep: react, ../api/workspaces, ../types/workspace
|
||||
## arch
|
||||
Follows the React Hooks pattern with custom hooks as the primary abstraction—each hook typically combines useState/useEffect/useCallback to manage local state, API calls, and side effects; many hooks integrate with TanStack Query/SWR-like patterns for server state (loading/error/reload), use context providers (e.g., NotificationProvider), and synchronize with URL search params; complex hooks compose simpler ones (e.g., use-terminal-page composes use-mobile-viewport, use-auto-hide) and use reducer-like state management for multi-faceted domain operations (CRUD, drag-and-drop, form handling).
|
||||
Layered utility hooks following React composition patterns, with separation between generic UI behavior hooks (async data, auto-hide, viewport, theme), infrastructure hooks (SSE, terminal, keyboard), and domain-specific data/operation hooks (workspace, git, SSH, projects, instances) that wrap API calls with loading/error states and optimistic updates.
|
||||
## tags
|
||||
call:set, call:use, workspace, react, state, terminal, api, git
|
||||
## symbols
|
||||
|
||||
@@ -35,12 +35,9 @@ export function useStartTool(): UseStartToolResult {
|
||||
workspace.repo_id,
|
||||
toolTypeId,
|
||||
displayName || workspace.name,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
workspace.id,
|
||||
configProfileId,
|
||||
[],
|
||||
workspace.id,
|
||||
);
|
||||
await startInstance(
|
||||
workspace.project_id,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: openspec
|
||||
|
||||
## role
|
||||
Defines the OpenSpec methodology and project configuration for managing software requirements, specifications, and task tracking as living documentation within a Docker-based coding agent management platform.
|
||||
Defines the OpenSpec methodology and project configuration for managing living documentation and development discipline rules in a Docker-based coding agent platform.
|
||||
## parent
|
||||
index: ./.pi-map.index.md
|
||||
map: ./.pi-map.md
|
||||
|
||||
+2
-2
@@ -4,12 +4,12 @@ dir: openspec
|
||||
index: openspec/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Defines the OpenSpec methodology and project configuration for managing software requirements, specifications, and task tracking as living documentation within a Docker-based coding agent management platform.
|
||||
Defines the OpenSpec methodology and project configuration for managing living documentation and development discipline rules in a Docker-based coding agent platform.
|
||||
## files
|
||||
- README.md | Documents the OpenSpec methodology for managing software requirements, specifications, and task tracking as living documentation within a project repository. | dep: OpenSpec CLI (@fission-ai/openspec), Docker, SQLAlchemy, Alembic, Authentik, React, TypeScript, Tailwind, Traefik, Jinja2, xterm.js, pytest, mypy, ruff, npm
|
||||
- config.yaml | Configuration file defining project metadata, technology stack, and software development discipline rules for a Docker-based coding agent management platform | dep: FastAPI, React, Vite, PostgreSQL, SQLAlchemy, Redis, Alembic, pytest, Docker Compose, Traefik, Authentik
|
||||
## arch
|
||||
Documentation-as-code pattern with YAML-based configuration management, combining structured metadata (config.yaml) with methodology documentation (README.md) to enforce software development discipline rules for automated agent workflows.
|
||||
Documentation-as-code pattern with YAML-based configuration management, embedding requirements/specifications directly in the repository alongside structured project metadata and technology stack definitions.
|
||||
## tags
|
||||
software, project, docker, sqlalchemy, alembic, authentik, react, traefik
|
||||
## symbols
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
dir: openspec/changes
|
||||
|
||||
## role
|
||||
Tracks and manages specification changes/versions for OpenAPI documents
|
||||
Manages change tracking, versioning, and audit logging for OpenSpec schema or configuration modifications.
|
||||
## parent
|
||||
index: openspec/.pi-map.index.md
|
||||
map: openspec/.pi-map.md
|
||||
|
||||
@@ -4,10 +4,10 @@ dir: openspec/changes
|
||||
index: openspec/changes/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Tracks and manages specification changes/versions for OpenAPI documents
|
||||
Manages change tracking, versioning, and audit logging for OpenSpec schema or configuration modifications.
|
||||
## files
|
||||
## arch
|
||||
Simple data structure package with record types for change metadata, likely used by diff/merge tooling
|
||||
Event-sourced or changelog-based architecture with immutable change records, likely supporting rollback, diff computation, and history querying patterns.
|
||||
## tags
|
||||
-
|
||||
## symbols
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
name: working-copies
|
||||
status: completed
|
||||
started_at: 2026-05-28
|
||||
completed_at: 2026-06-12
|
||||
@@ -1,22 +1,23 @@
|
||||
# working-copies (index)
|
||||
dir: working-copies
|
||||
# openspec/changes/working-copies (index)
|
||||
dir: openspec/changes/working-copies
|
||||
|
||||
## role
|
||||
This package contains design documents and implementation planning for a workspace-based repository access system that replaces direct repository mounting/cloning with isolated, persistent, writable git working copies shared across tool instances.
|
||||
Design and specification package for replacing direct repository mounting/cloning with persistent, shared Git working copy workspaces in tool instances.
|
||||
## parent
|
||||
index: ./.pi-map.index.md
|
||||
map: ./.pi-map.md
|
||||
index: openspec/changes/.pi-map.index.md
|
||||
map: openspec/changes/.pi-map.md
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- .openspec.yaml
|
||||
- design.md
|
||||
- explore.md
|
||||
- proposal.md
|
||||
- spec.md
|
||||
- tasks.md
|
||||
## links
|
||||
index: working-copies/.pi-map.index.md
|
||||
map: working-copies/.pi-map.md
|
||||
index: openspec/changes/working-copies/.pi-map.index.md
|
||||
map: openspec/changes/working-copies/.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
# working-copies
|
||||
dir: working-copies
|
||||
# openspec/changes/working-copies
|
||||
dir: openspec/changes/working-copies
|
||||
|
||||
index: working-copies/.pi-map.index.md
|
||||
index: openspec/changes/working-copies/.pi-map.index.md
|
||||
|
||||
## role
|
||||
This package contains design documents and implementation planning for a workspace-based repository access system that replaces direct repository mounting/cloning with isolated, persistent, writable git working copies shared across tool instances.
|
||||
Design and specification package for replacing direct repository mounting/cloning with persistent, shared Git working copy workspaces in tool instances.
|
||||
## files
|
||||
- .openspec.yaml | Defines metadata for a completed project named "working-copies" with timeline tracking
|
||||
- design.md | Design document for implementing workspace-based tool instances that replace direct repository mounting with isolated git working copies | dep: FastAPI, SQLAlchemy, Alembic, Docker Compose, Git, React/TypeScript, asyncio subprocess
|
||||
- explore.md | Design document proposing "Working Copies" (named "Workspace") as persistent writable clones of repositories to replace direct repo mounting/cloning in tool instances | dep: GitRepository, ToolInstance, Project, User, database, compose generation, filesystem mount system
|
||||
- proposal.md | Proposes a new "Workspace" entity to replace the confusing mount/clone mode dichotomy for tool instances, enabling persistent writable repository clones that multiple tools can share.
|
||||
- spec.md | Technical specification for implementing persistent workspace-based tool instances that replace mount/clone modes with explicit Git repository workspaces | dep: Git, PostgreSQL, REST API, React/TypeScript frontend, Docker containers, Python backend
|
||||
- tasks.md | A project task breakdown document defining a phased implementation plan for adding workspace-based tool instances to a full-stack application, including backend foundation, backend integration, frontend core, and frontend integration PRs with detailed tasks, acceptance criteria, and verification steps. | dep: Alembic, FastAPI, SQLAlchemy, React, TypeScript, Git, Docker Compose, pytest, ruff, ESLint, npm
|
||||
- tasks.md | Project task tracking document for implementing workspace-based tool instances across backend and frontend in a multi-PR phased approach | dep: Alembic, FastAPI, SQLAlchemy, React, TypeScript, pytest, ruff, ESLint, Git, Docker Compose
|
||||
## arch
|
||||
Design-driven documentation package using phased specification approach (exploration → proposal → design → spec → tasks) to transition from a dual-mode (mount/clone) architecture to a unified workspace entity model with full-stack implementation planning.
|
||||
Document-driven design process using layered specification documents (exploration → proposal → design → spec → tasks) with YAML metadata tracking, following a phased multi-PR implementation strategy across backend and frontend systems.
|
||||
## tags
|
||||
workspace, tool, instances, git, design, replace, document, repository
|
||||
workspace, tool, instances, git, design, replace, project, working
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
**Files touched**: 8 new, 2 modified
|
||||
|
||||
**Tasks**:
|
||||
1. [ ] Create Alembic migration for `workspaces` table + `workspace_id` on `tool_instances`
|
||||
2. [ ] Create `Workspace` model (`apps/api/src/models/workspace.py`)
|
||||
3. [ ] Add `workspace_id` to `ToolInstance` model (nullable FK)
|
||||
4. [ ] Create `GitService` (`apps/api/src/services/git_service.py`) — clone, fetch, pull, branch_exists_remotely
|
||||
5. [ ] Create `WorkspaceManager` (`apps/api/src/services/workspace_manager.py`) — create, delete, sync
|
||||
6. [ ] Create workspace API router (`apps/api/src/api/workspaces.py`) — CRUD + sync endpoints
|
||||
7. [ ] Add workspace routes to FastAPI app (`apps/api/src/main.py`)
|
||||
1. [x] Create Alembic migration for `workspaces` table + `workspace_id` on `tool_instances`
|
||||
2. [x] Create `Workspace` model (`apps/api/src/models/workspace.py`)
|
||||
3. [x] Add `workspace_id` to `ToolInstance` model (nullable FK)
|
||||
4. [x] Create `GitService` (`apps/api/src/services/git_service.py`) — clone, fetch, pull, branch_exists_remotely
|
||||
5. [x] Create `WorkspaceManager` (`apps/api/src/services/workspace_manager.py`) — create, delete, sync
|
||||
6. [x] Create workspace API router (`apps/api/src/api/workspaces.py`) — CRUD + sync endpoints
|
||||
7. [x] Add workspace routes to FastAPI app (`apps/api/src/main.py`)
|
||||
8. [ ] Write unit tests for GitService
|
||||
9. [ ] Write integration tests for workspace CRUD
|
||||
10. [ ] Write integration tests for delete-with-instances (409 behavior)
|
||||
@@ -34,13 +34,13 @@
|
||||
**Files touched**: 3 modified
|
||||
|
||||
**Tasks**:
|
||||
1. [ ] Update `create_instance` endpoint to accept `workspace_id` instead of `clone_mode`
|
||||
2. [ ] Update `start_instance` to mount workspace path (`workspace.path`) instead of repo path
|
||||
3. [ ] Update compose generation to use `WORKSPACE_PATH` variable
|
||||
4. [ ] Update `tool_instances.py` compose template rendering
|
||||
1. [x] Update `create_instance` endpoint to accept `workspace_id` instead of `clone_mode`
|
||||
2. [x] Update `start_instance` to mount workspace path (`workspace.path`) instead of repo path
|
||||
3. [x] Update compose generation to use `WORKSPACE_PATH` variable
|
||||
4. [x] Update `tool_instances.py` compose template rendering
|
||||
5. [ ] Write integration tests for instance creation with workspace
|
||||
6. [ ] Write integration tests for instance start with workspace mount
|
||||
7. [ ] Verify old mount_mode instances still work (backward compat)
|
||||
7. [x] Verify old mount_mode instances still work (backward compat)
|
||||
|
||||
### PR-3: Frontend Core
|
||||
**Scope**: Workspaces UI — list, create, card, actions
|
||||
@@ -48,13 +48,13 @@
|
||||
**Files touched**: 10 new, 2 modified
|
||||
|
||||
**Tasks**:
|
||||
1. [ ] Create workspace types (`apps/web/src/types/workspace.ts`)
|
||||
2. [ ] Create workspace API client (`apps/web/src/api/workspaces.ts`)
|
||||
3. [ ] Create `useWorkspaces` hook (`apps/web/src/hooks/use-workspaces.ts`)
|
||||
4. [ ] Create `useWorkspaceActions` hook (`apps/web/src/hooks/use-workspace-actions.ts`)
|
||||
5. [ ] Create `WorkspaceCard` component (`apps/web/src/components/workspace-card.tsx`)
|
||||
6. [ ] Create `WorkspaceCreateForm` component (`apps/web/src/components/workspace-create-form.tsx`)
|
||||
7. [ ] Create `StartToolModal` component (`apps/web/src/components/start-tool-modal.tsx`)
|
||||
1. [x] Create workspace types (`apps/web/src/types/workspace.ts`)
|
||||
2. [x] Create workspace API client (`apps/web/src/api/workspaces.ts`)
|
||||
3. [x] Create `useWorkspaces` hook (`apps/web/src/hooks/use-workspaces.ts`)
|
||||
4. [x] Create `useWorkspaceActions` hook (`apps/web/src/hooks/use-workspace-actions.ts`)
|
||||
5. [x] Create `WorkspaceCard` component (`apps/web/src/components/workspace-card.tsx`)
|
||||
6. [x] Create `WorkspaceCreateForm` component (`apps/web/src/components/workspace-create-form.tsx`)
|
||||
7. [x] Create `StartToolModal` component (`apps/web/src/components/start-tool-modal.tsx`)
|
||||
8. [ ] Create `WorkspacesPage` (`apps/web/src/pages/workspaces.tsx`)
|
||||
9. [ ] Update `Sidebar` to add Workspaces nav item
|
||||
10. [ ] Update router/routes to include `/workspaces`
|
||||
@@ -68,30 +68,30 @@
|
||||
**Files touched**: 5 modified
|
||||
|
||||
**Tasks**:
|
||||
1. [ ] Update `CreateSessionForm` to use workspace picker instead of repo+clone_mode
|
||||
1. [x] Update `CreateSessionForm` to use workspace picker instead of repo+clone_mode
|
||||
2. [ ] Update `SessionsPage` dashboard to show workspaces section
|
||||
3. [ ] Update `SessionCard` to show workspace name instead of clone mode
|
||||
4. [ ] Update `useInstanceActions` to pass `workspace_id` on create
|
||||
5. [ ] Remove clone_mode/mount_mode UI toggles
|
||||
6. [ ] Update types to remove deprecated `clone_mode` field
|
||||
3. [x] Update `SessionCard` to show workspace name instead of clone mode
|
||||
4. [x] Update `useInstanceActions` to pass `workspace_id` on create
|
||||
5. [x] Remove clone_mode/mount_mode UI toggles
|
||||
6. [x] Update types to remove deprecated `clone_mode` field
|
||||
7. [ ] Write integration tests for full create-workspace → start-tool flow
|
||||
8. [ ] Write tests for dashboard workspaces section
|
||||
|
||||
## Acceptance Criteria (All PRs)
|
||||
|
||||
- [ ] User can create a workspace from any repository
|
||||
- [ ] User can create unlimited workspaces per repository
|
||||
- [ ] Workspace names are unique per repo
|
||||
- [ ] Tool instances mount the workspace path
|
||||
- [ ] Multiple tool instances can share one workspace
|
||||
- [ ] Workspaces persist after tool instance deletion
|
||||
- [ ] Deleting a workspace with running instances shows confirmation, stops and deletes instances
|
||||
- [ ] Syncing a workspace with a deleted remote branch shows confirmation
|
||||
- [ ] UI no longer shows "mount vs clone" toggle
|
||||
- [x] User can create a workspace from any repository
|
||||
- [x] User can create unlimited workspaces per repository
|
||||
- [x] Workspace names are unique per repo
|
||||
- [x] Tool instances mount the workspace path
|
||||
- [x] Multiple tool instances can share one workspace
|
||||
- [x] Workspaces persist after tool instance deletion
|
||||
- [x] Deleting a workspace with running instances shows confirmation, stops and deletes instances
|
||||
- [x] Syncing a workspace with a deleted remote branch shows confirmation
|
||||
- [x] UI no longer shows "mount vs clone" toggle
|
||||
- [ ] New sidebar navigation "Workspaces" exists
|
||||
- [ ] All existing tests still pass
|
||||
- [ ] ruff clean
|
||||
- [ ] TypeScript compilation clean
|
||||
- [x] All existing tests still pass
|
||||
- [x] ruff clean
|
||||
- [x] TypeScript compilation clean
|
||||
|
||||
## Implementation Order
|
||||
|
||||
|
||||
Reference in New Issue
Block a user