Commit Graph

88 Commits

Author SHA1 Message Date
alex 2247ec47c9 fix(config-profiles): synchronize shared mount working copies
Use canonical profile files and writable Git working copies so editor and container changes share one source. Require confirmation before destructive Git refreshes and overlay profile files without composite snapshots.
2026-07-22 11:23:19 +02:00
Developer 886c863260 feat: refresh shared Git config mounts live
- Use profile-scoped canonical Git clone sources with locked refreshes
- Mount shared Git configuration read-only and isolate profile content
- Add API and desktop/mobile actions for live Git mount refresh

Quality gates: frontend build and backend py_compile passed.
Skipped: backend pytest/Ruff unavailable; Docker/manual checks not approved.
2026-07-21 14:37:42 +00:00
Developer add7c1b500 feat: add live config profile refresh
- Standardize built-in tool users for shared writable profile mounts
- Mount canonical non-Git profile sources across compatible instances
- Report restart-required outcomes and guard active profile deletion
- Surface restart feedback in config profile editing

Quality gates: frontend build passed; backend py_compile and LSP passed.
Skipped: backend pytest/Ruff unavailable; Docker/manual checks not approved.
2026-07-21 11:12:41 +00:00
Developer 93da9b42a2 chore(project-map): regenerate .pi-map artifacts across the repo 2026-06-17 11:31:24 +00:00
Developer 7ef8b0eb36 chore: patch project maps after stale backend test cleanup
Regenerate .pi-map*.md artifacts for source changes in:
- apps/api/src/api/tool/tool_types_validation.py
- apps/api/src/schemas/tool/tool_type.py
- apps/api/tests/integration/test_tool_types_api_extended.py
- and all affected test files from backend-frontend refactoring cleanup
2026-06-12 20:36:31 +00:00
Developer 3da7ea6408 WIP: frontend clone_mode removal in create form and API
- Remove clone_mode/branch/new_branch from createInstance API helper
- Remove clone mode UI and branch fields from CreateSessionForm

Remaining: wire workspace_id in form/tool-starter, remove session-card badge, tests
2026-06-12 15:32:19 +00:00
Developer 070cd4d5a5 chore: track all project map and index files
Add generated .pi-map.md and .pi-map.index.md files across the repository
so the project navigation maps are shared and versioned. These artifacts
are maintained by project_map_init/patch/validate and must be kept in
sync with source edits.

Note: .cache/ remains ignored (added in previous commit).
2026-06-12 13:46:23 +00:00
Developer f1b968bb88 feat: default session name to '{workspace} {tool_type}', improve terminal tab title
ToolStarter:
- Auto-populate Session Name as '{workspace.name} {tool_type.display_name}'
  when a tool type is selected
- Track whether user has manually edited the name (nameEdited flag) to avoid
  overwriting their custom input

Terminal page:
- Fetch instance display_name via getUserSessions for tab title
- Tab title format: '{display_name} {terminal_session_name} — Terminal'
  instead of just '{session_name} — Terminal'

Quality gates: tsc --noEmit pass, npm run build pass, 82/82 tests pass
2026-06-11 08:11:04 +00:00
Developer 1d10283fc9 feat: improve session naming, project display, rename support, tab titles
Backend:
- sessions.py: include workspace_name in session response
- instance_service.py: auto-generate display names as
  'Project / Workspace / Tool #N' instead of 'Workspace / Tool #N'
- instance_service.py: add rename_tool_instance() service function
- tool_instances.py: add PATCH /instances/{id} endpoint for renaming
  display_name

Frontend:
- api/sessions.ts: add workspace_name to Session type, add renameInstance()
- use-instance-actions.ts: add handleRename, set document.title when opening
- session-card.tsx: click-to-edit display_name inline; always show project
  context line (Project / Workspace or Repo / Tool)
- session-list.tsx: pass through onRename prop
- SessionsPage.tsx: wire handleRename to SessionCard and SessionList
- app-shell.tsx: sidebar tooltip includes workspace or repo name
- use-terminal-page.ts: set document.title based on active terminal session

