- Revert touch-action: none on .xterm-viewport so xterm.js can fall back
to its own viewport scrolling when the custom handler doesn't take over.
- Detect alternate screen via reference equality
(term.buffer.active === term.buffer.alternate) instead of the
string, which could report normal buffer incorrectly.
- Lower vertical-scroll activation threshold from 4px to 2px and only
prevent default once a vertical gesture is recognized.
- In normal buffer use term.scrollLines() so xterm.js handles the buffer
scroll consistently; in alternate screen continue sending SGR 1006
mouse-wheel sequences to tmux/vim.
Quality gates: typecheck, lint clean, npm test -- --run 87 passed.
- Add touch-action: none and overscroll-behavior: none to mobile terminal
page, content, wrapper, container, and xterm viewport so the browser
never treats swipes as page/address-bar scrolling or pull-to-refresh.
- Make .terminal-page.mobile fixed-position to prevent viewport layout
scroll; keep the overlay toolbar as absolute with pointer-events only
on interactive parts.
- Rework the mobile touch handler in terminal.tsx:
* Detect normal vs alternate buffer via term.buffer.active.type instead
of measuring the DOM viewport, which was unreliable in tmux/vim.
* Accumulate swipe distance and emit SGR 1006 mouse-wheel sequences in
steps, so tmux pane scrolling tracks the gesture correctly.
* Prevent default as soon as the swipe is recognized so the page does
not start a competing scroll gesture.
Quality gates: npm run typecheck, npm run lint clean, npm test -- --run 87 passed.
- Combine Projects and Workspaces into a single 'Spaces' grouped mobile
nav item that opens a bottom-sheet menu.
- Add SpacesBottomSheet component with Projects/Workspaces options.
- Extend MobileListView with optional renderItem prop for rich rows.
- Redesign mobile ProjectsPage rows to show project description and
repository chips.
- Replace mobile WorkspacesPage list with compact WorkspaceCard grid,
matching desktop card content.
- Add mobile-list-* CSS and mobile-workspaces-list spacing.
Quality gates: npm run typecheck, npm run lint clean,
npm test -- --run 87 passed.
Add a reusable LoadingOverlay component that dims and disables the
container owning an in-flight action, with a spinning indicator and
label. Apply it to:
- SessionCard (when actionBusyId matches)
- InstanceList cards (per busyInstanceId with action-specific labels)
- CreateSessionForm (while submitting)
- ToolStarter (while starting)
Also add .icon-spin animation and position:relative to the relevant
containers.
Quality gates: npm run typecheck, npm run lint, npm test -- --run
(87 passed).
The bottom-right progress panel duplicated feedback already shown by
toasts. Remove it and the operation-tracking state to simplify the UI:
- Delete state/session-operations.tsx and session-progress-panel.tsx.
- Remove SessionOperationsProvider/SessionProgressPanel from AppShell.
- Remove startOperation/completeOperation calls from useInstanceActions
and ToolStarter.
- Remove SessionOperationsProvider wrapper from DashboardPage.test.tsx.
- Remove .session-progress-panel CSS rules.
- Format use-events.test.ts mock to match project lint rules.
Quality gates: npm run typecheck, npm run lint, npm test -- --run
(87 passed).
- Add SessionOperationsContext + SessionProgressPanel for global,
non-blocking lifecycle progress (create/start/stop/restart/delete/
recreate-tunnel) driven by SSE events.
- Promote SessionsContext to authoritative shared session state with
refresh, addOrUpdateSession, and removeSession helpers.
- Wire AppShell, DashboardPage, SessionsPage, useInstanceActions,
ToolStarter, and InstanceList into shared state so lists update
immediately after create/delete without manual refresh.
- Remove legacy blocking overlays from CreateSessionForm, SessionCard,
and InstanceList; keep disabled states and inline spinners only.
- Update DashboardPage tests to wrap with SessionsProvider and
SessionOperationsProvider.
- Add .cache/ to .gitignore.
Quality gates: npm run typecheck, npm run lint, npm test -- --run
(82 passed).
- Remove useless document.title from handleOpen (it only changed the
caller page's title, not the new tab)
- Terminal tab title: simpler format without extra '— Headquarter' suffix
- Single session: '{name} — Terminal'
- Multiple sessions: '{name} · {session_name} — Terminal'
- Sidebar live sessions: show tool type in small muted text next to
display_name so sessions aren't indistinguishable when display_name
is just the workspace name
Quality gates: tsc --noEmit pass, npm run build pass, 82/82 tests pass
- ProjectsPage.tsx: detect mobile viewport, show MobileListView / custom detail view / MobileFAB
- Mobile list: tap project to view details (name, description, repositories, workspaces)
- Mobile detail: shows repositories with New Workspace buttons, Add Repository button, Edit/Delete project actions
- Mobile FAB: opens inline project creation form
- RepositoryCreateDialog reused for mobile 'Add Repository' flow
- New CSS: .mobile-form-actions, .mobile-form-group for mobile form layouts
Quality gates: tsc --noEmit pass, npm run build pass, 80/80 tests pass
Backend (health_monitor.py):
- Skip health checks for instances with no container_id
- Treat 'not_found' as error only when container was previously running
- Skip duplicate error notifications when already in error state
- Skip 'not_found' notifications for containers that never ran
Frontend (notification-item.tsx):
- Display notification.message (detailed error text)
- Add expandable Details section showing metadata (exit_code, previous_status, etc.)
- New CSS styles for message and metadata display
Quality gates: py_compile, tsc --noEmit, 80/80 tests pass