perf(sidebar): index session ownership and narrow live subscriptions

Replace repeated project-by-session directory matching across sidebar hooks with a shared ownership index that resolves each unique directory once and exposes direct project and folder-scope buckets.

Gate destructive folder reconciliation on authoritative session data and topology readiness, preserve last-known worktrees after discovery failures, and retain nested-project, VS Code, active/archive dedupe, and Windows drive-root semantics.

Narrow cross-directory subscriptions to session and status slices so streaming deltas no longer trigger global aggregation. Reuse a cached session ID index for permission lineage checks instead of rebuilding it on every session switch.

On the reported 15-project, 67-worktree, 14,561-session shape, ownership indexing averages 3.81 ms versus roughly 450 ms for the cache-only hotfix.

Validation: 28 targeted tests, UI type-check, UI lint, and dead-code analysis.
This commit is contained in:
Bohdan Triapitsyn
2026-07-13 23:18:12 +03:00
parent 799904f0f4
commit b36afbf5ee
19 changed files with 619 additions and 511 deletions
+9 -4
View File
@@ -2,7 +2,7 @@ import { create } from "zustand";
import { persist } from "zustand/middleware";
import type { Session } from "@opencode-ai/sdk/v2/client";
import { autoRespondsPermission, type PermissionAutoAcceptMap } from "./utils/permissionAutoAccept";
import { getAllSyncSessions } from "@/sync/sync-refs";
import { getAllSyncSessionMap } from "@/sync/sync-refs";
import { runtimeFetch } from "@/lib/runtime-fetch";
import { isVSCodeRuntime } from "@/lib/desktop";
import { createDeferredSafeJSONStorage } from "./utils/safeStorage";
@@ -39,8 +39,11 @@ const readSnapshot = async (response: Response): Promise<PermissionPolicySnapsho
const requestSnapshot = async (path: string, init?: RequestInit) => readSnapshot(await runtimeFetch(path, init));
const isAutoAccepting = (autoAccept: PermissionAutoAcceptMap, sessions: Session[], sessionId: string) =>
autoRespondsPermission({ autoAccept, sessions, sessionID: sessionId });
const isAutoAccepting = (
autoAccept: PermissionAutoAcceptMap,
sessionById: ReadonlyMap<string, Session>,
sessionId: string,
) => autoRespondsPermission({ autoAccept, sessions: [], sessionById, sessionID: sessionId });
export const usePermissionStore = create<PermissionStore>()(persist((set, get) => ({
autoAccept: {},
@@ -79,7 +82,9 @@ export const usePermissionStore = create<PermissionStore>()(persist((set, get) =
isSessionAutoAccepting: (sessionId) => {
if (!sessionId) return false;
return isAutoAccepting(get().autoAccept, getAllSyncSessions(), sessionId);
const autoAccept = get().autoAccept;
if (Object.keys(autoAccept).length === 0) return false;
return isAutoAccepting(autoAccept, getAllSyncSessionMap(), sessionId);
},
setSessionAutoAccept: async (sessionId, enabled) => {