diff --git a/.gitignore b/.gitignore index 878dbe41..39636667 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ release/ .vite/ .electron-vite/ out/ +.dir-locals.el \ No newline at end of file diff --git a/packages/server/src/config/schema.ts b/packages/server/src/config/schema.ts index a2c88f02..266d69b4 100644 --- a/packages/server/src/config/schema.ts +++ b/packages/server/src/config/schema.ts @@ -18,6 +18,7 @@ const PreferencesSchema = z.object({ toolOutputExpansion: z.enum(["expanded", "collapsed"]).default("expanded"), diagnosticsExpansion: z.enum(["expanded", "collapsed"]).default("expanded"), showUsageMetrics: z.boolean().default(true), + autoCleanupBlankSessions: z.boolean().default(true), }) const RecentFolderSchema = z.object({ diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index e76a69b7..dd8f5e2c 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -47,6 +47,7 @@ const App: Component = () => { preferences, recordWorkspaceLaunch, toggleShowThinkingBlocks, + toggleAutoCleanupBlankSessions, toggleUsageMetrics, setDiffViewMode, setToolOutputExpansion, @@ -206,6 +207,7 @@ const App: Component = () => { const { commands: paletteCommands, executeCommand } = useCommands({ preferences, + toggleAutoCleanupBlankSessions, toggleShowThinkingBlocks, toggleUsageMetrics, setDiffViewMode, diff --git a/packages/ui/src/lib/hooks/use-commands.ts b/packages/ui/src/lib/hooks/use-commands.ts index 087eebf9..6b5ff746 100644 --- a/packages/ui/src/lib/hooks/use-commands.ts +++ b/packages/ui/src/lib/hooks/use-commands.ts @@ -22,6 +22,7 @@ export interface UseCommandsOptions { preferences: Accessor toggleShowThinkingBlocks: () => void toggleUsageMetrics: () => void + toggleAutoCleanupBlankSessions: () => void setDiffViewMode: (mode: "split" | "unified") => void setToolOutputExpansion: (mode: ExpansionPreference) => void setDiagnosticsExpansion: (mode: ExpansionPreference) => void @@ -145,10 +146,10 @@ export function useCommands(options: UseCommandsOptions) { commandRegistry.register({ id: "cleanup-blank-sessions", - label: "Cleanup Blank Sessions", - description: "Remove empty sessions from the current instance", + label: "Scrub Sessions", + description: "Remove empty sessions, subagent sessions that have completed their primary task, and extraneous forked sessions.", category: "Session", - keywords: ["cleanup", "blank", "empty", "sessions", "remove", "delete"], + keywords: ["cleanup", "blank", "empty", "sessions", "remove", "delete", "scrub"], action: async () => { const instance = activeInstance() if (!instance) return @@ -481,6 +482,18 @@ export function useCommands(options: UseCommandsOptions) { keywords: ["token", "usage", "cost", "stats"], action: options.toggleUsageMetrics, }) + + commandRegistry.register({ + id: "auto-cleanup-blank-sessions", + label: () => { + const enabled = options.preferences().autoCleanupBlankSessions + return `Auto-Cleanup Blank Sessions ยท ${enabled ? "Enabled" : "Disabled"}` + }, + description: "Automatically clean up blank sessions when creating new ones", + category: "System", + keywords: ["auto", "cleanup", "blank", "sessions", "toggle"], + action: options.toggleAutoCleanupBlankSessions, + }) commandRegistry.register({ id: "help", diff --git a/packages/ui/src/stores/preferences.tsx b/packages/ui/src/stores/preferences.tsx index 59611498..5849dc3f 100644 --- a/packages/ui/src/stores/preferences.tsx +++ b/packages/ui/src/stores/preferences.tsx @@ -37,6 +37,7 @@ export interface Preferences { toolOutputExpansion: ExpansionPreference diagnosticsExpansion: ExpansionPreference showUsageMetrics: boolean + autoCleanupBlankSessions?: boolean } export interface OpenCodeBinary { @@ -64,6 +65,7 @@ const defaultPreferences: Preferences = { toolOutputExpansion: "expanded", diagnosticsExpansion: "expanded", showUsageMetrics: true, + autoCleanupBlankSessions: true, } function deepEqual(a: unknown, b: unknown): boolean { @@ -98,6 +100,7 @@ function normalizePreferences(pref?: Partial & { agentModelSelectio toolOutputExpansion: sanitized.toolOutputExpansion ?? defaultPreferences.toolOutputExpansion, diagnosticsExpansion: sanitized.diagnosticsExpansion ?? defaultPreferences.diagnosticsExpansion, showUsageMetrics: sanitized.showUsageMetrics ?? defaultPreferences.showUsageMetrics, + autoCleanupBlankSessions: sanitized.autoCleanupBlankSessions ?? defaultPreferences.autoCleanupBlankSessions, } } @@ -285,6 +288,11 @@ function toggleUsageMetrics(): void { updatePreferences({ showUsageMetrics: !preferences().showUsageMetrics }) } +function toggleAutoCleanupBlankSessions(): void { + console.log("toggle auto cleanup") + updatePreferences({ autoCleanupBlankSessions: !preferences().autoCleanupBlankSessions }) +} + function addRecentFolder(path: string): void { updateConfig((draft) => { draft.recentFolders = buildRecentFolderList(path, draft.recentFolders) @@ -386,6 +394,7 @@ interface ConfigContextValue { updateConfig: typeof updateConfig toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks toggleUsageMetrics: typeof toggleUsageMetrics + toggleAutoCleanupBlankSessions: typeof toggleAutoCleanupBlankSessions setDiffViewMode: typeof setDiffViewMode setToolOutputExpansion: typeof setToolOutputExpansion setDiagnosticsExpansion: typeof setDiagnosticsExpansion @@ -418,6 +427,7 @@ const configContextValue: ConfigContextValue = { updateConfig, toggleShowThinkingBlocks, toggleUsageMetrics, + toggleAutoCleanupBlankSessions, setDiffViewMode, setToolOutputExpansion, setDiagnosticsExpansion, @@ -473,6 +483,7 @@ export { updateConfig, updatePreferences, toggleShowThinkingBlocks, + toggleAutoCleanupBlankSessions, toggleUsageMetrics, recentFolders, addRecentFolder, diff --git a/packages/ui/src/stores/session-api.ts b/packages/ui/src/stores/session-api.ts index bfbe7212..ab213316 100644 --- a/packages/ui/src/stores/session-api.ts +++ b/packages/ui/src/stores/session-api.ts @@ -2,7 +2,7 @@ import type { Session } from "../types/session" import type { Message } from "../types/message" import { instances, refreshPermissionsForSession } from "./instances" -import { setAgentModelPreference } from "./preferences" +import { preferences, setAgentModelPreference } from "./preferences" import { setSessionCompactionState } from "./session-compaction" import { activeSessionId, @@ -231,7 +231,9 @@ async function createSession(instanceId: string, agent?: string): Promise