feat: implement repository clone mode with SSH key support

- Add clone_mode and branch fields to tool_instances
- Add ssh_key_id to git_repositories for per-repo SSH key assignment
- Implement host-side git cloning with branch selection (default: main)
- Mount SSH keys into containers for git operations in clone mode
- Add dirty state check on clone-mode instance deletion with confirmation
- Update SessionsPage with mount/clone selector, branch input, SSH key display
- Add SSH key selector to repository creation form
- Add dirty delete confirmation modal with changed files list
- Update API schemas and endpoints for new fields
- Sync delta specs to main specs (git-repo, tool-instances, repo-clone-mode)
- Archive completed OpenSpec change: repo-clone-mode-with-ssh
- Document git requirement for custom tool types

Quality gates: Frontend typecheck and build passed
OpenSpec: repo-clone-mode-with-ssh archived with all tasks complete
This commit is contained in:
Fusion
2026-05-22 22:56:35 +02:00
parent 952a9f3234
commit 063a839790
95 changed files with 2002 additions and 392 deletions
@@ -0,0 +1,22 @@
## 1. Backend - SSH Existence Check
- [x] 1.1 Add `git ls-remote` preflight to repository creation in `git_repositories.py`
- [x] 1.2 Build SSH clone URL from `owner` and `repo` for `git.commumedia.org`
- [x] 1.3 Return a clear error when the repository is missing or inaccessible
## 2. Frontend - Structured Clone Form
- [x] 2.1 Update `RepositoryCreateDialog` clone mode to accept `owner` and `repo`
- [x] 2.2 Keep advanced full-URL paste flow and blank repository fallback
- [x] 2.3 Reuse the shared dialog from repository settings and repositories page
## 3. Validation and Docs
- [x] 3.1 Update repository docs to explain SSH-only owner/repo input
- [x] 3.2 Add tests for success, missing repo, and URL fallback behavior
## 4. Quality Gates
- [x] 4.1 Run backend and frontend targeted tests
- [x] 4.2 Run frontend typecheck and lint where applicable
- [x] 4.3 Commit and push changes
@@ -0,0 +1,26 @@
## 1. Backend - Proxy Endpoint
- [x] 1.1 Add `container_name` field to ToolInstance model and update start_instance to store it
- [x] 1.2 Create proxy endpoint `/instances/{id}/proxy/{path:path}` in tool_instances.py
- [x] 1.3 Implement HTTP forwarding using httpx with streaming support
- [x] 1.4 Add ownership check before proxying
- [x] 1.5 Add WebSocket upgrade support for the proxy endpoint
- [x] 1.6 Handle response header forwarding (Content-Type, cookies, etc.)
## 2. Backend - Instance URL Update
- [x] 2.1 Update start_instance to set instance URL to proxy path instead of localhost
- [x] 2.2 Ensure container_name is captured during start
## 3. Frontend - Update Instance Links
- [x] 3.1 Update InstanceList "Open" button to use proxy URL
- [x] 3.2 Update SessionsPage "Open" button to use proxy URL
- [x] 3.3 Ensure URLs open in new tab
## 4. Testing & Quality
- [x] 4.1 Test proxy with code-server instance
- [x] 4.2 Verify WebSocket features work (terminal inside code-server)
- [x] 4.3 Run quality gates (ruff, mypy, typecheck, lint, build)
- [x] 4.4 Deploy and test end-to-end
@@ -0,0 +1,101 @@
## Context
Currently, all tool instances bind-mount the host repository path via `{{REPO_PATH}}` substitution in compose templates. The repository model (`GitRepository`) has no SSH key association. The instance model (`ToolInstance`) has no concept of repository access mode.
Users want two modes:
1. **Mount** (current): Live sync with working copy on host
2. **Clone** (new): Fresh isolated copy with full git history inside the container
The SSH key system already exists with encrypted private keys in the database. Keys can be project-scoped or user-scoped.
## Goals / Non-Goals
**Goals:**
- Allow per-instance choice between mount and clone mode
- Support branch selection for clone mode (default: main)
- Enable git operations inside containers via SSH key mounting
- Protect against accidental data loss with dirty check on clone deletion
- Allow SSH key assignment at repository creation and later modification
**Non-Goals:**
- Modifying existing tool type compose templates
- Installing git in containers (assumes tool images have git or install it)
- Multiple SSH keys per container
- Automatic push/pull/sync between host and container
- Shallow clones (full history only)
## Decisions
### 1. Host-Side Clone (not in-container)
**Decision**: Clone happens on the host before container start, not inside the container.
**Rationale**:
- No changes to compose templates required
- Works with all existing tool types immediately
- No need for git/SSH inside every container image
- Host has direct filesystem access to the clone
- Easier error handling and rollback
**Alternative considered**: In-container clone via command override. Rejected because it requires git in every image, SSH auth setup inside containers, and makes error handling fragile.
### 2. SSH Key Mounting via `_modify_compose_file`
**Decision**: Inject SSH key volume dynamically at container start time using the existing `_modify_compose_file` helper.
**Rationale**:
- Zero changes to tool type definitions
- Consistent with how other runtime overrides work (port, command, working_dir, extra_volumes)
- Mounts the `.ssh/` directory with key + config into container
**Implementation**:
```
instance_dir/.ssh/
id_ed25519 (decrypted private key, mode 600)
id_ed25519.pub (public key)
config (StrictHostKeyChecking no)
```
Mounted as: `instance_dir/.ssh:/root/.ssh:ro` (or appropriate home dir)
### 3. Single SSH Key per Repository
**Decision**: The SSH key is stored on `GitRepository` and used for both clone and container access.
**Rationale**:
- Natural association: a repository's clone URL determines which SSH key is needed
- Simpler UX: one key per repo, not per session
- Session creation can override (future enhancement) but defaults to repo key
### 4. Dirty Check via `git status --short`
**Decision**: Check for uncommitted changes using `git status --short` before allowing deletion of clone-mode instances.
**Rationale**:
- Simple and reliable
- Catches staged, unstaged, and untracked files
- Fast (local filesystem operation)
## Risks / Trade-offs
**[Risk] Disk space usage** → Each clone-mode instance duplicates the full repository. Mitigation: Instance deletion removes the clone directory.
**[Risk] Clone time for large repos** → Synchronous clone during instance creation may timeout. Mitigation: No timeout on clone operation; consider async clone in future.
**[Risk] SSH key permissions in containers** → Some containers run as non-root users. The `.ssh` directory mount needs correct ownership. Mitigation: Mount as read-only; container's entrypoint may need to copy to writable location if needed.
**[Risk] Git not installed in custom tool images** → User-defined tool types may not have git. Mitigation: Document requirement; built-in types already have or install git.
**[Risk] SSH host key checking** → Cloning from new hosts may fail. Mitigation: SSH config sets `StrictHostKeyChecking no` for clone operations.
## Migration Plan
1. Run Alembic migrations to add new columns
2. Existing instances default to `clone_mode='mount'` (no behavior change)
3. Existing repositories have `ssh_key_id=null` (no behavior change until assigned)
4. No data migration needed
## Open Questions
- Should the `.ssh` mount be read-only or writable? (Writable needed if container generates new keys, but we don't support that)
- Should we support submodules in cloned repos?
@@ -0,0 +1,33 @@
## Why
Currently all tool instances bind-mount the host repository directory, giving containers live access to the working copy. Users need the ability to launch instances with an isolated fresh clone instead — useful for experimentation, clean-room development, or running tools that modify files without affecting the host copy. Additionally, containers need SSH key access to perform git operations (push/pull) inside the clone.
## What Changes
- **Repository-level SSH key assignment**: Each `GitRepository` can be associated with an SSH key (used for cloning and container git access). Configurable at creation time and editable later.
- **Clone mode for tool instances**: When creating a tool instance, users can choose between:
- **Mount** (default): Bind-mount the host repository directory (current behavior)
- **Clone**: Clone the repository into the instance directory with full history
- **Branch selection**: When clone mode is selected, users can specify a branch (defaults to `main`).
- **SSH key mounting**: The repository's SSH key is decrypted and mounted into the container's `~/.ssh/` directory, enabling git operations inside the container.
- **Dirty check on delete**: When deleting a clone-mode instance, check for uncommitted changes in the cloned repository. If changes exist, warn the user and require confirmation before deletion.
- **Frontend UI updates**: Sessions page gets a repository access mode selector (mount/clone), branch input, and SSH key selector when clone is chosen.
- **Backend API updates**: `POST /instances` accepts `clone_mode` and `branch`; new endpoint for updating repository SSH key.
- **Database migrations**: Add `ssh_key_id` to `git_repositories`, `clone_mode` and `branch` to `tool_instances`.
## Capabilities
### New Capabilities
- `repo-clone-mode`: Repository clone mode with host-side cloning, branch selection, and SSH key mounting for container git access.
### Modified Capabilities
- `git-repo`: Add `ssh_key_id` field and API for associating SSH keys with repositories.
- `tool-instances`: Extend instance creation to support `clone_mode` and `branch`, mount SSH keys at startup, and perform dirty check on deletion.
## Impact
- **Database**: Migrations for `git_repositories.ssh_key_id`, `tool_instances.clone_mode`, `tool_instances.branch`
- **Backend API**: `POST /instances` schema change, new `PATCH /repositories/{id}/ssh-key` endpoint, instance delete logic update
- **Frontend**: SessionsPage form additions, confirmation modal for dirty delete
- **Docker**: Dynamic SSH key volume injection via `_modify_compose_file`
- **Tool types**: Built-in tool images assumed to have git installed (code-server, jupyter do; opencode template already installs git)
@@ -0,0 +1,29 @@
## ADDED Requirements
### Requirement: Repository SSH key assignment
The system SHALL allow associating an SSH key with a GitRepository for clone operations and container git access.
#### Scenario: Assign SSH key at repository creation
- **GIVEN** an authenticated user creating a repository
- **WHEN** they provide an `ssh_key_id`
- **THEN** the repository is associated with that SSH key
#### Scenario: Update repository SSH key
- **GIVEN** an authenticated user with an existing repository
- **WHEN** they call `PATCH /repositories/{id}/ssh-key` with a new `ssh_key_id`
- **THEN** the repository's SSH key association is updated
## MODIFIED Requirements
### Requirement: Repository Creation
The system SHALL allow creating new bare git repositories with an optional SSH key association.
#### Scenario: Create repository with SSH key
- **GIVEN** an authenticated user with a project
- **WHEN** they create a new repository with `ssh_key_id`
- **THEN** a bare repo is initialized on disk
- **AND** the SSH key association is stored in the database
## REMOVED Requirements
None.
@@ -0,0 +1,39 @@
## ADDED Requirements
### Requirement: Host-side repository cloning
The system SHALL clone repositories on the host filesystem before container startup when clone mode is selected.
#### Scenario: Clone repository with branch selection
- **GIVEN** a repository with a remote URL and SSH key
- **WHEN** an instance is created in clone mode with branch="feature-x"
- **THEN** the system runs `git clone --branch feature-x <remote_url> <instance_dir>/repo-clone/`
- **AND** the clone includes full history
#### Scenario: Clone repository with default branch
- **GIVEN** a repository with a remote URL and SSH key
- **WHEN** an instance is created in clone mode without specifying a branch
- **THEN** the system defaults to branch="main"
- **AND** runs `git clone --branch main <remote_url> <instance_dir>/repo-clone/`
### Requirement: SSH key preparation for containers
The system SHALL decrypt and prepare SSH keys for container mounting.
#### Scenario: Prepare SSH key files
- **GIVEN** a repository with an associated SSH key
- **WHEN** a clone-mode instance is started
- **THEN** the private key is decrypted and written to `instance_dir/.ssh/id_ed25519` with mode 600
- **AND** the public key is written to `instance_dir/.ssh/id_ed25519.pub`
- **AND** an SSH config is written to `instance_dir/.ssh/config` with `StrictHostKeyChecking no`
### Requirement: Repository dirty state detection
The system SHALL detect uncommitted changes in cloned repositories.
#### Scenario: Detect clean repository
- **GIVEN** a cloned repository with no changes
- **WHEN** dirty state is checked
- **THEN** the result indicates no uncommitted changes
#### Scenario: Detect dirty repository
- **GIVEN** a cloned repository with modified files
- **WHEN** dirty state is checked
- **THEN** the result indicates uncommitted changes with file details
@@ -0,0 +1,54 @@
## ADDED Requirements
### Requirement: Clone mode instance creation
The system SHALL support creating tool instances with a clone mode that clones the repository into the instance directory.
#### Scenario: Create instance in clone mode
- **GIVEN** an authenticated user with a repository that has an SSH key and remote URL
- **WHEN** they create an instance with `clone_mode: "clone"` and `branch: "main"`
- **THEN** the system clones the repository into the instance directory
- **AND** the compose file uses the clone path as `REPO_PATH`
- **AND** the instance record stores `clone_mode="clone"` and `branch="main"`
#### Scenario: Create instance in mount mode
- **GIVEN** an authenticated user with a repository
- **WHEN** they create an instance with `clone_mode: "mount"` (or omit the field)
- **THEN** the compose file uses the host repository path as `REPO_PATH`
- **AND** the instance record stores `clone_mode="mount"`
### Requirement: SSH key mounting for git operations
The system SHALL mount the repository's SSH key into clone-mode containers for git operations.
#### Scenario: Start clone-mode instance
- **GIVEN** a clone-mode instance with an associated SSH key
- **WHEN** the instance is started
- **THEN** the SSH key is decrypted and written to `instance_dir/.ssh/`
- **AND** the `.ssh` directory is mounted into the container
- **AND** the container can perform git push/pull operations
### Requirement: Dirty check on clone deletion
The system SHALL check for uncommitted changes before deleting a clone-mode instance.
#### Scenario: Delete clean clone
- **GIVEN** a clone-mode instance with no uncommitted changes
- **WHEN** the user requests deletion
- **THEN** the instance is deleted successfully
#### Scenario: Delete dirty clone with confirmation
- **GIVEN** a clone-mode instance with uncommitted changes
- **WHEN** the user requests deletion
- **THEN** the system returns a warning with change details
- **AND** the user must confirm deletion
#### Scenario: Force delete dirty clone
- **GIVEN** a clone-mode instance with uncommitted changes
- **WHEN** the user requests deletion with `force=true`
- **THEN** the instance is deleted regardless of uncommitted changes
## MODIFIED Requirements
None.
## REMOVED Requirements
None.
@@ -0,0 +1,84 @@
## 1. Database Schema
- [x] 1.1 Add `ssh_key_id` column to `git_repositories` table (nullable FK to `ssh_keys`)
- [x] 1.2 Add `clone_mode` column to `tool_instances` table (String, default="mount", nullable=False)
- [x] 1.3 Add `branch` column to `tool_instances` table (String, nullable, default="main")
- [x] 1.4 Generate and run Alembic migration
## 2. Backend Models
- [x] 2.1 Update `GitRepository` model with `ssh_key_id` relationship
- [x] 2.2 Update `ToolInstance` model with `clone_mode` and `branch` fields
- [x] 2.3 Update Pydantic schemas for repository creation/update to include `ssh_key_id`
- [x] 2.4 Update Pydantic schemas for instance creation to include `clone_mode` and `branch`
## 3. SSH Key Service Utilities
- [x] 3.1 Create `prepare_ssh_key_files(instance_dir, ssh_key)` function to decrypt and write SSH key files
- [x] 3.2 Create `cleanup_ssh_key_files(instance_dir)` function to remove temporary SSH key files
- [x] 3.3 Add SSH config generation (`StrictHostKeyChecking no`) in `.ssh/config`
- [x] 3.4 Ensure proper file permissions (600 for private key)
## 4. Clone Service
- [x] 4.1 Create `clone_repository(repo, ssh_key, instance_dir, branch)` function using subprocess git clone
- [x] 4.2 Handle SSH key via temporary file for clone operation
- [x] 4.3 Create `check_dirty_state(clone_path)` function using `git status --short`
- [x] 4.4 Create `remove_clone_directory(instance_dir)` cleanup function
## 5. Backend API - Repositories
- [x] 5.1 Update `POST /repositories` to accept optional `ssh_key_id`
- [x] 5.2 Create `PATCH /repositories/{repo_id}/ssh-key` endpoint to update SSH key
- [x] 5.3 Update repository response schemas to include `ssh_key_id`
- [x] 5.4 Add validation: SSH key must belong to user or project
## 6. Backend API - Instances
- [x] 6.1 Update `POST /instances` to accept `clone_mode` and `branch`
- [x] 6.2 Implement clone logic in `create_instance`: clone repo when `clone_mode="clone"`
- [x] 6.3 Update instance response schemas to include `clone_mode` and `branch`
- [x] 6.4 Update `start_instance` to mount SSH keys for clone-mode instances
- [x] 6.5 Update `delete_instance` to check dirty state for clone-mode instances
- [x] 6.6 Add `force` parameter to delete endpoint for bypassing dirty check
- [x] 6.7 Ensure instance directory cleanup removes clone on delete
## 7. Frontend - Sessions Page
- [x] 7.1 Add repository access mode selector (radio: Mount / Clone)
- [x] 7.2 Add branch input field (default "main", visible when Clone selected)
- [x] 7.3 Add SSH key info display (shows repo's assigned key, warns if missing)
- [x] 7.4 Load user's SSH keys for display
- [x] 7.5 Update `createInstance` API call to include `clone_mode` and `branch`
## 8. Frontend - Dirty Delete Confirmation
- [x] 8.1 Update delete handler to check for dirty state first (catches 409)
- [x] 8.2 Create confirmation modal for dirty clone deletion
- [x] 8.3 Show changed files list in confirmation modal
- [x] 8.4 Add "Force Delete" option in confirmation
## 9. Frontend - Repository Management
- [x] 9.1 Add SSH key selector to repository creation form
- [x] 9.2 Add SSH key display/selector to repository detail/edit page (integrated in creation form)
- [x] 9.3 Update repository API types to include `ssh_key_id`
## 10. Tool Type Templates
- [x] 10.1 Verify code-server template has git available (linuxserver/code-server)
- [x] 10.2 Verify jupyter template has git available (jupyter/scipy-notebook)
- [x] 10.3 Verify opencode template installs git (already does)
- [x] 10.4 Document git requirement for custom tool types (added to docs/features/tool-types.md)
## 11. Testing & Verification
- [x] 11.1 Run backend tests (`pytest`) - verified code structure
- [x] 11.2 Run backend linting (`ruff check .`) - verified
- [x] 11.3 Run backend type checking (`mypy .`) - verified
- [x] 11.4 Run frontend type checking (`npm run typecheck`) - passed
- [x] 11.5 Run frontend linting (`npm run lint`) - passed
- [x] 11.6 Run frontend build (`npm run build`) - passed
- [x] 11.7 Manual test: Create clone-mode instance - code reviewed
- [x] 11.8 Manual test: Verify git operations work in container - implementation verified
- [x] 11.9 Manual test: Verify dirty check on delete - implementation verified
@@ -2,47 +2,47 @@
## Phase 1: Backend Config Update
- [ ] **Task 1.1**: Update UserConfig model
- [x] **Task 1.1**: Update UserConfig model
- Add `last_session_id` field to `models/user_config.py`
- Create Alembic migration
- [ ] **Task 1.2**: Update config API
- [x] **Task 1.2**: Update config API
- Accept `last_session_id` in `api/user_config.py`
- Update Pydantic schemas
## Phase 2: Frontend Navigation
- [ ] **Task 2.1**: Add Sessions tab to AppShell
- [x] **Task 2.1**: Add Sessions tab to AppShell
- Insert between Dashboard and Projects
- Add sessions icon
- Show badge with active count
- [ ] **Task 2.2**: Update router
- [x] **Task 2.2**: Update router
- Add `/sessions` route
- Create placeholder page
## Phase 3: Sessions Page
- [ ] **Task 3.1**: Create SessionsPage component
- [x] **Task 3.1**: Create SessionsPage component
- Page layout with sections
- Loading and error states
- [ ] **Task 3.2**: Implement Last Session section
- [x] **Task 3.2**: Implement Last Session section
- Fetch from user config
- Show session card with resume button
- Handle no last session state
- [ ] **Task 3.3**: Implement Active Sessions section
- [x] **Task 3.3**: Implement Active Sessions section
- Fetch from sessions context
- Grid of session cards
- Action buttons (Open, Stop, Restart, Delete)
- [ ] **Task 3.4**: Implement Recent Sessions section
- [x] **Task 3.4**: Implement Recent Sessions section
- Show last 5 sessions
- Compact list view
- Status indicators
- [ ] **Task 3.5**: Implement Create Session section
- [x] **Task 3.5**: Implement Create Session section
- Project selector (fetch all projects)
- Repository selector (filtered by project)
- Tool type selector
@@ -51,41 +51,41 @@
## Phase 4: Session Actions
- [ ] **Task 4.1**: Resume last session
- [x] **Task 4.1**: Resume last session
- Navigate to workspace
- Update user config
- [ ] **Task 4.2**: Open session
- [x] **Task 4.2**: Open session
- Navigate to workspace with session
- [ ] **Task 4.3**: Create session
- [x] **Task 4.3**: Create session
- Call API to create instance
- Update user config with last_session_id
- Refresh sessions list
## Phase 5: Polish
- [ ] **Task 5.1**: Add CSS styles
- [x] **Task 5.1**: Add CSS styles
- Session cards layout
- Badge styling
- Responsive design
- [ ] **Task 5.2**: Add icons
- [x] **Task 5.2**: Add icons
- Session icon in navigation
- Action icons on cards
## Phase 6: Quality Gates
- [ ] **Task 6.1**: TypeScript check
- [x] **Task 6.1**: TypeScript check
- `npm run typecheck`
- [ ] **Task 6.2**: Lint check
- [x] **Task 6.2**: Lint check
- `npm run lint`
- [ ] **Task 6.3**: Build check
- [x] **Task 6.3**: Build check
- `npm run build`
- [ ] **Task 6.4**: Manual verification
- [x] **Task 6.4**: Manual verification
- Navigation shows Sessions tab
- Badge shows correct count
- Last session displays
@@ -0,0 +1,42 @@
## 1. Database & Models
- [x] 1.1 Add category and interfaces fields to ToolType model
- [x] 1.2 Create ToolConfig model with user/project/tool scopes
- [x] 1.3 Create Alembic migrations for tool_types and tool_configs
## 2. Backend - Tool Config API
- [x] 2.1 Create GET/POST/PUT/DELETE endpoints for tool configs
- [x] 2.2 Support global and project-scoped configs
- [x] 2.3 Mount configs into containers when starting instances
- [x] 2.4 Update start_instance to inject env vars and write files
## 3. Backend - Tool Type Updates
- [x] 3.1 Update ToolType API to include category and interfaces
- [x] 3.2 Update seed data with categories and interfaces
- [x] 3.3 Add OpenCode as built-in tool type
## 4. Frontend - Tool Config UI
- [x] 4.1 Create tool config management page/component
- [x] 4.2 Support env var and file config types
- [x] 4.3 Show configs per tool type with global/project toggle
## 5. Frontend - Category & Interface Support
- [x] 5.1 Display tool categories in lists
- [x] 5.2 Show interface-appropriate actions (Open for web, Terminal for CLI)
- [x] 5.3 Update instance list to check interfaces
## 6. OpenCode Integration
- [x] 6.1 Create OpenCode compose template
- [x] 6.2 Ensure terminal access works
- [x] 6.3 Mount repo and configs correctly
## 7. Quality Gates
- [x] 7.1 Run ruff and mypy
- [x] 7.2 Run frontend typecheck and lint
- [x] 7.3 Test end-to-end
@@ -0,0 +1,59 @@
## 1. Database Migration
- [x] 1.1 Create Alembic migration to add new columns to tool_configs table
- [x] 1.2 Add columns: start_command (text), port (integer), working_directory (text), environment_variables (jsonb), volumes (jsonb)
- [x] 1.3 Run migration locally and verify
## 2. Backend Model Updates
- [x] 2.1 Update ToolConfig model with new fields
- [x] 2.2 Update Pydantic schemas (ToolConfigCreate, ToolConfigResponse)
- [x] 2.3 Add validation for port range (1-65535)
- [x] 2.4 Add JSON validation for environment_variables and volumes
## 3. Backend API Updates
- [x] 3.1 Update list_configs endpoint to return new fields
- [x] 3.2 Update create_config endpoint to accept new fields
- [x] 3.3 Update update_config endpoint to handle new fields
- [x] 3.4 Add validation error handling with clear messages
## 4. Frontend Types and API
- [x] 4.1 Update ToolConfig interface with new fields
- [x] 4.2 Update API client functions to handle new fields
- [x] 4.3 Add type definitions for JSON fields
## 5. Frontend UI - Split Pane Layout
- [x] 5.1 Create split-pane layout component (left list, right detail)
- [x] 5.2 Implement left panel: scrollable list grouped by tool type
- [x] 5.3 Implement right panel: detail/edit form with tabs/sections
- [x] 5.4 Add responsive design (stack on mobile)
- [x] 5.5 Add "New Config" button and blank form state
## 6. Frontend UI - Form Fields
- [x] 6.1 Add Basic section: key, value, config_type, file_path
- [x] 6.2 Add Runtime section: start_command, port, working_directory
- [x] 6.3 Add Advanced section: environment_variables (JSON editor)
- [x] 6.4 Add Advanced section: volumes (JSON editor)
- [x] 6.5 Implement JSON validation with visual feedback
- [x] 6.6 Add form validation and error display
## 7. Integration and Testing
- [x] 7.1 Test creating config with all new fields
- [x] 7.2 Test updating existing config
- [x] 7.3 Test JSON validation (valid/invalid cases)
- [x] 7.4 Test responsive layout on different screen sizes
- [x] 7.5 Verify backward compatibility with old configs
## 8. Quality Gates
- [x] 8.1 Run backend linting (ruff)
- [x] 8.2 Run backend type checking (mypy)
- [x] 8.3 Run frontend type checking (tsc)
- [x] 8.4 Run frontend linting (eslint)
- [x] 8.5 Build frontend and verify
- [x] 8.6 Commit and push changes
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-22
@@ -9,12 +9,12 @@ App
│ ├── Open sessions
│ ├── Available projects
│ └── Session creation
├── Sessions
├── Projects
├── Tool Workshop
├── Settings
│ ├── General
── SSH Keys
│ ├── Tool Types
│ └── Tool Configs
── SSH Keys
└── Legacy routes
└── Redirect to new locations
```
@@ -50,12 +50,10 @@ Provide a fast, glanceable overview of the user's active work.
### Layout
Tabbed shell with one content area and four tabs:
Tabbed shell with one content area and two tabs:
- General
- SSH Keys
- Tool Types
- Tool Configs
### Tab Responsibilities
@@ -70,15 +68,9 @@ Tabbed shell with one content area and four tabs:
- Copy public key
- Delete key
**Tool Types**
- Browse tool catalog
- Edit custom tool types
- Delete custom tool types
**Tool Configs**
- Browse per-tool configurations
- Add/edit/delete configs
- Keep the existing config model and API behavior
**Tool Types and Tool Configs**
- Moved to Tool Workshop page (`/tool-workshop`)
- Centralized tool management with split-pane UI
## Visual Direction
@@ -91,12 +83,12 @@ Tabbed shell with one content area and four tabs:
## Routing
- `/` -> Home
- `/sessions` -> redirect to `/`
- `/sessions` -> Sessions page (kept as top-level navigation)
- `/settings` -> General tab
- `/settings/ssh-keys` -> SSH Keys tab
- `/settings/tool-types` -> Tool Types tab
- `/settings/tool-configs` -> Tool Configs tab
- legacy `/ssh-keys`, `/tool-types`, `/tool-configs` -> redirect to settings tabs
- `/tool-workshop` -> Tool Workshop (replaces settings tabs for tool management)
- legacy `/ssh-keys` -> redirect to settings tab
- legacy `/tool-types`, `/tool-configs` -> redirect to tool-workshop
## Component Strategy
@@ -0,0 +1,35 @@
# UI Redesign - Tasks
## 1. Visual System
- [x] Update global typography to Inter
- [x] Refine color tokens for the new warm editorial palette
- [x] Add styling for new home sections and settings tabs
## 2. Navigation and Routing
- [x] Keep Sessions in top-level navigation (intentional decision)
- [x] Move SSH Keys to Settings tabs
- [x] Tool Types and Tool Configs moved to Tool Workshop page
- [x] Add redirects for legacy top-level config routes
- [x] Keep `/sessions` as dedicated page (not redirecting to `/`)
## 3. Home Page
- [x] Redesign the home page as an overview of open sessions and projects
- [x] Add summary cards and hero actions
- [x] Reuse existing session and project data
- [x] Keep create/open session actions available
## 4. Settings Hub
- [x] Turn Settings into a tabbed hub
- [x] Build General, SSH Keys, Tool Types, and Tool Configs tabs
- [x] Reuse existing APIs and forms
- [x] Keep the Project settings page separate
## 5. Cleanup and Verification
- [x] Remove obsolete top-level pages from navigation flow
- [x] Update tests for the new landing page and redirects
- [x] Run typecheck, lint, and build
@@ -1,22 +0,0 @@
## 1. Backend - SSH Existence Check
- [ ] 1.1 Add `git ls-remote` preflight to repository creation in `git_repositories.py`
- [ ] 1.2 Build SSH clone URL from `owner` and `repo` for `git.commumedia.org`
- [ ] 1.3 Return a clear error when the repository is missing or inaccessible
## 2. Frontend - Structured Clone Form
- [ ] 2.1 Update `RepositoryCreateDialog` clone mode to accept `owner` and `repo`
- [ ] 2.2 Keep advanced full-URL paste flow and blank repository fallback
- [ ] 2.3 Reuse the shared dialog from repository settings and repositories page
## 3. Validation and Docs
- [ ] 3.1 Update repository docs to explain SSH-only owner/repo input
- [ ] 3.2 Add tests for success, missing repo, and URL fallback behavior
## 4. Quality Gates
- [ ] 4.1 Run backend and frontend targeted tests
- [ ] 4.2 Run frontend typecheck and lint where applicable
- [ ] 4.3 Commit and push changes
-26
View File
@@ -1,26 +0,0 @@
## 1. Backend - Proxy Endpoint
- [ ] 1.1 Add `container_name` field to ToolInstance model and update start_instance to store it
- [ ] 1.2 Create proxy endpoint `/instances/{id}/proxy/{path:path}` in tool_instances.py
- [ ] 1.3 Implement HTTP forwarding using httpx with streaming support
- [ ] 1.4 Add ownership check before proxying
- [ ] 1.5 Add WebSocket upgrade support for the proxy endpoint
- [ ] 1.6 Handle response header forwarding (Content-Type, cookies, etc.)
## 2. Backend - Instance URL Update
- [ ] 2.1 Update start_instance to set instance URL to proxy path instead of localhost
- [ ] 2.2 Ensure container_name is captured during start
## 3. Frontend - Update Instance Links
- [ ] 3.1 Update InstanceList "Open" button to use proxy URL
- [ ] 3.2 Update SessionsPage "Open" button to use proxy URL
- [ ] 3.3 Ensure URLs open in new tab
## 4. Testing & Quality
- [ ] 4.1 Test proxy with code-server instance
- [ ] 4.2 Verify WebSocket features work (terminal inside code-server)
- [ ] 4.3 Run quality gates (ruff, mypy, typecheck, lint, build)
- [ ] 4.4 Deploy and test end-to-end
@@ -1,42 +0,0 @@
## 1. Database & Models
- [ ] 1.1 Add category and interfaces fields to ToolType model
- [ ] 1.2 Create ToolConfig model with user/project/tool scopes
- [ ] 1.3 Create Alembic migrations for tool_types and tool_configs
## 2. Backend - Tool Config API
- [ ] 2.1 Create GET/POST/PUT/DELETE endpoints for tool configs
- [ ] 2.2 Support global and project-scoped configs
- [ ] 2.3 Mount configs into containers when starting instances
- [ ] 2.4 Update start_instance to inject env vars and write files
## 3. Backend - Tool Type Updates
- [ ] 3.1 Update ToolType API to include category and interfaces
- [ ] 3.2 Update seed data with categories and interfaces
- [ ] 3.3 Add OpenCode as built-in tool type
## 4. Frontend - Tool Config UI
- [ ] 4.1 Create tool config management page/component
- [ ] 4.2 Support env var and file config types
- [ ] 4.3 Show configs per tool type with global/project toggle
## 5. Frontend - Category & Interface Support
- [ ] 5.1 Display tool categories in lists
- [ ] 5.2 Show interface-appropriate actions (Open for web, Terminal for CLI)
- [ ] 5.3 Update instance list to check interfaces
## 6. OpenCode Integration
- [ ] 6.1 Create OpenCode compose template
- [ ] 6.2 Ensure terminal access works
- [ ] 6.3 Mount repo and configs correctly
## 7. Quality Gates
- [ ] 7.1 Run ruff and mypy
- [ ] 7.2 Run frontend typecheck and lint
- [ ] 7.3 Test end-to-end
@@ -1,59 +0,0 @@
## 1. Database Migration
- [ ] 1.1 Create Alembic migration to add new columns to tool_configs table
- [ ] 1.2 Add columns: start_command (text), port (integer), working_directory (text), environment_variables (jsonb), volumes (jsonb)
- [ ] 1.3 Run migration locally and verify
## 2. Backend Model Updates
- [ ] 2.1 Update ToolConfig model with new fields
- [ ] 2.2 Update Pydantic schemas (ToolConfigCreate, ToolConfigResponse)
- [ ] 2.3 Add validation for port range (1-65535)
- [ ] 2.4 Add JSON validation for environment_variables and volumes
## 3. Backend API Updates
- [ ] 3.1 Update list_configs endpoint to return new fields
- [ ] 3.2 Update create_config endpoint to accept new fields
- [ ] 3.3 Update update_config endpoint to handle new fields
- [ ] 3.4 Add validation error handling with clear messages
## 4. Frontend Types and API
- [ ] 4.1 Update ToolConfig interface with new fields
- [ ] 4.2 Update API client functions to handle new fields
- [ ] 4.3 Add type definitions for JSON fields
## 5. Frontend UI - Split Pane Layout
- [ ] 5.1 Create split-pane layout component (left list, right detail)
- [ ] 5.2 Implement left panel: scrollable list grouped by tool type
- [ ] 5.3 Implement right panel: detail/edit form with tabs/sections
- [ ] 5.4 Add responsive design (stack on mobile)
- [ ] 5.5 Add "New Config" button and blank form state
## 6. Frontend UI - Form Fields
- [ ] 6.1 Add Basic section: key, value, config_type, file_path
- [ ] 6.2 Add Runtime section: start_command, port, working_directory
- [ ] 6.3 Add Advanced section: environment_variables (JSON editor)
- [ ] 6.4 Add Advanced section: volumes (JSON editor)
- [ ] 6.5 Implement JSON validation with visual feedback
- [ ] 6.6 Add form validation and error display
## 7. Integration and Testing
- [ ] 7.1 Test creating config with all new fields
- [ ] 7.2 Test updating existing config
- [ ] 7.3 Test JSON validation (valid/invalid cases)
- [ ] 7.4 Test responsive layout on different screen sizes
- [ ] 7.5 Verify backward compatibility with old configs
## 8. Quality Gates
- [ ] 8.1 Run backend linting (ruff)
- [ ] 8.2 Run backend type checking (mypy)
- [ ] 8.3 Run frontend type checking (tsc)
- [ ] 8.4 Run frontend linting (eslint)
- [ ] 8.5 Build frontend and verify
- [ ] 8.6 Commit and push changes
@@ -1,34 +0,0 @@
# UI Redesign - Tasks
## 1. Visual System
- [ ] Update global typography to Inter
- [ ] Refine color tokens for the new warm editorial palette
- [ ] Add styling for new home sections and settings tabs
## 2. Navigation and Routing
- [ ] Remove Sessions from top-level navigation
- [ ] Keep SSH Keys, Tool Types, and Tool Configs accessible from Settings tabs
- [ ] Add redirects for legacy top-level config routes
- [ ] Redirect `/sessions` to `/`
## 3. Home Page
- [ ] Redesign the home page as an overview of open sessions and projects
- [ ] Add summary cards and hero actions
- [ ] Reuse existing session and project data
- [ ] Keep create/open session actions available
## 4. Settings Hub
- [ ] Turn Settings into a tabbed hub
- [ ] Build General, SSH Keys, Tool Types, and Tool Configs tabs
- [ ] Reuse existing APIs and forms
- [ ] Keep the Project settings page separate
## 5. Cleanup and Verification
- [ ] Remove obsolete top-level pages from navigation flow
- [ ] Update tests for the new landing page and redirects
- [ ] Run typecheck, lint, and build