Quality gates: py_compile all backend files pass, tsc --noEmit pass,
npm run build pass, 82/82 tests pass
2026-06-10 17:04:03 +00:00
Developer a9e2dd3552 fix: complete refactoring integration — rename remaining snake_case API files and fix test imports
During refactoring verification found several remaining inconsistencies:

API files (kebab-case naming):
- Rename config_profiles.ts → config-profiles.ts
- Rename tool_definitions.ts → tool-definitions.ts
- Update all imports across 8 files

Missing Python __init__.py (backend package structure):
- Add utils/__init__.py
- Add services/__init__.py
- Add schemas/__init__.py
- Add services/build/__init__.py

Test file import fixes (component reorganization fallout):
- DashboardPage.test.tsx: import from ./dashboard → ./DashboardPage
- ProjectsPage.test.tsx: import from ./projects → ./ProjectsPage
- event-toast-bridge.test.tsx: fix relative paths for moved components
  (../state/events → ../../../state/events, ./toast-rules → ../../toast-rules)
- notification-center.test.tsx: fix relative path
  (../state/notifications → ../../../state/notifications)

Quality gates: tsc --noEmit (pass), build (pass), py_compile (pass)
Tests: 9/12 test files pass (3 pre-existing UI test failures unrelated to refactoring)
2026-06-05 09:30:44 +00:00
alex 020f832eed refactor: rename frontend API files to kebab-case
Renamed:
- git_repositories.ts → git-repositories.ts
- ssh_keys.ts → ssh-keys.ts
- tool_types.ts → tool-types.ts
- tool_types.test.ts → tool-types.test.ts

Updated all imports across components, pages, and hooks.

Quality gates: verified no remaining old imports.
2026-06-04 12:33:10 +02:00
alex f34c733706 fix: remove trailing slashes causing FastAPI redirect → mixed-content
- workspaceUrl: no trailing slash on /{workspaceId} (backend route has none)
- deleteWorkspace: /workspaces/{id}?force= (was /{id}/?force= with slash before ?)

Quality gates: tsc --noEmit clean, pytest workspaces API (9 passed, 1 skipped)
2026-06-01 20:20:23 +02:00
alex 95efa5d029 fix: workspace delete mixed-content error via top-level endpoint
- Add top-level DELETE /workspaces/{workspace_id} endpoint (avoids nested path)
- Frontend deleteWorkspace now uses /workspaces/{id}/?force=... (no project/repo needed)
- Update useWorkspaceActions, ProjectsPage, WorkspacesPage to match new signature

Quality gates: ruff clean, tsc --noEmit clean, pytest workspaces API (9 passed, 1 skipped)
2026-06-01 20:03:24 +02:00
alex ab1843b1c3 fix: allow workspace creation from workspaces page
- Replace awkward first-workspace-guessing logic with inline project/repo selector
- New WorkspaceCreateInline component with cascading dropdowns:
  - Select project → loads repositories for that project
  - Select repository → enter workspace name + branch
  - Submit creates workspace via top-level POST /workspaces/
- Add createWorkspaceTopLevel() API client for flat endpoint
- Works even with zero existing workspaces (shows create button in empty state)
- Add CSS grid layout for inline create form
- TypeScript + eslint clean
2026-06-01 17:32:35 +02:00
alex 88a973dc68 feat: workspace-first UI refresh - PR-3 projects page + routing cleanup
- Rewrite ProjectsPage with inline repository and workspace display
- Expandable project cards showing repos + workspace chips
- Inline workspace creation from project page (New Workspace button per repo)
- Workspace chips link to workspace detail page
- Sync/delete actions on workspace chips
- Update Project type: add ProjectWithRepos, RepositorySummary, WorkspaceSummary
- Update listProjects API to return ProjectWithRepos[]
- Update dashboard, sessions, config-profiles to use ProjectWithRepos
- Remove old /projects/:projectId route (RepoWorkspace)
- Add chevron icons to Icon component
- Projects page CSS: project-toggle, repo-block, workspace-grid, workspace-chip
- TypeScript + eslint clean

