Commit Graph

634 Commits

Author SHA1 Message Date
Haileyesus
f175d20c4e refactor: normalize project paths across database and service modules 2026-04-29 18:02:33 +03:00
Haileyesus
0f93ef2781 refactor: improve session limit and offset validation in provider routes 2026-04-29 11:46:53 +03:00
Haileyesus
10f35c238d refactor(session-synchronizer): update last scanned timestamp based on synchronization results 2026-04-29 11:35:59 +03:00
Haileyesus
805e283fb6 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).
2026-04-28 17:15:13 +03:00
Haileyesus
8570bd7bab refactor: add handling for internal Codex metadata in conversation search 2026-04-27 22:30:31 +03:00
Haileyesus
5af2b719e2 fix: search performance 2026-04-27 22:23:50 +03:00
Haileyesus
9684aa0941 Merge branch 'refactor/use-database-for-session-managemnet' of https://github.com/siteboon/claudecodeui into refactor/use-database-for-session-managemnet 2026-04-27 21:39:56 +03:00
Haileyesus
50ee3c7548 refactor: move search to module 2026-04-27 21:39:48 +03:00
Haileyesus
9a8fb116ef refactor: implement pagination for project sessions loading 2026-04-27 21:22:56 +03:00
Haileyesus
14e6b5b7b2 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.
2026-04-27 21:07:54 +03:00
Haile
714c9214e6 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>
2026-04-27 15:21:53 +03:00
Haile
c027dc0813 fix: remove unused var
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-04-27 15:21:05 +03:00
Haileyesus
16954c883b refactor: move fetching messages to module 2026-04-27 14:30:09 +03:00
Haileyesus
9663f08fcb refactor: move rename and delete sessions to modules 2026-04-27 14:21:03 +03:00
Haileyesus
7ceaa9e326 refactor: move projects provider specific logic into respective session providers 2026-04-27 13:46:19 +03:00
Haileyesus
d3adc7afb8 refactor: optimize project auto-expand logic 2026-04-25 21:49:09 +03:00
Haileyesus
360aa514f9 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.
2026-04-25 21:45:30 +03:00
Haileyesus
68123dcc33 feat: optimistic update for session watcher 2026-04-25 21:32:24 +03:00
Haileyesus
edc7d6d184 refactor: implement optimistic UI for project star state management 2026-04-25 21:09:25 +03:00
Haileyesus
113c7631b8 refactor: move project star state from localStorage to backend 2026-04-25 21:08:16 +03:00
Haileyesus
7a82fb54dc refactor: move project deletion to module 2026-04-25 20:45:24 +03:00
Haileyesus
447f352e7b refactor: move project rename to module 2026-04-25 20:28:58 +03:00
Haileyesus
3188ef5fee refactor: remove loading sessions logic from sidebar 2026-04-25 19:56:50 +03:00
Haileyesus
bb86236520 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.
2026-04-25 19:36:47 +03:00
Haileyesus
7023a8cf7b refactor: remove unnecessary GitHub cloning logic from create-workspace endpoint 2026-04-25 17:56:14 +03:00
Haileyesus
5d7d6e478e refactor(index.js): fix import order 2026-04-25 16:17:21 +03:00
Haileyesus
1083746df5 refactor(index.js): reorganize code structure 2026-04-25 16:02:35 +03:00
Haileyesus
eec9701679 refactor(sessions-watcher): remove redundant logging after session sync completion 2026-04-25 15:44:26 +03:00
Haileyesus
2323a576a6 refactor(websocket): move websocket logic to its own module 2026-04-25 15:39:22 +03:00
Haileyesus
3fd2353ffe refactor: use updated session watcher
In addition, for projects_updated websocket response, send the sessionId instead
2026-04-24 21:56:19 +03:00
Haileyesus
b3445508e9 refactor: update import path for getProjectsWithSessions to include file extension 2026-04-24 19:09:30 +03:00
Haileyesus
c412aac8fb refactor(projects): rename getProjects with getProjectsWithSessions 2026-04-24 19:08:27 +03:00
Haileyesus
18e5a88c48 refactor(projects): reorganize project-related logic into dedicated modules 2026-04-24 19:06:40 +03:00
Haileyesus
dc5d73936a 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
2026-04-24 18:12:10 +03:00
Haileyesus
4bd07c3ece refactor: update import paths for database modules and remove legacy db.js and schema.js files 2026-04-24 15:11:25 +03:00
Haileyesus
15171e1428 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.
2026-04-24 13:30:04 +03:00
Haileyesus
f99af1ff67 feat: added session indexer logic 2026-04-23 17:32:08 +03:00
Haileyesus
7b75ed0b72 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.
2026-04-23 16:59:45 +03:00
Haileyesus
2e326214e1 refactor: rename session_names table and related code to sessions for clarity and consistency 2026-04-22 13:43:16 +03:00
Haileyesus
295b8846a7 refactor: remove unused fields from project and session objects 2026-04-22 13:28:44 +03:00
Haileyesus
80d010126f refactor: remove unused exports 2026-04-22 13:01:55 +03:00
viper151
f6200e3e95 chore(release): v1.30.0 v1.30.0 2026-04-21 16:43:54 +00:00
simosmik
fa5a23897c chore: add docker sandbox action 2026-04-21 16:41:40 +00:00
Simos Mikelatos
c5e55adc89 feat: introduce opus 4.7 (#682)
* feat: introduce opus 4.7
- Bump claude-agent-sdk from 0.2.59 to 0.2.116
- Forward process.env to SDK subprocess so ANTHROPIC_BASE_URL and other env vars work
- Add claude-opus-4-6 as a distinct mode

* feat: add "claude" as fallback in the cli path

* fix: base url config
2026-04-21 18:26:25 +02:00
Menny Even Danan
09dd407648 fix missing curly (#683) 2026-04-21 16:45:29 +02:00
Mahsum Aktaş
89b754d186 feat(i18n): add Turkish (tr) language support (#678)
* feat(i18n): add Turkish (tr) language support

Add comprehensive Turkish localization for the UI, following the
existing i18n pattern established by Japanese (#384), Russian (#514),
and German (#525) language support.

Changes:
- Add Turkish translation files for all 7 namespaces
  (auth, chat, codeEditor, common, settings, sidebar, tasks)
- Register Turkish locale in config.js with all resources
- Add Turkish entry to languages.js (value: tr, nativeName: Türkçe)
- Update .gitignore to allow src/i18n/locales/tr/tasks.json
  (matches existing en/ja/ru/de exceptions)

Translation details:
- 934 total strings translated (100% coverage, matches en.json key count)
- Translated by a native Turkish speaker with software engineering
  background; terminology reviewed against conventional Turkish
  tech community usage.
- Technical terms kept in English per Turkish dev community norms:
  Claude, Cursor, Codex, Gemini, CLI, MCP, PRD, JSON, YAML, stdio,
  http, commit, branch, token, prompt, minimap, sandbox, YOLO.
- Informal second-person singular (\"sen\") used throughout — fits the
  developer-facing nature of the UI.
- All interpolation placeholders preserved exactly (e.g. {{count}},
  {{projectName}}, {{email}}).
- i18next plural keys (_one/_other) kept intact.

Verification:
- Key structure parity with en.json confirmed (jq paths diff empty)
- All 38 unique interpolation variables preserved
- npm run build passes cleanly

* docs(readme): add Turkish README and language switcher links

Add README.tr.md — full Turkish translation of the main README,
following the structure of existing README.de.md / README.ja.md /
README.ko.md / README.ru.md / README.zh-CN.md.

Update the language switcher row in all 6 existing README variants
to include a Turkish link (matches the pattern used by #534 for the
German language link addition).

---------

Co-authored-by: Simos Mikelatos <simosmik@gmail.com>
2026-04-21 14:42:37 +02:00
Pereira Ricardo
86b6545c35 feat(i18n): add Italian language support (#677)
Add complete Italian (it) translations for all 7 namespaces:
common, auth, settings, sidebar, chat, codeEditor, and tasks.

Register Italian in languages.js and i18n config.
Add .gitignore exception for it/tasks.json.

Co-authored-by: Simos Mikelatos <simosmik@gmail.com>
2026-04-21 14:40:05 +02:00
Haile
49dd3cfb23 Refactor provider runtimes for sessions, auth, and MCP management (#666)
* feat: implement MCP provider registry and service

- Add provider registry to manage LLM providers (Claude, Codex, Cursor, Gemini).
- Create provider routes for MCP server operations (list, upsert, delete, run).
- Implement MCP service for handling server operations and validations.
- Introduce abstract provider class and MCP provider base for shared functionality.
- Add tests for MCP server operations across different providers and scopes.
- Define shared interfaces and types for MCP functionality.
- Implement utility functions for handling JSON config files and API responses.

* chore: remove dead code related to MCP server

* refactor: put /api/providers in index.js and remove /providers prefix from provider.routes.ts

* refactor(settings): move MCP server management into provider module

Extract MCP server settings out of the settings controller and agents tab into a
dedicated frontend MCP module. The settings UI now delegates MCP rendering and
behavior to a single module that only needs the selected provider and current
projects.

Changes:
- Add `src/components/mcp` as the single frontend MCP module
- Move MCP server list rendering into `McpServers`
- Move MCP add/edit modal into `McpServerFormModal`
- Move MCP API/state logic into `useMcpServers`
- Move MCP form state/validation logic into `useMcpServerForm`
- Add provider-specific MCP constants, types, and formatting helpers
- Use the unified `/api/providers/:provider/mcp/servers` API for all providers
- Support MCP management for Claude, Cursor, Codex, and Gemini
- Remove old settings-owned Claude/Codex MCP modal components
- Remove old provider-specific `McpServersContent` branching from settings
- Strip MCP server state, fetch, save, delete, and modal ownership from
  `useSettingsController`
- Simplify agents settings props so MCP only receives `selectedProvider` and
  `currentProjects`
- Keep Claude working-directory unsupported while preserving cwd support for
  Cursor, Codex, and Gemini
- Add progressive MCP loading:
  - render user/global scope first
  - load project/local scopes in the background
  - append project results as they resolve
  - cache MCP lists briefly to avoid slow tab-switch refetches
  - ignore stale async responses after provider switches

Verification:
- `npx eslint src/components/mcp`
- `npm run typecheck`
- `npm run build:client`

* fix(mcp): form with multiline text handling for args, env, headers, and envVars

* feat(mcp): add global MCP server creation flow

Add a separate global MCP add path in the settings MCP module so users can create
one shared MCP server configuration across Claude, Cursor, Codex, and Gemini from
the same screen.

The provider-specific add flow is still kept next to it because these two actions
have different intent. A global MCP server must be constrained to the subset of
configuration that every provider can accept, while a provider-specific server can
still use that provider's own supported scopes, transports, and fields. Naming the
buttons as "Add Global MCP Server" and "Add <Provider> MCP Server" makes that
distinction explicit without forcing users to infer it from the selected tab.

This also moves the explanatory copy to button hover text to keep the MCP toolbar
compact while still documenting the difference between global and provider-only
adds at the point of action.

Implementation details:
- Add global MCP form mode with shared user/project scopes and stdio/http transports.
- Submit global creates through `/api/providers/mcp/servers/global`.
- Reuse the existing MCP form modal with configurable scopes, transports, labels,
  and descriptions instead of duplicating form logic.
- Disable provider-only fields for the global flow because those fields cannot be
  safely written to every provider.
- Clear the MCP server cache globally after a global add because every provider tab
  may have changed.
- Surface partial global add failures with provider-specific error messages.

Validation:
- npx eslint src/components/mcp/view/McpServers.tsx
- npm run typecheck
- npm run build:client

* feat: implement platform-specific provider visibility for cursor agent

* refactor(providers): centralize message handling in provider module

Move provider-specific normalizeMessage and fetchHistory logic out of the legacy
server/providers adapters and into the refactored provider classes so callers can
depend on the main provider contract instead of parallel adapter plumbing.

Add a providers service to resolve concrete providers through the registry and
delegate message normalization/history loading from realtime handlers and the
unified messages route. Add shared TypeScript message/history types and normalized
message helpers so provider implementations and callers use the same contract.

Remove the old adapter registry/files now that Claude, Codex, Cursor, and Gemini
implement the required behavior directly.

* refactor(providers): move auth status checks into provider runtimes

Move provider authentication status logic out of the CLI auth route so auth checks
live with the provider implementations that understand each provider's install
and credential model.

Add provider-specific auth runtime classes for Claude, Codex, Cursor, and Gemini,
and expose them through the shared provider contract as `provider.auth`. Add a
provider auth service that resolves providers through the registry and delegates
status checks via `auth.getStatus()`.

Keep the existing `/api/cli/<provider>/status` endpoints, but make them thin route
adapters over the new provider auth service. This removes duplicated route-local
credential parsing and makes auth status a first-class provider capability beside
MCP and message handling.

* refactor(providers): clarify provider auth and MCP naming

Rename provider auth/MCP contracts to remove the overloaded Runtime suffix so
the shared interfaces read as stable provider capabilities instead of execution
implementation details.

Add a consistent provider-first auth class naming convention by renaming
ClaudeAuthProvider, CodexAuthProvider, CursorAuthProvider, and GeminiAuthProvider
to ClaudeProviderAuth, CodexProviderAuth, CursorProviderAuth, and
GeminiProviderAuth.

This keeps the provider module API easier to scan and aligns auth naming with
the main provider ownership model.

* refactor(providers): move session message delegation into sessions service

Move provider-backed session history and message normalization calls out of the
generic providers service so the service name reflects the behavior it owns.

Add a dedicated sessions service for listing session-capable providers,
normalizing live provider events, and fetching persisted session history through
the provider registry. Update realtime handlers and the unified messages route to
depend on `sessionsService` instead of `providersService`.

This separates session message operations from other provider concerns such as
auth and MCP, keeping the provider services easier to navigate as the module
grows.

* refactor(providers): move auth status routes under provider API

Move provider authentication status endpoints out of the legacy `/api/cli` route
namespace so auth status is exposed through the same provider module that owns
provider auth and MCP behavior.

Add `GET /api/providers/:provider/auth/status` to the provider router and route
it through the provider auth service. Remove the old `cli-auth` route file and
`/api/cli` mount now that provider auth status is handled by the unified provider
API.

Update the frontend provider auth endpoint map to call the new provider-scoped
routes and rename the endpoint constant to reflect that it is no longer CLI
specific.

* chore(api): remove unused backend endpoints after MCP audit

Remove legacy backend routes that no longer have frontend or internal
callers, including the old Claude/Codex MCP APIs, unused Cursor and Codex
helper endpoints, stale TaskMaster detection/next/initialize routes,
and unused command/project helpers.

This reduces duplicated MCP behavior now handled by the provider-based
MCP API, shrinks the exposed backend surface, and removes probe/service
code that only existed for deleted endpoints.

Add an MCP settings API audit document to capture the route-usage
analysis and explain why the legacy MCP endpoints were considered safe
to remove.

* refactor(providers): remove debug logging from Claude authentication status checks

* refactor(cursor): lazy-load better-sqlite3 and remove unused type definitions

* refactor(cursor): remove SSE from CursorMcpProvider constructor and error message

* refactor(auth): standardize API response structure and remove unused error handling

* refactor: make providers use dedicated session handling classes

* refactor: remove legacy provider selection UI and logic

* fix(server/providers): harden and correct session history normalization/pagination

Address correctness and safety issues in provider session adapters while
preserving existing normalized message shapes.

Claude sessions:
- Ensure user text content parts generate unique normalized message ids.
- Replace duplicate `${baseId}_text` ids with index-suffixed ids to avoid
  collisions when one user message contains multiple text segments.

Cursor sessions:
- Add session id sanitization before constructing SQLite paths to prevent
  path traversal via crafted session ids.
- Enforce containment by resolving the computed DB path and asserting it stays
  under ~/.cursor/chats/<cwdId>.
- Refactor blob parsing to a two-pass flow: first build blobMap and collect
  JSON blobs, then parse binary parent refs against the fully populated map.
- Fix pagination semantics so limit=0 returns an empty page instead of full
  history, with consistent total/hasMore/offset/limit metadata.

Gemini sessions:
- Honor FetchHistoryOptions pagination by reading limit/offset and slicing
  normalized history accordingly.
- Return consistent hasMore/offset/limit metadata for paged responses.

Validation:
- eslint passed for touched files.
- server TypeScript check passed (tsc --noEmit -p server/tsconfig.json).

---------
2026-04-21 14:38:51 +02:00
simosmik
457ca0daab fix: reduce size of permission mode button tap target and provider selector on mobile 2026-04-21 12:32:09 +00:00
simosmik
09dcea05fb fix: precise Claude SDK denial message detection in deriveToolStatus 2026-04-20 15:52:09 +00:00