Commit Graph

107 Commits

Author SHA1 Message Date
Fusion ac6bd3304d feat(opencode-web-terminal): complete OpenCode web terminal implementation
- Update OpenCode compose template with web server on port 3000
- Add default_port=3000 and interfaces=[terminal, web] to OpenCode seed data
- Remove hardcoded 8080 fallback in tunnel creation
- Fail gracefully when tool type has no default_port configured
- Update frontend ToolType API to include default_port, category, interfaces
- Add port, category, and interfaces fields to tool type creation form
- Display port and interfaces in tool type cards
- Create migration 0012 to make default_port non-nullable
- Set default_port values for existing built-in tool types
- Quality gates: typecheck ✓, build ✓, Python syntax ✓
2026-05-20 17:17:50 +02:00
Fusion 6ec35988cc feat(sessions): add stop confirmation, health checks, and tunnel recreation
- 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
2026-05-20 16:49:31 +02:00
Fusion e985f0122e debug(tunnels): add connectivity check before starting cloudflared tunnel 2026-05-20 16:28:39 +02:00
Fusion 2bd778117f feat(tunnels): switch to temporary Cloudflare tunnels
Replace persistent Cloudflare tunnels (API-based) with temporary tunnels using
'cloudflared tunnel --url'. This removes the need for Cloudflare API tokens,
DNS records, and persistent tunnel management.

Changes:
- Install cloudflared binary in API Dockerfile
- Add start_cloudflared_tunnel() and stop_cloudflared_tunnel() to docker.py
- Update instance start/stop/restart/delete to use temporary tunnels
- Store tunnel PID in tunnel_id field, temporary URL in url/public_url
- Remove Cloudflare API service (cloudflare_tunnel.py)
- Remove cloudflared container from docker-compose
- Remove Cloudflare env vars (CLOUDFLARE_API_TOKEN, ZONE_ID, etc.)
- Remove Cloudflare configuration from config.py
- Remove Cloudflare startup check from main.py
- Remove /health/cloudflare endpoint
2026-05-20 16:23:16 +02:00
Fusion 23ae12e69c debug(cloudflare): add detailed logging for tunnel creation failures 2026-05-20 16:09:47 +02:00
Fusion 65d4fad3c5 fix(cloudflare): fix delete_tunnel subdomain format and add startup config check
- Fix delete_tunnel calls to use correct subdomain format (instance-{id[:8]})
- Add Cloudflare configuration check at startup with clear warnings
- Help diagnose why tunnels aren't being created
2026-05-20 16:01:21 +02:00
Fusion e6f64c39f3 fix(cloudflare): add backend network to compose templates and improve tunnel diagnostics
- Add 'backend' external network to all compose templates so cloudflared can reach tool containers
- Add better error handling and logging to create_tunnel() with specific error messages for auth failures
- Add check_cloudflare_config() diagnostic function
- Add /health/cloudflare endpoint to verify Cloudflare configuration
- Import Any type for type hints
2026-05-20 15:55:20 +02:00
Fusion e7c42c17b9 fix(docker): copy Python packages to root home directory
Since API container runs as root (for Docker socket access),
copy Python packages to /root/.local instead of /home/appuser/.local
so uvicorn and other dependencies are in PATH.
2026-05-20 15:42:12 +02:00
Fusion f7be50952a fix(docker): run API container as root for Docker socket access
The API container needs to run docker compose commands via the
mounted Docker socket. Running as non-root user doesn't work well
with socket permissions across container boundaries.

- Remove USER appuser from Dockerfile (API service only)
- Remove group_add from docker-compose (no longer needed)
- Add security note about considering Docker-in-Docker or rootless

This fixes:
permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
2026-05-20 15:38:02 +02:00
Fusion 7450dd0ce5 fix(instances): add missing TOOL_NAME variable to compose template
The compose template uses {{TOOL_NAME}} for container_name but
we weren't passing it in the variables dict, causing YAML parse error.

Error was:
yaml: cannot use 'map[string]interface {}{"TOOL_NAME":interface {}(nil)}' as a map key
2026-05-20 15:30:45 +02:00
Fusion 7a88639250 chore(logging): add detailed debug logging to instance start and tunnel creation
Add comprehensive logging to trace 500 error:
- Log each step of docker compose up (returncode, stdout, stderr)
- Log container ID and name after start
- Log tool type and port being used
- Log each step of Cloudflare tunnel creation with API responses
- Log cloudflared config updates

