Commit Graph

140 Commits

Author SHA1 Message Date
Developer b6f89f9df0 merge: integrate main restructuring into dev
- Resolve 57 merge conflicts from codebase restructure
- Port dev feature code to new directory structure:
  * Update import paths to use @/ aliases
  * Add backward-compatible API signatures (createInstance, startInstance, deleteInstance)
  * Add missing type exports (ProjectWithRepos, InstanceHealth, Branch, BranchesResponse)
  * Extend Session and GitRepository types for dev features
  * Extend TerminalComponent props for mobile terminal wrapper
  * Add missing icon names (bell, drag, undo)

Quality gates: tsc pass (0 errors), build pass, 127/131 tests pass
(4 pre-existing failures unrelated to merge)
2026-06-03 09:42:44 +00:00
Developer be29da667f docs: add Task 5.2 report and update progress
- Add apply-5.2-report.md with quality gate results
- Update progress.md with completion status

Refs: repo-restructure Task 5.2
2026-06-02 23:01:06 +00:00
Developer e434c439c9 refactor: rename files to PascalCase components and kebab-case APIs (Task 4.4)
- Rename all component files to PascalCase matching exported names
- Move components into feature directories (git/, session/, project/, terminal/, workspace/, ui/, layout/)
- Rename all page files to PascalCase with Page suffix
- Rename all API files to kebab-case
- Update all imports across codebase with corrected relative depths
- Preserve git history via git mv

Quality gates: tsc (pass), eslint (pass), 66/74 tests pass (8 pre-existing failures)
Refs: repo-restructure Task 4.4
2026-06-02 22:58:10 +00:00
Developer 5d5b23894c test: add tests for extracted components (Task 5.1)
- LoadingState.test.tsx: default/custom message rendering
- ErrorState.test.tsx: message, retry button, callback
- FileBrowser.test.tsx: loading, entries, error states
- ToolTypesTab.test.tsx: loading, content, error states
- SessionCard.test.tsx: active/recent variants, unnamed fallback
- CreateSessionForm.test.tsx: render, validation, repo loading
- Fix vite.config.ts resolve.alias for @/ path mapping in tests

Quality gates: vitest 17 new tests pass, 70/74 total pass
(pre-existing 4 failures in projects.test.tsx unrelated)
Refs: repo-restructure Task 5.1
2026-06-02 22:31:29 +00:00
Developer a6eb6ec788 refactor: extract dashboard, workspace, tool-types, and tool-configs components (Task 4.3)
- Extract DashboardSummary, ActiveSessionsList, ProjectsSection, QuickCreateForm,
  RecentSessionsSection from dashboard.tsx (480 → 110 lines)
- Extract WorkspaceSidebar from repo-workspace.tsx
- Extract ToolTypeList + ToolTypeForm from tool-types.tsx (409 → 135 lines)
- Extract ToolConfigList + ToolConfigForm from tool-configs.tsx (391 → 178 lines)
- Add use-dashboard-actions hook for shared dashboard action handlers
- Update feature barrels with new exports

Quality gates: tsc (pass), eslint (pass)
Refs: repo-restructure Task 4.3
2026-06-02 22:23:13 +00:00
Developer 6bd7443e68 refactor: extract sessions page components (Task 4.2)
- Extract CreateSessionForm component with self-contained form state
- Extract SessionList component managing confirmations and health polling
- Extract SessionCard presentational component for active/recent variants
- Add ConfirmDialog reusable UI primitive
- Slim sessions page from ~668 lines to 156 lines
- Keep lastSession section inline per design decision

