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
87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
getArchivedScopeKey,
|
|
resolveArchivedFolderName,
|
|
} from '../utils';
|
|
import type { SessionOwnershipIndex } from '../sessionOwnership';
|
|
|
|
type ProjectForArchivedFolders = {
|
|
id: string;
|
|
normalizedPath: string;
|
|
};
|
|
|
|
type FolderEntry = {
|
|
id: string;
|
|
name: string;
|
|
sessionIds: string[];
|
|
};
|
|
|
|
type Args = {
|
|
enabled?: boolean;
|
|
normalizedProjects: ProjectForArchivedFolders[];
|
|
ownership: SessionOwnershipIndex;
|
|
isSessionsLoading: boolean;
|
|
hasAuthoritativeGlobalSessions: boolean;
|
|
isWorktreeTopologyLoading: boolean;
|
|
unresolvedWorktreeProjectPaths: ReadonlySet<string>;
|
|
foldersMap: Record<string, FolderEntry[]>;
|
|
createFolder: (scopeKey: string, name: string, parentId?: string | null) => FolderEntry;
|
|
addSessionToFolder: (scopeKey: string, folderId: string, sessionId: string) => void;
|
|
};
|
|
|
|
export const useArchivedAutoFolders = (args: Args): void => {
|
|
const {
|
|
normalizedProjects,
|
|
enabled = true,
|
|
ownership,
|
|
isSessionsLoading,
|
|
hasAuthoritativeGlobalSessions,
|
|
isWorktreeTopologyLoading,
|
|
unresolvedWorktreeProjectPaths,
|
|
foldersMap,
|
|
createFolder,
|
|
addSessionToFolder,
|
|
} = args;
|
|
|
|
React.useEffect(() => {
|
|
if (!enabled || isSessionsLoading || !hasAuthoritativeGlobalSessions || isWorktreeTopologyLoading) {
|
|
return;
|
|
}
|
|
|
|
normalizedProjects.forEach((project) => {
|
|
if (unresolvedWorktreeProjectPaths.has(project.normalizedPath)) {
|
|
return;
|
|
}
|
|
const scopeKey = getArchivedScopeKey(project.normalizedPath);
|
|
const projectArchivedSessions = ownership.archivedSessionsByProject.get(project.id) ?? [];
|
|
const existingFolders = foldersMap[scopeKey] ?? [];
|
|
const folderByName = new Map(existingFolders.map((folder) => [folder.name.toLowerCase(), folder]));
|
|
|
|
projectArchivedSessions.forEach((session) => {
|
|
const folderName = resolveArchivedFolderName(session, project.normalizedPath);
|
|
const key = folderName.toLowerCase();
|
|
let folder = folderByName.get(key);
|
|
if (!folder) {
|
|
folder = createFolder(scopeKey, folderName);
|
|
folderByName.set(key, folder);
|
|
}
|
|
|
|
if (!folder.sessionIds.includes(session.id)) {
|
|
addSessionToFolder(scopeKey, folder.id, session.id);
|
|
}
|
|
});
|
|
});
|
|
}, [
|
|
normalizedProjects,
|
|
enabled,
|
|
ownership,
|
|
isSessionsLoading,
|
|
hasAuthoritativeGlobalSessions,
|
|
isWorktreeTopologyLoading,
|
|
unresolvedWorktreeProjectPaths,
|
|
foldersMap,
|
|
createFolder,
|
|
addSessionToFolder,
|
|
]);
|
|
};
|