This will help identify exactly where the failure occurs.
2026-05-20 15:27:55 +02:00
Fusion 1d33735e2f fix(cloudflare): use correct container port in tunnel config
Cloudflared was hardcoded to route to port 8080, but containers
listen on different ports (8443 for code-server, 8888 for jupyter).

- Add instance_port parameter to create_tunnel and update_cloudflared_config
- Fetch tool type default_port when creating tunnels
- Route to correct internal port instead of hardcoded 8080
2026-05-20 15:23:39 +02:00
Fusion d11b43b69f fix(settings): properly save and clear configuration values
Backend:
- Replace dict mutation with dict replacement to fix SQLAlchemy JSON
  mutation tracking issue (config.config = {**config.config, **update_data})

Frontend:
- Send explicit null values instead of undefined so fields can be cleared
- Update UserConfigUpdate interface to accept null values
2026-05-20 15:17:33 +02:00
Fusion 1a922d4171 fix(sessions): correct session state categorization
- Backend now returns stopped and error sessions too
- Active sessions include running/building/pending
- Recent sessions show stopped/error only
- Status badge shows actual status (running/building/pending)
2026-05-20 14:49:30 +02:00
Fusion b40eb3e88c feat(cloudflare-tunnel): integrate Cloudflare tunnels for instance access
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.
2026-05-20 14:25:06 +02:00
Fusion 98795e31dd fix(proxy): use internal container port instead of host port
The proxy was using instance.port which is a dynamically allocated
host port (e.g., 10001). But containers communicate on the Docker
network using their internal ports (8443 for code-server, 8888 for
jupyter). This caused connection failures when opening instances.

- Add default_port field to ToolType model (null for terminal-only tools)
- Create migration 0010 for default_port column
- Update seed data: code-server=8443, jupyter=8888, opencode=null
- Update proxy to use tool type's default_port instead of instance.port
- Update frontend ToolType interface to include default_port

Fixes: Opening instances now routes to correct internal container port
2026-05-20 13:55:42 +02:00
Fusion 9d27cd9fe8 fix: install Docker CLI and mount socket for instance management
- Install docker-ce-cli and docker-compose-plugin in API Dockerfile
- Mount /var/run/docker.sock into API container
- Add appuser to docker group for socket permissions
- Fixes FileNotFoundError when deleting instances
2026-05-20 11:32:58 +02:00
Fusion f824a1e6fe fix: settings save and session deletion bugs
Settings save:
- Remove exclude_none=True from user_config.py model_dump() call
- Fixes fields not updating when cleared or set to null/undefined

Session deletion:
- Add project_id and repository_id to get_user_sessions response
- Update frontend Session interface with new fields
- Fix handleDelete to use IDs instead of names, resolving 404 errors
2026-05-20 11:20:43 +02:00
Fusion ad09ffa6ec feat(tool-configs): add frontend tool config management page
- 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
2026-05-20 11:13:25 +02:00
Fusion 63ae706dd0 feat(tool-config): add categories, interfaces, and config management
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.
2026-05-20 11:03:09 +02:00
Fusion 74b5d0dc8c feat(instance-proxy): add HTTP proxy for tool instances
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.
2026-05-20 10:37:21 +02:00
Fusion 25662e525c fix(docker): make instance directory configurable and writable
- Add INSTANCE_BASE_PATH config option (defaults to /data/instances)
- Update docker.py to use configured path instead of hardcoded 'data/instances'
- Update Dockerfile to create /data/instances and chown to appuser
- Add instance_data volume to docker-compose.traefik.yml and docker-compose.yml
- Set INSTANCE_BASE_PATH env var in both compose files

This fixes the PermissionError when creating tool instances because
appuser can now write to /data/instances.
2026-05-20 10:09:37 +02:00
Fusion d4e992a9e2 fix(cors): add API domain to CORS origins and improve instance error handling
- Add API base URL to CORS allowed origins alongside web base URL
- Add CORS origin logging on startup for debugging
- Wrap instance creation in try/except with detailed error logging
- Return proper error message instead of raw 500 for instance creation failures

This fixes CORS errors when the frontend makes cross-origin requests and
provides better diagnostics for instance creation failures.
2026-05-20 10:03:53 +02:00
Fusion 35ada0e662 fix(auth): set session cookie on redirect response
The OAuth callback was setting the session cookie on the 'response'
parameter but returning a brand new RedirectResponse, causing the
cookie to be lost. This created an infinite login loop where the
callback succeeded but /auth/me always returned 401.

