feat(app): daemon-sourced Event Center feed, read-model, bell badge

Source Event Center from daemon event_log (seed + live event/events_read push).
Unread/Errors tabs filter real EventRecord flags; bell shows numeric unread badge;
clicking an entry calls focusSurface + markEventsRead(ids). notify.ts param widened
to string so exit kind type-checks without breaking existing NOTIFY_STATES guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 08:23:26 +07:00
parent d08a446b6f
commit 834d61c69a
5 changed files with 113 additions and 53 deletions
+27 -1
View File
@@ -62,6 +62,30 @@ export async function getStatus(): Promise<WorkspaceStatus[]> {
return data.workspaces;
}
export interface EventRecord {
id: number;
surface_id: string;
workspace_id: string;
workspace_name: string;
agent_label: string | null;
kind: "done" | "wait" | "error" | "exit";
ts: number;
read: boolean;
}
export type MarkReadTarget =
| { target: "all" }
| { target: "ids"; value: number[] }
| { target: "surface"; value: string };
export async function getEventLog(limit?: number): Promise<{ events: EventRecord[]; unread: number }> {
return await invoke<{ events: EventRecord[]; unread: number }>("event_log", { limit: limit ?? null });
}
export async function markEventsRead(target: MarkReadTarget): Promise<void> {
await invoke("mark_read", { target });
}
export type DaemonEvt =
| { evt: "exit"; data: { surface_id: string; code: number } }
| { evt: "surface_created"; data: { surface_id: string; workspace_id: string } }
@@ -69,7 +93,9 @@ export type DaemonEvt =
| { evt: "state"; data: { surface_id: string; state: import("./layoutTypes").SurfaceState } }
| { evt: "layout_changed"; data: { workspace_id: string } }
| { evt: "workspace_changed"; data: unknown }
| { evt: "groups_changed"; data: unknown };
| { evt: "groups_changed"; data: unknown }
| { evt: "event"; data: { record: EventRecord } }
| { evt: "events_read"; data: { ids: number[] } };
export function onDaemonEvent(handler: (evt: DaemonEvt) => void): Promise<() => void> {
return listen<DaemonEvt>("spacesh:evt", (e) => handler(e.payload));