Quality gates: tsc --noEmit clean, eslint clean
2026-06-01 17:18:51 +02:00
alex 27c77af591 feat: workspace-first UI refresh - PR-2 workspace detail page
- Add workspace detail page (/workspaces/:id) with 4 tabs:
  - Files: file tree, viewer, editor, git toolbar (commit/push/pull/fetch)
  - Git: branch selector, commit history
  - Tools: instance grid, start tool modal
  - Settings: workspace info read-only
- Add workspace API clients: workspace-files, workspace-git, workspace-instances
- Add hooks: useWorkspaceFiles, useWorkspaceGit, useWorkspaceInstances
- WorkspaceCard links to detail page via router Link
- Add comprehensive CSS for workspace detail layout
- Mobile: bottom tab bar, responsive file tree/split
- TypeScript + eslint clean

Quality gates: tsc --noEmit clean, eslint clean
2026-06-01 17:04:44 +02:00
alex 59b125d8e2 fix: add top-level GET /workspaces endpoint and derive project/repo from workspace data
- Add all_workspaces_router with GET /workspaces/ (no project/repo required)
- Include project_id in workspace responses
- Frontend: useWorkspaces() calls listAllWorkspaces when no args
- Frontend: WorkspacesPage uses top-level list, derives project/repo from workspace for mutations
- Fixes 422 from invalid UUID path params
2026-06-01 00:20:19 +02:00
alex b05de96569 fix: add trailing slash to workspace API URLs
FastAPI auto-redirects /workspaces to /workspaces/ with 307.
Behind Traefik (HTTP internal), the 307 becomes http://,
triggering Mixed Content in the browser. Adding trailing
slashes avoids the redirect entirely.
2026-06-01 00:03:33 +02:00
alex a5d64d1859 fix: add from __future__ import annotations to workspace_manager.py
Fixes NameError: ToolInstance not defined at runtime because
type annotations are evaluated at class definition time.
Deferring annotation evaluation with __future__ annotations
keeps TYPE_CHECKING imports from causing runtime crashes.

Also includes ruff formatting cleanup on workspace-related files.
2026-05-31 23:41:45 +02:00
alex 5bba2bbd92 feat: workspace frontend integration (PR-4)
- Add workspace_id parameter to createInstance API client
- Wire WorkspacesPage 'Start Tool' modal to createInstance + startInstance
- Pass workspace_id when creating instance from workspace page
- TypeScript + eslint clean
2026-05-31 23:30:09 +02:00
alex 986091ac56 feat: workspace frontend core (PR-3)
- Workspace types, API client, hooks (useWorkspaces, useWorkspaceActions)
- WorkspaceCard, WorkspaceCreateForm, StartToolModal components
- WorkspacesPage with list, create, sync, delete, start-tool flow
- Sidebar navigation: new 'Workspaces' entry
- Router: /workspaces route
- TypeScript + eslint clean
2026-05-31 23:27:10 +02:00
Alex Blank 2b5223097f feat: filter notifications to warnings/errors/ready only and add clear-all button
Notification filtering:
- lifecycle_hooks.py: only instance.error and instance.health_changed
  with status=running generate notifications. All other lifecycle events
  (created, started, stopped, restarted, deleted) are filtered out.
- health_monitor.py: only error and unhealthy states generate notifications.
  Running/recovered state no longer creates info notifications.
- _derive_title now maps instance.health_changed to "Container ready".

Clear-all button:
- Added dismiss_all() to NotificationService
- Added DELETE /notifications endpoint for bulk dismiss
- Frontend: clearAllNotifications API, clearAll in notification context,
  "Clear all" button in notification drawer alongside "Mark all as read"
- Added CSS for .notification-clear-all with danger hover state
- Updated notification-center tests

Quality gates: pytest (21 passed), vitest (11 passed)
2026-05-29 16:42:31 +02:00
alex 19242b4152 feat: notification center toast coordination (PR-4)
- EventToastBridge checks notification_toast_level and notification_mute_categories
- toast-rules.ts: event-to-category/severity mapping functions
- Settings page: notification preferences section (toast level dropdown, mute checkboxes)
- Settings API types extended with notification preference fields
- 17 frontend tests (toast-rules + bridge)
- Preference hierarchy: mute categories → toast level → show/hide

