@schlessera/brain-ui-react 0.34.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/README.md +12 -0
  2. package/dist/components/activity/activity-page.d.ts.map +1 -1
  3. package/dist/components/activity/activity-page.js +8 -149
  4. package/dist/components/activity/activity-page.js.map +1 -1
  5. package/dist/components/activity/activity-rollups.d.ts +5 -0
  6. package/dist/components/activity/activity-rollups.d.ts.map +1 -0
  7. package/dist/components/activity/activity-rollups.js +39 -0
  8. package/dist/components/activity/activity-rollups.js.map +1 -0
  9. package/dist/components/activity/activity-run-detail.d.ts +11 -0
  10. package/dist/components/activity/activity-run-detail.d.ts.map +1 -0
  11. package/dist/components/activity/activity-run-detail.js +111 -0
  12. package/dist/components/activity/activity-run-detail.js.map +1 -0
  13. package/dist/components/activity/activity-run-list.d.ts +15 -0
  14. package/dist/components/activity/activity-run-list.d.ts.map +1 -0
  15. package/dist/components/activity/activity-run-list.js +25 -0
  16. package/dist/components/activity/activity-run-list.js.map +1 -0
  17. package/dist/components/chat/brain-markdown-code.d.ts +4 -0
  18. package/dist/components/chat/brain-markdown-code.d.ts.map +1 -0
  19. package/dist/components/chat/brain-markdown-code.js +47 -0
  20. package/dist/components/chat/brain-markdown-code.js.map +1 -0
  21. package/dist/components/chat/brain-markdown-entities.d.ts +14 -0
  22. package/dist/components/chat/brain-markdown-entities.d.ts.map +1 -0
  23. package/dist/components/chat/brain-markdown-entities.js +93 -0
  24. package/dist/components/chat/brain-markdown-entities.js.map +1 -0
  25. package/dist/components/chat/brain-markdown-links.d.ts +36 -0
  26. package/dist/components/chat/brain-markdown-links.d.ts.map +1 -0
  27. package/dist/components/chat/brain-markdown-links.js +176 -0
  28. package/dist/components/chat/brain-markdown-links.js.map +1 -0
  29. package/dist/components/chat/brain-markdown-share.d.ts +15 -0
  30. package/dist/components/chat/brain-markdown-share.d.ts.map +1 -0
  31. package/dist/components/chat/brain-markdown-share.js +40 -0
  32. package/dist/components/chat/brain-markdown-share.js.map +1 -0
  33. package/dist/components/chat/brain-markdown.d.ts +1 -34
  34. package/dist/components/chat/brain-markdown.d.ts.map +1 -1
  35. package/dist/components/chat/brain-markdown.js +9 -402
  36. package/dist/components/chat/brain-markdown.js.map +1 -1
  37. package/dist/components/chat/composer.d.ts.map +1 -1
  38. package/dist/components/chat/composer.js +14 -1
  39. package/dist/components/chat/composer.js.map +1 -1
  40. package/dist/components/chat/session-drawer.d.ts.map +1 -1
  41. package/dist/components/chat/session-drawer.js +25 -10
  42. package/dist/components/chat/session-drawer.js.map +1 -1
  43. package/dist/components/chat/tool-views.d.ts +2 -2
  44. package/dist/components/chat/tool-views.d.ts.map +1 -1
  45. package/dist/components/chat/tool-views.js +2 -16
  46. package/dist/components/chat/tool-views.js.map +1 -1
  47. package/dist/components/chat/use-markdown-highlight.d.ts +12 -0
  48. package/dist/components/chat/use-markdown-highlight.d.ts.map +1 -0
  49. package/dist/components/chat/use-markdown-highlight.js +56 -0
  50. package/dist/components/chat/use-markdown-highlight.js.map +1 -0
  51. package/dist/components/connectivity/connection-gate.d.ts.map +1 -1
  52. package/dist/components/connectivity/connection-gate.js +94 -8
  53. package/dist/components/connectivity/connection-gate.js.map +1 -1
  54. package/dist/components/connectivity/connection-state.d.ts +12 -0
  55. package/dist/components/connectivity/connection-state.d.ts.map +1 -0
  56. package/dist/components/connectivity/connection-state.js +23 -0
  57. package/dist/components/connectivity/connection-state.js.map +1 -0
  58. package/dist/components/graph/graph-canvas-lazy.d.ts +2 -0
  59. package/dist/components/graph/graph-canvas-lazy.d.ts.map +1 -0
  60. package/dist/components/graph/graph-canvas-lazy.js +4 -0
  61. package/dist/components/graph/graph-canvas-lazy.js.map +1 -0
  62. package/dist/components/graph/graph-controls.js +4 -1
  63. package/dist/components/graph/graph-controls.js.map +1 -1
  64. package/dist/components/graph/graph-maintenance.d.ts +8 -0
  65. package/dist/components/graph/graph-maintenance.d.ts.map +1 -0
  66. package/dist/components/graph/graph-maintenance.js +115 -0
  67. package/dist/components/graph/graph-maintenance.js.map +1 -0
  68. package/dist/components/graph/graph-page.d.ts.map +1 -1
  69. package/dist/components/graph/graph-page.js +11 -306
  70. package/dist/components/graph/graph-page.js.map +1 -1
  71. package/dist/components/graph/graph-scene.d.ts +8 -0
  72. package/dist/components/graph/graph-scene.d.ts.map +1 -0
  73. package/dist/components/graph/graph-scene.js +208 -0
  74. package/dist/components/graph/graph-scene.js.map +1 -0
  75. package/dist/components/graph/graph-spinner.d.ts +2 -0
  76. package/dist/components/graph/graph-spinner.d.ts.map +1 -0
  77. package/dist/components/graph/graph-spinner.js +6 -0
  78. package/dist/components/graph/graph-spinner.js.map +1 -0
  79. package/dist/components/layout/app-shell.d.ts.map +1 -1
  80. package/dist/components/layout/app-shell.js +2 -1
  81. package/dist/components/layout/app-shell.js.map +1 -1
  82. package/dist/components/quick-actions/add-modal.d.ts.map +1 -1
  83. package/dist/components/quick-actions/add-modal.js +47 -4
  84. package/dist/components/quick-actions/add-modal.js.map +1 -1
  85. package/dist/components/quick-actions/search-modal.d.ts.map +1 -1
  86. package/dist/components/quick-actions/search-modal.js +46 -18
  87. package/dist/components/quick-actions/search-modal.js.map +1 -1
  88. package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -1
  89. package/dist/components/quick-actions/streaming-modal.js +4 -1
  90. package/dist/components/quick-actions/streaming-modal.js.map +1 -1
  91. package/dist/components/settings/devices-agents-tab.d.ts +5 -0
  92. package/dist/components/settings/devices-agents-tab.d.ts.map +1 -0
  93. package/dist/components/settings/devices-agents-tab.js +96 -0
  94. package/dist/components/settings/devices-agents-tab.js.map +1 -0
  95. package/dist/components/settings/one-time-agent-credential.d.ts +3 -0
  96. package/dist/components/settings/one-time-agent-credential.d.ts.map +1 -0
  97. package/dist/components/settings/one-time-agent-credential.js +55 -0
  98. package/dist/components/settings/one-time-agent-credential.js.map +1 -0
  99. package/dist/components/settings/settings-panel.d.ts.map +1 -1
  100. package/dist/components/settings/settings-panel.js +16 -3
  101. package/dist/components/settings/settings-panel.js.map +1 -1
  102. package/dist/hooks/use-vpn-status.d.ts +6 -1
  103. package/dist/hooks/use-vpn-status.d.ts.map +1 -1
  104. package/dist/hooks/use-vpn-status.js +67 -30
  105. package/dist/hooks/use-vpn-status.js.map +1 -1
  106. package/dist/hooks/use-websocket.d.ts +3 -2
  107. package/dist/hooks/use-websocket.d.ts.map +1 -1
  108. package/dist/hooks/use-websocket.js +65 -254
  109. package/dist/hooks/use-websocket.js.map +1 -1
  110. package/dist/hooks/websocket-handlers/activity.d.ts +5 -0
  111. package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -0
  112. package/dist/hooks/websocket-handlers/activity.js +10 -0
  113. package/dist/hooks/websocket-handlers/activity.js.map +1 -0
  114. package/dist/hooks/websocket-handlers/chat.d.ts +17 -0
  115. package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -0
  116. package/dist/hooks/websocket-handlers/chat.js +175 -0
  117. package/dist/hooks/websocket-handlers/chat.js.map +1 -0
  118. package/dist/hooks/websocket-handlers/connection.d.ts +6 -0
  119. package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -0
  120. package/dist/hooks/websocket-handlers/connection.js +27 -0
  121. package/dist/hooks/websocket-handlers/connection.js.map +1 -0
  122. package/dist/hooks/websocket-handlers/index.d.ts +4 -0
  123. package/dist/hooks/websocket-handlers/index.d.ts.map +1 -0
  124. package/dist/hooks/websocket-handlers/index.js +19 -0
  125. package/dist/hooks/websocket-handlers/index.js.map +1 -0
  126. package/dist/hooks/websocket-handlers/mask.d.ts +4 -0
  127. package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -0
  128. package/dist/hooks/websocket-handlers/mask.js +14 -0
  129. package/dist/hooks/websocket-handlers/mask.js.map +1 -0
  130. package/dist/hooks/websocket-handlers/provider.d.ts +4 -0
  131. package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -0
  132. package/dist/hooks/websocket-handlers/provider.js +31 -0
  133. package/dist/hooks/websocket-handlers/provider.js.map +1 -0
  134. package/dist/hooks/websocket-handlers/types.d.ts +24 -0
  135. package/dist/hooks/websocket-handlers/types.d.ts.map +1 -0
  136. package/dist/hooks/websocket-handlers/types.js +2 -0
  137. package/dist/hooks/websocket-handlers/types.js.map +1 -0
  138. package/dist/lib/api-client.d.ts +32 -0
  139. package/dist/lib/api-client.d.ts.map +1 -1
  140. package/dist/lib/api-client.js +11 -0
  141. package/dist/lib/api-client.js.map +1 -1
  142. package/dist/lib/format-time.d.ts +3 -0
  143. package/dist/lib/format-time.d.ts.map +1 -0
  144. package/dist/lib/format-time.js +25 -0
  145. package/dist/lib/format-time.js.map +1 -0
  146. package/dist/lib/push-registration.d.ts +7 -0
  147. package/dist/lib/push-registration.d.ts.map +1 -0
  148. package/dist/lib/push-registration.js +26 -0
  149. package/dist/lib/push-registration.js.map +1 -0
  150. package/dist/stores/activity-store-helpers.d.ts +50 -0
  151. package/dist/stores/activity-store-helpers.d.ts.map +1 -0
  152. package/dist/stores/activity-store-helpers.js +143 -0
  153. package/dist/stores/activity-store-helpers.js.map +1 -0
  154. package/dist/stores/activity-store-types.d.ts +48 -0
  155. package/dist/stores/activity-store-types.d.ts.map +1 -0
  156. package/dist/stores/activity-store-types.js +2 -0
  157. package/dist/stores/activity-store-types.js.map +1 -0
  158. package/dist/stores/activity-store.d.ts +2 -78
  159. package/dist/stores/activity-store.d.ts.map +1 -1
  160. package/dist/stores/activity-store.js +22 -142
  161. package/dist/stores/activity-store.js.map +1 -1
  162. package/dist/stores/connection-store.d.ts +14 -2
  163. package/dist/stores/connection-store.d.ts.map +1 -1
  164. package/dist/stores/connection-store.js +17 -0
  165. package/dist/stores/connection-store.js.map +1 -1
  166. package/dist/stores/file-store.d.ts.map +1 -1
  167. package/dist/stores/file-store.js +54 -18
  168. package/dist/stores/file-store.js.map +1 -1
  169. package/dist/stores/principal-store.d.ts +16 -0
  170. package/dist/stores/principal-store.d.ts.map +1 -0
  171. package/dist/stores/principal-store.js +29 -0
  172. package/dist/stores/principal-store.js.map +1 -0
  173. package/dist/stores/ui-store.d.ts +1 -1
  174. package/dist/stores/ui-store.d.ts.map +1 -1
  175. package/dist/styles.css +1 -1
  176. package/package.json +2 -2
  177. package/src/components/activity/activity-page.tsx +6 -477
  178. package/src/components/activity/activity-rollups.tsx +94 -0
  179. package/src/components/activity/activity-run-detail.tsx +301 -0
  180. package/src/components/activity/activity-run-list.tsx +97 -0
  181. package/src/components/chat/brain-markdown-code.tsx +60 -0
  182. package/src/components/chat/brain-markdown-entities.tsx +116 -0
  183. package/src/components/chat/brain-markdown-links.tsx +247 -0
  184. package/src/components/chat/brain-markdown-share.ts +47 -0
  185. package/src/components/chat/brain-markdown.tsx +27 -535
  186. package/src/components/chat/composer.tsx +14 -1
  187. package/src/components/chat/session-drawer.tsx +29 -10
  188. package/src/components/chat/tool-views.tsx +2 -13
  189. package/src/components/chat/use-markdown-highlight.ts +63 -0
  190. package/src/components/connectivity/connection-gate.tsx +128 -14
  191. package/src/components/connectivity/connection-state.ts +37 -0
  192. package/src/components/graph/graph-canvas-lazy.tsx +4 -0
  193. package/src/components/graph/graph-controls.tsx +4 -1
  194. package/src/components/graph/graph-maintenance.tsx +304 -0
  195. package/src/components/graph/graph-page.tsx +11 -840
  196. package/src/components/graph/graph-scene.tsx +548 -0
  197. package/src/components/graph/graph-spinner.tsx +9 -0
  198. package/src/components/layout/app-shell.tsx +2 -0
  199. package/src/components/quick-actions/add-modal.tsx +49 -4
  200. package/src/components/quick-actions/search-modal.tsx +46 -18
  201. package/src/components/quick-actions/streaming-modal.tsx +3 -1
  202. package/src/components/settings/devices-agents-tab.tsx +231 -0
  203. package/src/components/settings/one-time-agent-credential.tsx +131 -0
  204. package/src/components/settings/settings-panel.tsx +20 -5
  205. package/src/hooks/use-vpn-status.ts +71 -31
  206. package/src/hooks/use-websocket.ts +74 -275
  207. package/src/hooks/websocket-handlers/activity.ts +13 -0
  208. package/src/hooks/websocket-handlers/chat.ts +210 -0
  209. package/src/hooks/websocket-handlers/connection.ts +30 -0
  210. package/src/hooks/websocket-handlers/index.ts +59 -0
  211. package/src/hooks/websocket-handlers/mask.ts +17 -0
  212. package/src/hooks/websocket-handlers/provider.ts +35 -0
  213. package/src/hooks/websocket-handlers/types.ts +27 -0
  214. package/src/lib/api-client.ts +40 -1
  215. package/src/lib/format-time.ts +20 -0
  216. package/src/lib/push-registration.ts +29 -0
  217. package/src/stores/activity-store-helpers.ts +164 -0
  218. package/src/stores/activity-store-types.ts +55 -0
  219. package/src/stores/activity-store.ts +21 -217
  220. package/src/stores/connection-store.ts +33 -2
  221. package/src/stores/file-store.ts +42 -12
  222. package/src/stores/principal-store.ts +38 -0
  223. package/src/stores/ui-store.ts +1 -1
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Re-assert an existing browser subscription after authentication changes.
3
+ * This does not request permission or create a subscription: it only binds an
4
+ * already-enabled endpoint to the newly issued server principal.
5
+ */
6
+ export declare function rebindPushSubscriptionAfterLogin(): Promise<void>;
7
+ //# sourceMappingURL=push-registration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-registration.d.ts","sourceRoot":"","sources":["../../src/lib/push-registration.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBtE"}
@@ -0,0 +1,26 @@
1
+ import { api } from "./api-client.js";
2
+ /**
3
+ * Re-assert an existing browser subscription after authentication changes.
4
+ * This does not request permission or create a subscription: it only binds an
5
+ * already-enabled endpoint to the newly issued server principal.
6
+ */
7
+ export async function rebindPushSubscriptionAfterLogin() {
8
+ if (typeof Notification === "undefined" ||
9
+ Notification.permission !== "granted" ||
10
+ typeof navigator === "undefined" ||
11
+ !("serviceWorker" in navigator)) {
12
+ return;
13
+ }
14
+ // Capture before awaiting: the page may begin navigating immediately after
15
+ // login while the service-worker readiness promise settles.
16
+ const serviceWorker = navigator.serviceWorker;
17
+ const label = typeof navigator.userAgent === "string"
18
+ ? navigator.userAgent.slice(0, 100)
19
+ : undefined;
20
+ const registration = await serviceWorker.ready;
21
+ const subscription = await registration.pushManager.getSubscription();
22
+ if (!subscription)
23
+ return;
24
+ await api.pushSubscribe(subscription.toJSON(), label);
25
+ }
26
+ //# sourceMappingURL=push-registration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-registration.js","sourceRoot":"","sources":["../../src/lib/push-registration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC;IACpD,IACE,OAAO,YAAY,KAAK,WAAW;QACnC,YAAY,CAAC,UAAU,KAAK,SAAS;QACrC,OAAO,SAAS,KAAK,WAAW;QAChC,CAAC,CAAC,eAAe,IAAI,SAAS,CAAC,EAC/B,CAAC;QACD,OAAO;IACT,CAAC;IAED,2EAA2E;IAC3E,4DAA4D;IAC5D,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,CAAC;IAC9C,MAAM,KAAK,GACT,OAAO,SAAS,CAAC,SAAS,KAAK,QAAQ;QACrC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QACnC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC;IAC/C,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC;IACtE,IAAI,CAAC,YAAY;QAAE,OAAO;IAC1B,MAAM,GAAG,CAAC,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { ActivitySpan, ActivitySpanEvent } from "@schlessera/brain-ui-sdk/protocol";
2
+ import type { ActivityState, MirrorMaps } from "./activity-store-types.js";
3
+ export declare function rootSpanOf(byId: Record<string, ActivitySpan>): ActivitySpan | undefined;
4
+ /** Drop a whole run from the mirror — spans, events, high-water, reverse index. */
5
+ export declare function evictRun(maps: MirrorMaps, runId: string): void;
6
+ /**
7
+ * Enforce the terminal-run bound in place. Returns whether anything was
8
+ * evicted. Runs whose root span is still open (or unknown) are never touched.
9
+ */
10
+ export declare function pruneTerminalRuns(maps: MirrorMaps): boolean;
11
+ export declare function insertEvent(list: ActivitySpanEvent[] | undefined, event: ActivitySpanEvent): ActivitySpanEvent[];
12
+ /** All spans of a run, roots first, then by start time. */
13
+ export declare function runSpans(state: ActivityState, runId: string): ActivitySpan[];
14
+ /** Direct children of a span (e.g. the tool calls inside a subagent). */
15
+ export declare function childSpans(state: ActivityState, parentSpanId: string): ActivitySpan[];
16
+ /** The subagent spans spawned by a turn's Agent tool calls, live status included. */
17
+ export declare function subagentSpans(state: ActivityState, sessionId: string): ActivitySpan[];
18
+ /** Stable empty result for `eventsFor` — a fresh `[]` per call would defeat
19
+ * reference-equality checks in zustand selectors. */
20
+ export declare const EMPTY_EVENTS: ActivitySpanEvent[];
21
+ /** Ordered events of a span; the shared frozen empty array when none. */
22
+ export declare function eventsFor(state: ActivityState, spanId: string): ActivitySpanEvent[];
23
+ /**
24
+ * The recorded input/output payload events of a tool span (AE7). Returns a
25
+ * fresh array per call — subscribe through `useShallow` (like `childSpans`).
26
+ */
27
+ export declare function payloadEventsFor(state: ActivityState, spanId: string): ActivitySpanEvent[];
28
+ /**
29
+ * Everything recorded against a span that is NOT a tool input/output payload:
30
+ * transcript excerpts, job output, and any span-sink event type a producer
31
+ * invents. Rendered as the span's narrative so an unknown type degrades to a
32
+ * labelled block rather than to invisibility.
33
+ */
34
+ export declare function narrativeEventsFor(state: ActivityState, spanId: string): ActivitySpanEvent[];
35
+ /** Every event recorded under a run, ordered by time — the run detail's
36
+ * narrative stream and the raw-trace dump both read through this. */
37
+ export declare function runEvents(state: ActivityState, runId: string): ActivitySpanEvent[];
38
+ /** The span behind one tool call (span ids ARE toolUseIds), if streamed. */
39
+ export declare function spanForTool(state: ActivityState, toolUseId: string): ActivitySpan | null;
40
+ /**
41
+ * Server-stamped timing for a tool call. One clock for live and reloaded
42
+ * views: when the activity stream carries the span, its timestamps win over
43
+ * client stamps (AE2 — live and revisit must render identical timings).
44
+ * `waitUntil` marks the approval-wait/execution boundary.
45
+ */
46
+ export declare function timingFor(state: ActivityState, toolUseId: string): {
47
+ startedAt: number;
48
+ endedAt?: number;
49
+ } | null;
50
+ //# sourceMappingURL=activity-store-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-store-helpers.d.ts","sourceRoot":"","sources":["../../src/stores/activity-store-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAK3E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,YAAY,GAAG,SAAS,CAEvF;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQ9D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAc3D;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,iBAAiB,EAAE,GAAG,SAAS,EACrC,KAAK,EAAE,iBAAiB,GACvB,iBAAiB,EAAE,CAMrB;AAID,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAO5E;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,EAAE,CAMrF;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAQrF;AAED;sDACsD;AACtD,eAAO,MAAM,YAAY,EAAE,iBAAiB,EAEpB,CAAC;AAEzB,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAEnF;AAOD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAK1F;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,MAAM,GACb,iBAAiB,EAAE,CAKrB;AAED;sEACsE;AACtE,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAUlF;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAGxF;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,MAAM,GAChB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAOhD"}
@@ -0,0 +1,143 @@
1
+ /** Bound on the mirror: how many TERMINAL runs stay held. Live runs never count. */
2
+ const MAX_TERMINAL_RUNS = 50;
3
+ export function rootSpanOf(byId) {
4
+ return Object.values(byId).find((span) => span.parentSpanId === undefined);
5
+ }
6
+ /** Drop a whole run from the mirror — spans, events, high-water, reverse index. */
7
+ export function evictRun(maps, runId) {
8
+ for (const spanId of Object.keys(maps.spans[runId] ?? {})) {
9
+ delete maps.events[spanId];
10
+ delete maps.spanRun[spanId];
11
+ }
12
+ delete maps.spans[runId];
13
+ delete maps.highWater[runId];
14
+ delete maps.deltaSeq[runId];
15
+ }
16
+ /**
17
+ * Enforce the terminal-run bound in place. Returns whether anything was
18
+ * evicted. Runs whose root span is still open (or unknown) are never touched.
19
+ */
20
+ export function pruneTerminalRuns(maps) {
21
+ const terminal = [];
22
+ for (const [runId, byId] of Object.entries(maps.spans)) {
23
+ const root = rootSpanOf(byId);
24
+ if (root && root.outcome !== undefined) {
25
+ terminal.push({ runId, startedAt: root.startedAt });
26
+ }
27
+ }
28
+ if (terminal.length <= MAX_TERMINAL_RUNS)
29
+ return false;
30
+ terminal.sort((a, b) => a.startedAt - b.startedAt);
31
+ for (const { runId } of terminal.slice(0, terminal.length - MAX_TERMINAL_RUNS)) {
32
+ evictRun(maps, runId);
33
+ }
34
+ return true;
35
+ }
36
+ export function insertEvent(list, event) {
37
+ const existing = list ?? [];
38
+ if (existing.some((e) => e.eventIndex === event.eventIndex))
39
+ return existing;
40
+ const next = [...existing, event];
41
+ next.sort((a, b) => a.eventIndex - b.eventIndex);
42
+ return next;
43
+ }
44
+ // --- Selectors (plain functions over the state, like activeChat) ---
45
+ /** All spans of a run, roots first, then by start time. */
46
+ export function runSpans(state, runId) {
47
+ const byId = state.spans[runId];
48
+ if (!byId)
49
+ return [];
50
+ return Object.values(byId).sort((a, b) => (a.parentSpanId ? 1 : 0) - (b.parentSpanId ? 1 : 0) || a.startedAt - b.startedAt);
51
+ }
52
+ /** Direct children of a span (e.g. the tool calls inside a subagent). */
53
+ export function childSpans(state, parentSpanId) {
54
+ const runId = state.spanRun[parentSpanId];
55
+ if (!runId)
56
+ return [];
57
+ return Object.values(state.spans[runId] ?? {})
58
+ .filter((s) => s.parentSpanId === parentSpanId)
59
+ .sort((a, b) => a.startedAt - b.startedAt);
60
+ }
61
+ /** The subagent spans spawned by a turn's Agent tool calls, live status included. */
62
+ export function subagentSpans(state, sessionId) {
63
+ const out = [];
64
+ for (const byId of Object.values(state.spans)) {
65
+ for (const span of Object.values(byId)) {
66
+ if (span.kind === "subagent" && span.sessionId === sessionId)
67
+ out.push(span);
68
+ }
69
+ }
70
+ return out.sort((a, b) => a.startedAt - b.startedAt);
71
+ }
72
+ /** Stable empty result for `eventsFor` — a fresh `[]` per call would defeat
73
+ * reference-equality checks in zustand selectors. */
74
+ export const EMPTY_EVENTS = Object.freeze([]);
75
+ /** Ordered events of a span; the shared frozen empty array when none. */
76
+ export function eventsFor(state, spanId) {
77
+ return state.events[spanId] ?? EMPTY_EVENTS;
78
+ }
79
+ /** Payload event types the tool expander owns — every OTHER type belongs to
80
+ * the narrative stream (`narrativeEventsFor`) so nothing recorded is
81
+ * rendered nowhere. */
82
+ const TOOL_PAYLOAD_TYPES = new Set(["tool_input", "tool_output"]);
83
+ /**
84
+ * The recorded input/output payload events of a tool span (AE7). Returns a
85
+ * fresh array per call — subscribe through `useShallow` (like `childSpans`).
86
+ */
87
+ export function payloadEventsFor(state, spanId) {
88
+ const events = state.events[spanId];
89
+ if (!events)
90
+ return EMPTY_EVENTS;
91
+ const payloads = events.filter((e) => TOOL_PAYLOAD_TYPES.has(e.eventType));
92
+ return payloads.length > 0 ? payloads : EMPTY_EVENTS;
93
+ }
94
+ /**
95
+ * Everything recorded against a span that is NOT a tool input/output payload:
96
+ * transcript excerpts, job output, and any span-sink event type a producer
97
+ * invents. Rendered as the span's narrative so an unknown type degrades to a
98
+ * labelled block rather than to invisibility.
99
+ */
100
+ export function narrativeEventsFor(state, spanId) {
101
+ const events = state.events[spanId];
102
+ if (!events)
103
+ return EMPTY_EVENTS;
104
+ const rest = events.filter((e) => !TOOL_PAYLOAD_TYPES.has(e.eventType));
105
+ return rest.length > 0 ? rest : EMPTY_EVENTS;
106
+ }
107
+ /** Every event recorded under a run, ordered by time — the run detail's
108
+ * narrative stream and the raw-trace dump both read through this. */
109
+ export function runEvents(state, runId) {
110
+ const byId = state.spans[runId];
111
+ if (!byId)
112
+ return EMPTY_EVENTS;
113
+ const out = [];
114
+ for (const spanId of Object.keys(byId)) {
115
+ const events = state.events[spanId];
116
+ if (events)
117
+ out.push(...events);
118
+ }
119
+ if (out.length === 0)
120
+ return EMPTY_EVENTS;
121
+ return out.sort((a, b) => a.ts - b.ts || a.eventIndex - b.eventIndex);
122
+ }
123
+ /** The span behind one tool call (span ids ARE toolUseIds), if streamed. */
124
+ export function spanForTool(state, toolUseId) {
125
+ const runId = state.spanRun[toolUseId];
126
+ return runId ? (state.spans[runId]?.[toolUseId] ?? null) : null;
127
+ }
128
+ /**
129
+ * Server-stamped timing for a tool call. One clock for live and reloaded
130
+ * views: when the activity stream carries the span, its timestamps win over
131
+ * client stamps (AE2 — live and revisit must render identical timings).
132
+ * `waitUntil` marks the approval-wait/execution boundary.
133
+ */
134
+ export function timingFor(state, toolUseId) {
135
+ const span = spanForTool(state, toolUseId);
136
+ if (!span)
137
+ return null;
138
+ return {
139
+ startedAt: span.waitUntil ?? span.startedAt,
140
+ ...(span.endedAt !== undefined ? { endedAt: span.endedAt } : {}),
141
+ };
142
+ }
143
+ //# sourceMappingURL=activity-store-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-store-helpers.js","sourceRoot":"","sources":["../../src/stores/activity-store-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { ActivitySpan, ActivitySpanEvent, ServerActivityDelta, ServerActivitySnapshot } from "@schlessera/brain-ui-sdk/protocol";
2
+ import type { ActivityIntent } from "../lib/api-client.js";
3
+ export interface ActivityState {
4
+ /** server_hello said this host records activity. */
5
+ supported: boolean;
6
+ /** Session ids this connection has an activity subscription for. */
7
+ subscribed: Record<string, true>;
8
+ /** Bumped on every new connection so subscribe effects re-send. */
9
+ connectionEpoch: number;
10
+ /** Live span state per run, keyed runId -> spanId. */
11
+ spans: Record<string, Record<string, ActivitySpan>>;
12
+ /** Ordered events per span (already sorted by eventIndex). */
13
+ events: Record<string, ActivitySpanEvent[]>;
14
+ /** Per-run high-water seq from the snapshot; deltas at or below drop. */
15
+ highWater: Record<string, number>;
16
+ /**
17
+ * Newest APPLIED delta seq per run. Kept apart from `highWater` on
18
+ * purpose: the snapshot staleness guard compares against the max of both
19
+ * (a snapshot older than an applied delta must not roll it back), while
20
+ * the delta gate keeps comparing against the snapshot floor alone so
21
+ * out-of-order delta delivery stays tolerated (insert-if-absent absorbs it).
22
+ */
23
+ deltaSeq: Record<string, number>;
24
+ /** spanId -> runId reverse index, for timing lookups by toolUseId. */
25
+ spanRun: Record<string, string>;
26
+ /** Unacknowledged notification intents — the guaranteed-tier inbox. */
27
+ inbox: ActivityIntent[];
28
+ loadInbox: () => Promise<void>;
29
+ acknowledgeIntent: (id: number) => Promise<void>;
30
+ acknowledgeAllIntents: () => Promise<void>;
31
+ setSupported: (supported: boolean) => void;
32
+ /** New connection: server-side subscriptions are gone; re-subscribe lazily. */
33
+ resetSubscriptions: () => void;
34
+ bumpConnectionEpoch: () => void;
35
+ markSubscribed: (sessionId: string) => void;
36
+ applySnapshot: (msg: ServerActivitySnapshot) => void;
37
+ applyDelta: (msg: ServerActivityDelta) => void;
38
+ clear: () => void;
39
+ }
40
+ /** The five indexes that make up the mirror, mutated together during merges. */
41
+ export interface MirrorMaps {
42
+ spans: Record<string, Record<string, ActivitySpan>>;
43
+ events: Record<string, ActivitySpanEvent[]>;
44
+ highWater: Record<string, number>;
45
+ deltaSeq: Record<string, number>;
46
+ spanRun: Record<string, string>;
47
+ }
48
+ //# sourceMappingURL=activity-store-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-store-types.d.ts","sourceRoot":"","sources":["../../src/stores/activity-store-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACjC,mEAAmE;IACnE,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACpD,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC5C,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC,uEAAuE;IACvE,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,+EAA+E;IAC/E,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACrD,UAAU,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC/C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=activity-store-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-store-types.js","sourceRoot":"","sources":["../../src/stores/activity-store-types.ts"],"names":[],"mappings":""}
@@ -1,5 +1,5 @@
1
- import type { ActivitySpan, ActivitySpanEvent, ServerActivityDelta, ServerActivitySnapshot } from "@schlessera/brain-ui-sdk/protocol";
2
- import { type ActivityIntent } from "../lib/api-client.js";
1
+ import type { ActivityState } from "./activity-store-types.js";
2
+ export { EMPTY_EVENTS, childSpans, eventsFor, narrativeEventsFor, payloadEventsFor, runEvents, runSpans, spanForTool, subagentSpans, timingFor, } from "./activity-store-helpers.js";
3
3
  /**
4
4
  * Client mirror of the server's activity record, fed by the snapshot-then-
5
5
  * delta stream. The server computes; this store only holds and indexes what
@@ -20,43 +20,6 @@ import { type ActivityIntent } from "../lib/api-client.js";
20
20
  * evicted wholesale (spans, events, high-water, reverse index). Live runs
21
21
  * are never evicted; evicted history remains fetchable over REST.
22
22
  */
