// Tiny in-app event bus for session metadata changes that need to propagate // across hooks (e.g. AI rename arriving via WS in the session view needs to // also refresh the sidebar's session list). import type { Chat, Project, Session } from '@/api/types'; import type { Attachment } from '@/lib/attachments'; export interface SessionRenamedEvent { type: 'session_renamed'; session_id: string; name: string; } export interface ProjectCreatedEvent { type: 'project_created'; project: Project; } export interface ProjectDeletedEvent { type: 'project_deleted'; project_id: string; } export interface SessionCreatedEvent { type: 'session_created'; session: Session; project_id: string; } export interface SessionDeletedEvent { type: 'session_deleted'; session_id: string; project_id: string; } export interface SessionUpdatedEvent { type: 'session_updated'; session_id: string; project_id: string; name: string; updated_at: string; } export interface SessionLoadedEvent { type: 'session_loaded'; session_id: string; project_id: string; } export interface OpenFileInBrowserEvent { type: 'open_file_in_browser'; path: string; // project-relative } export interface AttachChatFileEvent { type: 'attach_chat_file'; attachment: Omit; } export interface OpenChatInActivePaneEvent { type: 'open_chat_in_active_pane'; chat_id: string; } export interface SessionArchivedEvent { type: 'session_archived'; session_id: string; project_id: string; } export interface ChatCreatedEvent { type: 'chat_created'; chat: Chat; session_id: string; } export interface ChatUpdatedEvent { type: 'chat_updated'; chat_id: string; session_id: string; name: string | null; updated_at: string; } export interface ChatArchivedEvent { type: 'chat_archived'; chat_id: string; session_id: string; } export interface ChatUnarchivedEvent { type: 'chat_unarchived'; chat: Chat; } export interface ChatDeletedEvent { type: 'chat_deleted'; chat_id: string; session_id: string; } export interface ProjectArchivedEvent { type: 'project_archived'; project_id: string; } export interface ProjectUnarchivedEvent { type: 'project_unarchived'; project: Project; } export interface ProjectUpdatedEvent { type: 'project_updated'; project_id: string; name: string; } export type SessionEvent = | SessionRenamedEvent | ProjectCreatedEvent | ProjectDeletedEvent | SessionCreatedEvent | SessionDeletedEvent | SessionUpdatedEvent | SessionLoadedEvent | OpenFileInBrowserEvent | AttachChatFileEvent | OpenChatInActivePaneEvent | SessionArchivedEvent | ChatCreatedEvent | ChatUpdatedEvent | ChatArchivedEvent | ChatUnarchivedEvent | ChatDeletedEvent | ProjectArchivedEvent | ProjectUnarchivedEvent | ProjectUpdatedEvent; type Listener = (event: SessionEvent) => void; const listeners = new Set(); export const sessionEvents = { emit(event: SessionEvent) { for (const listener of listeners) { try { listener(event); } catch { // swallow — one bad listener shouldn't break others } } }, subscribe(listener: Listener): () => void { listeners.add(listener); return () => { listeners.delete(listener); }; }, };