Quality gates: vitest 17 passed, tsc clean, eslint clean
2026-05-29 13:52:49 +02:00
Alex Blank ceaed9af66 Merge remote dev branch 2026-05-29 13:34:08 +02:00
Alex Blank e9364fa70f feat: instance-level SSH key selection for container mounting
- Revert mistaken ssh_key_id from ConfigProfile (model, API, resolver, frontend)
- Add ssh_key_ids JSON column to tool_instances via migration
- Update create_instance to accept and store ssh_key_ids
- Update start_instance to mount selected SSH keys to {home_dir}/.ssh
- Update list_instances to return ssh_key_ids
- Frontend CreateSessionForm: multi-select SSH key checkboxes
- Frontend instance-list: SSH key selector for start/restart actions
- Maintain separate SSH key dirs per key to avoid conflicts

Quality gates: pytest (231 passed, 6 pre-existing), tsc --noEmit clean
2026-05-29 13:30:53 +02:00
alex 2bec205a30 feat: notification center frontend core (PR-3)
- Bell icon in icon registry (Phosphor Bell)
- NotificationProvider context with polling (15s unread / 30s list)
- useNotifications() hook with optimistic updates
- NotificationCenter component: bell + badge + dropdown panel
- NotificationItem component: severity icon, title, relative time, actions
- AppShell integration: mount in header-actions, hidden on mobile
- CSS styles: dropdown, items, unread/read states, empty state
- formatRelativeTime utility (custom, no new deps)
- 25 frontend tests (9 hook + 6 item + 10 center)

Quality gates: vitest 25 passed, tsc clean, eslint clean
2026-05-29 13:17:22 +02:00
Alex Blank 57ff236f2d feat: add ssh_key_id to config profiles for container key mounting
- Add ssh_key_id column to ConfigProfile model and migration
- Update config profile API to accept/return ssh_key_id
- Include ssh_key_id in ResolvedProfile and resolver logic
- Mount selected SSH key into container home dir at start_instance
- Frontend config profile form with SSH key selector dropdown
- Git mount URL validation defaults to profile's SSH key

Quality gates: pytest (231 passed, 6 pre-existing), tsc --noEmit clean
2026-05-29 12:53:51 +02:00
Alex Blank 090edf7ef6 feat: git mount URL validation with branch detection
- Add POST /config-profiles/validate-git-url endpoint:
  - Parses URL using existing parse_git_url utility
  - Suggests corrected URL for browser URLs
  - Runs git ls-remote --heads to verify reachability
  - Lists available branches from remote
  - Supports SSH key for private repos
  - Returns structured response: valid, suggested_url, branches,
    default_branch, error, error_code

- Update frontend GitMountEditor:
  - Add Check button next to URL field with loading state
  - Show validation result: valid (green), suggestion (yellow),
    invalid (red)
  - Suggestion includes Use this button to apply corrected URL
  - Branch field becomes dropdown when URL is validated,
    populated with remote branches
  - Mappings section disabled until URL is validated
  - Shows hint: Validate the URL first

- Quality gates: pytest (218 passed, 6 pre-existing),
  tsc --noEmit (clean)
2026-05-29 12:15:30 +02:00
alex f13a63dc2f feat: container monitoring frontend UI (PR-2)
- Custom ToastContext + ToastProvider + ToastContainer (~170 lines, no deps)
- useEvents() SSE hook with exponential backoff reconnect
- EventProvider context for app-wide SSE stream sharing
- Event-to-toast bridge with severity mapping and deduplication
- Real-time status badge updates replacing 30s polling
- EventSource auth probe (401/429 detection via fetch)
- 14 frontend tests (useEvents + toast-rules)