23
- interface ActivityState {
24
- /** server_hello said this host records activity. */
25
- supported: boolean;
26
- /** Session ids this connection has an activity subscription for. */
27
- subscribed: Record<string, true>;
28
- /** Bumped on every new connection so subscribe effects re-send. */
29
- connectionEpoch: number;
30
- /** Live span state per run, keyed runId -> spanId. */
31
- spans: Record<string, Record<string, ActivitySpan>>;
32
- /** Ordered events per span (already sorted by eventIndex). */
33
- events: Record<string, ActivitySpanEvent[]>;
34
- /** Per-run high-water seq from the snapshot; deltas at or below drop. */
35
- highWater: Record<string, number>;
36
- /**
37
- * Newest APPLIED delta seq per run. Kept apart from `highWater` on
38
- * purpose: the snapshot staleness guard compares against the max of both
39
- * (a snapshot older than an applied delta must not roll it back), while
40
- * the delta gate keeps comparing against the snapshot floor alone so
41
- * out-of-order delta delivery stays tolerated (insert-if-absent absorbs it).
42
- */
43
- deltaSeq: Record<string, number>;
44
- /** spanId -> runId reverse index, for timing lookups by toolUseId. */
45
- spanRun: Record<string, string>;
46
- /** Unacknowledged notification intents — the guaranteed-tier inbox. */
47
- inbox: ActivityIntent[];
48
- loadInbox: () => Promise<void>;
49
- acknowledgeIntent: (id: number) => Promise<void>;
50
- acknowledgeAllIntents: () => Promise<void>;
51
- setSupported: (supported: boolean) => void;
52
- /** New connection: server-side subscriptions are gone; re-subscribe lazily. */
53
- resetSubscriptions: () => void;
54
- bumpConnectionEpoch: () => void;
55
- markSubscribed: (sessionId: string) => void;
56
- applySnapshot: (msg: ServerActivitySnapshot) => void;
57
- applyDelta: (msg: ServerActivityDelta) => void;
58
- clear: () => void;
59
- }
60
23
  export declare const useActivityStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ActivityState>>;
