mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-16 22:59:04 +02:00
State management - Pending task / live timeline are now Query-cache single source; Zustand mirror removed (fixes duplicate assistant render caused by the invalidate→refetch race window) - WS subscriptions moved from ChatWindow to global useRealtimeSync so pending state survives minimize and refresh - New GET /chat/sessions/:id/pending-task to recover live state on mount - Drafts persisted per-session (was per-workspace) Unread tracking - Migration 040: chat_session.unread_since (event-driven; old chats stay clean — no mass backfill) - POST /chat/sessions/:id/read clears unread; broadcasts chat:session_read so other devices sync - New GET /chat/pending-tasks aggregate for the FAB - ChatFab: brand-color impulse animation while running, brand-dot badge of unread session count - ChatWindow auto-marks read when user is viewing the session Header redesign - Two independent dropdowns: agent (avatar + name + My/Others grouping) at the input bottom-left; session (title + agent avatar) in the header - ⊕ new-chat button replaces the old + and history buttons - Session dropdown lists all sessions across agents with avatars - Empty state: 3 clickable starter prompts that send immediately - Mention link renderer falls through to default span on null — fixes @member/@agent/@all silently disappearing app-wide - User messages render through Markdown - Enter submits in chat input only (with IME guard + codeBlock skip); bubble menu hidden in chat Misc - Partial index on agent_task_queue for fast pending-task lookup - 2 new storage keys added to clearWorkspaceStorage - useMarkChatSessionRead has onError rollback - chat.* namespace logs across store, mutations, components, realtime Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
export { createChatStore, CHAT_MIN_W, CHAT_MIN_H, CHAT_DEFAULT_W, CHAT_DEFAULT_H, DRAFT_NEW_SESSION } from "./store";
|
|
export type { ChatStoreOptions, ChatState, ChatTimelineItem } from "./store";
|
|
|
|
import type { createChatStore as CreateChatStoreFn } from "./store";
|
|
|
|
type ChatStoreInstance = ReturnType<typeof CreateChatStoreFn>;
|
|
|
|
/** Module-level singleton — set once at app boot via `registerChatStore()`. */
|
|
let _store: ChatStoreInstance | null = null;
|
|
|
|
/**
|
|
* Register the chat store instance created by the app.
|
|
* Must be called at boot before any component renders.
|
|
*/
|
|
export function registerChatStore(store: ChatStoreInstance) {
|
|
_store = store;
|
|
}
|
|
|
|
/**
|
|
* Singleton accessor — a Zustand hook backed by the registered instance.
|
|
* Supports `useChatStore(selector)` and `useChatStore.getState()`.
|
|
*/
|
|
export const useChatStore: ChatStoreInstance = new Proxy(
|
|
(() => {}) as unknown as ChatStoreInstance,
|
|
{
|
|
apply(_target, _thisArg, args) {
|
|
if (!_store)
|
|
throw new Error(
|
|
"Chat store not initialised — call registerChatStore() first",
|
|
);
|
|
return (_store as unknown as (...a: unknown[]) => unknown)(...args);
|
|
},
|
|
get(_target, prop) {
|
|
if (!_store) return undefined;
|
|
return Reflect.get(_store, prop);
|
|
},
|
|
},
|
|
);
|