* fix(server): resolve terminal WebSocket proxy conflict and implement server-side transport
- Disables proxy websocket handling conflict in server proxy config to fix 1006 abnormal closes.
- Implements server-side WebSocket upgrade and connection handling for terminal input.
- Adds server-side debug instrumentation for WS lifecycle events.
- Includes terminal input WS protocol definition and unit tests.
* feat(ui): implement hardened terminal WebSocket transport with idempotency and diagnostics
- Adds client-side WebSocket transport manager with automatic reconnection and jitter.
- Implements idempotency and debug instrumentation for terminal input WS.
- Adds HMR dispose cleanup for terminal WS transport manager.
- Primes terminal input transport when terminal view becomes active.
- Updates terminal session types to include input capabilities.
* refactor(terminal): remove temporary websocket debug instrumentation
* feat(ui): redesigned Git view layout
* feat: stabilize git views layout with min-h-0 and scroll
- Introduce min-h-0 and flex-1 on git layout containers
- Apply min-h-0 on PR checks dialog content and related areas
- Configure ScrollableOverlay to disable horizontal scroll and overscroll
* Add getRemotes API endpoint
- Add getRemotes() function to git-service.js using simple-git's getRemotes(true)
- Returns array of {name, fetchUrl, pushUrl} for each remote
- Add GET /api/git/remotes endpoint to server/index.js
- Follows existing patterns for git endpoints (directory query param, error handling)
* Add merge and rebase API endpoints
- Add rebase(), abortRebase(), merge(), abortMerge() to git-service.js
- Add POST /api/git/rebase, /api/git/rebase/abort endpoints
- Add POST /api/git/merge, /api/git/merge/abort endpoints
- All functions return { success, conflict?, conflictFiles? }
- Conflict detection via error message parsing and git status
* Add client API functions for git remotes, merge, and rebase
- Added GitRemote, GitMergeResult, GitRebaseResult interfaces to types.ts
- Added getRemotes(), rebase(), abortRebase(), merge(), abortMerge() to gitApiHttp.ts
- Added corresponding exports and runtime wrappers to gitApi.ts
- All functions follow existing patterns with proper error handling
- Lint and type-check pass
* feat(git): add remote selection dropdown to SyncActions
- Add remotes prop to SyncActions component
- Change callbacks to accept GitRemote parameter
- Show dropdown menu when multiple remotes exist
- Execute immediately for single remote repos
- Display remote name and fetch URL in dropdown items
* feat: add BranchIntegrationSection component
- Branch selector dropdown (local + remote branches)
- Merge and Rebase buttons with loading states
- Props: currentBranch, localBranches, remoteBranches, onMerge, onRebase, disabled, isOperating
- Follows existing UI patterns (Command + DropdownMenu)
- Tooltips for all interactive elements
* Add ConflictDialog component for merge/rebase conflicts
- Shows when merge/rebase returns conflict
- Three action options: Resolve in New Session, Abort, Continue Later
- Resolve in New Session opens OpenChamber session in conflict directory
- Displays list of conflicted files
- Uses theme tokens for colors
- Follows existing dialog patterns from AboutDialog.tsx
* Integrate git remote selection and branch operations into GitView
- Fetch remotes on mount and store in state
- Pass remotes to SyncActions and update handleSyncAction to accept GitRemote parameter
- Add BranchIntegrationSection component below sync actions for merge/rebase operations
- Add ConflictDialog to handle merge/rebase conflicts with option to resolve in new session
- Export BranchIntegrationSection and ConflictDialog from git/index.ts
- Update GitHeader to accept remotes prop and pass to SyncActions
- Handle single vs multiple remote scenarios (immediate action vs dropdown)
- Fix React hooks exhaustive-deps warnings by capturing status in local variable
* fix: add missing git API methods to web and vscode packages
* feat: extend VSCode bridge with git remote/rebase/merge endpoints
* feat: add stash support for git operations across UI and API
* hive(01-add-types-for-conflict-details): Added MergeConflictDetails interface to packages/u
* hive(02-add-server-side-conflict-details-function): Added `getConflictDetails(directory)` function to
* hive(03-add-server-endpoint-for-conflict-details): Added GET /api/git/conflict-details endpoint to pa
* hive(04-add-client-side-api-for-conflict-details): Added client-side API for conflict details:
1. **
* hive(05-enhance-conflictdialog-with-rich-context): Enhanced ConflictDialog to fetch and use rich conf
* hive(06-add-state-persistence-for-conflicts): Added state persistence for merge/rebase conflicts
* feat: add conflict details API and AI resolve flow
* fix: improve focus handling in git UI and adjust web dev server port
* feat: add continue merge/rebase support and logs
* fix: address bugs in git merge/rebase feature
- Add explicit parentheses to hasUnresolvedConflicts logic for clarity
- Add error handling for stash operation in handleStashAndRetry
- Fix SSH key path escaping on Windows by normalizing before validation
* fix: add default value for remotes prop to prevent crash
When remotes is undefined, accessing .length throws TypeError.
Add default empty array to handle undefined case gracefully.
* fix: replace DialogFooter with plain div for proper button layout
DialogFooter's default flex-col-reverse and sm:flex-row styles
were conflicting with the intended vertical button stack layout,
causing buttons to not display properly.
* Fix lint erorr
* fix: remove duplicate BranchIntegrationSection and fix broken vscode bridge
- Remove duplicate BranchIntegrationSection from GitView.tsx (already in GitHeader)
- Fix vscode bridge calling non-existent ensureOpenChamberIgnored function
(legacy worktree function was removed, make api:git/ignore-openchamber a no-op)
* fix: handleResolveWithAIFromBanner now properly detects conflicts from status
The function was checking conflictFiles state which may be empty when
the banner is shown. Now it extracts conflict files directly from the
git status (files with 'U' status) and properly sets up the conflict
dialog state before opening it.
* refactor(chat): adjust mobile controls layout
Improve alignment of mobile model and agent buttons with action buttons
Constrain mobile controls to a max width to prevent overflow on small screens
* fix: improve MobileAgentButton mobile interaction
Replace touch-none with touch-pan-x to enable horizontal swipe
Wrap the agent label in a scrollable container to prevent truncation
* fix(ui): allow horizontal scroll for model label
Enable horizontal scrolling for long model labels on mobile
Prevent truncation by letting the label overflow horizontally
Improve visibility by keeping the full label accessible without clipping
* feat: refactored sessions sidebar to be workspaces centric
- Add createWorktreeOnly helper and status checks
- Add createWorktreeOnly to create a standalone worktree for the active project
- Show error toasts when no active project or not a Git repository
- Refresh session list and show success toast with created worktree details
* feat: show attention indicator and status marker in SessionSidebar
- Show unread attention indicator for sessions with pending updates
- Display status marker combining streaming and unread indicators in the session row
- Introduce attention diamond pulse animation and associated CSS for the new indicator
* fix(SessionSidebar): reserve header actions space when repo state is known
* chore(doc): add PR status colors to custom themes
* feat(session-status): implement server-authoritative session status tracking
- Add server-side session states and attention tracking with Map storage
- Implement SSE event broadcasting (openchamber:session-status)
- Add REST API endpoints for status/attention queries
- Replace client-side polling with HTTP polling + SSE push
- Track needsAttention based on user message + completion + unviewed
- Add MobileSessionStatusBar for mobile UI
- Handle session view/unview/message-sent state transitions
- Add 24h cleanup for old session states
* feat(session-status): add unread indicator to mobile session status bar
* refactor(session-status): extract SessionStatusHeader component
Extract the session status header into a reusable component and improve
layout structure in CollapsedView and ExpandedView.
* feat(session-status): optimize mobile session status bar UI
* refactor(session-status): remove interval polling, use snapshot sync on reconnect/visibility
- unifies session status/attention sync with existing SSE lifecycle, fixes no-op store churn bug, and drops duplicated client activity state while preserving mobile unread/running UX.
---------
Co-authored-by: Jovines <jovines@qq.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
- Start API server on port 3001 and Vite dev server on port 5173 in the desktop dev flow
- Proxy /auth, /health, and /api to the local API server for development
- Gracefully handle startup/shutdown and report failures clearly
- Remove legacy worktree API usage and related state
- Add Manage Branches button in the Git header for quick access
- Introduce worktree status utilities to derive root branch hints
* feat(chat): add message history navigation in ChatInput
* feat: Adds settng to persist draft of messages to local storage to save work if page refreshes or crashes
* feat: add view ready and destroy callbacks to CodeMirrorEditor
Provide onViewReady callback that receives the EditorView once created
Provide onViewDestroy callback invoked when the editor is destroyed
* feat: render inline drafts in PlanView with portal
Add editorView state to track the active CodeMirror instance
Render inline drafts through a portal anchored to the editor scroll container
Position drafts relative to the corresponding start line in the editor
* feat(PierreDiffViewer): enable editing inline diff drafts
Enable editing of existing inline diff drafts with draftID handling
Auto-focus comment input when opening editor and place cursor at end
* feat: enable editing inline drafts and auto focus
Enable editing of existing inline drafts via new editingDraftId state and updateDraft
Auto focus the comment input and place cursor at end when a line is selected
Add edit action button in the inline actions bar to start editing
* feat: add updateDraft to inline comment drafts store
Add updateDraft action to modify a specific draft by session and id
Merge updates into the target draft without altering other fields
Retains existing draft management actions like remove and clear
Enable horizontal scrolling for main navigation tabs in header
Prevent back button from shrinking on mobile by fixing flex behavior
Show badges and activity dots on tab buttons
## What / Why
This PR finishes the desktop refactor: the Tauri app is now a thin shell that launches the web server as a sidecar and loads the UI from `http://127.0.0.1:<port>`. All real backend logic lives in `packages/web/server/index.js`; desktop Rust keeps only native integrations (menu/dialog/notifications/updater/deep-link + window chrome).
This unblocks:
- consistent behavior across web/desktop/vscode (single backend)
- simpler desktop maintenance (no duplicated Rust backend)
- host switching between Local + remote instances in desktop
- reliable cold-start behavior on slow machines (VSCode + desktop)
## Key changes
- Desktop sidecar runtime
- build pipeline to bundle web dist + `openchamber-server` sidecar (`packages/desktop/scripts/build-sidecar.mjs`)
- robust local port selection (prefer saved/default, fallback to random; persisted in `~/.config/openchamber/settings.json`)
- improved PATH handling so the sidecar can locate `opencode` CLI (incl `~/.opencode/bin`, overrides, common bins)
- disable native right-click context menu in production builds (dev keeps it)
- Desktop instance switcher (Tauri-only)
- header button + modal to add/edit/delete remote hosts, set default, probe status/ping, switch back to Local escape hatch
- auth gate includes host switcher so you can recover when a remote host is broken/auth-required
- host list stored desktop-locally (not tied to the currently selected remote server)
- Notifications
- decision logic moved server-side; desktop notifications emitted via sidecar stdout and shown natively by Tauri
- prevent double-notifications on desktop Local origin (UI ignores SSE notification when native path is active)
- restore macOS notification sound
- Updates
- Tauri updater used only when viewing Local instance in desktop shell (avoid “remote web update” triggering desktop restart)
- Settings persistence & UX polish
- persist model favorites/recents via `/api/config/settings` (works for web + desktop; not origin-dependent)
- persist per-project sidebar collapse state in `projects[].sidebarCollapsed` via `/api/config/settings` (with debounce on toggles)
- macOS header sizing/traffic-lights offsets fixed (marketing macOS major injected from desktop; MultiRun header aligned)
- VSCode cold-start: keep retrying provider/agent loads after connection to avoid empty UI on slow machines
- misc lint/type fixes + bun.lock sync
- Desktop bootstrap / resiliency
- show onboarding screen when OpenCode CLI is missing (desktop Local origin), with retry hook to restart OpenCode after install
## Testing notes
- Desktop (macOS): switch Local <-> remote, set default host, verify auth gate recovery, native notifications (with sound), updater gated to Local
- Web: favorites/recents + per-project collapsed state persist across reload/restart
- VSCode: slow startup no longer results in missing providers/agents/models
* feat(mobile): split controls into separate Agent and Model buttons
- Add MobileAgentButton with tap-to-cycle and long-press-to-open behavior
- Add MobileModelButton for direct model panel access
- Remove agent selection from UnifiedControlsDrawer for cleaner mobile UX
- Agent cycling accessible via Tab key shortcut
* fix(mobile): optimize controls layout and touch handling
---------
Co-authored-by: Jovines <jovines@qq.com>
* feat(mobile): add quick actions button and improve mobile UX
Add mobile-optimized quick action buttons and improve autocomplete UX.
- Add quick command button (/) in mobile chat footer
- Add tabbed autocomplete interface for Commands/Agents/Files
- Fix agent selector conflict with model selector
- Improve TerminalViewport Android IME support
- Add reusable Slider component for settings
- Update StatusChip styling for mobile layout
Files changed:
- ChatInput.tsx: Mobile quick actions, command menu, autocomplete tabs
- AgentMentionAutocomplete.tsx: Tab support for mobile
- CommandAutocomplete.tsx: Tab support and touch handling
- FileMentionAutocomplete.tsx: Tab support for mobile
- ModelControls.tsx: Agent selector fix
- StatusChip.tsx: Mobile layout improvements
- TerminalViewport.tsx: Android IME improvements
- ui/slider.tsx: New reusable slider component
* feat(chat): remove unused BrowserVoiceButton component from ChatInput
* fix: Resolve linter errors
Add TextSelectionMenu component that appears when selecting text in messages.
Provides quick actions: Add to chat, New session, Copy.
- Add TextSelectionMenu.tsx component with desktop and mobile layouts
- Integrate menu into MessageBody with message-content-text ref
- Add mobile CSS for text selection behavior
* feat: extend quota providers and add usage dropdown
Add new quota providers:
- Claude (Anthropic API)
- Codex (OpenAI/ChatGPT)
- GitHub Copilot (base + add-on)
- Kimi for Coding
- OpenRouter
UI enhancements:
- Add rate limits dropdown in header with timer icon
- Desktop: sticky header with Used/Remaining toggle, refresh button
- Mobile: full-screen dropdown with same controls
- Per-provider sticky headers with provider logos
- Auto-refresh on open if no data exists
Usage settings page:
- Provider icon next to header
- Show in dropdown toggle per provider
- Global display selector (Usage vs Quota remaining)
- Auto-refresh controls in sidebar
Settings persistence:
- Add usageDisplayMode and usageDropdownProviders settings
- Server-side sanitization for new settings
Provider logo aliases:
- codex -> openai, claude -> anthropic
Bug fixes:
- Fix React error #310 by calling hooks before early returns
- Add aria-describedby to SettingsWindow dialog
- Remove horizontal scroll from dropdown
* fix: Remove duplicate github copilot declarations
* refactor(assets): rename logo svg files to include dimensions
* feat(assets): add 192x192 png versions of logos for PWA support
* fix(pwa): update static webmanifest with new logo paths and sizes
* fix(pwa): update dynamic manifest generation to use new 512px and 192px icons
* feat(chat): support inline comment drafts in chat input
Add per-session inline comment draft tracking
Append inline drafts to outgoing messages when queuing
Consume drafts after sending to clear state
* feat: add actions menu to PierreDiffViewer
Add a dropdown actions menu in the diff viewer with More and Delete options
Enable inline comment drafting support and selection synchronization to prevent loops
Replace previous action icon with contextual actions in the header
* feat(plan): enable inline comment drafting in PlanView
Add inline comment draft support with addDraft, removeDraft and drafts state
Compute session key for drafts based on currentSessionId and draft state
Prepare dropdown and toast utilities for draft actions in PlanView
* feat: add inline comment formatting utilities
Introduce formatInlineCommentDraft to render inline comments for diff and plan views
Add appendInlineComments to attach comments to existing messages with proper separation
Provide hasInlineComments to detect inline comment blocks in text
* feat: add inline comment draft store
Persist drafts per session key for inline comments
Add, remove, and clear drafts with unique IDs per session
Consume drafts to move them out of store after submission
* types: add optional context parameter to generatePullRequestDescription signature
* api: update gitApi to pass optional context to PR description generation
* http: include trimmed context in PR description API request body
* ui: add additional context input for PR generation with desktop disclosure and mobile sheet
* desktop: pass optional context to Tauri generate_pr_description command
* tauri: add optional context parameter and inject into PR description prompt
* server: read optional context from request and inject into PR description prompt
* vscode: update type signature for context parameter (compatibility only)
* fix(vscode): drop context from pr-description payload
Remove context field from PR description payload
Send only base and head to the bridge API for PR descriptions
Clarify payload compatibility across web/desktop environments
- Implement rate limiting for login attempts (10 attempts per 5min window, 15min lockout)
- Add Retry-After header and 429 response for rate-limited requests
- UI shows rate-limited state with countdown message
- Separate limits for identified IPs vs unknown clients (3 attempts without IP)
- Add cleanup mechanism for stale rate limit records
Co-authored-by: Jovines <jovines@qq.com>