Quality gates: tsc (pass), eslint (pass), build (pass)
Refs: repo-restructure Task 4.2
2026-06-02 21:57:44 +00:00
Developer ae420708f2 refactor: split tool-workshop page into tab components (Task 4.1)
- Extract ToolTypesTab, ToolConfigsTab, ConfigFoldersTab from inline page
- Each tab is self-contained with own state, API calls, and forms
- Slim page to 77 lines (tab switcher + composition only)
- Add barrel export for tool-workshop feature components
- Add tsconfig path alias for @/* imports

Quality gates: tsc (pass), eslint (pass)
Refs: repo-restructure Task 4.1
2026-06-02 21:49:20 +00:00
Developer cccf4379d8 refactor: extract CSS modules for session/settings and delete styles.css (Task 2.3)
- Create InstanceList.module.css, AppShell.module.css, SettingsTabLayout.module.css
- Create CommitPanel.module.css, FileViewer.module.css
- Create page CSS files: sessions, repo-workspace, dashboard, projects,
  git-history, ssh-keys, settings
- Update components to import and use CSS modules
- Delete monolithic styles.css (2,255 lines)
- Update main.tsx to import page CSS and new modules

Quality gates: tsc (pass), eslint (pass), build (pass)
Refs: repo-restructure Task 2.3
2026-06-02 21:09:57 +00:00
Developer dd7696b5a4 refactor: extract CSS modules for terminal and git components (Task 2.2)
- Create TerminalComponent.module.css with terminal-* styles
- Create GitToolbar.module.css with git toolbar styles
- Create CommitDialog.module.css with commit dialog styles
- Create MergeDialog.module.css with merge dialog styles
- Create FileEditor.module.css with file editor styles
- Update all components to import their CSS modules
- Remove extracted rules from styles.css (~441 lines removed)

Quality gates: tsc (pass), eslint (pass), build (pass)
Refs: repo-restructure Task 2.2
2026-06-02 20:39:32 +00:00
Developer 58a9728d5e refactor: extract pydantic schemas from routers into schemas/ directory (Task 3.2)
- Create schemas/ directory with 12 schema files covering all domains
- Extract 70+ Pydantic models from 11 router files
- Routers now import from src.schemas.{domain} instead of defining inline
- Zero inline BaseModel definitions remain in any router

Quality gates: py_compile all schemas (pass), py_compile all routers (pass)
Refs: repo-restructure Task 3.2
2026-06-02 20:19:05 +00:00
Developer c5fbb6722b refactor: extract global styles and tokens (Task 2.1)
- Create styles/tokens.css with CSS custom properties and dark theme
- Create styles/global.css with resets, shell layout, and navigation
- Create styles/utilities.css with generic utilities and primitives
- Create styles/syntax-highlight.css with Prism.js theme
- Update main.tsx to import the 4 new style files
- Keep styles.css intact for backward compatibility

Quality gates: build (pass), lint (pass)
Refs: repo-restructure Task 2.1
2026-06-02 19:29:38 +00:00
Developer c50d6663d5 refactor: extract shared auth dependencies (Task 3.1)
- Add get_owned_project() to auth/dependencies.py
- Remove duplicated _get_user() and _get_owned_project() from all routers
- Update tool_instances, git_repositories, projects, ssh_keys, users,
  user_config, tool_types routers to use FastAPI dependency injection
- Route handlers now receive User/Project models via Depends() instead
  of calling inline async helpers

Quality gates: Python syntax check (pass), no duplicated helpers (pass)
Refs: repo-restructure Task 3.1
2026-06-02 19:18:12 +00:00
Developer aee3987c24 refactor: extract FileBrowser and shared UI primitives (Task 1.2)
- Extract FileBrowser from inline definition in repo-workspace.tsx
- Create components/features/git/FileBrowser.tsx with module CSS
- Create reusable UI primitives: LoadingState, ErrorState, StatusBadge
- Create barrel exports for components/ui/ and components/features/git/
- Replace inline loading/error patterns in dashboard, sessions, repo-workspace

Quality gates: tsc (pass), eslint (pass)
Refs: repo-restructure Task 1.2
2026-06-02 19:10:33 +00:00
Developer ee1fa6bee5 refactor: centralize types and extract seed data (Task 1.1)
- Create types/ directory with centralized domain types:
  session, tool-instance, tool-type, git-repository, config-folder,
  tool-config, project, user, api-response
- Remove inline type definitions from API modules;
  re-export from types/ for backward compatibility
- Update state/sessions.tsx to import Session from types/session.ts
- Update all consumer components/pages to import from types/
- Extract seed_builtin_tool_types from main.py to
  seeds/builtin_tool_types.py
- Create types/index.ts barrel export

Quality gates: tsc (pass), eslint (pass), Python syntax (pass)
2026-06-02 18:56:54 +00:00
Alex Blank c754984df8 feat: high-performance web terminal with asyncio-native I/O
Complete rewrite of the terminal pipeline for VS Code Server-level
responsiveness. Key improvements:

Backend:
- Replace blocking select.select(0.1) with asyncio.add_reader() for
  event-driven PTY reading (eliminates ~110ms polling latency)
- Add output batching (2ms window) to reduce WebSocket frame overhead
- Add flow control: client acks processed bytes, server pauses PTY reads
  at 64KB threshold, resumes at 32KB
- Add 5s ack timeout fallback to prevent stuck sessions

Frontend:
- Switch WebSocket to binary mode (binaryType = 'arraybuffer')
- Eliminate Blob -> arrayBuffer async conversion overhead
- Add flow control ack messages (every 4096 bytes or 100ms)
- Add xterm-addon-webgl with graceful DOM fallback
- Add performance tuning (scrollback=10000, fastScrollSensitivity)

SDD artifacts:
- openspec/explorations/terminal-responsiveness.md
- openspec/proposals/terminal-responsiveness.md
- openspec/specs/terminal-responsiveness.md
- openspec/designs/terminal-responsiveness.md
- openspec/tasks/terminal-responsiveness.md

Quality gates: pytest (19 passed, 1 skipped), tsc --noEmit clean
2026-06-02 14:40:32 +02:00
alex e7587ca9f5 feat: workspace-first UI refresh - PR-1 backend endpoints
- Add FileService for workspace-scoped file operations
- Add GitOperations service for workspace-scoped git commands
- Add workspace_files API: GET/POST /workspaces/{id}/files
- Add workspace_git API: status, branches, commit, push, pull, fetch, checkout, history
- Add workspace_instances API: list instances per workspace
- Add top-level POST /workspaces/ (accepts repo_id directly)
- Enrich GET /projects/ with nested repositories and workspaces
- Register all new routers in main.py
- 23 tests passing (17 existing + 6 new)

Quality gates: ruff clean
2026-06-01 16:47:09 +02:00
alex d567225bf7 feat: workspace backend foundation (PR-1)
- Add workspaces table migration (2026_06_01_add_workspaces)
- Create Workspace model with repo_id, user_id, branch, path, status
- Add workspace_id nullable FK to ToolInstance
- Create GitService for clone/fetch/pull/branch_exists_remotely
- Create WorkspaceManager for create/delete/sync lifecycle
- Create workspace CRUD API with 409 handling for duplicates and instances
- Wire workspace routes into FastAPI app
- 17 tests passing (8 unit + 9 integration), 1 skipped

Quality gates: ruff clean
2026-05-31 23:02:45 +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 cbd3436ff7 Merge remote dev branch 2026-05-29 12:55:03 +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 6085859874 feat: notification center backend integration (PR-2)
- Wire lifecycle_hooks.py to NotificationService after event bus publish
- Wire health_monitor.py to NotificationService after state changes
- Category/severity mapping: instance.* → info, error → error, unhealthy → warning
- Extend UserConfig API with notification_mute_categories and notification_toast_level
- 6 integration tests for event-to-notification flow
- All producer calls wrapped in try/except — failures logged, pipeline continues

Quality gates: pytest 41 passed (monitoring + lifecycle), ruff clean
2026-05-29 12:40:15 +02:00
Alex Blank d413fb84a5 Merge branch 'dev' of ssh://git.commumedia.org:2222/alex/headquarter into dev 2026-05-29 12:16:40 +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 cbaebcf649 feat: notification center backend core (PR-1)
- Add notifications table with Alembic migration
- Notification model with user-scoped indexing and partial index on unread
- NotificationService singleton with create/list/count/mark-read/dismiss
- FastAPI router: GET /notifications, GET /unread, PATCH /{id}/read,
  POST /mark-all-read, DELETE /{id}
- Mute categories filtering from UserConfig
- 13 unit tests for NotificationService
- 10 integration tests for API endpoints
- Updated test_models.py with new table registration

Quality gates: pytest 23 new passed, ruff clean
2026-05-29 12:09:14 +02:00
Alex Blank ea006b68c2 fix: mount config profile files individually instead of replacing directories
The previous sorting fix exposed a deeper bug: ResolvedMount always
mounted its staging directory as a single bind mount. When a config
profile mount targeted /workspace/x/y and contained a single file
z.json, the staging directory (containing only z.json) replaced the
ENTIRE /workspace/x/y directory, hiding all sibling files from git
repo mounts.

- Change apply_resolved_profile to mount each file individually:
  - source: staging_dir/relative_path
  - target: expanded_target/relative_path
  - Sibling files from other mounts are preserved.
  - Empty mounts produce no volume entries.

- Keep volume sorting (parent paths before child paths) which is
  still necessary for directory mounts and ensures parent dirs exist
  before file mounts inside them.

- Add 4 unit tests for file-level mount behavior.

Quality gates: pytest (218 passed, 6 pre-existing), tsc --noEmit (clean)
2026-05-29 11:58:50 +02:00
Alex Blank 0952aa8217 fix: sort mount volumes by specificity to prevent parent mounts hiding children
When git repo mounts and regular file mounts have overlapping target
paths, broader parent mounts hide deeper child mounts because Docker
Compose applies volumes in array order.

- Add sort_volumes_by_specificity() to docker.py:
  - Sorts by target path depth (parent paths first, child paths last)
  - Logs warnings for duplicate targets
  - Handles :bind and :ro suffixes correctly

- Integrate into manifest flow (compile_compose):
  - Sorts manifest mounts + EXTRA_VOLUMES before writing compose

- Integrate into legacy flow (_modify_compose_file):
  - Sorts after appending extra_volumes to existing template volumes

- Add 6 unit tests covering parent/child ordering, stable sort,
  type suffixes, empty list, single volume, and duplicate warnings.

Quality gates: pytest (214 passed, 6 pre-existing), tsc --noEmit (clean)
2026-05-29 11:35:27 +02:00
Alex Blank f728011b2a fix: prevent cumulative terminal shrinkage in fullscreen mode
When switching terminal sessions in fullscreen mode, the viewport
shrank cumulatively because .terminal-wrapper uses
grid-template-rows: auto 1fr. With showControls=false, the single
child (.terminal-container) landed in the auto track instead of 1fr,
creating a feedback loop with xterm fit().

- Add .terminal-wrapper.no-controls with grid-template-rows: 1fr
  so the container fills the wrapper when the header is hidden.
- Apply no-controls class in TerminalComponent when showControls=false.
- Replace setTimeout(50) with double requestAnimationFrame in
  TerminalPage for more reliable fit() timing after tab switches.

Quality gates: tsc --noEmit (clean), pytest (208 passed, 6 pre-existing)
2026-05-29 10:53:02 +02:00
Alex Blank 569876538a Merge branch 'dev' of ssh://git.commumedia.org:2222/alex/headquarter into dev 2026-05-29 10:35:47 +02:00
Alex Blank 8926152fca fix: unified fullscreen terminal header
- Add showControls prop to TerminalComponent to optionally hide internal header
- Add reset() method to TerminalRef for external reset control
- TerminalPage now renders a unified fullscreen header bar combining:
  - Session tabs (TerminalSessionTabs)
  - Terminal controls (status dot, A-, A+, Reset, Exit Fullscreen)
- Unified header is always visible in fullscreen (no hover-to-reveal)
- TerminalComponent internal header hidden when in fullscreen mode
- Remove old CSS that hid session tabs with opacity:0 until hover

Quality gates: pytest 188 passed, frontend typecheck clean

Fixes: terminal-fullscreen-unified-header
2026-05-29 10:34:31 +02:00
alex 2682e0268c feat: container monitoring integration + polish (PR-3)
- Integration tests: SSE auth, connection limits, lifecycle hooks, event persistence (6 tests)
- Instance events history API: GET /instances/{id}/events
- Documentation updates: terminal.md, backend.md, frontend.md
- Performance: SSE max 5 connections, health monitor write-on-change

Quality gates: pytest 21 monitoring passed, 172 unit passed (4 pre-existing), vitest 14 passed, tsc clean, eslint clean, ruff clean
2026-05-29 10:25:00 +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 4a7f24348c feat: container monitoring backend core (PR-1)
- Add instance_events and health_checks tables with Alembic migration
- InstanceEventBus: typed pub/sub singleton with wildcard support
- HealthMonitor: async background loop polling containers every 15s
- SSE endpoint GET /events/stream with auth and connection limits
- Lifecycle hooks in tool_instances.py (create/start/stop/restart/delete)
- Structured JSON logging with correlation IDs
- 15 new unit tests (EventBus, HealthMonitor, MonitoringModels)

Quality gates: pytest 15 new passed, ruff 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 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 Blank 3e99e7f197 feat: legacy fallback tests and docs (PR 3)
- Add test_tool_instances_legacy.py with 8 unit tests:
  - dockerfile definition type builds from template
  - dockerfile build failure raises HTTP 500
  - compose definition type renders template
  - manifest compiler is NOT called for legacy types
  - start_instance legacy/compose/dockerfile types all skip manifest flow
  - start_instance manifest type correctly invokes compiler
- Mark T3.2 and T3.3 tasks complete in OpenSpec
- Add openspec/docs/tool-workshop-guide.md with user guide covering
  definition types, manifest creation workflow, base definitions,
  migration path, and permissions
2026-05-28 14:54:32 +02:00
Alex Blank 5deee8c65c feat: tool definition manifest system (PR 1)
- Add ToolDefinitionManifest model with base image versioning
- Add manifest compiler: Dockerfile + Compose generation from JSON manifests
- Add permission fixer: post-start chown/chmod for mount policies
- Add tool definition CRUD API with live compile preview endpoint
- Integrate manifest-based startup flow in start_instance
- Add Alembic migration with data conversion for pi-agent
- Add 48 unit tests for manifest compiler, permission fixer, docker service
- Keep backward compatibility with legacy dockerfile_template/compose_template

Migration: applied successfully. Pi-agent converted to manifest.
Quality gates: pytest (146 passed, 4 pre-existing unrelated failures)
2026-05-28 13:37:34 +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 7000f2075d docs: add SDD verify report for responsive terminal 2026-05-27 21:48:55 +02:00
alex 6c8cfe9157 feat: responsive web terminal with auto-reconnect, heartbeat, and local echo
Implements a resilient, responsive web terminal that survives network blips,
provides instant typing feedback, and restores scrollback on reconnect.

Backend changes:
- Add heartbeat tracking (15s ping interval, 60s idle timeout)
- Add message batching (16ms flush window) for efficient I/O
- Add termios echo detection and set_echo_state control messages
- Add graceful session_ended notification before close
- Add ping/pong protocol support

Frontend changes:
- Rewrite TerminalComponent with status bar, connection indicator,
  session-ended overlay, reconnect banner, and ResizeObserver
- Add useTerminalConnection hook with:
  - Exponential backoff auto-reconnect (1s → 30s max, 10 attempts)
  - Heartbeat/ping-pong with latency tracking
  - Local echo for printable ASCII with server deduplication
  - Resize debounce (200ms) + throttle (500ms)
  - Scrollback serialization via xterm-addon-serialize
  - Ctrl+Shift+R manual reconnect shortcut
- Add WebSocket protocol types and encoding utilities
- Add xterm-addon-serialize dependency

Tests:
- 16 backend unit tests (TerminalSession + TerminalManager)
- 13 frontend hook tests (connection lifecycle, reconnect, resize,
  scrollback, callbacks)

Quality gates:
- Frontend typecheck: clean
- Frontend lint: clean
- Frontend tests: 48 passed
- Backend unit tests: 101 passed
- Backend ruff: clean

SDD artifacts: openspec/changes/responsive-terminal/
2026-05-27 21:27:49 +02:00
Alex Blank 33d08faf70 feat: allow relative target paths for git mounts
- Remove absolute path requirement from target_path validation
- Resolve relative paths against working_directory at instance startup
- Fall back to /home/user if no working_directory is configured
- Update frontend to allow relative target paths
- Update spec to document relative path support
- Update tests to allow relative paths and test path traversal rejection
2026-05-27 15:01:16 +02:00
Alex Blank 8231e750d9 docs: update spec to use remote_url instead of repo_id for git mounts
- Change git mount schema from repo_id to remote_url
- Update validation rules to check URL format instead of repo existence
- Update cloning scenarios to clone directly from URL
- Update UI scenarios to show URL input instead of repo selector
- Remove references to internal/existing repositories
2026-05-27 14:27:39 +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 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 c4be7163d6 docs: add config profile git mounts documentation
- API documentation for config profiles with git mounts endpoint details
- User guide for using git repositories in config profiles
- Document branch pinning, glob patterns, error handling, and best practices
- Update API README to link to new config-profiles documentation
2026-05-26 22:54:59 +02:00
Alex Blank 13f55fff47 docs: mark test tasks as complete in spec 2026-05-26 22:50:06 +02:00