Quality gates: vitest 14 passed, tsc clean, eslint clean
2026-05-29 10:25:00 +02:00
Alex Blank 29a12bb102 feat: expand ~ and $HOME in mount target paths
- Add expand_container_path() helper that resolves ~/ and $HOME/ prefixes
- Add get_manifest_home_dir() to compute /home/{user.name} or /root from manifest
- Set ENV HOME=... and ENV USER=... in generated Dockerfile for runtime compatibility
- Pass home_dir through instance creation and startup pipeline
- Expand mount targets in apply_resolved_profile() for regular profile mounts
- Expand mapping targets in _resolve_git_mount_mappings() for git mounts
- Expand working_directory and volume targets in _modify_compose_file()
- Update _prepare_manifest_instance to return home_dir alongside image tag
- Fetch tool_type early in start_instance to determine home_dir before profile application

Quality gates: pytest 188 passed, frontend typecheck clean

Addresses: home-path-expansion
2026-05-29 00:01:04 +02:00
Alex Blank 0e6521e433 feat: config profile multi-repo mounts
- Add mappings array support to git_mount entries
- Clone repository once per git_mount entry, mount multiple subdirectories
- Normalize legacy source_path+target_path to mappings on read
- Update _merge_git_mounts to dedup by (remote_url, branch) and concatenate mappings
- Add _normalize_git_mount, _clone_git_repo, _resolve_git_mount_mappings helpers
- Update GitMountItem Pydantic model with GitMountMapping and model_validator
- Update frontend GitMountEditor component with mappings UI
- Auto-convert legacy git mount entries to mappings format on load
- Add 15 backend unit tests for normalization, resolution, and glob expansion
- Update existing config profile resolver tests for new merge behavior

Quality gates: pytest 167 passed, frontend typecheck clean

Addresses: config-profile-multi-repo-mounts
2026-05-28 23:35:22 +02:00
Alex Blank 9bd5fc5c68 refactor: remove Tool Configs and Config Folders
These features are fully superseded by Config Profiles which provide:
- Env vars, file mounts, port overrides, start commands, working dirs
- Git mounts, profile composition, cycle detection
- Default selection, project/tool-type scoping

Changes:
- Delete backend models: ToolConfig, ConfigFolder
- Delete backend APIs: tool_configs.py, config_folders.py
- Delete frontend API clients: tool_configs.ts, config_folders.ts
- Remove Tool Config fetching from start_instance, use ConfigProfile only
- Simplify merge_with_config to accept only profile (no tool_configs)
- Remove configs/folders tabs from Tool Workshop page
- Delete associated integration and unit tests
- Add Alembic migration to drop tool_configs and config_folders tables

Quality gates: backend tests 59 passed, frontend typecheck clean
2026-05-28 20:08:48 +02:00
Alex Blank 62c1fb3836 Merge branch 'feat/tool-definition-manifest' into dev
Conflicts resolved:
- models/__init__.py: kept both TerminalSessionModel (from dev) and
  ToolDefinitionManifest (from feature branch)
- alembic migration: kept full migration (already applied to DB)
- openspec/config.yaml: kept full config with SDD settings
2026-05-28 15:49:56 +02:00
alex 569c20cf63 fix(terminal): simplify REST endpoints to use instance_id only
The frontend router navigates to /instances/:instanceId/terminal without
project_id or repo_id. The backend terminal REST endpoints were requiring
these path params, causing 404s.

