import { create } from 'zustand'; import { hostApiFetch } from '@/lib/host-api'; import type { ProjectConversationState, ProjectSessionMetadata, } from '../../shared/project-conversations'; type ProjectConversationResponse = { state?: ProjectConversationState; success?: boolean; error?: string; }; type ConversationAction = 'link' | 'archive' | 'restore' | 'delete' | 'read' | 'increment-unread' | 'complete'; type ProjectConversationStore = { statesByProjectId: Record; loadingProjectId: string | null; errorsByProjectId: Record; load: (projectId: string) => Promise; linkSession: (projectId: string, sessionId: string, agentId: string) => Promise; archiveSession: (projectId: string, sessionId: string) => Promise; restoreSession: (projectId: string, sessionId: string) => Promise; deleteSession: (projectId: string, sessionId: string) => Promise; markSessionRead: (projectId: string, sessionId: string) => Promise; markSessionUnread: (projectId: string, sessionId: string) => Promise; completeSession: (projectId: string, sessionId: string, incrementUnread?: boolean) => Promise; getSession: (projectId: string, sessionId: string) => ProjectSessionMetadata | undefined; remove: (projectId: string) => void; }; function emptyState(): ProjectConversationState { return { schemaVersion: 1, sessions: [], updatedAt: new Date().toISOString() }; } export const useProjectConversationStore = create((set, get) => { async function dispatch(projectId: string, sessionId: string, action: ConversationAction, agentId?: string, unread?: boolean) { const response = await hostApiFetch('/api/opencode/projects/conversations', { method: 'POST', body: JSON.stringify({ projectId, sessionId, action, ...(agentId ? { agentId } : {}), ...(unread ? { unread: true } : {}) }), }); if (!response.success || !response.state) throw new Error(response.error || '更新会话归属失败'); set((state) => ({ statesByProjectId: { ...state.statesByProjectId, [projectId]: response.state as ProjectConversationState }, errorsByProjectId: Object.fromEntries(Object.entries(state.errorsByProjectId).filter(([id]) => id !== projectId)), })); return response.state; } return { statesByProjectId: {}, loadingProjectId: null, errorsByProjectId: {}, async load(projectId) { set({ loadingProjectId: projectId }); try { const response = await hostApiFetch( `/api/opencode/projects/conversations?projectId=${encodeURIComponent(projectId)}`, ); const nextState = response.state ?? emptyState(); set((state) => ({ loadingProjectId: null, statesByProjectId: { ...state.statesByProjectId, [projectId]: nextState }, errorsByProjectId: Object.fromEntries(Object.entries(state.errorsByProjectId).filter(([id]) => id !== projectId)), })); return nextState; } catch (error) { const message = error instanceof Error ? error.message : String(error); set((state) => ({ loadingProjectId: null, errorsByProjectId: { ...state.errorsByProjectId, [projectId]: message }, })); throw error; } }, linkSession(projectId, sessionId, agentId) { return dispatch(projectId, sessionId, 'link', agentId); }, archiveSession(projectId, sessionId) { return dispatch(projectId, sessionId, 'archive'); }, restoreSession(projectId, sessionId) { return dispatch(projectId, sessionId, 'restore'); }, deleteSession(projectId, sessionId) { return dispatch(projectId, sessionId, 'delete'); }, markSessionRead(projectId, sessionId) { return dispatch(projectId, sessionId, 'read'); }, markSessionUnread(projectId, sessionId) { return dispatch(projectId, sessionId, 'increment-unread'); }, completeSession(projectId, sessionId, incrementUnread = false) { return dispatch(projectId, sessionId, 'complete', undefined, incrementUnread); }, getSession(projectId, sessionId) { return get().statesByProjectId[projectId]?.sessions.find((item) => item.sessionId === sessionId); }, remove(projectId) { set((state) => ({ statesByProjectId: Object.fromEntries(Object.entries(state.statesByProjectId).filter(([id]) => id !== projectId)), errorsByProjectId: Object.fromEntries(Object.entries(state.errorsByProjectId).filter(([id]) => id !== projectId)), })); }, }; });