export type LLMProvider = 'claude' | 'cursor' | 'codex' | 'gemini'; export type AppTab = 'chat' | 'files' | 'shell' | 'git' | 'tasks' | 'preview' | `plugin:${string}`; export interface ProjectSession { id: string; title?: string; summary?: string; name?: string; createdAt?: string; created_at?: string; updated_at?: string; lastActivity?: string; messageCount?: number; __provider?: LLMProvider; // Tags the session with the owning project's DB `projectId` so UI handlers // (session switching, sidebar focus, etc.) can match against selectedProject. __projectId?: string; [key: string]: unknown; } export interface ProjectSessionMeta { total?: number; hasMore?: boolean; [key: string]: unknown; } export interface ProjectTaskmasterInfo { hasTaskmaster?: boolean; status?: string; metadata?: Record; [key: string]: unknown; } // After the projectName → projectId migration the backend no longer returns a // folder-derived `name` string. Projects are now addressed everywhere by the // DB-assigned `projectId` (primary key in the `projects` table), and the UI // uses the same identifier for routing, state keys and API calls. export interface Project { projectId: string; displayName: string; fullPath: string; path?: string; isStarred?: boolean; sessions?: ProjectSession[]; cursorSessions?: ProjectSession[]; codexSessions?: ProjectSession[]; geminiSessions?: ProjectSession[]; sessionMeta?: ProjectSessionMeta; taskmaster?: ProjectTaskmasterInfo; [key: string]: unknown; } export interface LoadingProgress { type?: 'loading_progress'; phase?: string; current: number; total: number; currentProject?: string; [key: string]: unknown; } export interface ProjectsUpdatedMessage { type: 'projects_updated'; projects: Project[]; updatedSessionId?: string; [key: string]: unknown; } export interface LoadingProgressMessage extends LoadingProgress { type: 'loading_progress'; } export type AppSocketMessage = | LoadingProgressMessage | ProjectsUpdatedMessage | { type?: string;[key: string]: unknown };