perf: overhaul session loading, caching, and runtime isolation (#2360)

Improve OpenChamber responsiveness under large session workloads while fixing
cache, synchronization, and persistence correctness across runtimes, projects,
directories, and worktrees.

- prioritize selected and visible sessions during bootstrap and defer
  non-critical enrichment work
- reduce redundant message loading, event processing, store publication, and
  hidden sidebar work
- prevent stale session and message requests from overwriting newer
  authoritative state
- preserve existing data when authoritative fetches fail instead of treating
  failures as successful empty responses
- scope session materialization, messages, drafts, queues, todos, pins,
  permissions, folders, tabs, Git state, and pull request data by runtime and
  directory identity
- harden runtime switching, reconnect, cleanup, mutation reconciliation, and
  persisted-state ordering
- preserve live subagent Task linkage when metadata arrives after an older
  message request or while streaming parts are suspended
- coalesce overlapping tail refreshes without losing newer refresh demand
- improve cold-session loading by moving deferrable work out of the critical
  bootstrap path
- isolate URL authentication, mobile credentials, native secrets, and other
  runtime-owned state across endpoint changes
- bound long-lived caches and remove avoidable allocations from event and
  rendering hot paths
- limit virtualization to archive collections where it improves rendering
  without disrupting active sidebar layout
- stabilize session folders, pin ordering, expanded state, and persisted
  sidebar behavior
- open skill files through the same secure editor and outside-workspace grant
  flow used by file navigation, including worktree sessions
- expand regression coverage for stale completions, runtime collisions,
  reconnect behavior, persistence races, authoritative empty results, and
  subagent refresh ordering
- document the updated synchronization, cache ownership, performance, and
  runtime-isolation invariants
This commit is contained in:
Bohdan Triapitsyn
2026-07-21 20:52:20 +03:00
committed by GitHub
parent 485efc7117
commit 85400459e9
197 changed files with 10835 additions and 3400 deletions
@@ -1,105 +1,175 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { getRuntimeKey } from '@/lib/runtime-switch';
import { normalizePath } from '@/lib/pathNormalization';
import { createDeferredSafeJSONStorage } from './utils/safeStorage';
export type InlineCommentSource = 'diff' | 'plan' | 'file' | 'preview-console' | 'preview-annotation' | 'terminal';
export type InlineCommentDraftTarget = {
directory: string;
sessionKey: string;
};
export interface InlineCommentDraft {
id: string;
sessionKey: string; // sessionId or 'draft' for new sessions
sessionKey: string;
source: InlineCommentSource;
fileLabel: string; // filename or 'plan'
fileLabel: string;
startLine: number;
endLine: number;
side?: 'original' | 'modified'; // diff only
side?: 'original' | 'modified';
code: string;
language: string;
text: string;
createdAt: number;
}
export const EMPTY_INLINE_COMMENT_DRAFTS: InlineCommentDraft[] = [];
interface InlineCommentDraftState {
drafts: Record<string, InlineCommentDraft[]>; // sessionKey -> drafts
drafts: Record<string, InlineCommentDraft[]>;
touchedAt: Record<string, number>;
}
interface InlineCommentDraftActions {
addDraft: (draft: Omit<InlineCommentDraft, 'id' | 'createdAt'>) => void;
updateDraft: (sessionKey: string, draftId: string, updates: Partial<Omit<InlineCommentDraft, 'id' | 'createdAt' | 'sessionKey'>>) => void;
removeDraft: (sessionKey: string, draftId: string) => void;
clearDrafts: (sessionKey: string) => void;
getDrafts: (sessionKey: string) => InlineCommentDraft[];
consumeDrafts: (sessionKey: string) => InlineCommentDraft[];
restoreDrafts: (sessionKey: string, drafts: InlineCommentDraft[]) => void;
getDraftCount: (sessionKey: string) => number;
hasDrafts: (sessionKey: string) => boolean;
addDraft: (target: InlineCommentDraftTarget, draft: Omit<InlineCommentDraft, 'id' | 'createdAt' | 'sessionKey'>) => string | null;
updateDraft: (target: InlineCommentDraftTarget, draftId: string, updates: Partial<Omit<InlineCommentDraft, 'id' | 'createdAt' | 'sessionKey'>>) => void;
removeDraft: (target: InlineCommentDraftTarget, draftId: string) => void;
clearDrafts: (target: InlineCommentDraftTarget) => void;
getDrafts: (target: InlineCommentDraftTarget) => InlineCommentDraft[];
consumeDrafts: (target: InlineCommentDraftTarget) => InlineCommentDraft[];
restoreDrafts: (target: InlineCommentDraftTarget, drafts: InlineCommentDraft[]) => void;
getDraftCount: (target: InlineCommentDraftTarget) => number;
hasDrafts: (target: InlineCommentDraftTarget) => boolean;
clearSessionDrafts: (runtimeKey: string, directory: string, sessionId: string) => void;
}
type InlineCommentDraftStore = InlineCommentDraftState & InlineCommentDraftActions;
const isValidSource = (value: unknown): value is InlineCommentSource =>
value === 'diff' || value === 'plan' || value === 'file' || value === 'preview-console' || value === 'preview-annotation' || value === 'terminal';
const MAX_SESSIONS = 50;
const MAX_DRAFTS_PER_SESSION = 20;
const MAX_PERSISTED_BYTES = 1024 * 1024;
const encoder = new TextEncoder();
const isValidSide = (value: unknown): value is 'original' | 'modified' =>
value === 'original' || value === 'modified';
const toPositiveLine = (value: unknown): number | null => {
const parsed = typeof value === 'number' ? value : Number(value);
if (!Number.isFinite(parsed)) return null;
return Math.max(1, Math.floor(parsed));
type SerializedSizeIndex = {
draftEntries: Map<string, number>;
touchedEntries: Map<string, number>;
total: number;
};
const sanitizeDraft = (input: unknown): InlineCommentDraft | null => {
if (!input || typeof input !== 'object') return null;
const draft = input as Partial<InlineCommentDraft>;
const serializedSizeByDrafts = new WeakMap<Record<string, InlineCommentDraft[]>, SerializedSizeIndex>();
const EMPTY_ENVELOPE_BYTES = encoder.encode(JSON.stringify({ drafts: {}, touchedAt: {} })).byteLength;
if (typeof draft.sessionKey !== 'string' || draft.sessionKey.trim().length === 0) return null;
if (!isValidSource(draft.source)) return null;
const startLine = toPositiveLine(draft.startLine);
const endLine = toPositiveLine(draft.endLine);
if (!startLine || !endLine) return null;
const id = typeof draft.id === 'string' && draft.id.trim().length > 0
? draft.id
: `icd-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
const code = typeof draft.code === 'string' ? draft.code : '';
if (draft.source === 'terminal' && !code.trim()) return null;
return {
id,
sessionKey: draft.sessionKey,
source: draft.source,
fileLabel: typeof draft.fileLabel === 'string' ? draft.fileLabel : 'unknown',
startLine,
endLine,
side: isValidSide(draft.side) ? draft.side : undefined,
code,
language: typeof draft.language === 'string' ? draft.language : 'text',
text: typeof draft.text === 'string' ? draft.text : '',
createdAt: Number.isFinite(draft.createdAt) ? Number(draft.createdAt) : Date.now(),
};
export const getInlineCommentDraftKey = (runtimeKey: string, directory: string, sessionKey: string): string | null => {
const normalizedDirectory = normalizePath(directory);
if (!runtimeKey || !normalizedDirectory || !sessionKey) return null;
return JSON.stringify([runtimeKey, normalizedDirectory, sessionKey]);
};
const sanitizeDraftMap = (input: unknown): Record<string, InlineCommentDraft[]> => {
if (!input || typeof input !== 'object') return {};
const getCurrentKey = (target: InlineCommentDraftTarget): string | null =>
getInlineCommentDraftKey(getRuntimeKey(), target.directory, target.sessionKey);
const entries = Object.entries(input as Record<string, unknown>);
const result: Record<string, InlineCommentDraft[]> = {};
const serializedEntryBytes = (key: string, value: unknown): number =>
encoder.encode(`${JSON.stringify(key)}:${JSON.stringify(value)}`).byteLength;
for (const [sessionKey, sessionDrafts] of entries) {
if (!Array.isArray(sessionDrafts)) continue;
const sumEntryBytes = (entries: Map<string, number>): number => {
let total = 0;
for (const bytes of entries.values()) total += bytes;
return total;
};
const sanitized = sessionDrafts
.map(sanitizeDraft)
.filter((draft): draft is InlineCommentDraft => Boolean(draft))
.filter((draft) => draft.sessionKey === sessionKey);
const indexedTotal = (draftEntries: Map<string, number>, touchedEntries: Map<string, number>): number => (
EMPTY_ENVELOPE_BYTES
+ sumEntryBytes(draftEntries)
+ Math.max(0, draftEntries.size - 1)
+ sumEntryBytes(touchedEntries)
+ Math.max(0, touchedEntries.size - 1)
);
if (sanitized.length > 0) {
result[sessionKey] = sanitized;
const buildSerializedSizeIndex = (
drafts: Record<string, InlineCommentDraft[]>,
touchedAt: Record<string, number>,
): SerializedSizeIndex => {
const draftEntries = new Map<string, number>();
const touchedEntries = new Map<string, number>();
for (const [key, value] of Object.entries(drafts)) draftEntries.set(key, serializedEntryBytes(key, value));
for (const [key, value] of Object.entries(touchedAt)) touchedEntries.set(key, serializedEntryBytes(key, value));
const index = { draftEntries, touchedEntries, total: indexedTotal(draftEntries, touchedEntries) };
serializedSizeByDrafts.set(drafts, index);
return index;
};
const updateSerializedSizeIndex = (
previous: InlineCommentDraftState,
drafts: Record<string, InlineCommentDraft[]>,
touchedAt: Record<string, number>,
changedKey: string,
): SerializedSizeIndex => {
const previousIndex = serializedSizeByDrafts.get(previous.drafts)
?? buildSerializedSizeIndex(previous.drafts, previous.touchedAt);
const draftEntries = new Map(previousIndex.draftEntries);
const touchedEntries = new Map(previousIndex.touchedEntries);
const bucket = drafts[changedKey];
if (bucket) draftEntries.set(changedKey, serializedEntryBytes(changedKey, bucket));
else draftEntries.delete(changedKey);
const touched = touchedAt[changedKey];
if (typeof touched === 'number') touchedEntries.set(changedKey, serializedEntryBytes(changedKey, touched));
else touchedEntries.delete(changedKey);
return { draftEntries, touchedEntries, total: indexedTotal(draftEntries, touchedEntries) };
};
const boundState = (
previous: InlineCommentDraftState,
drafts: Record<string, InlineCommentDraft[]>,
touchedAt: Record<string, number>,
changedKey: string,
): { drafts: Record<string, InlineCommentDraft[]>; touchedAt: Record<string, number> } | null => {
const keys = Object.keys(drafts).sort((left, right) => (touchedAt[right] ?? 0) - (touchedAt[left] ?? 0));
const retainedKeys = keys.slice(0, MAX_SESSIONS);
const retainedDrafts: Record<string, InlineCommentDraft[]> = {};
const retainedTouchedAt: Record<string, number> = {};
for (const key of retainedKeys) {
retainedDrafts[key] = drafts[key].length > MAX_DRAFTS_PER_SESSION
? drafts[key].slice(-MAX_DRAFTS_PER_SESSION)
: drafts[key];
retainedTouchedAt[key] = touchedAt[key] ?? Date.now();
}
const sizeIndex = updateSerializedSizeIndex(previous, retainedDrafts, retainedTouchedAt, changedKey);
for (const key of keys) {
if (!(key in retainedDrafts)) {
sizeIndex.draftEntries.delete(key);
sizeIndex.touchedEntries.delete(key);
} else if (retainedDrafts[key] !== drafts[key]) {
sizeIndex.draftEntries.set(key, serializedEntryBytes(key, retainedDrafts[key]));
}
if (key !== changedKey && retainedTouchedAt[key] !== previous.touchedAt[key]) {
sizeIndex.touchedEntries.set(key, serializedEntryBytes(key, retainedTouchedAt[key]));
}
}
sizeIndex.total = indexedTotal(sizeIndex.draftEntries, sizeIndex.touchedEntries);
const evictionKeys = [...retainedKeys];
while (evictionKeys.length > 0 && sizeIndex.total > MAX_PERSISTED_BYTES) {
const oldest = evictionKeys.pop()!;
delete retainedDrafts[oldest];
delete retainedTouchedAt[oldest];
sizeIndex.draftEntries.delete(oldest);
sizeIndex.touchedEntries.delete(oldest);
sizeIndex.total = indexedTotal(sizeIndex.draftEntries, sizeIndex.touchedEntries);
}
if (sizeIndex.draftEntries.size === 0 && keys.length > 0) return null;
serializedSizeByDrafts.set(retainedDrafts, sizeIndex);
return { drafts: retainedDrafts, touchedAt: retainedTouchedAt };
};
return result;
const removeDraftKey = (state: InlineCommentDraftState, key: string): InlineCommentDraftState => {
if (!(key in state.drafts)) return state;
const drafts = { ...state.drafts };
const touchedAt = { ...state.touchedAt };
delete drafts[key];
delete touchedAt[key];
return { drafts, touchedAt };
};
export const useInlineCommentDraftStore = create<InlineCommentDraftStore>()(
@@ -107,143 +177,115 @@ export const useInlineCommentDraftStore = create<InlineCommentDraftStore>()(
persist(
(set, get) => ({
drafts: {},
addDraft: (draft) => {
if (draft.source === 'terminal' && !draft.code.trim()) return;
touchedAt: {},
addDraft: (target, draft) => {
const key = getCurrentKey(target);
if (!key || (draft.source === 'terminal' && !draft.code.trim())) return null;
const id = `icd-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
const newDraft: InlineCommentDraft = {
...draft,
id,
createdAt: Date.now(),
};
const nextDraft: InlineCommentDraft = { ...draft, sessionKey: target.sessionKey, id, createdAt: Date.now() };
let accepted = false;
set((state) => {
const currentDrafts = state.drafts[draft.sessionKey] ?? [];
if (draft.source === 'terminal' && currentDrafts.some((current) => current.source === 'terminal' && current.fileLabel === draft.fileLabel && current.startLine === draft.startLine && current.endLine === draft.endLine && current.code === draft.code)) {
return state;
}
return {
drafts: {
...state.drafts,
[draft.sessionKey]: [...currentDrafts, newDraft],
},
};
const current = state.drafts[key] ?? [];
const isDuplicateTerminalDraft = draft.source === 'terminal' && current.some((item) => (
item.source === 'terminal'
&& item.fileLabel === draft.fileLabel
&& item.startLine === draft.startLine
&& item.endLine === draft.endLine
&& item.code === draft.code
));
if (isDuplicateTerminalDraft) return state;
const bounded = boundState(
state,
{ ...state.drafts, [key]: [...current, nextDraft] },
{ ...state.touchedAt, [key]: Date.now() },
key,
);
if (!bounded || !bounded.drafts[key]?.some((item) => item.id === id)) return state;
accepted = true;
return bounded;
});
return id;
return accepted ? id : null;
},
updateDraft: (sessionKey, draftId, updates) => {
updateDraft: (target, draftId, updates) => {
const key = getCurrentKey(target);
if (!key) return;
set((state) => {
const currentDrafts = state.drafts[sessionKey] ?? [];
const newDrafts = currentDrafts.map((draft) => {
if (draft.id !== draftId) {
return draft;
}
return {
...draft,
...updates,
};
});
return {
drafts: {
...state.drafts,
[sessionKey]: newDrafts,
},
};
const current = state.drafts[key] ?? [];
if (!current.some((draft) => draft.id === draftId)) return state;
const bounded = boundState(
state,
{ ...state.drafts, [key]: current.map((draft) => draft.id === draftId ? { ...draft, ...updates } : draft) },
{ ...state.touchedAt, [key]: Date.now() },
key,
);
return bounded ?? state;
});
},
removeDraft: (sessionKey, draftId) => {
removeDraft: (target, draftId) => {
const key = getCurrentKey(target);
if (!key) return;
set((state) => {
const currentDrafts = state.drafts[sessionKey] ?? [];
const newDrafts = currentDrafts.filter((d) => d.id !== draftId);
const current = state.drafts[key] ?? [];
const remaining = current.filter((draft) => draft.id !== draftId);
if (remaining.length === current.length) return state;
if (remaining.length === 0) return removeDraftKey(state, key);
if (newDrafts.length === 0) {
const { [sessionKey]: _removed, ...rest } = state.drafts;
void _removed;
return { drafts: rest };
}
return {
drafts: {
...state.drafts,
[sessionKey]: newDrafts,
},
};
const drafts = { ...state.drafts };
const touchedAt = { ...state.touchedAt };
drafts[key] = remaining;
touchedAt[key] = Date.now();
return { drafts, touchedAt };
});
},
clearDrafts: (sessionKey) => {
set((state) => {
const { [sessionKey]: _removed, ...rest } = state.drafts;
void _removed;
return { drafts: rest };
});
clearDrafts: (target) => {
const key = getCurrentKey(target);
if (!key) return;
set((state) => removeDraftKey(state, key));
},
getDrafts: (sessionKey) => {
return get().drafts[sessionKey] ?? [];
getDrafts: (target) => {
const key = getCurrentKey(target);
return key ? get().drafts[key] ?? EMPTY_INLINE_COMMENT_DRAFTS : EMPTY_INLINE_COMMENT_DRAFTS;
},
consumeDrafts: (sessionKey) => {
const drafts = get().drafts[sessionKey] ?? [];
if (drafts.length === 0) return [];
// Sort by creation time to maintain order
const sortedDrafts = [...drafts].sort((a, b) => a.createdAt - b.createdAt);
// Clear drafts after consuming
set((state) => {
const { [sessionKey]: _removed, ...rest } = state.drafts;
void _removed;
return { drafts: rest };
});
return sortedDrafts;
consumeDrafts: (target) => {
const key = getCurrentKey(target);
if (!key) return [];
const drafts = [...(get().drafts[key] ?? [])].sort((left, right) => left.createdAt - right.createdAt);
if (drafts.length > 0) set((state) => removeDraftKey(state, key));
return drafts;
},
restoreDrafts: (sessionKey, drafts) => {
if (drafts.length === 0) return;
restoreDrafts: (target, draftsToRestore) => {
const key = getCurrentKey(target);
if (!key || draftsToRestore.length === 0) return;
set((state) => {
const current = state.drafts[sessionKey] ?? [];
const current = state.drafts[key] ?? [];
const currentIds = new Set(current.map((draft) => draft.id));
const restored = drafts.filter((draft) => draft.sessionKey === sessionKey && !currentIds.has(draft.id));
const restored = draftsToRestore.filter((draft) => draft.sessionKey === target.sessionKey && !currentIds.has(draft.id));
if (restored.length === 0) return state;
return {
drafts: {
...state.drafts,
[sessionKey]: [...restored, ...current].sort((a, b) => a.createdAt - b.createdAt),
},
};
return boundState(
state,
{ ...state.drafts, [key]: [...restored, ...current].sort((left, right) => left.createdAt - right.createdAt) },
{ ...state.touchedAt, [key]: Date.now() },
key,
) ?? state;
});
},
getDraftCount: (sessionKey) => {
return (get().drafts[sessionKey] ?? []).length;
},
hasDrafts: (sessionKey) => {
return (get().drafts[sessionKey] ?? []).length > 0;
getDraftCount: (target) => get().getDrafts(target).length,
hasDrafts: (target) => get().getDrafts(target).length > 0,
clearSessionDrafts: (runtimeKey, directory, sessionId) => {
const key = getInlineCommentDraftKey(runtimeKey, directory, sessionId);
if (!key) return;
set((state) => removeDraftKey(state, key));
},
}),
{
name: 'openchamber-inline-comment-drafts',
storage: createDeferredSafeJSONStorage(),
version: 1,
migrate: (persistedState: unknown) => {
if (!persistedState || typeof persistedState !== 'object') {
return { drafts: {} };
}
const state = persistedState as { drafts?: unknown };
return {
drafts: sanitizeDraftMap(state.drafts),
};
},
}
version: 2,
partialize: (state) => ({ drafts: state.drafts, touchedAt: state.touchedAt }),
migrate: () => ({ drafts: {}, touchedAt: {} }),
},
),
{ name: 'inline-comment-draft-store' }
)
{ name: 'inline-comment-draft-store' },
),
);