perf(ui): index and batch session updates

Batch global session, status, ordering, and activity timing mutations at the existing directory event boundary so large subagent bursts publish each owner once.

Maintain active session roots, children, and directory buckets in the global store, reuse them in Sidebar projections, and avoid rebuilding live aggregates and structural data for unrelated renders while preserving authoritative ordering reconciliation.
This commit is contained in:
c_w_xiaohei
2026-08-26 00:42:37 +08:00
parent df924aa532
commit 701173e399
16 changed files with 1153 additions and 376 deletions
@@ -2,14 +2,17 @@ import { beforeEach, describe, expect, test } from "bun:test"
import type { Event } from "@opencode-ai/sdk/v2/client"
import {
applyGlobalSessionStatusEvent,
applyGlobalSessionStatusEvents,
applyGlobalSessionStatusSnapshot,
useGlobalSessionStatusStore,
} from "./global-session-status"
import { resetSessionOrdering, useSessionOrderingStore } from "./session-ordering"
import { resetSessionActivityTiming, useSessionActivityTimingStore } from "./session-activity-timing"
beforeEach(() => {
useGlobalSessionStatusStore.setState({ statusById: new Map() })
resetSessionOrdering()
resetSessionActivityTiming()
})
describe("global session status index", () => {
@@ -171,4 +174,44 @@ describe("global session status index", () => {
expect(useGlobalSessionStatusStore.getState().statusById.has("session-a")).toBe(false)
})
test("publishes status, ordering, and timing once for a large event batch", () => {
let statusPublications = 0
let orderingPublications = 0
let timingPublications = 0
const unsubscribeStatus = useGlobalSessionStatusStore.subscribe(() => { statusPublications += 1 })
const unsubscribeOrdering = useSessionOrderingStore.subscribe(() => { orderingPublications += 1 })
const unsubscribeTiming = useSessionActivityTimingStore.subscribe(() => { timingPublications += 1 })
const events = Array.from({ length: 1_000 }, (_, index) => ({
type: "session.status",
properties: { sessionID: `session-${index}`, status: { type: "busy" } },
} as Event))
applyGlobalSessionStatusEvents("/repo", events)
unsubscribeStatus()
unsubscribeOrdering()
unsubscribeTiming()
expect(useGlobalSessionStatusStore.getState().activeSessionIds.size).toBe(1_000)
expect(statusPublications).toBe(1)
expect(orderingPublications).toBe(1)
expect(timingPublications).toBe(1)
})
test("keeps lifecycle event order inside a batch", () => {
applyGlobalSessionStatusEvents("/repo", [
{
type: "session.status",
properties: { sessionID: "session-a", status: { type: "busy" } },
} as Event,
{
type: "session.deleted",
properties: { sessionID: "session-a" },
} as Event,
])
expect(useGlobalSessionStatusStore.getState().statusById.has("session-a")).toBe(false)
expect(useSessionOrderingStore.getState().rankById.has("session-a")).toBe(false)
expect(useSessionActivityTimingStore.getState().startedAt.has("session-a")).toBe(false)
})
})