mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-01 18:28:38 +00:00
9f2afebc66efb26847d5a932db22207c091e0b9b
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9f2afebc66 |
Create command palette and add new features for search and actions (#728)
* refactor(ui): replace in-repo Command primitive with cmdk wrapper * feat(command-palette): add global Cmd+K palette with v1 actions * feat(command-palette): add session, file, and commit search sources * refactor: add provider names to model constants * feat(command-palette): add settings, navigation, message search, and ⌘K hints * feat(command-palette): add git fetch/pull/push and branch switch actions * refactor(command-palette): consolidate fetch source hooks behind useApiSource * refactor(command-palette): extract useCommandKey and SETTINGS_MAIN_TABS metadata * refactor(command-palette): extract groups into declarative registry * refactor(command-palette): wire openFile through PaletteOpsContext * refactor: migrate openSettings and refreshProjects from window.* to PaletteOpsContext * refactor(command-palette): inline groups and delete registry indirection * refactor(command-palette): return items array directly from source hooks * refactor(palette-ops): flatten Handle wrapper into ref-based registry * refactor: inline useCommandKey as MOD_KEY constant in two call sites * feat: introduce pages and fix bug on branch switching * fix: small labels * fix: coderabbit issues * fix: coderabbit comments * Update src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
44edf94f3a |
Refactor provider/session architecture to be DB-driven, modular, and sessionId-first across backend and frontend (#715)
* refactor: remove unused exports
* refactor: remove unused fields from project and session objects
* refactor: rename session_names table and related code to sessions for clarity and consistency
* refactor(database): move db into typescript
- Implemented githubTokensDb for managing GitHub tokens with CRUD operations.
- Created
otificationPreferencesDb to handle user notification preferences.
- Added projectsDb for project path management and related operations.
- Introduced pushSubscriptionsDb for managing browser push subscriptions.
- Developed scanStateDb to track the last scanned timestamp.
- Established sessionsDb for session management with CRUD functionalities.
- Created userDb for user management, including authentication and onboarding.
- Implemented apidKeysDb for storing and managing VAPID keys.
feat(database): define schema for new database tables
- Added SQL schema definitions for users, API keys, user credentials, notification preferences, VAPID keys, push subscriptions, projects, sessions, scan state, and app configuration.
- Included necessary indexes for performance optimization.
refactor(shared): enhance type definitions and utility functions
- Updated shared types and interfaces for improved clarity and consistency.
- Added new types for credential management and provider-specific operations.
- Refined utility functions for better error handling and message normalization.
* feat: added session indexer logic
* perf(projects): lazy-load TaskMaster metadata per selected project
Why:
- /api/projects is a hot path (initial load, sidebar refresh, websocket sync).
- Scanning .taskmaster for every project on each call added avoidable fs I/O and payload size.
- TaskMaster metadata is only needed after selecting a specific project.
- Moving it to a project-scoped endpoint makes loading cost match user intent.
- The UI now hydrates TaskMaster state on selection and keeps it across refresh events.
- This prevents status flicker/regression while still removing global scan overhead.
- Selection fetches are sequence-guarded to block stale async responses on fast switching.
- isManuallyAdded was removed from responses to keep the public project contract minimal.
- Project dumps now use incrementing snapshot files to preserve history for debugging.
What changed:
- Added GET /api/projects/:projectName/taskmaster and getProjectTaskMaster().
- Removed TaskMaster detection from bulk getProjects().
- Added api.projectTaskmaster(...) plus selection-time hydration in frontend contexts.
- Merged cached taskmaster values into refreshed project lists for continuity.
- Removed isManuallyAdded from manual project payloads.
* refactor: update import paths for database modules and remove legacy db.js and schema.js files
* refactor(projects): identify projects by DB projectId instead of folder-derived name
GET /api/projects used to scan ~/.claude/projects/ on every request, derive
each project's identity from the encoded folder name, and re-parse JSONL
files to build session lists. Using the folder-derived name as the project
identifier leaked the Claude CLI's on-disk encoding into every API route,
forced every downstream endpoint to re-resolve a real path via JSONL
'cwd' inspection, and made the project list endpoint O(projects x sessions)
on disk I/O.
This change switches the entire API surface to identify projects by the
stable primary key from the 'projects' table and drives the listing
straight from the DB:
- Add projectsDb.getProjectPathById as the canonical projectId -> path
resolver so routes no longer need to touch the filesystem to figure out
where a project lives.
- Rewrite getProjects so it reads the project list from the 'projects'
table and the per-project session list from the 'sessions' table (one
SELECT per project). No filesystem scanning happens for this endpoint
anymore, which removes the dependency on ~/.claude/projects existing,
on Cursor's MD5-hashed chat folders being discoverable, and on Codex's
JSONL history being on disk. Per the migration spec each session now
exposes 'summary' sourced from sessions.custom_name, 'messageCount' = 0
(message counting is not implemented), and sessionMeta.hasMore is
pinned to false since this endpoint doesn't drive session pagination.
- Introduce id-based wrappers (getSessionsById, renameProjectById,
deleteSessionById, deleteProjectById, getProjectTaskMasterById) so
every caller can pass projectId and resolve the real path through the
DB. renameProjectById also writes to projects.custom_project_name so
the DB-driven getProjects response reflects renames immediately; it
keeps project-config.json in sync for any legacy reader that still
consults the JSON file.
- Migrate every /api/projects/:projectName route in server/index.js,
server/routes/taskmaster.js, and server/routes/messages.js to
:projectId, and change server/routes/git.js so the 'project'
query/body parameter carries a projectId that is resolved through the
DB before any git command runs. TaskMaster WebSocket broadcasts emit
'projectId' for the same reason so the frontend can match
notifications against its current selection without another lookup.
- Delete helpers that existed only to feed the old getProjects path
(getCursorSessions, getGeminiCliSessions, getProjectTaskMaster) along
with their unused imports (better-sqlite3's Database,
applyCustomSessionNames). The legacy folder-name helpers (getSessions,
renameProject, deleteSession, deleteProject, extractProjectDirectory)
are kept as internal implementation details of the id-based wrappers
and of destructive cleanup / conversation search, but they are no
longer re-exported.
- searchConversations still walks JSONL to produce match snippets (that
data doesn't live in the DB), but it now includes the resolved
projectId in each result so the sidebar can cross-reference hits with
its already loaded project list without a second round-trip.
Frontend migration:
- Project.name is replaced by Project.projectId in src/types/app.ts, and
ProjectSession.__projectName becomes __projectId so session tagging
and sidebar state keys stay aligned with the backend identifier.
Settings continues to use SettingsProject.name for legacy consumers,
but it is populated from projectId by normalizeProjectForSettings.
- All places that previously indexed per-project state by project.name
(sidebar expanded/starred/loading/deletingProjects sets,
additionalSessions map, projectHasMoreOverrides, starredProjects
localStorage, command history and draft-input localStorage,
TaskMaster caches) now key on projectId so state survives
display-name edits and is consistent across the app.
- src/utils/api.js renames every endpoint parameter to projectId, the
unified messages endpoint takes projectId in its query string, and
useSessionStore forwards projectId on fetchFromServer / fetchMore /
refreshFromServer. Git panel, file tree, code editor, PRD editor,
plugins context, MCP server flows and TaskMaster hooks are all
updated to pass projectId.
- DEFAULT_PROJECT_FOR_EMPTY_SHELL is updated to carry a 'default'
projectId sentinel so the empty-shell placeholder still satisfies the
Project contract.
Bug fix bundled in:
- sessionsDb.setName no longer bumps updated_at when a row already
exists. Renaming is a label change, not activity, so there is no
reason for it to reset 'last activity' in the sidebar. It also no
longer relies on SQLite's CURRENT_TIMESTAMP, which stores a naive
'YYYY-MM-DD HH:MM:SS' value that JavaScript parses as local time and
caused renamed sessions to appear shifted backwards by the client's
UTC offset. When an INSERT actually happens it now writes ISO-8601
UTC with a 'Z' suffix.
- buildSessionsByProviderFromDb normalizes any legacy naive timestamps
in the sessions table to ISO-8601 UTC on the way out so rows written
before this change also render correctly on the client.
Other cleanup:
- Removed the filesystem-first project-discovery comment block at the
top of server/projects.js and replaced it with a short note that
describes the new DB-driven flow and lists the few remaining
filesystem-dependent helpers (message reads, search, destructive
delete, manual project registration).
- server/modules/providers/index.ts is added as a small barrel so the
providers module exposes a stable public surface.
Made-with: Cursor
* refactor(projects): reorganize project-related logic into dedicated modules
* refactor(projects): rename getProjects with getProjectsWithSessions
* refactor: update import path for getProjectsWithSessions to include file extension
* refactor: use updated session watcher
In addition, for projects_updated websocket response, send the sessionId instead
* refactor(websocket): move websocket logic to its own module
* refactor(sessions-watcher): remove redundant logging after session sync completion
* refactor(index.js): reorganize code structure
* refactor(index.js): fix import order
* refactor: remove unnecessary GitHub cloning logic from create-workspace endpoint
* refactor: modularize project services, and wizard create/clone flow
Restructure project creation, listing, GitHub clone progress, and TaskMaster
details behind a dedicated TypeScript module under server/modules/projects/,
and align the client wizard with a single path-based flow.
Server / routing
- Remove server/routes/projects.js and mount server/modules/projects/
projects.routes.ts at /api/projects (still behind authenticateToken).
- Drop duplicate handlers from server/index.js for GET /api/projects and
GET /api/projects/:projectId/taskmaster; those live on the new router.
- Import WORKSPACES_ROOT and validateWorkspacePath from shared utils in
index.js instead of the deleted projects route module.
Projects router (projects.routes.ts)
- GET /: list projects with sessions (existing snapshot behavior).
- POST /create-project: validate body, reject legacy workspaceType and
mixed clone fields, delegate to createProject service, return distinct
success copy when an archived path is reactivated.
- GET /clone-progress: Server-Sent Events for clone progress/complete/error;
requires authenticated user id for token resolution; wires startCloneProject.
- GET /:projectId/taskmaster: delegates to getProjectTaskMaster.
Services (new)
- project-management.service.ts: path validation, workspace directory
creation, persistence via projectsDb.createProjectPath, mapping to API
project shape; surfaces AppError for validation, conflict, and not-found
cases; optional dependency injection for tests.
- project-clone.service.ts: validates workspace, resolves GitHub auth
(stored token or inline token), runs git clone with progress callbacks,
registers project via createProject on success; sanitizes errors and
supports cancellation; injectable dependencies for tests.
- projects-has-taskmaster.service.ts: moves TaskMaster detection and
normalization out of server/projects.js; resolve-by-id and public
getProjectTaskMaster with structured AppError responses.
Persistence and shared types
- projectsDb.createProjectPath now returns CreateProjectPathResult
(created | reactivated_archived | active_conflict) using INSERT … ON
CONFLICT with selective update when the row is archived; normalizes
display name from path or custom name; repository row typing moves to
shared ProjectRepositoryRow.
- getProjectPaths() returns only non-archived rows (isArchived = 0).
- shared/types.ts: ProjectRepositoryRow, CreateProjectPathResult/outcome,
WorkspacePathValidationResult.
- shared/utils.ts: WORKSPACES_ROOT, forbidden path lists, validateWorkspacePath,
asyncHandler for Express async routes.
Legacy cleanup
- server/projects.js: remove detectTaskMasterFolder, normalizeTaskMasterInfo,
and getProjectTaskMasterById (logic lives in the new service).
- server/routes/agent.js: register external API project paths with
projectsDb.createProjectPath instead of addProjectManually try/catch;
treat active_conflict as an existing registration and continue.
Tests
- Add Node test suites for project-management, project-clone, and
projects-has-taskmaster services; update projects.service test import
for renamed projects-with-sessions-fetch.service.ts.
Rename
- projects.service.ts → projects-with-sessions-fetch.service.ts;
re-export from modules/projects/index.ts.
Client (project creation wizard)
- Remove StepTypeSelection and workspaceType from form state and types;
wizard is two steps (configure path/GitHub auth, then review).
- createWorkspaceRequest → createProjectRequest; clone vs create-only
inferred from githubUrl (pathUtils / isCloneWorkflow).
- Adjust step indices, WizardProgress, StepConfiguration/Review,
WorkspacePathField, and src/utils/api.js as needed for the new API.
Docs
- Minor websocket README touch-up.
Net: ~1.6k insertions / ~0.9k deletions across 29 files; behavior is
centralized in typed services with explicit HTTP errors and test seams.
* refactor: remove loading sessions logic from sidebar
* refactor: move project rename to module
* refactor: move project deletion to module
* refactor: move project star state from localStorage to backend
* refactor: implement optimistic UI for project star state management
* feat: optimistic update for session watcher
* fix(projects-state): stop websocket message reprocessing loop
The websocket projects effect in useProjectsState could re-handle the same
latestMessage after local state writes triggered re-renders.
Under bursty websocket traffic, this created an update feedback cycle
that surfaced as 'Maximum update depth exceeded', often from Sidebar.
What changed:
- Added lastHandledMessageRef so each latestMessage object is handled once.
- Added an early return guard when the current message was already handled.
- Made projects updates idempotent by comparing previous and merged payloads
before calling setProjects.
Result:
- Breaks the effect -> state update -> effect re-entry cycle.
- Reduces redundant renders during rapid projects_updated traffic while
preserving normal project/session synchronization.
* refactor: optimize project auto-expand logic
* refactor: move projects provider specific logic into respective session providers
* refactor: move rename and delete sessions to modules
* refactor: move fetching messages to module
* fix: remove unused var
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* Potential fix for pull request finding 'Useless assignment to local variable'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* refactor(projects/sidebar): remove temp snapshot side-effects and simplify session metadata UX
Why this change was needed:
- Project listing had an implicit side effect: every fetch wrote a debug snapshot under `.tmp/project-dumps`.
That added unnecessary disk I/O to a hot path, introduced hidden runtime behavior, and created maintenance
overhead for code that was not part of product functionality.
- Keeping snapshot-specific exports/tests around made the projects module API broader than needed and coupled
tests to temporary/debug behavior instead of user-visible behavior.
- Codex sessions could remain stuck with a placeholder name (`Untitled Codex Session`) even after a real title
became available from newer sync data, which degraded session discoverability in the UI.
- Sidebar session rows showed duplicated provider branding and long-form relative times, which added visual noise
and reduced scan speed when many sessions are listed.
What changed:
- Removed temporary projects snapshot dumping from `projects-with-sessions-fetch.service.ts`:
- deleted snapshot types/helpers and file-write flow
- removed the write call from `getProjectsWithSessions`
- Removed snapshot-related surface area from `projects/index.ts`.
- Removed the snapshot-focused test `projects.service.test.ts` that only validated removed debug behavior.
- Updated `codex-session-synchronizer.provider.ts` to upgrade session names when an existing session still has
the placeholder title but a real parsed name is now available.
- Updated `SidebarSessionItem.tsx`:
- removed duplicate provider logo rendering in each session row
- moved age indicator to the right side
- made age indicator fade on hover to prioritize action controls
- switched to compact relative time format (`<1m`, `Xm`, `Xhr`, `Xd`) for faster list scanning
Outcome:
- Lower overhead and fewer hidden side effects in project fetches.
- Cleaner module boundaries in projects.
- Better Codex session naming consistency after sync.
- Cleaner sidebar density and clearer hover/action behavior.
* refactor: implement pagination for project sessions loading
* refactor: move search to module
* fix: search performance
* refactor: add handling for internal Codex metadata in conversation search
* fix(migrations,projects,clone): normalize legacy schema before writes and harden conflict detection
Why
- Legacy installs can have a sessions table shape that predates provider/custom_name columns. Running migrateLegacySessionNames first caused its INSERT OR REPLACE INTO sessions (...) to target columns that may not exist and fail during startup migration.
- Some upgraded databases had projects.project_id as plain TEXT instead of a real PRIMARY KEY. That breaks assumptions used by id-based lookups and can allow invalid/duplicate identity semantics over time.
- projectsDb.createProjectPath inferred outcomes from
ow.isArchived, but the upsert path always returns the post-update row with isArchived=0, so archived-reactivation and fresh-create could be misclassified.
- git clone accepted user-controlled URLs directly in argv position, so inputs beginning with - could be interpreted as options instead of a repository argument.
What
- Added
ebuildProjectsTableWithPrimaryKeySchema in migrations: detect table shape via getTableInfo('projects'), verify project_id has pk=1, and rebuild when missing.
- Rebuild flow now creates a canonical projects__new table (project_id TEXT PRIMARY KEY), copies rows with transformation, backfills empty ids via SQLITE_UUID_SQL, deduplicates conflicting ids/paths, then swaps tables inside a transaction.
- Replaced the prior ddColumnToTableIfNotExists(...) + UPDATE project_id sequence with PK-aware detection/rebuild logic so legacy DBs converge to the required schema.
- Reordered migration sequence to run
ebuildSessionsTableWithProjectSchema before migrateLegacySessionNames, ensuring sessions is normalized before legacy session_names merge writes execute.
- Updated projectsDb.createProjectPath to generate an ttemptedId before insert, pass it into the prepared statement, and classify outcomes by comparing returned
ow.project_id to ttemptedId (created vs
eactivated_archived), with no-row remaining ctive_conflict.
- Hardened clone execution by inserting -- before clone URL in git argv and rejecting normalized GitHub URLs that start with - in startCloneProject.
Tests
- Added integration coverage for projectsDb.createProjectPath branches: fresh insert, archived reactivation, and active conflict.
- Added clone service test for option-prefixed githubUrl rejection (INVALID_GITHUB_URL).
* refactor(session-synchronizer): update last scanned timestamp based on synchronization results
* refactor: improve session limit and offset validation in provider routes
* refactor: normalize project paths across database and service modules
* refactor(database): make session id the primary key in sessions table
* fix(codex): preserve reasoning entries as thinking blocks
Codex history normalization was downgrading reasoning into plain assistant text
because of branch ordering, not because the raw data was missing.
Why this mattered:
- Codex reasoning JSONL entries are intentionally mapped to history items with
type thinking, but they also carry message.role assistant.
- normalizeHistoryEntry evaluated the assistant-role branch before the
thinking branch.
- As a result, reasoning content matched the assistant-text path first and was
emitted as kind text instead of kind thinking.
- This collapses semantic intent, so UI and downstream features that rely on
thinking blocks (separate rendering, filtering, and interpretation of model
thought process vs final answer) receive the wrong message kind.
What changed:
- Prioritized thinking detection (raw.type === thinking or raw.isReasoning)
before role-based assistant normalization.
- Kept a non-empty content guard for thinking payloads to avoid emitting empty
artifacts.
Impact:
- Reasoning entries from persisted Codex JSONL now remain thinking blocks
end-to-end.
- Regular assistant text normalization behavior remains unchanged.
* refactor: remove dead code
* refactor: directly use getProjectPathById from projectsDb
* refactor: add gemini jsonl session support
|
||
|
|
e9c7a5041c | feat: deleting from sidebar will now ask whether to remove all data as well | ||
|
|
96463df8da |
Feature/backend ts support andunification of auth settings on frontend (#654)
* fix: remove project dependency from settings controller and onboarding * fix(settings): remove onClose prop from useSettingsController args * chore: tailwind classes order * refactor: move provider auth status management to custom hook * refactor: rename SessionProvider to LLMProvider * feat(frontend): support for @ alias based imports) * fix: replace init.sql with schema.js * fix: refactor database initialization to use schema.js for SQL statements * feat(server): add a real backend TypeScript build and enforce module boundaries The backend had started to grow beyond what the frontend-only tooling setup could support safely. We were still running server code directly from /server, linting mainly the client, and relying on path assumptions such as "../.." that only worked in the source layout. That created three problems: - backend alias imports were hard to resolve consistently in the editor, ESLint, and the runtime - server code had no enforced module boundary rules, so cross-module deep imports could bypass intended public entry points - building the backend into a separate output directory would break repo-level lookups for package.json, .env, dist, and public assets because those paths were derived from source-only relative assumptions This change makes the backend tooling explicit and runtime-safe. A dedicated backend TypeScript config now lives in server/tsconfig.json, with tsconfig.server.json reduced to a compatibility shim. This gives the language service and backend tooling a canonical project rooted in /server while still preserving top-level compatibility for any existing references. The backend alias mapping now resolves relative to /server, which avoids colliding with the frontend's "@/..." -> "src/*" mapping. The package scripts were updated so development runs through tsx with the backend tsconfig, build now produces a compiled backend in dist-server, and typecheck/lint cover both client and server. A new build-server.mjs script runs TypeScript and tsc-alias and cleans dist-server first, which prevents stale compiled files from shadowing current source files after refactors. To make the compiled backend behave the same as the source backend, runtime path resolution was centralized in server/utils/runtime-paths.js. Instead of assuming fixed relative paths from each module, server entry points now resolve the actual app root and server root at runtime. That keeps package.json, .env, dist, public, and default database paths stable whether code is executed from /server or from /dist-server/server. ESLint was expanded from a frontend-only setup into a backend-aware one. The backend now uses import resolution tied to the backend tsconfig so aliased imports resolve correctly in linting, import ordering matches the frontend style, and unused/duplicate imports are surfaced consistently. Most importantly, eslint-plugin-boundaries now enforces server module boundaries. Files under server/modules can no longer import another module's internals directly. Cross-module imports must go through that module's barrel file (index.ts/index.js). boundaries/no-unknown was also enabled so alias-resolution gaps cannot silently bypass the rule. Together, these changes make the backend buildable, keep runtime path resolution stable after compilation, align server tooling with the client where appropriate, and enforce a stricter modular architecture for server code. * fix: update package.json to include dist-server in files and remove tsconfig.server.json * refactor: remove build-server.mjs and inline its logic into package.json scripts * fix: update paths in package.json and bin.js to use dist-server directory * feat(eslint): add backend shared types and enforce compile-time contract for imports * fix(eslint): update shared types pattern --------- Co-authored-by: Haileyesus <something@gmail.com> |
||
|
|
3950c0e47f |
feat: add full-text search across conversations (#482)
* feat: add full-text search across conversations in sidebar Add a search mode toggle (Projects/Conversations) to the sidebar search bar. In Conversations mode, search text content across all JSONL session files with debounced API calls, highlighted snippets, and click-to-navigate results. * fix: address PR review feedback - session summary tracking, search sequence invalidation, fallback navigation, SSE streaming - Track session summaries per-session in a Map instead of file-scoped variable - Increment searchSeqRef when clearing conversation search to invalidate in-flight requests - Add fallback session navigation when session not loaded in sidebar paging - Stream search results via SSE for progressive display with progress indicator * feat(search): add Codex/Gemini search and scroll-to-message navigation - Search now includes Codex sessions (JSONL from ~/.codex/sessions/) and Gemini sessions (in-memory via sessionManager) in addition to Claude - Search results include provider info and display a provider badge - Click handler resolves the correct provider instead of hardcoding claude - Clicking a search result loads all messages and scrolls to the matched message with a highlight flash animation * fix(search): Codex search path matching and scroll reliability - Fix Codex search scanning all sessions for every project by checking session_meta cwd match BEFORE scanning messages (was inflating match count and hitting limit before reaching later projects) - Fix Codex search missing user messages in response_item entries (role=user with input_text content parts) - Fix scroll-to-message being overridden by initial scrollToBottom using searchScrollActiveRef to inhibit competing scroll effects - Fix snippet matching using contiguous substring instead of filtered words (which created non-existent phrases) * feat(search): add Gemini CLI session support for search and history viewing Gemini CLI sessions stored in ~/.gemini/tmp/<project>/chats/*.json are now indexed for conversation search and can be loaded for viewing. Previously only sessions created through the UI (sessionManager) were searchable. * fix(search): full-word matching and longer highlight flash - Search now uses word boundaries (\b) instead of substring matching, so "hi" no longer matches "this" - Highlight flash extended to 4s with thicker outline and subtle background tint for better visibility |
||
|
|
844de26ada |
Refactor/shared and tasks components (#473)
* refactor: remove unused TasksSettings component
* refactor: migrate TodoList component to a new file with improved structure and normalization logic
* refactor: Move Tooltip and DarkModeToggle to shared/ui
* refactor: Move Tooltip and DarkModeToggle to shared/view/ui
* refactor: move GeminiLogo to llm-logo-provider and update imports
* refactor: remove unused GeminiStatus component
* refactor: move components in src/components/ui to src/shared/view/ui
* refactor: move ErrorBoundary component to main-content/view and update imports
* refactor: move VersionUpgradeModal to its own module
* refactor(wizard): rebuild project creation flow as modular TypeScript components
Replace the monolithic `ProjectCreationWizard.jsx` with a feature-based TS
implementation under `src/components/project-creation-wizard`, while preserving
existing behavior and improving readability, maintainability, and state isolation.
Why:
- The previous wizard mixed API logic, flow state, folder browsing, and UI in one file.
- Refactoring and testing were difficult due to tightly coupled concerns.
- We needed stronger type safety and localized component state.
What changed:
- Deleted:
- `src/components/ProjectCreationWizard.jsx`
- Added new modular structure:
- `src/components/project-creation-wizard/index.ts`
- `src/components/project-creation-wizard/ProjectCreationWizard.tsx`
- `src/components/project-creation-wizard/types.ts`
- `src/components/project-creation-wizard/data/workspaceApi.ts`
- `src/components/project-creation-wizard/hooks/useGithubTokens.ts`
- `src/components/project-creation-wizard/utils/pathUtils.ts`
- `src/components/project-creation-wizard/components/*`
- `WizardProgress`, `WizardFooter`, `ErrorBanner`
- `StepTypeSelection`, `StepConfiguration`, `StepReview`
- `WorkspacePathField`, `GithubAuthenticationCard`, `FolderBrowserModal`
- Updated import usage:
- `src/components/sidebar/view/subcomponents/SidebarModals.tsx`
now imports from `../../../project-creation-wizard`.
Implementation details:
- Migrated wizard logic to TypeScript using `type` aliases only.
- Kept component prop types colocated in each component file.
- Split responsibilities by feature:
- container/orchestration in `ProjectCreationWizard.tsx`
- API/SSE and request parsing in `data/workspaceApi.ts`
- GitHub token loading/caching behavior in `useGithubTokens`
- path/URL helpers in `utils/pathUtils.ts`
- Localized UI-only state to child components:
- folder browser modal state (current path, hidden folders, create-folder input)
- path suggestion dropdown state with debounced lookup
- Preserved existing UX flows:
- step navigation and validation
- existing/new workspace modes
- optional GitHub clone + auth modes
- clone progress via SSE
- folder browsing + folder creation
- Added focused comments for non-obvious logic (debounce, SSE auth constraint, path edge cases).
* refactor(quick-settings): migrate panel to typed feature-based modules
Refactor QuickSettingsPanel from a single JSX component into a modular TypeScript feature structure while preserving behavior and translations.
Highlights:
- Replace legacy src/components/QuickSettingsPanel.jsx with a typed entrypoint (src/components/QuickSettingsPanel.tsx).
- Introduce src/components/quick-settings-panel/ with clear separation of concerns:
- view/: panel shell, header, handle, section wrappers, toggle rows, and content sections.
- hooks/: drag interactions and whisper mode persistence.
- constants.ts and types.ts for shared config and strict local typing.
- Move drag logic into useQuickSettingsDrag with explicit touch/mouse handling, drag threshold detection, click suppression after drag, position clamping, and localStorage persistence.
- Keep user-visible behavior intact:
- same open/close panel interactions.
- same mobile/desktop drag behavior and persisted handle position.
- same quick preference toggles and wiring to useUiPreferences.
- same hidden whisper section behavior and localStorage/event updates.
- Improve readability and maintainability by extracting repetitive setting rows and section scaffolding into reusable components.
- Add focused comments around non-obvious behavior (drag click suppression, touch scroll lock, hidden whisper section intent).
- Keep files small and reviewable (all new/changed files are under 300 lines).
Validation:
- npm run typecheck
- npm run build
* refactor(quick-settings-panel): restructure QuickSettingsPanel import and create index file
* refactor(shared): move shared ui components to share/view/ui without subfolders
* refactor(LanguageSelector): move LanguageSelector to shared UI components
* refactor(prd-editor): modularize PRD editor with typed feature modules
Break the legacy PRDEditor.jsx monolith into a feature-based TypeScript architecture under src/components/prd-editor while keeping behavior parity and readability.
Key changes:
- Replace PRDEditor.jsx with a typed orchestrator component and a compatibility export bridge at src/components/PRDEditor.tsx.
- Split responsibilities into dedicated hooks: document loading/init, existing PRD registry fetching, save workflow with overwrite detection, and keyboard shortcuts.
- Split UI into focused view components: header, editor/preview body, footer stats, loading state, generate-tasks modal, and overwrite-confirm modal.
- Move filename concerns into utility helpers (sanitize, extension handling, default naming) and centralize template/constants.
- Keep component-local state close to the UI that owns it (workspace controls/modal toggles), while shared workflow state remains in the feature container.
- Reuse the existing MarkdownPreview component for safer markdown rendering instead of ad-hoc HTML conversion.
- Update TaskMasterPanel integration to consume typed PRDEditor directly (remove any-cast) and pass isExisting metadata for correct overwrite behavior.
- Keep all new/changed files below 300 lines and add targeted comments where behavior needs clarification.
Validation:
- npm run typecheck
- npm run build
* refactor(TaskMasterPanel): update PRDEditor import path to match new structure
* refactor(TaskMaster): Remove unused TaskMasterSetupWizard and TaskMasterStatus components
* refactor(TaskDetail): remove unused TaskIndicator import
* refactor(task-master): migrate tasks to a typed feature module
- introduce a new feature-oriented TaskMaster domain under src/components/task-master
- add typed TaskMaster context/provider with explicit project, task, MCP, and loading state handling
- split task UI into focused components (panel, board, toolbar, content, card, detail modal, setup/help modals, banner)
- move task board filtering/sorting/kanban derivation into dedicated hooks and utilities
- relocate CreateTaskModal into the feature module and keep task views modular/readable
- remove legacy monolithic TaskList/TaskDetail/TaskCard files and route main task panel to the new feature panel
- replace contexts/TaskMasterContext.jsx with a typed contexts/TaskMasterContext.ts re-export to the feature context
- update MainContent project sync logic to compare by project name to avoid state churn
- validation: npm run typecheck, npm run build
* refactor(MobileNav): remove unused React import and TaskMasterContext
* refactor(auth): migrate login and setup flows to typed feature module
- Introduce a new feature-based auth module under src/components/auth with clear separation of concerns:\n - context/AuthContext.tsx for session lifecycle, onboarding status checks, token persistence, and auth actions\n - view/* components for loading, route guarding, form layout, input fields, and error display\n - shared auth constants, utility helpers, and type aliases (no interfaces)\n- Convert login and setup UIs to TypeScript and keep form state local to each component for readability and component-level ownership\n- Add explicit API payload typing and safe JSON parsing helpers to improve resilience when backend responses are malformed or incomplete\n- Centralize error fallback handling for auth requests to reduce repeated logic
- Replace legacy auth entrypoints with the new feature module in app wiring:\n - App now imports AuthProvider and ProtectedRoute from src/components/auth\n - WebSocketContext, TaskMasterContext, and Onboarding now consume useAuth from the new typed auth context\n- Remove duplicated legacy auth screens (LoginForm.jsx, SetupForm.jsx, ProtectedRoute.jsx)\n- Keep backward compatibility by turning src/contexts/AuthContext.jsx into a thin re-export of the new provider/hook
Result: auth code now follows a feature/domain structure, is fully typed, easier to navigate, and cleaner to extend without touching unrelated UI areas.
* refactor(AppContent): update MobileNav import path and add MobileNav component
* refactor(DiffViewer): rename different diff viewers and place them in different components
* refactor(components): reorganize onboarding/provider auth/sidebar indicator into domain features
- Move onboarding out of root-level components into a dedicated feature module:
- add src/components/onboarding/view/Onboarding.tsx
- split onboarding UI into focused subcomponents:
- OnboardingStepProgress
- GitConfigurationStep
- AgentConnectionsStep
- AgentConnectionCard
- add onboarding-local types and utils for provider status and validation helpers
- Move multi-provider login modal into a dedicated provider-auth feature:
- add src/components/provider-auth/view/ProviderLoginModal.tsx
- add src/components/provider-auth/types.ts
- keep provider-specific command/title behavior and Gemini setup guidance
- preserve compatibility for both onboarding flow and settings login flow
- Move TaskIndicator into the sidebar domain:
- add src/components/sidebar/view/subcomponents/TaskIndicator.tsx
- update SidebarProjectItem to consume local sidebar TaskIndicator
- Update integration points to the new structure:
- ProtectedRoute now imports onboarding from onboarding feature
- Settings now imports ProviderLoginModal directly (remove legacy cast wrapper)
- git panel consumers now import shared GitDiffViewer by explicit name
- Rename git shared diff view to clearer domain naming:
- replace shared DiffViewer with shared GitDiffViewer
- update FileChangeItem and CommitHistoryItem imports accordingly
- Remove superseded root-level legacy components:
- delete src/components/LoginModal.jsx
- delete src/components/Onboarding.jsx
- delete src/components/TaskIndicator.jsx
- delete old src/components/git-panel/view/shared/DiffViewer.tsx
- Result:
- clearer feature boundaries (auth vs onboarding vs provider-auth vs sidebar)
- easier navigation and ownership by domain
- preserved runtime behavior with improved readability and modularity
* refactor(MainContent): remove TaskMasterPanel import and relocate to task-master component
* fix: update import paths for Input component in FileTree and FileTreeNode
* refactor(FileTree): make file tree context menu a typescript component and move it inside the file tree view
* refactor(FileTree): remove unused ScrollArea import
* feat: setup eslint with typescript and react rules, add unused imports plugin
* fix: remove unused imports, functions, and types after discovering using `npm run lint`
* feat: setup eslint-plugin-react, react-refresh, import-x, and tailwindcss plugins with recommended rules and configurations
* chore: reformat files after running `npm run lint:fix`
* chore: add omments about eslint config plugin uses
* feat: add husky and lint-staged for pre-commit linting
* feat: setup commitlint with conventional config
* fix: i18n translations
---------
Co-authored-by: Haileyesus <something@gmail.com>
Co-authored-by: viper151 <simosmik@gmail.com>
|
||
|
|
198e3da89b |
feat: implement session rename with SQLite storage (#413)
* feat: implement session rename with SQLite storage (closes #72, fixes #358) - Add session_names table to store custom display names per provider - Add PUT /api/sessions/:sessionId/rename endpoint - Replace stub updateSessionSummary with real API call - Apply custom names across all providers (Claude, Codex, Cursor) - Fix project rename destroying config (spread merge instead of overwrite) - Thread provider parameter through sidebar component chain - Add i18n error messages for rename failures (en, ja, ko, zh-CN) * fix: address CodeRabbit review feedback for session rename - Log migration errors instead of swallowing them silently (db.js) - Add try/catch to applyCustomSessionNames to prevent getProjects abort - Move applyCustomSessionNames to db.js as shared helper (DRY) - Fix Cursor getSessionName to check session.summary for custom names - Move edit state clearing to finally block in updateSessionSummary - Sanitize sessionId, add 500-char summary limit, validate provider whitelist - Remove dead applyCustomSessionNames call on empty manual project sessions * fix: reject sessionId on mismatch instead of silent normalization Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: enable rename for all providers, add Gemini support, clean up orphans - Enable rename UI (pencil icon) for Codex, Cursor, and Gemini sessions - Keep delete button hidden for Cursor (no backend delete endpoint) - Add 'gemini' to VALID_PROVIDERS and hoist to module scope - Add sessionNamesDb.deleteName on session delete (claude, codex, gemini) - Fix token-usage endpoint sessionId mismatch validation - Remove redundant try/catch in sessionNamesDb methods - Let session_names migration errors propagate to outer handler --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Haileyesus <118998054+blackmammoth@users.noreply.github.com> |
||
|
|
a367edd515 |
feat: Google's gemini-cli integration (#422)
* 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> |
||
|
|
412102c531 | feat: show .env syntax highlighting and markdown viewer | ||
|
|
f891316ec0 |
Refactor/app content main content and chat interface (#374)
* feat: improve version comparison logic in useVersionCheck hook
* refactor: useVersionCheck.js to typescript
* refactor: move VersionUpgradeModal component to its own file and remove it from AppContent component
* refactor: improve VersionUpgradeModal props and extract ReleaseInfo type
Using useVersionCheck hook in 2 places caused github requests to be made twice, which is not ideal.
* refactor: handleUpdateNow function with useCallback and error display in VersionUpgradeModal
* refactor: move isOpen check to the correct position in VersionUpgradeModal
* refactor: move VersionUpgradeModal and collapsed sidebar to Sidebar component from App.jsx
* refactor: remove unused SettingsIcon import from App.jsx
* refactor: move formatTimeAgo function to dateUtils.ts
* refactor: replace useLocalStorage with useUiPreferences for better state management in AppContent
* refactor: use shared props for Sidebar props in AppContent
* refactor: remove showQuickSettings state and toggle from AppContent, manage isOpen state directly in QuickSettingsPanel
* refactor: move preference props directly to QuickSettingsPanel and MainContent
* refactor: remove unused isPWA prop
* refactor: remove unused isPWA prop from AppContent
* refactor: remove unused generatingSummary state from Sidebar component
* refactor: remove unused isPWA prop from MainContent component
* refactor: use usePrefrences for sidebar visibility in Sidebar component
* refactor: extract device detection into hook and localize PWA handling to Sidebar
- Add new `useDeviceSettings` hook (`src/hooks/useDeviceSettings.ts`) to centralize
device-related state:
- exposes `isMobile` and `isPWA`
- supports options: `mobileBreakpoint`, `trackMobile`, `trackPWA`
- listens to window resize for mobile updates
- listens to `display-mode: standalone` changes for PWA updates
- includes `matchMedia.addListener/removeListener` fallback for older environments
- Update `AppContent` (`src/App.jsx`) to consume `isMobile` from
`useDeviceSettings({ trackPWA: false })`:
- remove local `isMobile` state/effect
- remove local `isPWA` state/effect
- keep existing `isMobile` behavior for layout and mobile sidebar flow
- stop passing `isPWA` into `Sidebar` props
- Update `Sidebar` (`src/components/Sidebar.jsx`) to own PWA detection:
- consume `isPWA` from `useDeviceSettings({ trackMobile: false })`
- add effect to toggle `pwa-mode` class on `document.documentElement` and `document.body`
- retain use of `isMobile` prop from `App` for sidebar/mobile rendering decisions
Why:
- removes duplicated device-detection logic from `AppContent`
- makes device-state logic reusable and easier to maintain
- keeps PWA-specific behavior where it is actually used (`Sidebar`)
* chore(to-remove): comment todo's
* refactor: remove unused createNewProject and cancelNewProject functions from Sidebar component
* refactor(sidebar): extract typed app/sidebar architecture and split Sidebar into modular components
- Replace `src/App.jsx` with `src/App.tsx` and move route-level UI orchestration into `src/components/app/AppContent.tsx`.
This separates provider/bootstrap concerns from runtime app layout logic, keeps route definitions minimal, and improves readability of the root app entry.
- Introduce `src/hooks/useProjectsState.ts` to centralize project/session/sidebar state management previously embedded in `App.jsx`.
This keeps the existing behavior for:
project loading,
Cursor session hydration,
WebSocket `loading_progress` handling,
additive-update protection for active sessions,
URL-based session selection,
sidebar refresh/delete/new-session flows.
The hook now exposes a typed `sidebarSharedProps` contract and typed handlers used by `AppContent`.
- Introduce `src/hooks/useSessionProtection.ts` for active/processing session lifecycle logic.
This preserves session-protection behavior while isolating `activeSessions`, `processingSessions`, and temporary-session replacement into a dedicated reusable hook.
- Replace monolithic `src/components/Sidebar.jsx` with typed `src/components/Sidebar.tsx` as a thin orchestrator.
`Sidebar.tsx` now focuses on wiring controller state/actions, modal visibility, collapsed mode, and version modal behavior instead of rendering every UI branch inline.
- Add `src/hooks/useSidebarController.ts` to encapsulate sidebar interaction/state logic.
This includes expand/collapse state, inline project/session editing state, project starring/sorting/filtering, lazy session pagination, delete confirmations, rename/delete actions, refresh state, and mobile touch click handling.
- Add strongly typed sidebar domain models in `src/components/sidebar/types.ts` and move sidebar-derived helpers into `src/components/sidebar/utils.ts`.
Utility coverage now includes:
session provider normalization,
session view-model creation (name/time/activity/message count),
project sorting/filtering,
task indicator status derivation,
starred-project persistence and readbacks.
- Split sidebar rendering into focused components under `src/components/sidebar/`:
`SidebarContent.tsx` for top-level sidebar layout composition.
`SidebarProjectList.tsx` for project-state branching and project iteration.
`SidebarProjectsState.tsx` for loading/empty/no-search-result placeholders.
`SidebarProjectItem.tsx` for per-project desktop/mobile header rendering and actions.
`SidebarProjectSessions.tsx` for expanded session area, skeletons, pagination, and new-session controls.
`SidebarSessionItem.tsx` for per-session desktop/mobile item rendering and session actions.
`SessionProviderIcon.tsx` for provider icon normalization.
`SidebarHeader.tsx`, `SidebarFooter.tsx`, `SidebarCollapsed.tsx`, and `SidebarModals.tsx` as dedicated typed UI surfaces.
This keeps rendering responsibilities local and significantly improves traceability.
- Convert shared UI primitives from JSX to TSX:
`src/components/ui/button.tsx`,
`src/components/ui/input.tsx`,
`src/components/ui/badge.tsx`,
`src/components/ui/scroll-area.tsx`.
These now provide typed props/variants (`forwardRef` where appropriate) while preserving existing class/behavior.
- Add shared app typings in `src/types/app.ts` for projects/sessions/websocket/loading contracts used by new hooks/components.
- Add global window declarations in `src/types/global.d.ts` for `__ROUTER_BASENAME__`, `refreshProjects`, and `openSettings`, removing implicit `any` usage for global integration points.
- Update `src/main.jsx` to import `App.tsx` and keep app bootstrap consistent with the TS migration.
- Update `src/components/QuickSettingsPanel.jsx` to self-resolve mobile state via `useDeviceSettings` (remove `isMobile` prop dependency), and update `src/components/ChatInterface.jsx` to render `QuickSettingsPanel` directly.
This reduces prop drilling and keeps quick settings colocated with chat UI concerns.
* refactor(sidebar): integrate settings modal into SidebarModals and update props
* fix(mobile): prevent menu tap from triggering unintended dashboard navigation
The mobile sidebar menu button redirects users to `cloudcli.ai/dashboard` when a
session was active. The redirect happened because
the menu was opened on `touchstart`, which mounted the sidebar before the touch
sequence completed; the follow-up tap/click then landed on the sidebar header
anchor.
This change rewrites mobile menu interaction handling in `MainContent.jsx` to
eliminate touch/click event leakage and ghost-click behavior.
Key changes:
- Added `suppressNextMenuClickRef` to guard against synthetic click events that
fire after a touch interaction.
- Added `openMobileMenu(event)` helper to centralize `preventDefault`,
`stopPropagation`, and `onMenuClick()` invocation.
- Added `handleMobileMenuTouchEnd(event)`:
- opens the menu on `touchend` instead of `touchstart`
- sets a short suppression window (350ms) for the next click.
- Added `handleMobileMenuClick(event)`:
- ignores/suppresses click events during the suppression window
- otherwise opens the menu normally.
- Updated all mobile menu button instances in `MainContent.jsx` (loading state,
no-project state, active header state) to use:
- `onTouchEnd={handleMobileMenuTouchEnd}`
- `onClick={handleMobileMenuClick}`
- Removed the previous `onTouchStart` path that caused premature DOM mutation.
Behavioral impact:
- Mobile sidebar still opens reliably with one tap.
- Tap no longer leaks to newly-mounted sidebar header links.
- Prevents accidental redirects while preserving existing menu UX.
* refactor(main-content): migrate MainContent to TypeScript and modularize UI/state boundaries
Replace the previous monolithic MainContent.jsx with a typed one and
extract focused subcomponents/hooks to improve readability, local state ownership,
and maintainability while keeping runtime behavior unchanged.
Key changes:
- Replace `src/components/MainContent.jsx` with `src/components/MainContent.tsx`.
- Add typed contracts for main-content domain in `src/components/main-content/types.ts`.
- Extract header composition into:
- `MainContentHeader.tsx`
- `MainContentTitle.tsx`
- `MainContentTabSwitcher.tsx`
- `MobileMenuButton.tsx`
- Extract loading/empty project views into `MainContentStateView.tsx`.
- Extract editor presentation into `EditorSidebar.tsx`.
- Move editor file-open + resize behavior into `useEditorSidebar.ts`.
- Move mobile menu touch/click suppression logic into `useMobileMenuHandlers.ts`.
- Extract TaskMaster-specific concerns into `TaskMasterPanel.tsx`:
- task detail modal state
- PRD editor modal state
- PRD list loading/refresh
- PRD save notification lifecycle
Behavior/compatibility notes:
- Preserve existing tab behavior, session passthrough props, and Chat/Git/File flows.
- Keep interop with existing JS components via boundary `as any` casts where needed.
- No intentional functional changes; this commit is structural/type-oriented refactor.
Validation:
- `npm run typecheck` passes.
- `npm run build` passes (existing unrelated CSS minify warnings remain).
* refactor(chat): split monolithic chat interface into typed modules and hooks
Replace the legacy monolithic ChatInterface.jsx implementation with a modular TypeScript architecture centered around a small orchestration component (ChatInterface.tsx).
Core architecture changes:
- Remove src/components/ChatInterface.jsx and add src/components/ChatInterface.tsx as a thin coordinator that wires provider state, session state, realtime WebSocket handlers, and composer behavior via dedicated hooks.
- Update src/components/MainContent.tsx to use typed ChatInterface directly (remove AnyChatInterface cast).
State ownership and hook extraction:
- Add src/hooks/chat/useChatProviderState.ts to centralize provider/model/permission-mode state, provider/session synchronization, cursor model bootstrap from backend config, and pending permission request scoping.
- Add src/hooks/chat/useChatSessionState.ts to own chat/session lifecycle state: session loading, cursor/claude/codex history loading, pagination, scroll restoration, visible-window slicing, token budget loading, persisted chat hydration, and processing-state restoration.
- Add src/hooks/chat/useChatRealtimeHandlers.ts to isolate WebSocket event processing for Claude/Cursor/Codex, including session filtering, streaming chunk buffering, session-created/pending-session transitions, permission request queueing/cancellation, completion/error handling, and session status updates.
- Add src/hooks/chat/useChatComposerState.ts to own composer-local state and interactions: input/draft persistence, textarea sizing and keyboard behavior, slash command execution, file mentions, image attachment/drop/paste workflow, submit/abort flows, permission decision responses, and transcript insertion.
UI modularization under src/components/chat:
- Add view/ChatMessagesPane.tsx for message list rendering, loading/empty states, pagination affordances, and thinking indicator.
- Add view/ChatComposer.tsx for composer shell layout and input area composition.
- Add view/ChatInputControls.tsx for mode toggles, token display, command launcher, clear-input, and scroll-to-bottom controls.
- Add view/PermissionRequestsBanner.tsx for explicit tool-permission review actions (allow once / allow & remember / deny).
- Add view/ProviderSelectionEmptyState.tsx for provider and model selection UX plus task starter integration.
- Add messages/MessageComponent.tsx and markdown/Markdown.tsx to isolate message rendering concerns, markdown/code rendering, and rich tool-output presentation.
- Add input/ImageAttachment.tsx for attachment previews/removal/progress/error overlay rendering.
Shared chat typing and utilities:
- Add src/components/chat/types.ts with shared types for providers, permission mode, message/tool payloads, pending permission requests, and ChatInterfaceProps.
- Add src/components/chat/utils/chatFormatting.ts for html decoding, code fence normalization, regex escaping, math-safe unescaping, and usage-limit text formatting.
- Add src/components/chat/utils/chatPermissions.ts for permission rule derivation, suggestion generation, and grant flow.
- Add src/components/chat/utils/chatStorage.ts for resilient localStorage access, quota handling, and normalized Claude settings retrieval.
- Add src/components/chat/utils/messageTransforms.ts for session message normalization (Claude/Codex/Cursor) and cached diff computation utilities.
Command/file input ergonomics:
- Add src/hooks/chat/useSlashCommands.ts for slash command fetching, usage-based ranking, fuzzy filtering, keyboard navigation, and command history persistence.
- Add src/hooks/chat/useFileMentions.tsx for project file flattening, @mention suggestions, mention highlighting, and keyboard/file insertion behavior.
TypeScript support additions:
- Add src/types/react-syntax-highlighter.d.ts module declarations to type-check markdown code highlighting imports.
Behavioral intent:
- Preserve existing chat behavior and provider flows while improving readability, separation of concerns, and future refactorability.
- Move state closer to the components/hooks that own it, reducing cross-cutting concerns in the top-level chat component.
* perf(project-loading): eliminate repeated Codex session rescans and duplicate cursor fetches
The staged changes remove the main source of project-load latency by avoiding repeated full scans of ~/.codex/sessions for every project and by removing redundant client-side cursor session refetches.
Server changes (server/projects.js):\n- Add a per-request Codex index reference in getProjects so Codex metadata is built once and reused across all projects, including manually added ones.\n- Introduce normalizeComparablePath() to canonicalize project paths (including Windows long-path prefixes and case-insensitive matching on Windows).\n- Introduce findCodexJsonlFiles() + buildCodexSessionsIndex() to perform a single recursive Codex scan and group sessions by normalized cwd.\n- Update getCodexSessions() to accept indexRef and read from the prebuilt index, with fallback index construction when no ref is provided.\n- Preserve existing session limiting behavior (limit=5 default, limit=0 returns all).
Client changes (src/hooks/useProjectsState.ts):\n- Remove loadCursorSessionsForProjects(), which previously triggered one extra /api/cursor/sessions request per project after /api/projects.\n- Use /api/projects response directly during initial load and refresh.\n- Expand projectsHaveChanges() to treat both cursorSessions and codexSessions as external session deltas.\n- Keep refresh comparison aligned with external session updates by using includeExternalSessions=true in sidebar refresh path.
Impact:\n- Reduces backend work from roughly O(projects * codex_session_files) to O(codex_session_files + projects) for Codex discovery during a project load cycle.\n- Removes an additional client-side O(projects) network fan-out for Cursor session fetches.\n- Improves perceived and actual sidebar project-loading time, especially in large session datasets.
* fix(chat): make Stop and Esc reliably abort active sessions
Problem
Stop requests were unreliable because aborting depended on currentSessionId being set, Esc had no actual global abort binding, stale pending session ids could be reused, and abort failures were surfaced as successful interruptions. Codex sessions also used a soft abort flag without wiring SDK cancellation.
Changes
- Add global Escape key handler in chat while a run is loading/cancellable to trigger the same abort path as the Stop button.
- Harden abort session target selection in composer by resolving from multiple active session id sources (current, pending view, pending storage, cursor storage, selected session) and ignoring temporary new-session-* ids.
- Clear stale pendingSessionId when launching a brand-new session to prevent aborting an old run.
- Update realtime abort handling to respect backend success=false responses: keep loading state when abort fails and emit an explicit failure message instead of pretending interruption succeeded.
- Improve websocket send reliability by checking socket.readyState === WebSocket.OPEN directly before send.
- Implement real Codex cancellation via AbortController + runStreamed(..., { signal }), propagate aborted status, and suppress expected abort-error noise.
Impact
This makes both UI Stop and Esc-to-stop materially more reliable across Claude/Cursor/Codex flows, especially during early-session windows before currentSessionId is finalized, and prevents false-positive interrupted states when backend cancellation fails.
Validation
- npm run -s typecheck
- npm run -s build
- node --check server/openai-codex.js
* refactor: tool components
* refactor: tool components
* fix: remove one-line logic from messagecomponent
* refactor(design): change the design of bash
* refactor(design): fix bash design and config
* refactor(design): change the design of tools and introduce todo list and task list.
* refactor(improvement):add memo on diffviewer, cleanup messsagecomponent
* refactor: update readme and remove unusedfiles.
* refactor(sidebar): remove duplicate loading message in SidebarProjectsState
* refactor(sidebar): move VersionUpgradeModal into SidebarModals
* refactor: replace individual provider logos with a unified SessionProviderLogo component
* fix(commands): restore /cost slash command and improve command execution errors
The /cost command was listed as built-in but had no handler, causing execution to
fall through to custom command logic and return 400 ("command path is required").
- Add a built-in /cost handler in server/routes/commands.js
- Return the expected payload shape for the chat UI (`action: "cost"`, token usage,
estimated cost, model)
- Normalize token usage inputs and compute usage percentage
- Add provider-based default pricing for cost estimation
- Fix model selection in command execution context so codex uses `codexModel`
instead of `claudeModel`
- Improve frontend command error handling by parsing backend error responses and
showing meaningful error messages instead of a generic failure
* fix(command-menu): correct slash command selection with frequent commands
When the “Frequently Used” section is visible, command clicks/hover could use a
UI-local index instead of the canonical `filteredCommands` index, causing the
wrong command to execute (e.g. clicking `/help` running `/clear`).
- map rendered menu items back to canonical command indices using a stable key
(`name + namespace/type + path`)
- use canonical index for hover/click selection callbacks
- deduplicate frequent commands from other grouped sections to avoid duplicate
rows and selection ambiguity
- keep and restore original inline comments, with clarifications where needed
* refactor(sidebar): update sessionMeta handling for session loading logic
- This fixes an issue where the sidebar was showing 6+ even when there were only 5 sessions, due to the hasMore logic not accounting for the case where there are exactly 6 sessions.
It was also showing "Show more sessions" even where there were no more sessions to load.
- This was because `hasMore` was sometimes `undefined` and the logic checked for hasMore !== false, which treated undefined as true.
Now we explicitly check for hasMore === true to determine if there are more sessions to load.
* refactor(project-watcher): add codex and cursor file watchers
* fix: chat session scroll to bottom error even when scrolled up
* fix(chat): clear stuck loading state across realtime lifecycle events
The chat UI could remain in a stale "Thinking/Processing" state when session IDs
did not line up exactly between view state (`currentSessionId`), selected route
session, pending session IDs, and provider lifecycle events. This was most visible
with Codex completion/abort flows, but the same mismatch risk existed in shared
handlers.
Unify lifecycle cleanup behavior in realtime handlers and make processing tracking
key off the active viewed session identity.
Changes:
- src/hooks/chat/useChatRealtimeHandlers.ts
- src/components/ChatInterface.tsx
- src/hooks/chat/useChatSessionState.ts
What changed:
- Added shared helpers in realtime handling:
- `collectSessionIds(...)` to normalize and dedupe candidate session IDs.
- `clearLoadingIndicators()` to consistently clear `isLoading`, abort UI, and status.
- `markSessionsAsCompleted(...)` to consistently notify inactive/not-processing state.
- Updated lifecycle branches to use shared cleanup logic:
- `cursor-result`
- `claude-complete`
- `codex-response` (`turn_complete` and `turn_failed`)
- `codex-complete`
- `session-aborted`
- Expanded completion/abort cleanup to include all relevant session IDs
(`latestMessage.sessionId`, `currentSessionId`, `selectedSession?.id`,
`pendingSessionId`, and Codex `actualSessionId` when present).
- Switched processing-session marking in `ChatInterface` to use
`selectedSession?.id || currentSessionId` instead of `currentSessionId` alone.
- Switched processing-session rehydration in `useChatSessionState` to use
the same active-view session identity fallback.
Result:
- Prevents stale loading indicators after completion/abort when IDs differ.
- Keeps processing session bookkeeping aligned with the currently viewed session.
- Reduces provider-specific drift by using one lifecycle cleanup pattern.
* fix(chat): stabilize long-history scroll-up pagination behavior
- fix top-pagination lockups by only locking when older messages are actually fetched
- make fetched older messages visible immediately by increasing `visibleMessageCount` on prepend
- prevent unintended auto-scroll-to-bottom during older-message loading and scroll restore
- replace state-based pagination offset with a ref to avoid stale offset/reload side effects
- ensure initial auto-scroll runs only after initial session load completes
- reset top-load lock/restore state and visible window when switching sessions
- loosen top-lock release near the top to avoid requiring a full down/up cycle
* refactor: Restructure files and folders to better mimic feature-based architecture
* refactor: reorganize chat view components and types
* feat(chat): move thinking modes, token usage pie, and related logic into chat folder
* refactor(tools): add agent category for Task tool
Add visual distinction for the Task tool (subagent invocation) by
introducing a new 'agent' category with purple border styling. This
separates subagent tasks from regular task management tools
(TaskCreate, TaskUpdate, etc.) for clearer user feedback.
Also refactor terminal command layout in OneLineDisplay to properly
nest flex containers, fixing copy button alignment issues.
* refactor(tools): improve Task tool display formatting
Update Task tool config to show cleaner subagent information in the UI.
Simplifies the input display by showing only the prompt when no
optional fields are present, reducing visual clutter. Updates title
format to "Subagent / {type}" for better categorization. Enhances
result display to better handle complex agent response structures with
array content types, extracting text blocks for cleaner presentation.
* fix: show auth url panel in shell only on mobile
- use static url: https://auth.openai.com/codex/device, for codex login.
- add an option for hiding the panel
* fix(chat): escape command name in regex to prevent unintended matches
* fix(chat): handle JSON parsing errors for saved chat messages
* refactor(chat): replace localStorage provider retrieval with prop usage in MessageComponent
* fix(chat): handle potential null content in message before splitting lines
* refactor(todo): update TodoListContentProps to include optional id and priority fields that are used in TodoList.jsx
* fix(watcher): ensure provider folders exist before creating watchers to maintain active watching
* refactor(chat): improve message handling by cloning state updates and improving structured message parsing
* refactor(chat): exclude currentSessionId from dependency array to prevent unnecessary reloading of messages
* refactor(useFileMentions): implement abort controller for fetch requests
* refactor(MessageComponent): add types
* refactor(calculateDiff): optimize LCS algorithm for improved diff calculation
* refactor(createCachedDiffCalculator): use both newStr and oldStr as cache keys
* refactor(useSidebarController): manage project session overrides in local state
* refactor(ScrollArea): adjust ref placement and className order
* fix: type annotations
* refactor(ChatInputControls): update import statement for ThinkingModeSelector
* refactor(dateUtils): update type annotation for formatTimeAgo function
* refactor(ToolRenderer): ensure stable hook order
* refactor(useProjectsState): normalize refreshed session metadata to maintain provider stability; use getProjectSessions helper for session retrieval.
* refactor(useChatComposerState): improve input handling and command execution flow
* refactor(useChatRealtimeHandlers): normalize interactive prompt content to string for consistent ChatMessage shape
* refactor(OneLineDisplay): improve clipboard functionality with fallback for unsupported environments
* refactor(QuickSettingsPanel): simplify state management by removing localIsOpen and using isOpen directly
* refactor(ChatMessagesPane): use stable message key
* refactor:: move AssistantThinkingIndicator component to its own file
* refactor(ChatMessagesPane): extract message key generation logic to a utility function
* refactor(SidebarModals): move normalizeProjectForSettings into utils file
* refactor(ToolConfigs): use optional chaining for content retrieval
* fix(chat): stabilize provider/message handling and complete chat i18n coverage
Unify provider typing, harden realtime message effects, normalize tool input
serialization, and finish i18n/a11y updates across chat UI components.
- tighten provider contracts from `Provider | string` to `SessionProvider` in:
- `useChatProviderState`
- `useChatComposerState`
- `useChatRealtimeHandlers`
- `ChatMessagesPane`
- `ProviderSelectionEmptyState`
- refactor `AssistantThinkingIndicator` to accept `selectedProvider` via props
instead of reading provider from local storage during render
- fix stale-closure risk in `useChatRealtimeHandlers` by:
- adding missing effect dependencies
- introducing `lastProcessedMessageRef` to prevent duplicate processing when
dependencies change without a new message object
- standardize `toolInput` shape in `messageTransforms`:
- add `normalizeToolInput(...)`
- ensure all conversion paths produce consistent string output
- remove mixed `null`/raw/stringified variants across cursor/session branches
- harden tool display fallback in `CollapsibleDisplay`:
- default border class now falls back safely for unknown categories
- improve chat i18n consistency:
- localize hardcoded strings in `MessageComponent`
(`permissions.*`, `interactive.*`, `thinking.emoji`, `json.response`,
`messageTypes.error`)
- localize button titles in `ChatInputControls`
(`input.clearInput`, `input.scrollToBottom`)
- localize provider-specific empty-project prompt in `ChatInterface`
(`projectSelection.startChatWithProvider`)
- localize repeated “Start the next task” prompt in
`ProviderSelectionEmptyState` (`tasks.nextTaskPrompt`)
- add missing translation keys in all supported chat locales:
- `src/i18n/locales/en/chat.json`
- `src/i18n/locales/ko/chat.json`
- `src/i18n/locales/zh-CN/chat.json`
- new keys:
- `input.clearInput`
- `input.scrollToBottom`
- `projectSelection.startChatWithProvider`
- `tasks.nextTaskPrompt`
- improve attachment remove-button accessibility in `ImageAttachment`:
- add `type="button"` and `aria-label`
- make control visible on touch/small screens and focusable states
- preserve hover behavior on larger screens
Validation:
- `npm run typecheck`
* fix(chat): sync quick settings state and stabilize thinking toggle
Synchronize useUiPreferences instances via custom sync events and storage listeners so Quick Settings updates apply across UI consumers immediately.
Also hide standalone thinking messages when showThinking is disabled, while preserving hook order to avoid Rendered fewer hooks runtime errors.
* refactor(validateGitRepository): improve directory validation for git work tree
* refactor(GitPanel): clear stale state on project change and improve error handling
* refactor(git): use spawnAsync for command execution and improve commit log retrieval
* fix: iOS pwa bottom margin
* fix: pass diff information to code editor
* refactor(sidebar): remove touch event handlers from project and session items
* bumping node to v22
* Release 1.17.0
---------
Co-authored-by: Haileyesus <something@gmail.com>
Co-authored-by: simosmik <simosmik@gmail.com>
|