* feat: add opencode support
* fix: stabilize opencode session startup
* fix: /models
* fix: improveUI for commands
* fix: format commands.js
* feat: load models through provider adapters
Provider model selection had outgrown a single hardcoded service.
The old service mixed shared caching with provider catalogs and CLI lookup details.
That made stale model lists more likely as providers changed on separate schedules.
Move model discovery behind each provider so lookup lives next to the integration.
The shared service now focuses on provider resolution, caching, persistence, and dedupe.
Return cache metadata and add bypassCache because model availability changes outside the app.
The UI and /models command can show freshness and let users force a provider refresh.
Surface model descriptions while keeping fallback catalogs for unavailable CLIs or SDKs.
* feat(models): resolve active session models through provider adapters
The model inventory command was showing a mix of catalog defaults and
composer-local state instead of the model that is actually active for a
real provider session. That made /models, /cost, and /status
misleading once a session had already started, especially for providers
whose effective runtime model can differ from the optimistic model value
held in the UI.
Introduce an explicit getCurrentActiveModel() contract on
IProviderModels so model resolution lives next to each provider's
catalog logic and uses the provider-native source of truth:
- Claude reads the init event from a resumed stream-json run
- Codex reads model from ~/.codex/config.toml
- Cursor reads lastUsedModel from the chat store.db
- OpenCode reads the persisted session model from opencode.db
- Gemini intentionally returns its default because the CLI does not
provide a reliable active-session lookup
Keep the returned shape intentionally minimal ({ model }). The goal is
to expose only what downstream command consumers need and avoid leaking
provider-specific metadata into a shared transport shape that would
create extra UI coupling and future cleanup cost.
Also make command behavior session-aware: when there is no concrete
session id, do not spawn provider processes or inspect provider session
storage just to answer /models, /cost, or /status. In a new-session
view the correct answer is simply the provider default, and doing more
work there adds latency and unnecessary side effects for no user value.
As part of this, centralize two supporting concerns:
- add a shared helper for building the default current-model result from
a provider catalog so fallbacks stay aligned with DEFAULT
- move leaf-directory validation into shared utils so Cursor session
readers and model lookup code enforce the same path-safety rule
Tests were expanded to cover both the new service delegation path and
the sessionless command behavior, while keeping cache-sensitive tests
isolated from persisted host cache state.
Why this change:
- command output should reflect the model actually driving a session
- new-session views should stay fast and side-effect free
- provider-specific active-model lookup should not be scattered across
routes or UI code
- fallback behavior should be explicit, consistent, and limited to the
provider default when no true active model can be resolved
* feat: support session-scoped model overrides
Model selection was acting like a provider-level preference.
That made resumed sessions drift back to a default or request-time model.
Users expect /models changes made inside a conversation to affect that session.
Store explicit session choices in app-owned ~/.cloudcli state.
This avoids editing provider transcripts or native provider config.
Resolve the effective model before launching each provider runtime.
Claude, Cursor, Codex, Gemini, and OpenCode now honor stored resume choices.
Expose a backend active-model change endpoint for existing sessions.
The models modal can now distinguish default changes from session overrides.
It also shows when a selected model will apply on the next response.
For Claude, stop probing active model state by resuming with a dummy prompt.
Read the indexed JSONL transcript from the end instead.
This preserves provider history while honoring /model stdout or model fields.
Add service tests for adapter delegation and resume-model precedence.
The tests keep cache state, override state, and requested fallback separate.
* feat: make command modal more compact
* fix: preserve opencode session creation events
OpenCode emits the real session id asynchronously on its first JSON output. The runner
registered that id from a helper that could not see the spawned process because
the process reference was scoped inside the model-resolution callback. That
ReferenceError was swallowed by the generic JSON parse fallback, so the client
never received session_created. Without that event, a new OpenCode chat stayed
on / and the assistant stream was not attached to the new session view.
Keep the process reference in the outer spawn scope so registration can update
the active-process map and websocket writer as soon as OpenCode announces the
session id. Split JSON parsing from event processing so malformed non-JSON
output can still stream as raw text, while registration or adapter failures are
surfaced as real errors instead of being hidden as assistant content.
Add a fake opencode executable regression test to lock in the expected lifecycle
ordering: session_created must be sent before live assistant messages, and the
same session id must carry through stream_end and complete.
* fix: clarify model refresh and onboarding providers
OpenCode is now a supported chat provider, but first-run onboarding still only offered
Claude, Cursor, Codex, and Gemini. That made OpenCode harder to discover and
forced users to finish setup before finding the provider in settings or chat.
Adding it to onboarding keeps first-run setup aligned with the providers the
application already supports elsewhere.
The model refresh control was also doing too much visual work. In the new chat
model picker, the previous Hard Refresh label looked like the dialog heading,
which made the primary task unclear. Users open that dialog to choose a model;
refreshing catalogs is only a secondary maintenance action for stale cached
provider model lists.
Rename and reposition the refresh affordance so the model picker reads as a
model picker first. The copy now explains why catalogs are cached, when a refresh
is useful, and that the refresh checks every provider. The /models modal gets the
same clarification so both model-selection surfaces describe the cache behavior
consistently.
* fix: format opencode model catalog labels
OpenCode returns provider-prefixed ids directly from the CLI. Passing those ids through as
labels made the model picker hard to scan: users saw values like
anthropic/claude-3-5-sonnet-20241022 or lowercased, hyphen-split text instead
of readable model names.
Keep the exact OpenCode id as the option value because that is what the CLI
expects, but derive a presentation label for the frontend. The formatter is
intentionally generic rather than a catalog of known providers. It handles common
identifier structure such as provider/model, hyphen-delimited words, v-prefixed
versions, adjacent numeric version tokens, and 8-digit date suffixes.
This keeps OpenCode usable as its model list expands across many upstream
providers without requiring code changes for every new provider or model family.
The description keeps the raw provider-prefixed id visible so users can still
confirm the precise model being selected.
* feat: add more fallback models for cursor
* docs: move model catalog out of shared
The model catalog is no longer a frontend/backend runtime contract.
Keeping it under shared made ownership misleading. It implied the catalog was
application code shared by runtime consumers, even though it now only supports
README links and public API documentation.
Move the catalog into public so it lives beside the docs surfaces that need it.
This gives the API docs a stable, served module and gives README readers a
linkable source without suggesting frontend or backend runtime dependency.
Render the API docs model list from the exported provider registry instead of a
hardcoded Claude/Cursor/Codex subset. That keeps Gemini and OpenCode visible and
makes future provider documentation changes flow through one docs-specific file.
Update README links, provider maintenance notes, and package files so published
artifacts include the standalone docs page and model catalog without relying on
the old shared path.
* fix: simplify empty-state model selector
Keep the provider empty state focused on the setup action users need there:
choosing a model.
The refresh control, cache timestamp, and refresh explanation made the dialog feel
like a cache-management surface.
That extra action is out of place in the empty state, where the goal is to start
a chat with the selected provider and model.
Remove the refresh-specific UI from ProviderSelectionEmptyState and drop the
now-unused refresh/cache props from the ChatMessagesPane pass-through.
Refresh behavior remains available in the dedicated command result flow.
* feat: introduce notification system and claude notifications
* fix(sw): prevent caching of API requests and WebSocket upgrades
* default to false for webpush notifications and translations for the button
* fix: notifications orchestrator and add a notification when first enabled
* fix: remove unused state update and dependency in settings controller hook
* fix: show notifications settings tab
* fix: add notifications for response completion for all providers
* feat: show session name in notification and don't reload tab on clicking
--- the notification
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Haileyesus <something@gmail.com>
* feat: integrate Gemini AI agent provider
- Core Backend: Ported gemini-cli.js and gemini-response-handler.js to establish the CLI bridge. Registered 'gemini' as an active provider within index.js.
- Core Frontend: Extended QuickSettingsPanel.jsx, Settings.jsx, and AgentListItem.jsx to render the Gemini provider option, models (gemini-pro, gemini-flash, etc.), and handle OAuth states.
- WebSocket Pipeline: Added support for gemini-command executions in backend and payload processing of gemini-response and gemini-error streams in useChatRealtimeHandlers.ts. Resolved JSON double-stringification and sessionId stripping issues in the transmission handler.
- Platform Compatibility: Added scripts/fix-node-pty.js postinstall script and modified posix_spawnp calls with sh -c wrapper to prevent ENOEXEC and MacOS permission errors when spawning the gemini headless binary.
- UX & Design: Imported official Google Gemini branding via GeminiLogo.jsx and gemini-ai-icon.svg. Updated translations (chat.json) for en, zh-CN, and ko locales.
* fix: propagate gemini permission mode from settings to cli
- Added Gemini Permissions UI in Settings to toggle Auto Edit and YOLO modes
- Synced gemini permission mode to localStorage
- Passed permissionMode in useChatComposerState for Gemini commands
- Mapped frontend permission modes to --yolo and --approval-mode options in gemini-cli.js
* feat(gemini): Refactor Gemini CLI integration to use stream-json
- Replaced regex buffering text-system with NDJSON stream parsing
- Added fallback for restricted models like gemini-3.1-pro-preview
* feat(gemini): Render tool_use and tool_result UI bubbles
- Forwarded gemini tool NDJSON objects to the websocket
- Added React state handlers in useChatRealtimeHandlers to match Claude's tool UI behavior
* feat(gemini): Add native session resumption and UI token tracking
- Captured cliSessionId from init events to map ClaudeCodeUI's chat sessionId directly into Gemini's internal session manager.
- Updated gemini-cli.js spawn arguments to append the --resume proxy flag instead of naively dumping the accumulated chat history into the command prompt.
- Handled result stream objects by proxying total_tokens back into the frontend's claude-status tracker to natively populate the UI label.
- Eliminated gemini-3 model proxy filter entirely.
* fix(gemini): Fix static 'Claude' name rendering in chat UI header
- Added "gemini": "Gemini" translation strings to messageTypes across English, Korean, and Chinese loc dictionaries.
- Updated AssistantThinkingIndicator and MessageComponent ternary checks to identify provider === 'gemini' and render the appropriate brand label instead of statically defaulting to Claude.
* feat: Add Gemini session persistence API mapping and Sidebar UI
* fix(gemini): Watch ~/.gemini/sessions for live UI updates
Added the .gemini/sessions directory to PROVIDER_WATCH_PATHS so that Chokidar emits projects_updated websocket events when new Gemini sessions are created or modified, fixing live sidebar updates.
* fix(gemini): Fix Gemini authentication status display in Settings UI
- Injected 'checkGeminiAuthStatus' into the Settings.jsx React effect hook so that the UI can poll and render the 'geminiAuthStatus' state.
- Updated 'checkGeminiCredentials()' inside server/routes/cli-auth.js to read from '~/.gemini/oauth_creds.json' and '~/.gemini/google_accounts.json', resolving the email address correctly.
* Use logo-only icon for gemini
* feat(gemini): Add Gemini 3 preview models to UI selection list
* Fix Gemini CLI session resume bug and PR #422 review nitpicks
* Fix Gemini tool calls disappearing from UI after completion
* fix(gemini): resolve outstanding PR #422 feedback and stabilize gemini CLI timeouts
* fix(gemini): resolve resume flag and shell session initialization issues
This commit addresses the remaining PR comments for the Gemini CLI integration:
- Moves the `--resume` flag logic outside the prompt command block, ensuring Gemini sessions correctly resume even when a new prompt isn't passed.
- Updates `handleShellConnection` to correctly lookup the native `cliSessionId` from the internal `sessionId` when spawning Gemini sessions in a plain shell.
- Refactors dynamic import of `sessionManager.js` back to a native static import for code consistency.
* chore: fix TypeScript errors and remove gemini CLI dependency
* fix: use cross-spawn on Windows to resolve gemini.cmd correctly
---------
Co-authored-by: Haileyesus <118998054+blackmammoth@users.noreply.github.com>
Previously, the model parameter was accepted by the /api/agent endpoint
and extracted from requests, but was never passed through to the Claude
SDK or Codex SDK, causing all requests to use default models regardless
of user selection.
Changes:
- Add model parameter to queryClaudeSDK() options in routes/agent.js
- Add model to threadOptions in openai-codex.js
- Remove unused /cost slash command and PRICING constants
- Centralize all model definitions in shared/modelConstants.js
- Update API documentation to dynamically load models from constants
Added createBranch and createPR options to the agent API endpoint, enabling automatic branch creation and pull request generation after successful agent task completion. Branch names are auto-generated from the agent message, and PR titles/descriptions are auto-generated from commit messages. This streamlines CI/CD workflows by eliminating manual Git operations after agent runs.
Implement comprehensive API key management functionality including
generation, validation, and CRUD operations.
Changes:
- Add API key database schema and operations (create, validate, delete,
toggle)
- Generating a commit message will now work properly with claude sdk and cursor cli and return a suggested commit message
- Implement crypto-based key generation with 'ck_' prefix
- Add session ID tracking in claude-sdk.js and cursor-cli.js
- Update database layer with API key validation and last_used tracking
- Support multi-user API key management with user association
This enables secure programmatic access to the agent service
* feat: Add token budget tracking and multiple improvements
## Features
- **Token Budget Visualization**: Added real-time token usage tracking with pie chart display showing percentage used (blue < 50%, orange < 75%, red ≥ 75%)
- **Show Thinking Toggle**: Added quick settings option to show/hide reasoning sections in messages
- **Cache Clearing Utility**: Added `/clear-cache.html` page for clearing service workers, caches, and storage
## Improvements
- **Package Upgrades**: Migrated from deprecated `xterm` to `@xterm/*` scoped packages
- **Testing Setup**: Added Playwright for end-to-end testing
- **Build Optimization**: Implemented code splitting for React, CodeMirror, and XTerm vendors to improve initial load time
- **Deployment Scripts**: Added `scripts/start.sh` and `scripts/stop.sh` for cleaner server management with automatic port conflict resolution
- **Vite Update**: Upgraded Vite from 7.0.5 to 7.1.8
## Bug Fixes
- Fixed static file serving to properly handle routes vs assets
- Fixed session state reset to preserve token budget on initial load
- Updated default Vite dev server port to 5173 (Vite's standard)
## Technical Details
- Token budget is parsed from Claude CLI `modelUsage` field in result messages
- Budget updates are sent via WebSocket as `token-budget` events
- Calculation includes input, output, cache read, and cache creation tokens
- Token budget state persists during active sessions but resets on session switch
* feat: Add session processing state persistence
Fixes issue where "Thinking..." banner and stop button disappear when
switching between sessions. Users can now navigate freely while Claude
is processing without losing the ability to monitor or stop the session.
Features:
- Processing state tracked in processingSessions Set (App.jsx)
- Backend session status queries via check-session-status WebSocket message
- UI state (banner + stop button) restored when returning to processing sessions
- Works after page reload by querying backend's authoritative process maps
- Proper cleanup when sessions complete in background
Backend Changes:
- Added sessionId to claude-complete, cursor-result, session-aborted messages
- Exported isClaudeSessionActive, isCursorSessionActive helper functions
- Exported getActiveClaudeSessions, getActiveCursorSessions for status queries
- Added check-session-status and get-active-sessions WebSocket handlers
Frontend Changes:
- processingSessions state tracking in App.jsx
- onSessionProcessing/onSessionNotProcessing callbacks
- Session status check on session load and switch
- Completion handlers only update UI if message is for current session
- Always clean up processing state regardless of which session is active
* feat: Make context window size configurable via environment variables
Removes hardcoded 160k token limit and makes it configurable through
environment variables. This allows easier adjustment for different
Claude models or use cases.
Changes:
- Added CONTEXT_WINDOW env var for backend (default: 160000)
- Added VITE_CONTEXT_WINDOW env var for frontend (default: 160000)
- Updated .env.example with documentation
- Replaced hardcoded values in token usage calculations
- Replaced hardcoded values in pie chart display
Why 160k? Claude Code reserves ~40k tokens for auto-compact feature,
leaving 160k available for actual usage from the 200k context window.
* fix: Decode HTML entities in chat message display
HTML entities like < and > were showing as-is instead of being
decoded to < and > characters. Added decodeHtmlEntities helper function
to properly display angle brackets and other special characters.
Applied to:
- Regular message content
- Streaming content deltas
- Session history loading
- Both string and array content types
* refactor: Align package.json with main branch standards
- Revert to main branch's package.json scripts structure
- Remove custom scripts/start.sh and scripts/stop.sh
- Update xterm dependencies to scoped @xterm packages (required for code compatibility)
- Replace xterm with @xterm/xterm
- Replace xterm-addon-fit with @xterm/addon-fit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: Replace CLI implementation with Claude Agents SDK
This commit completes the migration to the Claude Agents SDK, removing the legacy CLI-based implementation and making the SDK the exclusive integration method.
Changes:
- Remove claude-cli.js legacy implementation
- Add claude-sdk.js with full SDK integration
- Remove CLAUDE_USE_SDK feature flag (SDK is now always used)
- Update server/index.js to use SDK functions directly
- Add .serena/ to .gitignore for AI assistant cache
Benefits:
- Better performance (no child process overhead)
- Native session management with interrupt support
- Cleaner codebase without CLI/SDK branching
- Full feature parity with previous CLI implementation
- Maintains compatibility with Cursor integration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update server/claude-sdk.js
Whoops. This is correct.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update server/index.js
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update src/components/ChatInterface.jsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update src/components/ChatInterface.jsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update src/components/ChatInterface.jsx
Left my test code in, but that's fixed.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fix: Prevent stale token-usage data from updating state on session switch
- Add AbortController to cancel in-flight token-usage requests when session/project changes
- Capture session/project IDs before fetch and verify they match before updating state
- Handle AbortError gracefully without logging as error
- Prevents race condition where old session data overwrites current session's token budget
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update src/components/TokenUsagePie.jsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: viper151 <simosmik@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Updated ClaudeStatus component to accept a provider prop for better flexibility.
- Added CursorLogo component for displaying cursor sessions.
- Modified MainContent to conditionally display session names based on provider.
- Updated Shell component to show session names and summaries based on provider.
- Enhanced Sidebar to handle both Claude and Cursor sessions, including sorting and displaying session icons.
- Introduced new ToolsSettings functionality to manage tools for both Claude and Cursor, including allowed and disallowed commands.
- Implemented fetching and saving of Cursor-specific settings and commands.
- Added UI elements for managing Cursor tools, including permission settings and command lists.