- Set cookies on the RedirectResponse instead of the unused response param
- Remove unused 'response: Response' parameter from callback handler
- Fixes login loop in production with cross-domain cookies
2026-05-19 23:29:24 +02:00
Fusion c3e2264771 debug: add logging to auth /me endpoint to diagnose login loop 2026-05-19 23:25:30 +02:00
Fusion 76741d3ee6 debug: add logging to settings save to diagnose issue 2026-05-19 23:21:48 +02:00
Fusion 62752a8390 fix: add validation logging and debug info for tool instance creation
- Add RequestValidationError handler to log validation errors
- Add extra=ignore to CreateInstanceRequest to be more lenient
- Add logging to create_instance endpoint to see received data
- Add missing logger import in tool_instances.py
2026-05-19 23:17:08 +02:00
Fusion 94aa88c154 feat: add Sessions Hub page
- 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 ✓
2026-05-19 23:06:54 +02:00
Fusion 4f695d7e62 fix: accept tool instance creation params in request body
The create_instance endpoint was expecting tool_type_id and display_name
as query parameters, but the frontend sends them in the JSON body.
Added CreateInstanceRequest Pydantic model to properly parse the request body.

Fixes 422 Unprocessable Content error on instance creation.
2026-05-19 22:55:47 +02:00
Fusion 7a48180dc3 fix: correct get_db_session import in tool_instances.py
Import get_db_session from src.auth.dependencies instead of src.database.
Fixes ImportError on application startup.
2026-05-19 21:39:29 +02:00
Fusion a0b0944709 fix: correct get_db_session import in terminal.py
Import get_db_session from src.auth.dependencies instead of src.database.
Fixes ImportError on application startup.
2026-05-19 21:37:00 +02:00
Fusion 40a940304b docs: comprehensive API documentation
- Create enhanced health endpoints with /health and /health/db
- Add comprehensive docstrings to all API endpoints
- Add Pydantic response models with Field descriptions
- Create apps/api/README.md with setup guide
- Create ADR-001 for session auth decision
- Create ADR-002 for async SQLAlchemy decision
- Quality gates: Python syntax OK, TypeScript OK
2026-05-19 21:31:20 +02:00
Fusion e344e961d6 feat: implement web terminal for tool instances
- Add TerminalSession backend service for docker exec subprocess management
- Add TerminalManager for WebSocket session lifecycle management
- Create WebSocket endpoint at /ws/tool-instances/{id}/terminal
- Add session cookie authentication and instance ownership verification
- Install xterm.js with fit and web-links addons
- Create TerminalComponent with xterm.js integration
- Create TerminalPage with full-screen terminal view
- Add terminal route at /instances/:id/terminal
- Add terminal button to InstanceList for running instances
- Add terminal and arrow-left icons to icon registry
- Add comprehensive terminal CSS styles (dark theme, responsive)

Quality gates: typecheck ✓, lint ✓, build ✓, Python syntax ✓
2026-05-19 21:11:29 +02:00
Fusion c795f8f873 feat: implement tool instances backend and session navigation
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 ✓
2026-05-19 20:42:59 +02:00
Fusion cccc4a9d5a fix: correct binary file detection in git file viewer
- Remove useless git diff --numstat call that failed in bare repos
- Use raw bytes instead of text decoding to avoid encoding issues
- Properly check subprocess return codes

Fixes false positive binary detection for text files like .env.sample
2026-05-19 18:55:58 +02:00
Fusion 7fc8b82621 fix: add missing GET /projects/{id} endpoint
Frontend workspace was calling GET /projects/{id} which didn't exist,
causing 405 errors and preventing WorkspaceHeader from rendering.

Add get_project endpoint that returns a single project by ID with
ownership verification.
2026-05-19 15:34:26 +02:00
Fusion 965f6f6585 feat: add git control tests and mark all tasks complete
- Add integration tests for git control utilities
- Test status, branch operations, and commit functionality
- All 9 tests passing
2026-05-19 15:10:31 +02:00
Fusion 762e0de44c feat: add git control endpoints (status, branch, commit, fetch, pull, push, merge)
- Add GitStatus dataclass and git control utilities
- Add endpoints:
  - GET /status - working directory status
  - POST /branches - create branch
  - DELETE /branches/{name} - delete branch
  - POST /checkout - checkout branch
  - POST /commit - commit changes
  - POST /fetch - fetch from remote
  - POST /pull - pull updates
  - POST /push - push changes
  - POST /merge - merge branches

