* 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>
* fix: remove unnecessary websocket.js file and replace its usage directly in `WebSocketContext`
* fix: connect() doesn't need to be async
* fix: update WebSocket context import to use useWebSocket hook
* fix: use `useRef` for WebSocketContext
The main issue with using states was, previously the websocket never closed
properly on unmount, so multiple connections could be opened.
This was because the useEffect cleanup function was closing an old websocket
(that was initialized to null) instead of the current one.
We could have fixed this by adding `ws` to the useEffect dependency array, but
this was unnecessary since `ws` doesn't affect rendering so we shouldn't use a state.
* fix: replace `WebSocketContext` default value with null and add type definitions
* fix: add type definition for WebSocket URL and remove redundant protocol declaration
* fix: Prevent WebSocket reconnection attempts after unmount
Right now, when the WebSocketContext component unmounts,
there is still a pending reconnection attempt that tries
to reconnect the WebSocket after 3 seconds.
* refactor: Extract WebSocket URL construction into a separate function
* refactor: Centralize platform mode detection using IS_PLATFORM constant; use `token` from Auth context in WebSocket connection
* refactor: Use IS_PLATFORM constant for platform detection in authenticatedFetch function (backend)
* refactor: move IS_PLATFORM to config file for both frontend and backend
The reason we couldn't place it in shared/modelConstants.js is that the
frontend uses Vite which requires import.meta.env for environment variables,
while the backend uses process.env. Therefore, we created separate config files
for the frontend (src/constants/config.ts) and backend (server/constants/config.js).
* refactor: update import path for IS_PLATFORM constant to use config file
* refactor: replace `messages` with `latestMessage` in WebSocket context and related components
Why?
Because, messages was only being used to access the latest message in the components it's used in.
* refactor: optimize WebSocket connection handling with useCallback and useMemo
* refactor: comment out debug log for render count in AppContent component
* refactor(backend): update environment variable handling and replace VITE_IS_PLATFORM with IS_PLATFORM constant
* refactor: update WebSocket connection effect to depend on token changes for reconnection
---------
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