feat(chats): add managed projectless chat sessions
Create projectless chat sessions under a managed, date-scoped Chats directory and clean abandoned or deleted session folders. Add Chats to sidebar state, startup cache, shared context, and Electron Mini Chat while keeping VS Code project-only. Resolve managed chat directories to one server-side memory owner and document the runtime contracts.
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
worktreeMapsEqual,
|
||||
} from '@/lib/worktrees/worktreeManager';
|
||||
import type { WorktreeMetadata } from '@/types/worktree';
|
||||
import { CHAT_DRAFT_PROJECT_ID } from '@/lib/chatDirectories';
|
||||
|
||||
const MINI_CHAT_PRESENCE_CHANNEL = 'openchamber:mini-chat-presence';
|
||||
|
||||
@@ -153,9 +154,9 @@ const MiniChatBootstrap: React.FC<{ config: MiniChatConfig }> = ({ config }) =>
|
||||
const sessionId = typeof detail?.sessionId === 'string' ? detail.sessionId.trim() : '';
|
||||
if (!sessionId) return;
|
||||
if (useSessionUIStore.getState().currentSessionId === sessionId) return;
|
||||
const directory = typeof detail?.directory === 'string' && detail.directory.trim().length > 0
|
||||
? detail.directory.trim()
|
||||
: (sessions.find((entry) => entry.id === sessionId) as { directory?: string | null } | undefined)?.directory ?? null;
|
||||
const sessionDirectory = (sessions.find((entry) => entry.id === sessionId) as { directory?: string | null } | undefined)?.directory?.trim();
|
||||
const directory = sessionDirectory
|
||||
|| (typeof detail?.directory === 'string' && detail.directory.trim().length > 0 ? detail.directory.trim() : null);
|
||||
void sync.ensureSessionRenderable(sessionId);
|
||||
setCurrentSession(sessionId, directory);
|
||||
sessionBootstrappedRef.current = true;
|
||||
@@ -166,9 +167,11 @@ const MiniChatBootstrap: React.FC<{ config: MiniChatConfig }> = ({ config }) =>
|
||||
|
||||
React.useEffect(() => {
|
||||
if (config.mode !== 'draft' || draftOpen || currentSessionId) return;
|
||||
const hasProjectTarget = Boolean(config.projectId || config.directory);
|
||||
openNewSessionDraft({
|
||||
selectedProjectId: config.projectId,
|
||||
directoryOverride: config.directory,
|
||||
target: hasProjectTarget ? 'project' : 'chat',
|
||||
selectedProjectId: hasProjectTarget ? config.projectId : CHAT_DRAFT_PROJECT_ID,
|
||||
directoryOverride: hasProjectTarget ? config.directory : null,
|
||||
preserveDirectoryOverride: Boolean(config.directory),
|
||||
});
|
||||
}, [config, currentSessionId, draftOpen, openNewSessionDraft]);
|
||||
@@ -278,10 +281,11 @@ const MiniChatPresencePublisher: React.FC = () => {
|
||||
const useSessionUnavailable = (config: MiniChatConfig): boolean => {
|
||||
const sessions = useSessions();
|
||||
const currentSessionId = useSessionUIStore((state) => state.currentSessionId);
|
||||
const draftOpen = useSessionUIStore((state) => state.newSessionDraft.open);
|
||||
const [timedOut, setTimedOut] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (config.mode !== 'session' || !config.sessionId || currentSessionId === config.sessionId) {
|
||||
if (draftOpen || config.mode !== 'session' || !config.sessionId || currentSessionId) {
|
||||
setTimedOut(false);
|
||||
return;
|
||||
}
|
||||
@@ -291,7 +295,7 @@ const useSessionUnavailable = (config: MiniChatConfig): boolean => {
|
||||
}
|
||||
const timeout = window.setTimeout(() => setTimedOut(true), 5000);
|
||||
return () => window.clearTimeout(timeout);
|
||||
}, [config.mode, config.sessionId, currentSessionId, sessions]);
|
||||
}, [config.mode, config.sessionId, currentSessionId, draftOpen, sessions]);
|
||||
|
||||
return timedOut;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user