= ({
{(() => {
const isExpanded = expandedSessionGroups.has(group.id);
- const maxVisible = 7;
+ const maxVisible = hideDirectoryControls ? 10 : 7;
const totalSessions = group.sessions.length;
const visibleSessions = isExpanded ? group.sessions : group.sessions.slice(0, maxVisible);
const remainingCount = totalSessions - visibleSessions.length;
diff --git a/packages/ui/src/components/ui/CommandPalette.tsx b/packages/ui/src/components/ui/CommandPalette.tsx
index 80960db6..525455ad 100644
--- a/packages/ui/src/components/ui/CommandPalette.tsx
+++ b/packages/ui/src/components/ui/CommandPalette.tsx
@@ -12,7 +12,6 @@ import {
import { useUIStore } from '@/stores/useUIStore';
import { useSessionStore } from '@/stores/useSessionStore';
import { useDirectoryStore } from '@/stores/useDirectoryStore';
-import { useConfigStore } from '@/stores/useConfigStore';
import { useThemeSystem } from '@/contexts/useThemeSystem';
import { useDeviceInfo } from '@/lib/device';
import { RiAddLine, RiChatAi3Line, RiCheckLine, RiCodeLine, RiComputerLine, RiGitBranchLine, RiLayoutLeftLine, RiMoonLine, RiQuestionLine, RiRestartLine, RiSettings3Line, RiSunLine, RiTerminalBoxLine } from '@remixicon/react';
@@ -31,14 +30,12 @@ export const CommandPalette: React.FC = () => {
} = useUIStore();
const {
- createSession,
+ openNewSessionDraft,
setCurrentSession,
getSessionsByDirectory,
- initializeNewOpenChamberSession,
} = useSessionStore();
const { currentDirectory } = useDirectoryStore();
- const { agents } = useConfigStore();
const { themeMode, setThemeMode } = useThemeSystem();
const handleClose = () => {
@@ -46,10 +43,9 @@ export const CommandPalette: React.FC = () => {
};
const handleCreateSession = async () => {
- const session = await createSession();
- if (session) {
- initializeNewOpenChamberSession(session.id, agents);
- }
+ setActiveMainTab('chat');
+ setSessionSwitcherOpen(false);
+ openNewSessionDraft();
handleClose();
};
diff --git a/packages/ui/src/hooks/useKeyboardShortcuts.ts b/packages/ui/src/hooks/useKeyboardShortcuts.ts
index 7aed46b8..e0c0ae8a 100644
--- a/packages/ui/src/hooks/useKeyboardShortcuts.ts
+++ b/packages/ui/src/hooks/useKeyboardShortcuts.ts
@@ -1,13 +1,12 @@
import React from 'react';
import { useSessionStore } from '@/stores/useSessionStore';
import { useUIStore } from '@/stores/useUIStore';
-import { useConfigStore } from '@/stores/useConfigStore';
import { useThemeSystem } from '@/contexts/useThemeSystem';
import { useAssistantStatus } from '@/hooks/useAssistantStatus';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
export const useKeyboardShortcuts = () => {
- const { createSession, abortCurrentOperation, initializeNewOpenChamberSession, armAbortPrompt, clearAbortPrompt, currentSessionId } = useSessionStore();
+ const { openNewSessionDraft, abortCurrentOperation, armAbortPrompt, clearAbortPrompt, currentSessionId } = useSessionStore();
const {
toggleCommandPalette,
toggleHelpDialog,
@@ -17,7 +16,6 @@ export const useKeyboardShortcuts = () => {
setActiveMainTab,
setSettingsDialogOpen,
} = useUIStore();
- const { agents } = useConfigStore();
const { themeMode, setThemeMode } = useThemeSystem();
const { working } = useAssistantStatus();
const abortPrimedUntilRef = React.useRef(null);
@@ -86,11 +84,9 @@ export const useKeyboardShortcuts = () => {
return;
}
- createSession().then(session => {
- if (session) {
- initializeNewOpenChamberSession(session.id, agents);
- }
- });
+ setActiveMainTab('chat');
+ setSessionSwitcherOpen(false);
+ openNewSessionDraft();
}
if ((e.metaKey || e.ctrlKey) && e.key === '/') {
@@ -189,7 +185,7 @@ export const useKeyboardShortcuts = () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [
- createSession,
+ openNewSessionDraft,
abortCurrentOperation,
toggleCommandPalette,
toggleHelpDialog,
@@ -200,8 +196,6 @@ export const useKeyboardShortcuts = () => {
setSettingsDialogOpen,
setThemeMode,
themeMode,
- initializeNewOpenChamberSession,
- agents,
working,
armAbortPrompt,
resetAbortPriming,
diff --git a/packages/ui/src/hooks/useMenuActions.ts b/packages/ui/src/hooks/useMenuActions.ts
index 8213f028..e40d72b0 100644
--- a/packages/ui/src/hooks/useMenuActions.ts
+++ b/packages/ui/src/hooks/useMenuActions.ts
@@ -2,7 +2,6 @@ import React from 'react';
import { toast } from 'sonner';
import { useSessionStore } from '@/stores/useSessionStore';
import { useUIStore } from '@/stores/useUIStore';
-import { useConfigStore } from '@/stores/useConfigStore';
import { useDirectoryStore } from '@/stores/useDirectoryStore';
import { useThemeSystem } from '@/contexts/useThemeSystem';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
@@ -32,17 +31,17 @@ type MenuAction =
export const useMenuActions = (
onToggleMemoryDebug?: () => void
) => {
- const { createSession, initializeNewOpenChamberSession } = useSessionStore();
+ const { openNewSessionDraft } = useSessionStore();
const {
toggleCommandPalette,
toggleHelpDialog,
toggleSidebar,
+ setSessionSwitcherOpen,
setSessionCreateDialogOpen,
setActiveMainTab,
setSettingsDialogOpen,
setAboutDialogOpen,
} = useUIStore();
- const { agents } = useConfigStore();
const { setDirectory } = useDirectoryStore();
const { setThemeMode } = useThemeSystem();
const isDownloadingLogsRef = React.useRef(false);
@@ -87,11 +86,9 @@ export const useMenuActions = (
break;
case 'new-session':
- createSession().then(session => {
- if (session) {
- initializeNewOpenChamberSession(session.id, agents);
- }
- });
+ setActiveMainTab('chat');
+ setSessionSwitcherOpen(false);
+ openNewSessionDraft();
break;
case 'worktree-creator':
@@ -183,17 +180,16 @@ export const useMenuActions = (
window.addEventListener(MENU_ACTION_EVENT, handleMenuAction);
return () => window.removeEventListener(MENU_ACTION_EVENT, handleMenuAction);
}, [
- createSession,
- initializeNewOpenChamberSession,
+ openNewSessionDraft,
toggleCommandPalette,
toggleHelpDialog,
toggleSidebar,
+ setSessionSwitcherOpen,
setSessionCreateDialogOpen,
setActiveMainTab,
setSettingsDialogOpen,
setAboutDialogOpen,
setThemeMode,
- agents,
onToggleMemoryDebug,
handleChangeWorkspace,
]);
diff --git a/packages/ui/src/stores/sessionStore.ts b/packages/ui/src/stores/sessionStore.ts
index a849b060..fe84bb6a 100644
--- a/packages/ui/src/stores/sessionStore.ts
+++ b/packages/ui/src/stores/sessionStore.ts
@@ -721,7 +721,7 @@ export const useSessionStore = create()(
set((state) => {
const filteredSessions = state.sessions.filter((session) => !deletedSet.has(session.id));
if (state.currentSessionId && deletedSet.has(state.currentSessionId)) {
- nextCurrentId = filteredSessions.length > 0 ? filteredSessions[0].id : null;
+ nextCurrentId = null;
} else {
nextCurrentId = state.currentSessionId;
}
diff --git a/packages/ui/src/stores/types/sessionTypes.ts b/packages/ui/src/stores/types/sessionTypes.ts
index a7295519..ce9b56f1 100644
--- a/packages/ui/src/stores/types/sessionTypes.ts
+++ b/packages/ui/src/stores/types/sessionTypes.ts
@@ -56,6 +56,13 @@ export const MEMORY_LIMITS = {
export const ACTIVE_SESSION_WINDOW = 180;
+export type NewSessionDraftState = {
+ open: boolean;
+ directoryOverride: string | null;
+ parentID: string | null;
+ title?: string;
+};
+
export interface SessionStore {
sessions: Session[];
@@ -98,10 +105,16 @@ export interface SessionStore {
pendingInputText: string | null;
+ newSessionDraft: NewSessionDraftState;
+
getSessionAgentEditMode: (sessionId: string, agentName: string | undefined, defaultMode?: EditPermissionMode) => EditPermissionMode;
toggleSessionAgentEditMode: (sessionId: string, agentName: string | undefined, defaultMode?: EditPermissionMode) => void;
setSessionAgentEditMode: (sessionId: string, agentName: string | undefined, mode: EditPermissionMode, defaultMode?: EditPermissionMode) => void;
loadSessions: () => Promise;
+
+ openNewSessionDraft: (options?: { directoryOverride?: string | null; parentID?: string | null; title?: string }) => void;
+ closeNewSessionDraft: () => void;
+
createSession: (title?: string, directoryOverride?: string | null, parentID?: string | null) => Promise;
createSessionFromAssistantMessage: (sourceMessageId: string) => Promise;
diff --git a/packages/ui/src/stores/useSessionStore.ts b/packages/ui/src/stores/useSessionStore.ts
index d5bc77fd..7dad6306 100644
--- a/packages/ui/src/stores/useSessionStore.ts
+++ b/packages/ui/src/stores/useSessionStore.ts
@@ -95,6 +95,7 @@ export const useSessionStore = create()(
sessionActivityPhase: new Map(),
userSummaryTitles: new Map(),
pendingInputText: null,
+ newSessionDraft: { open: true, directoryOverride: null, parentID: null },
getSessionAgentEditMode: (sessionId: string, agentName: string | undefined, defaultMode?: EditPermissionMode) => {
return useContextStore.getState().getSessionAgentEditMode(sessionId, agentName, defaultMode);
@@ -109,7 +110,46 @@ export const useSessionStore = create()(
},
loadSessions: () => useSessionManagementStore.getState().loadSessions(),
+
+ openNewSessionDraft: (options) => {
+ set({
+ newSessionDraft: {
+ open: true,
+ directoryOverride: options?.directoryOverride ?? null,
+ parentID: options?.parentID ?? null,
+ title: options?.title,
+ },
+ currentSessionId: null,
+ error: null,
+ });
+
+ try {
+ const configState = useConfigStore.getState();
+ const visibleAgents = configState.getVisibleAgents();
+ const agentName =
+ configState.currentAgentName ||
+ visibleAgents.find((agent) => agent.name === 'build')?.name ||
+ visibleAgents[0]?.name;
+
+ if (agentName) {
+ configState.setAgent(agentName);
+ }
+ } catch {
+ // ignored
+ }
+ },
+
+ closeNewSessionDraft: () => {
+ const realCurrentSessionId = useSessionManagementStore.getState().currentSessionId;
+ set({
+ newSessionDraft: { open: false, directoryOverride: null, parentID: null, title: undefined },
+ currentSessionId: realCurrentSessionId,
+ });
+ },
+
createSession: async (title?: string, directoryOverride?: string | null, parentID?: string | null) => {
+ get().closeNewSessionDraft();
+
const result = await useSessionManagementStore.getState().createSession(title, directoryOverride, parentID);
if (result?.id) {
@@ -179,7 +219,11 @@ export const useSessionStore = create()(
shareSession: (id: string) => useSessionManagementStore.getState().shareSession(id),
unshareSession: (id: string) => useSessionManagementStore.getState().unshareSession(id),
setCurrentSession: async (id: string | null) => {
- const previousSessionId = get().currentSessionId;
+ if (id) {
+ get().closeNewSessionDraft();
+ }
+
+ const previousSessionId = useSessionManagementStore.getState().currentSessionId;
const sessionDirectory = resolveSessionDirectory(
useSessionManagementStore.getState().sessions,
@@ -224,7 +268,64 @@ export const useSessionStore = create()(
get().evictLeastRecentlyUsed();
},
loadMessages: (sessionId: string) => useMessageStore.getState().loadMessages(sessionId),
- sendMessage: (content: string, providerID: string, modelID: string, agent?: string, attachments?: AttachedFile[], agentMentionName?: string) => {
+ sendMessage: async (content: string, providerID: string, modelID: string, agent?: string, attachments?: AttachedFile[], agentMentionName?: string) => {
+ const draft = get().newSessionDraft;
+
+ if (draft?.open) {
+ const created = await useSessionManagementStore
+ .getState()
+ .createSession(draft.title, draft.directoryOverride ?? null, draft.parentID ?? null);
+
+ if (!created?.id) {
+ throw new Error('Failed to create session');
+ }
+
+ const configState = useConfigStore.getState();
+ const draftAgentName = configState.currentAgentName;
+ const draftProviderId = configState.currentProviderId;
+ const draftModelId = configState.currentModelId;
+
+ if (draftProviderId && draftModelId) {
+ try {
+ useContextStore.getState().saveSessionModelSelection(created.id, draftProviderId, draftModelId);
+ } catch {
+ // ignored
+ }
+ }
+
+ if (draftAgentName) {
+ try {
+ useContextStore.getState().saveSessionAgentSelection(created.id, draftAgentName);
+ } catch {
+ // ignored
+ }
+
+ if (draftProviderId && draftModelId) {
+ try {
+ useContextStore
+ .getState()
+ .saveAgentModelForSession(created.id, draftAgentName, draftProviderId, draftModelId);
+ } catch {
+ // ignored
+ }
+ }
+ }
+
+ try {
+ useSessionManagementStore
+ .getState()
+ .initializeNewOpenChamberSession(created.id, configState.agents);
+ } catch {
+ // ignored
+ }
+
+ get().closeNewSessionDraft();
+
+ return useMessageStore
+ .getState()
+ .sendMessage(content, providerID, modelID, agent, created.id, attachments, agentMentionName);
+ }
+
const currentSessionId = useSessionManagementStore.getState().currentSessionId;
return useMessageStore.getState().sendMessage(content, providerID, modelID, agent, currentSessionId || undefined, attachments, agentMentionName);
},
@@ -309,6 +410,10 @@ export const useSessionStore = create()(
setSessionDirectory: (sessionId: string, directory: string | null) => useSessionManagementStore.getState().setSessionDirectory(sessionId, directory),
getWorktreeMetadata: (sessionId: string) => useSessionManagementStore.getState().getWorktreeMetadata(sessionId),
getContextUsage: (contextLimit: number, outputLimit: number) => {
+ if (get().newSessionDraft?.open) {
+ return null;
+ }
+
const currentSessionId = useSessionManagementStore.getState().currentSessionId;
if (!currentSessionId) return null;
const messages = useMessageStore.getState().messages;
@@ -420,9 +525,11 @@ useSessionManagementStore.subscribe((state, prevState) => {
return;
}
+ const draftOpen = useSessionStore.getState().newSessionDraft?.open;
+
useSessionStore.setState({
sessions: state.sessions,
- currentSessionId: state.currentSessionId,
+ currentSessionId: draftOpen ? null : state.currentSessionId,
lastLoadedDirectory: state.lastLoadedDirectory,
isLoading: state.isLoading,
error: state.error,
@@ -535,9 +642,11 @@ usePermissionStore.subscribe((state, prevState) => {
});
});
+const bootDraftOpen = useSessionStore.getState().newSessionDraft?.open;
+
useSessionStore.setState({
sessions: useSessionManagementStore.getState().sessions,
- currentSessionId: useSessionManagementStore.getState().currentSessionId,
+ currentSessionId: bootDraftOpen ? null : useSessionManagementStore.getState().currentSessionId,
lastLoadedDirectory: useSessionManagementStore.getState().lastLoadedDirectory,
isLoading: useSessionManagementStore.getState().isLoading,
error: useSessionManagementStore.getState().error,