Quality gates: ruff ✓, mypy ✓
2026-05-19 14:49:22 +02:00
Fusion 6807f449b7 feat: add repository workspace as default project view
- Create git file utilities (list_tree, get_file_content, list_branches, commit_file)
- Add file browsing API endpoints (list, content, branches, update)
- Create RepoWorkspace page with sidebar + main content layout
- Add FileTree component with directory navigation
- Add FileViewer component for viewing file contents
- Update project list to link to workspace
- Add workspace CSS styles
- Update router with workspace route

Quality gates: ruff ✓, mypy ✓, typecheck ✓, build ✓
2026-05-19 13:43:49 +02:00
Fusion 92d0d5b891 fix: don't combine --all with branch name in git log
Using 'git log --all <branch>' creates ambiguous behavior. Now:
- Without branch: uses --all to show all commits from all refs
- With branch: shows only commits from that specific branch

This ensures consistent commit counts between git CLI and API.
2026-05-19 13:19:36 +02:00
Fusion 9873a8186a fix: send ISO format dates instead of Unix timestamps
Backend was sending Unix timestamps as strings (e.g. '1716112800')
which JavaScript Date couldn't parse. Now sends proper ISO 8601
format dates that work with new Date() in the browser.
2026-05-19 13:10:10 +02:00
Fusion d4b52668aa fix: align backend commit response with frontend expectations
Backend was returning fields like 'author', 'email', 'date' but frontend
expected 'author_name', 'author_email', 'author_date'. Also 'branches' and
'tags' were separate but frontend expects unified 'refs' array.

- Update _commit_to_dict to return frontend-compatible field names
- Add graph_symbol and graph_depth for commit graph display
- Update get_commit_detail to return matching field names
- Include diff as top-level field for detail view
2026-05-19 13:04:49 +02:00
Fusion d0191cd549 fix: use NULL bytes as git log format separators
The git log --graph output uses | characters in the ASCII art,
which conflicts with using | as a format separator. Switch to
NULL bytes (\x00) which won't appear in commit data.

Also removed --graph flag since we build graph data from
parent relationships instead.
2026-05-19 13:00:22 +02:00
Fusion 0ae0e3fec1 feat: add git history backend implementation
- Add git_history.py utility for extracting commit history and details
- Add API endpoints for repository history and commit details
- Integrate with existing git_repositories router

This completes the backend for git history visualization.
2026-05-19 12:50:57 +02:00
Fusion 8b70daed53 feat: smart git URL parsing for browser URLs
- Add git URL parsing utilities (extract_base_repo_url, parse_git_url)
- Support GitHub, GitLab, Bitbucket browser URL detection
- Add /projects/repositories/parse-url endpoint
- Enhance repository creation to detect browser URLs and suggest corrections
- Add real-time URL validation in frontend with debouncing
- Show visual indicators (green/yellow/red) for URL validity
- Display inline suggestions with 'Use Suggested' button
- Add comprehensive unit tests for URL parsing
- Quality gates: ruff ✓, mypy ✓, typecheck ✓, lint ✓, build ✓
2026-05-19 12:25:44 +02:00
Fusion ac6c97b6ce fix: add missing timestamps to ssh_keys model
SSHKey model was missing created_at/updated_at columns which the API
response model expected. Add TimestampMixin and Alembic migration.
2026-05-19 11:51:39 +02:00
Fusion a433c82488 fix: datetime serialization in API response models
Tool types and git repositories response models declared created_at/
updated_at as str but ORM returns datetime objects. Change to datetime
type so Pydantic serializes correctly to ISO format strings.
2026-05-19 11:42:14 +02:00
Fusion f8700fd7ed fix: dashboard endpoint and SSH key Fernet key generation
- Create missing /dashboard/summary endpoint that frontend expects
- Fix SSH key Fernet key generation to use proper base64 encoding
  (was using raw session secret slice which failed validation)
2026-05-19 11:38:25 +02:00
Fusion 0fcfc745ff fix: add alias=session to Cookie dependencies
FastAPI uses parameter name as cookie name by default.
get_current_user_id was looking for 'session_cookie' but we set
the cookie as 'session'. Add alias='session' to match.
2026-05-19 10:56:11 +02:00
Fusion d214ab82db debug: add logging to auth cookie handling
Add debug logging to understand why /auth/me succeeds but
/users/me/config fails with 401.
2026-05-19 10:52:33 +02:00