- Simplify _get_terminal_instance to validate by instance_id only
- Update all REST routes from /projects/{pid}/repositories/{rid}/instances/{iid}/terminal/*
  to /instances/{instance_id}/terminal/*
- Update frontend API client to match new paths
- Update useTerminalSessions hook to take instanceId only
- Update TerminalPage to use simplified hook
- Update tests to match new paths

Fixes: 404 on GET /projects/repositories/instances/{id}/terminal/sessions
2026-05-28 15:40:02 +02:00
Alex Blank e46b4f9249 feat: Tool Workshop manifest editor (PR 2)
- Add tool_definitions API client with types for manifests
- Add ManifestEditor component: base image selector, package editors
  (apt/npm/pip/node), script editors (build/startup), mount schema
  designer, runtime config, and live preview panel
- Integrate ManifestEditor into Tool Workshop as 'Manifest (Declarative)'
  definition type alongside Compose and Dockerfile
- Update ToolType API types to include manifest_id and 'manifest'
  definition_type
- Frontend builds clean, TypeScript typecheck passes
2026-05-28 14:35:04 +02:00
alex 62d1bdc462 feat: multi-session terminal frontend UI + tests (PR 3)
- Add TerminalSessionTabs component with status dots, rename, close, max-5 limit
- Add 7 component tests for tab rendering, selection, close, rename
- TerminalComponent: sessionId prop, forwardRef with fit() method
- TerminalPage: multi-session orchestration, tab switching, auto-create default
- Fullscreen mode: Alt+Shift+F toggle, auto-hide tabs, Esc exit
- Keyboard shortcuts: Alt+Shift+N/W/ArrowLeft/ArrowRight/R
- Add CSS for tabs, fullscreen, mobile responsive
- Update useTerminalSessions hook for session CRUD
- terminal_manager.py: lookup by internal session_id fallback

Quality gates: tsc --noEmit clean, vitest (7/7 new tests passed), pytest (182 passed)
2026-05-28 13:35:45 +02:00
alex 0b35ae3bf0 feat: multi-session terminal backend API + frontend client (PR 2)
- Add WebSocket route /ws/tool-instances/{instance_id}/terminal/{session_id}
- Preserve /terminal as default-session alias for backward compatibility
- Extract shared _handle_terminal_websocket handler for both routes
- Add REST endpoints: GET list, POST create, DELETE close, POST reset, POST rename
- Preserve legacy POST .../terminal/reset as default session alias
- Add frontend API client (apps/web/src/api/terminal.ts)
- Add useTerminalSessions React hook for session CRUD + state management
- Add integration tests for auth requirements on all new endpoints

Quality gates: pytest (8 new passed, 182 total passed, 51 pre-existing failures)
2026-05-28 12:08:37 +02:00
alex 22474cdba5 style: fix all ruff and eslint errors across codebase
Backend (ruff):
- Fix 106 errors: move imports to top of file (E402)
- Remove unused imports (F401)
- Add missing imports for undefined names (F821)
- Remove unused variables (F841)
- Fix test_models.py broken RefreshToken test
- Fix test_projects_api.py missing TestClient import

Frontend (eslint):
- Remove unused imports/variables across 10 files
- Fix explicit any types in client.ts and sessions.ts
- Clean up empty block statements in terminal.tsx

Quality gates: ruff (pass), eslint (pass), tsc --noEmit (pass),
pytest (98 passed, 4 pre-existing failures)
2026-05-28 10:15:59 +02:00
Alex Blank 6ce645d210 fix: correct API endpoints for repository listing
- Change frontend to call /repositories instead of /projects/repositories
- Change parse-url endpoint to /repositories/parse-url
- Fixes 422 error from route mismatch
2026-05-27 14:18:13 +02:00
Alex Blank 89ca9f10c7 feat: simplify git mounts to use direct URLs instead of repo references
- Change git mount schema from repo_id to remote_url
- Remove database lookups for git mount resolution
- Clone directly from URL at instance startup
- Simplify frontend UI to text input for Git URL
- Fix route ordering in git_repositories.py to prevent 422 errors
- Update all tests to use remote_url field

Breaking change: Git mounts now use remote_url instead of repo_id
2026-05-27 11:53:25 +02:00
Alex Blank baabd1fa62 feat: allow creating external repositories directly from git mount editor
- Add createExternalRepository API function
- Update GitMountEditor with "+ Add new repository..." option
- Show form to enter repo name and remote URL
- Auto-create external repo and refresh list on success
- Update config-profiles page to pass onCreateRepository handler
2026-05-27 11:17:27 +02:00
Alex Blank e07938098a feat: add external repository support for config profile git mounts
- Add POST /repositories endpoint for external repos (no project_id)
- Update GitRepositoryResponse to allow nullable project_id
- Update list_repositories to support listing all user repos
- Add _pull_repository_updates for auto-pull on container creation
- Update git mount validation to allow external repos
- Frontend: Update listRepositories to support optional projectId
- Spec updates: external repos, auto-clone, per-instance isolation
2026-05-27 11:03:12 +02:00
Alex Blank 93b415c53e feat: support external repositories for git mounts
- Make project_id nullable in git_repositories table (migration)
- Allow external repos not tied to any project
- Update validation to allow user-owned external repos in git mounts
- Add /projects/repositories endpoint to list all user repos
- Update frontend to fetch all user repos for git mount selector
- TypeScript and build pass
2026-05-27 10:28:31 +02:00
Alex Blank 4c11163bff feat: implement config profile git mounts
- Add git_mounts column to config_profiles table (JSONB)
- Create GitMount Pydantic models with validation
- Add repo validation in create/update endpoints
- Update profile resolver to merge git mounts from includes
- Implement auto-clone, branch checkout, and glob expansion
- Add parallel processing for git mount resolution
- Create GitMountEditor frontend component
- Update TypeScript types and API clients
- Add CSS styles for git mount UI
- Frontend type check and build pass

Implements tasks 1.1-7.9 of config-profile-git-mounts spec
2026-05-26 22:27:04 +02:00
OpenCode Agent 01a0ef46c9 feat: terminal startup command and container tools
- Add startup_command field to ToolType model and API
- Execute startup command before interactive shell in terminal sessions
- Add tmux and ranger to OpenCode container spec
- Update Tool Workshop UI with startup_command input for terminal types
- Add backend tests for startup_command CRUD operations
- Sync specs: tool-terminal, tool-types-definition, opencode-web-server
- New spec: tool-terminal-startup-command

Quality gates: Frontend typecheck/lint passed. Backend tests blocked by environment (Python/Docker not available).

OpenSpec: terminal-startup-and-container-tools
2026-05-24 22:21:55 +00:00
Fusion 3fc392a314 fix: handle ERR_NETWORK_CHANGED from Docker network changes
- Add retry logic for transient network errors in API client
- Retry up to 2 times with exponential backoff on network errors
- Reduce session polling from 10s to 30s to decrease error frequency
- Handle 502/503/504 gateway errors with retries as well
2026-05-24 21:29:16 +02:00
alex c8da0ab6c4 fix: retry start/restart on network errors
When Docker starts a container, it creates network interfaces which
triggers Chrome's ERR_NETWORK_CHANGED error, aborting the request.
The backend successfully starts the container but the frontend never
gets the response, showing 'failed to create session' even though
the session is up.

Fix: Add retry with exponential backoff for startInstance and
restartInstance when network errors occur (no HTTP response).
Retries up to 2 times with 1.5s delay between attempts.

Fixes: False 'failed to create session' errors when launching tools.
2026-05-24 18:33:25 +00:00
alex 9ad11a021c feat: add config profiles
- Add ConfigProfile and ConfigProfileInclude data models with migrations
- Implement profile resolver service with ordered includes and merge rules
- Add profile CRUD API with validation, compatibility, and cycle detection
- Add instance API plumbing for profile selection on create/start/restart
- Add resolved profile preview and default resolution APIs
- Add frontend config profile API client and management UI
- Add launch/restart profile selection UI
- Add backend integration and unit tests (31 passing)

OpenSpec: add-config-profiles
Quality gates: ruff, TypeScript compile, 31 tests passing
2026-05-24 17:58:39 +00:00
Fusion cce3fa773a feat: hide tunnel UI for terminal sessions and show session metadata
Backend:
- Add created_at to get_user_sessions response

Frontend:
- Hide tunnel error badges, probe output, and 'Recreate Tunnel' button for terminal-only sessions
- Show session start time (created_at) in active sessions list
- Show repository configuration (clone_mode, branch) for each session
- Skip health check polling for terminal-only sessions
- Update Session type to include created_at field
2026-05-24 13:02:06 +02:00
alex 5cec4a7a6f Merge branch 'feat/session-branch-selection' into dev
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).
2026-05-24 10:06:14 +00:00