- Add null checks and try/catch around fitAddon.fit() to prevent viewport errors
- Use requestAnimationFrame to ensure DOM is stable before fitting
- Remove isMobile condition from font size buttons in TerminalComponent
- Font size controls now visible on both mobile and desktop terminals
- TerminalComponent: expose changeFontSize via onTerminalReady callback
- MobileTerminalWrapper: pass changeFontSize to header
- MobileTerminalHeader: add A- and A+ font size buttons
- CSS: collapse header height/padding/margin/border when hidden to reclaim space
- Remove useSpecialKeys hook state, export pure utility functions instead
- MobileTerminalWrapper now owns activeModifier state
- SpecialKeysStrip and SpecialKeysPanel receive modifier via props
- TerminalComponent applies modifier to virtual keyboard input via activeModifier prop
- Modifier now works with both special keys AND virtual keyboard input
- Modifier clears after any key press (special or virtual keyboard)
- Redesign useSpecialKeys hook with modifier state tracking
- Add one-shot activation for Ctrl and Alt keys
- Visual feedback: active modifiers shown with yellow highlight
- Fix focusInput to use term.focus() instead of hidden input
- Always refocus terminal after sending any special key
- Add requestAnimationFrame for reliable focus restoration
- Add tabIndex={-1} to all special key buttons to prevent focus
- Add onFocus handler to immediately blur if focused
- Terminal focus stays intact when tapping special keys
- Move terminal hidden input to off-screen position (-9999px) to prevent
text selection/caret visibility on mobile
- Add user-select: none to prevent any selection UI
- Fix create-session-form to use new listRepositoryBranches API signature
(projectId, repoId) and access response.branches/default_branch
Resolved conflicts:
- Moved branch selection UI from inline sessions.tsx to CreateSessionForm component
- Integrated branch dropdown and new branch creation into CreateSessionForm
- Removed duplicate branch state management from sessions.tsx
All branch selection tests pass (7/7).
- Use onPointerDown with preventDefault() instead of onClick
- Add onKeepFocus callback to SpecialKeysStrip and SpecialKeysPanel
- Expose focusInput via onTerminalReady in TerminalComponent
- MobileTerminalWrapper passes focus callback to keep keyboard open
- Remove status from TerminalComponent useEffect dependencies to prevent recreation on WebSocket status changes
- Use ref for onTerminalReady callback to avoid parent re-renders triggering terminal recreation
- Wrap MobileTerminalWrapper onTerminalReady with useCallback for stable reference
- 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
- Add isMirror prop to GitToolbar\n- Show warning banner when repo is a bare mirror\n- Explain that editing/committing/pulling/merging are unavailable\n- Suggest deleting and recreating to enable full features\n\nQuality gates: vitest (43 passed)
- Create orphan branches when HEAD does not exist yet\n- Use current branch as the default branch base in the toolbar\n- Keep push disabled for remote-less repos\n\nQuality gates: vitest repositories-settings-tab (passed); api pytest blocked by missing fastapi in environment
- Create normal working clones for remote repositories
- Initialize blank repositories with a main branch
- Align pull and branch helpers with unborn HEAD handling
- Gate fetch/pull on repositories with a remote
Quality gates: vitest repositories-settings-tab (passed); api pytest blocked by missing fastapi in environment
- Extract the repository create dialog into a shared component
- Reuse the same clone/validation flow in project settings and repository management pages
- Keep the shared UI covered with focused tests
Quality gates: tsc --noEmit, vitest run src/components/repositories-settings-tab.test.tsx
- Make the add repository dialog explicitly support cloning from a remote git server
- Keep blank repo creation as a fallback option
- Add validation and tests for the clone-first flow
Quality gates: tsc --noEmit, vitest run src/components/repositories-settings-tab.test.tsx
- Add repository creation dialog to the project settings repositories tab
- Reuse shared repository API for list/create/delete operations
- Add coverage for the create flow in the settings tab
Quality gates: tsc --noEmit, vitest run src/components/repositories-settings-tab.test.tsx
- Add inline confirmation dialog before stopping instances
- Delete instances from state immediately without page reload
- Add health check polling every 30s for running instances
- Show tunnel error badge when tunnel is unreachable
- Add 'Fix Tunnel' button to recreate broken tunnels
- Update API client with health check and tunnel recreation endpoints
Backend:
- Add cloudflare_tunnel.py service for creating/deleting tunnels via Cloudflare API
- Add public_url and tunnel_id fields to ToolInstance model
- Update start_instance to create Cloudflare tunnel after container starts
- Update stop_instance to delete tunnel before stopping container
- Update delete_instance to cleanup tunnel before deletion
- Update restart_instance to recreate tunnel on restart
- Create Alembic migration 0011 for tunnel fields
- Add Cloudflare config settings (API token, zone ID, account ID, base domain)
Infrastructure:
- Add cloudflared service to docker-compose.traefik.yml
- Mount shared cloudflared_config volume between API and cloudflared containers
- Add Cloudflare env vars to API service
Frontend:
- Update instance Open button to handle both full URLs and proxy paths
The instance URL is now set to the Cloudflare tunnel public URL when available,
falling back to the API proxy path if tunnel creation fails.
- Create ToolConfigsPage with tool type selector, config list, and add/edit form
- Support both env and file config types
- Add route /tool-configs and navigation item
- Update API client with tool config endpoints
- Build passes successfully
Add support for tool categories, interface types, and per-tool configuration.
Backend:
- Add category and interfaces fields to ToolType model
- Create ToolConfig model for storing tool-specific settings
- Add tool_configs API endpoints (CRUD)
- Update built-in tool types with categories and interfaces:
- code-server: editor, [web]
- jupyter-notebook: notebook, [web]
- opencode: ai-assistant, [terminal]
- Update instance API to include tool type interfaces
- Create Alembic migrations 0008 and 0009
Frontend:
- Update ToolType and Session interfaces with new fields
- Conditionally show Open/Terminal buttons based on tool interfaces
- Add API client for tool configs
OpenSpec: tool-config-management change created and implemented.
Add API proxy endpoint so users can access running tool instances
through the backend API instead of internal Docker network.
Backend:
- Add container_name field to ToolInstance model
- Create /instances/{id}/proxy/{path:path} endpoint with ownership checks
- Proxy HTTP requests to containers via docker network using container names
- Support all HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)
- Store proxy URL in instance.url instead of localhost
- Add Alembic migration 0007 for container_name column
- Add get_container_name() utility to docker.py
Frontend:
- Update Open button to use full proxy URL (API_BASE_URL + instance.url)
Closes instance-proxy OpenSpec change.
- Add Sessions tab to navigation between Dashboard and Projects
- Show active session count badge in navigation
- Create SessionsPage with:
- Last session section with resume button
- Active sessions grid with open/stop actions
- Recent sessions list
- Create session form with project/repo/tool selectors
- Add last_session_id to user config
- Update UserConfig schemas (backend and frontend)
- Add comprehensive CSS for sessions page
Quality gates: typecheck ✓, lint ✓, build ✓
Backend:
- Create ToolInstance model with status tracking
- Add Alembic migration for tool_instances table
- Create Docker service for compose template rendering and container execution
- Add CRUD API endpoints for tool instances
- Add lifecycle endpoints (start/stop/restart)
- Add user sessions endpoint for navigation
- Register routers in main.py
Frontend:
- Create SessionsProvider with React context
- Create sessions API client
- Update AppShell with sessions section in navigation
- Add session status indicators and polling
- Add CSS for session navigation
Quality gates: typecheck ✓, lint ✓, build ✓
- Create SettingsTabLayout component with sidebar navigation
- Create ProjectSettingsPage with General settings tab
- Create RepositoriesSettingsTab for repo management
- Add Members placeholder tab
- Update router with settings routes
- Add CSS styles for settings layout
- Navigate to /projects/:id/settings from workspace header
- Add CommitPanel component for viewing changed files and committing
- Show file status indicators (M/A/D/?) in file tree
- Integrate git status with workspace for real-time updates
- Add CSS styles for commit panel and status badges
Part of git-control change implementation.
- Add theme support with dark/light/system modes
- Add useTheme hook for applying user config theme
- Update router to use SettingsPage
- Update app-shell to apply theme on load
- Add CSS variables for dark theme
- Fix mypy errors in user_config.py
- Quality gates pass: ruff, mypy, typecheck, lint, build
- Add backend API for git repository CRUD (create, list, delete)
- Support bare repository initialization and mirror cloning
- Add cascade delete for repositories when project is deleted
- Add frontend page for repository management per project
- Update project page with link to repositories
- Add repo_base_path to config
- Quality gates: ruff, mypy, typecheck, lint, build all pass