61
24
  /**
62
25
  * Pull a session's recent FINISHED runs from the REST activity API into the
@@ -76,43 +39,4 @@ export declare function loadSessionActivityHistory(sessionId: string): Promise<v
76
39
  * at the same high-water still applies and events insert-if-absent.
77
40
  */
78
41
  export declare function loadSpanPayloads(spanId: string): Promise<void>;
79
- /** All spans of a run, roots first, then by start time. */
80
- export declare function runSpans(state: ActivityState, runId: string): ActivitySpan[];
81
- /** Direct children of a span (e.g. the tool calls inside a subagent). */
82
- export declare function childSpans(state: ActivityState, parentSpanId: string): ActivitySpan[];
83
- /** The subagent spans spawned by a turn's Agent tool calls, live status included. */
84
- export declare function subagentSpans(state: ActivityState, sessionId: string): ActivitySpan[];
85
- /** Stable empty result for `eventsFor` — a fresh `[]` per call would defeat
86
- * reference-equality checks in zustand selectors. */
87
- export declare const EMPTY_EVENTS: ActivitySpanEvent[];
88
- /** Ordered events of a span; the shared frozen empty array when none. */
89
- export declare function eventsFor(state: ActivityState, spanId: string): ActivitySpanEvent[];
90
- /**
91
- * The recorded input/output payload events of a tool span (AE7). Returns a
92
- * fresh array per call — subscribe through `useShallow` (like `childSpans`).
93
- */
94
- export declare function payloadEventsFor(state: ActivityState, spanId: string): ActivitySpanEvent[];
95
- /**
96
- * Everything recorded against a span that is NOT a tool input/output payload:
97
- * transcript excerpts, job output, and any span-sink event type a producer
98
- * invents. Rendered as the span's narrative so an unknown type degrades to a
99
- * labelled block rather than to invisibility.
100
- */
101
- export declare function narrativeEventsFor(state: ActivityState, spanId: string): ActivitySpanEvent[];
102
- /** Every event recorded under a run, ordered by time — the run detail's
103
- * narrative stream and the raw-trace dump both read through this. */
104
- export declare function runEvents(state: ActivityState, runId: string): ActivitySpanEvent[];
105
- /** The span behind one tool call (span ids ARE toolUseIds), if streamed. */
106
- export declare function spanForTool(state: ActivityState, toolUseId: string): ActivitySpan | null;
107
- /**
108
- * Server-stamped timing for a tool call. One clock for live and reloaded
109
- * views: when the activity stream carries the span, its timestamps win over
110
- * client stamps (AE2 — live and revisit must render identical timings).
111
- * `waitUntil` marks the approval-wait/execution boundary.
112
- */
113
- export declare function timingFor(state: ActivityState, toolUseId: string): {
114
- startedAt: number;
115
- endedAt?: number;
116
- } | null;
117
- export {};
118
42
  //# sourceMappingURL=activity-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"activity-store.d.ts","sourceRoot":"","sources":["../../src/stores/activity-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"activity-store.d.ts","sourceRoot":"","sources":["../../src/stores/activity-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,2BAA2B,CAAC;AAQ3E,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,6BAA6B,CAAC;AAKrC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,gBAAgB,4EAoJ1B,CAAC;AAgBJ;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BjF;AAKD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpE"}
@@ -1,10 +1,30 @@
1
1
  import { create } from "zustand";
2
2
  import { api } from "../lib/api-client.js";
3
3
  import { registerDevHandle } from "../config.js";
4
+ import { evictRun, insertEvent, pruneTerminalRuns, rootSpanOf, } from "./activity-store-helpers.js";
5
+ export { EMPTY_EVENTS, childSpans, eventsFor, narrativeEventsFor, payloadEventsFor, runEvents, runSpans, spanForTool, subagentSpans, timingFor, } from "./activity-store-helpers.js";
4
6
  /** How many finished runs' details are fetched when a session opens. */
5
7
  const HISTORY_RUN_LIMIT = 10;
6
- /** Bound on the mirror: how many TERMINAL runs stay held. Live runs never count. */
7
- const MAX_TERMINAL_RUNS = 50;
8
+ /**
9
+ * Client mirror of the server's activity record, fed by the snapshot-then-
10
+ * delta stream. The server computes; this store only holds and indexes what
11
+ * arrived — no aggregation, no derived rollups (those come from the REST
12
+ * activity API).
13
+ *
14
+ * Ordering contract (AE6): a snapshot sets the per-run high-water seq; a
15
+ * delta at or below it is DISCARDED (its content is already in the
16
+ * snapshot). Applying a delta is idempotent — span deltas upsert by spanId,
17
+ * event deltas insert-if-absent by (spanId, eventIndex) — so a duplicate
18
+ * delivery can never corrupt state. The guard is symmetric: a snapshot
19
+ * whose per-run high-water is STRICTLY LOWER than what is held (a stale
20
+ * frame racing a reconnect) is skipped for that run; an equal value still
21
+ * applies, so chunked append frames keep working.
22
+ *
23
+ * Bounded mirror: at most MAX_TERMINAL_RUNS finished runs are held — once a
24
+ * run past the cap, the oldest terminal runs (by root start time) are
25
+ * evicted wholesale (spans, events, high-water, reverse index). Live runs
26
+ * are never evicted; evicted history remains fetchable over REST.
27
+ */
8
28
  export const useActivityStore = create((set, get) => ({
9
29
  supported: false,
10
30
  subscribed: {},
@@ -243,146 +263,6 @@ export async function loadSpanPayloads(spanId) {
243
263
  payloadLoadedRuns.delete(runId);
244
264
  }
245
265
  }
246
- function rootSpanOf(byId) {
247
- return Object.values(byId).find((span) => span.parentSpanId === undefined);
248
- }
249
- /** Drop a whole run from the mirror — spans, events, high-water, reverse index. */
250
- function evictRun(maps, runId) {
251
- for (const spanId of Object.keys(maps.spans[runId] ?? {})) {
252
- delete maps.events[spanId];
253
- delete maps.spanRun[spanId];
254
- }
255
- delete maps.spans[runId];
256
- delete maps.highWater[runId];
257
- delete maps.deltaSeq[runId];
258
- }
259
- /**
260
- * Enforce the terminal-run bound in place. Returns whether anything was
261
- * evicted. Runs whose root span is still open (or unknown) are never touched.
262
- */
263
- function pruneTerminalRuns(maps) {
264
- const terminal = [];
265
- for (const [runId, byId] of Object.entries(maps.spans)) {
266
- const root = rootSpanOf(byId);
267
- if (root && root.outcome !== undefined) {
268
- terminal.push({ runId, startedAt: root.startedAt });
269
- }
270
- }
271
- if (terminal.length <= MAX_TERMINAL_RUNS)
272
- return false;
273
- terminal.sort((a, b) => a.startedAt - b.startedAt);
274
- for (const { runId } of terminal.slice(0, terminal.length - MAX_TERMINAL_RUNS)) {
275
- evictRun(maps, runId);
276
- }
277
- return true;
278
- }
279
- function insertEvent(list, event) {
280
- const existing = list ?? [];
281
- if (existing.some((e) => e.eventIndex === event.eventIndex))
282
- return existing;
283
- const next = [...existing, event];
284
- next.sort((a, b) => a.eventIndex - b.eventIndex);
285
- return next;
286
- }
287
- // --- Selectors (plain functions over the state, like activeChat) ---
288
- /** All spans of a run, roots first, then by start time. */
289
- export function runSpans(state, runId) {
290
- const byId = state.spans[runId];
291
- if (!byId)
292
- return [];
293
- return Object.values(byId).sort((a, b) => (a.parentSpanId ? 1 : 0) - (b.parentSpanId ? 1 : 0) || a.startedAt - b.startedAt);
294
- }
295
- /** Direct children of a span (e.g. the tool calls inside a subagent). */
296
- export function childSpans(state, parentSpanId) {
297
- const runId = state.spanRun[parentSpanId];
298
- if (!runId)
299
- return [];
300
- return Object.values(state.spans[runId] ?? {})
301
- .filter((s) => s.parentSpanId === parentSpanId)
302
- .sort((a, b) => a.startedAt - b.startedAt);
303
- }
304
- /** The subagent spans spawned by a turn's Agent tool calls, live status included. */
305
- export function subagentSpans(state, sessionId) {
306
- const out = [];
307
- for (const byId of Object.values(state.spans)) {
308
- for (const span of Object.values(byId)) {
309
- if (span.kind === "subagent" && span.sessionId === sessionId)
310
- out.push(span);
311
- }
312
- }
313
- return out.sort((a, b) => a.startedAt - b.startedAt);
314
- }
315
- /** Stable empty result for `eventsFor` — a fresh `[]` per call would defeat
316
- * reference-equality checks in zustand selectors. */
317
- export const EMPTY_EVENTS = Object.freeze([]);
318
- /** Ordered events of a span; the shared frozen empty array when none. */
319
- export function eventsFor(state, spanId) {
320
- return state.events[spanId] ?? EMPTY_EVENTS;
321
- }
322
- /** Payload event types the tool expander owns — every OTHER type belongs to
323
- * the narrative stream (`narrativeEventsFor`) so nothing recorded is
324
- * rendered nowhere. */
325
- const TOOL_PAYLOAD_TYPES = new Set(["tool_input", "tool_output"]);
326
- /**
327
- * The recorded input/output payload events of a tool span (AE7). Returns a
328
- * fresh array per call — subscribe through `useShallow` (like `childSpans`).
329
- */
330
- export function payloadEventsFor(state, spanId) {
331
- const events = state.events[spanId];
332
- if (!events)
333
- return EMPTY_EVENTS;
334
- const payloads = events.filter((e) => TOOL_PAYLOAD_TYPES.has(e.eventType));
335
- return payloads.length > 0 ? payloads : EMPTY_EVENTS;
336
- }
337
- /**
338
- * Everything recorded against a span that is NOT a tool input/output payload:
339
- * transcript excerpts, job output, and any span-sink event type a producer
340
- * invents. Rendered as the span's narrative so an unknown type degrades to a
341
- * labelled block rather than to invisibility.
342
- */
343
- export function narrativeEventsFor(state, spanId) {
344
- const events = state.events[spanId];
345
- if (!events)
346
- return EMPTY_EVENTS;
347
- const rest = events.filter((e) => !TOOL_PAYLOAD_TYPES.has(e.eventType));
348
- return rest.length > 0 ? rest : EMPTY_EVENTS;
349
- }
350
- /** Every event recorded under a run, ordered by time — the run detail's
351
- * narrative stream and the raw-trace dump both read through this. */
352
- export function runEvents(state, runId) {
353
- const byId = state.spans[runId];
354
- if (!byId)
355
- return EMPTY_EVENTS;
356
- const out = [];
357
- for (const spanId of Object.keys(byId)) {
358
- const events = state.events[spanId];
359
- if (events)
360
- out.push(...events);
361
- }
362
- if (out.length === 0)
363
- return EMPTY_EVENTS;
364
- return out.sort((a, b) => a.ts - b.ts || a.eventIndex - b.eventIndex);
365
- }
366
- /** The span behind one tool call (span ids ARE toolUseIds), if streamed. */
367
- export function spanForTool(state, toolUseId) {
368
- const runId = state.spanRun[toolUseId];
369
- return runId ? (state.spans[runId]?.[toolUseId] ?? null) : null;
370
- }
371
- /**
372
- * Server-stamped timing for a tool call. One clock for live and reloaded
373
- * views: when the activity stream carries the span, its timestamps win over
374
- * client stamps (AE2 — live and revisit must render identical timings).
375
- * `waitUntil` marks the approval-wait/execution boundary.
376
- */
377
- export function timingFor(state, toolUseId) {
378
- const span = spanForTool(state, toolUseId);
379
- if (!span)
380
- return null;
381
- return {
382
- startedAt: span.waitUntil ?? span.startedAt,
383
- ...(span.endedAt !== undefined ? { endedAt: span.endedAt } : {}),
384
- };
385
- }
386
266
  registerDevHandle(() => {
387
267
  if (typeof window === "undefined")
388
268
  return;