From 4b7ef9c213a66d6cae56f741d0829b19d0302753 Mon Sep 17 00:00:00 2001 From: Pedram Amini Date: Thu, 5 Feb 2026 21:09:08 -0600 Subject: [PATCH] feat: add working directory deletion option to quit confirmation modal Add agent name input with confirmation pattern to enable a "Quit & Delete Working Dirs" button. Widen modal, reduce button size/font, prevent wrapping. Guard against window.maestro timing issues in production. --- src/renderer/App.tsx | 11 ++++ src/renderer/components/AppModals.tsx | 6 +++ src/renderer/components/QuitConfirmModal.tsx | 55 ++++++++++++++++++-- src/renderer/hooks/settings/useSettings.ts | 4 ++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index bdecffbe..432c8bd4 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -851,6 +851,12 @@ function MaestroConsoleInner() { window.maestro.app.confirmQuit(); }, []); + const handleConfirmQuitAndDelete = useCallback(() => { + setQuitConfirmModalOpen(false); + // TODO: Implement working directory deletion before quit + window.maestro.app.confirmQuit(); + }, []); + const handleCancelQuit = useCallback(() => { setQuitConfirmModalOpen(false); window.maestro.app.cancelQuit(); @@ -4135,6 +4141,10 @@ function MaestroConsoleInner() { // Quit confirmation handler - shows modal when trying to quit with busy agents useEffect(() => { + // Guard against window.maestro not being defined yet (production timing) + if (!window.maestro?.app?.onQuitConfirmationRequest) { + return; + } const unsubscribe = window.maestro.app.onQuitConfirmationRequest(() => { // Get all busy AI sessions (agents that are actively thinking) const busyAgents = sessions.filter( @@ -13518,6 +13528,7 @@ You are taking over this conversation. Based on the context above, provide a bri onCloseConfirmModal={handleCloseConfirmModal} quitConfirmModalOpen={quitConfirmModalOpen} onConfirmQuit={handleConfirmQuit} + onConfirmQuitAndDelete={handleConfirmQuitAndDelete} onCancelQuit={handleCancelQuit} // AppSessionModals props newInstanceModalOpen={newInstanceModalOpen} diff --git a/src/renderer/components/AppModals.tsx b/src/renderer/components/AppModals.tsx index a5fb9e62..cd7792b5 100644 --- a/src/renderer/components/AppModals.tsx +++ b/src/renderer/components/AppModals.tsx @@ -291,6 +291,7 @@ export interface AppConfirmModalsProps { // Quit Confirm Modal quitConfirmModalOpen: boolean; onConfirmQuit: () => void; + onConfirmQuitAndDelete: () => void; onCancelQuit: () => void; } @@ -312,6 +313,7 @@ export function AppConfirmModals({ // Quit Confirm Modal quitConfirmModalOpen, onConfirmQuit, + onConfirmQuitAndDelete, onCancelQuit, }: AppConfirmModalsProps) { // Compute busy agents for QuitConfirmModal @@ -338,6 +340,7 @@ export function AppConfirmModals({ busyAgentCount={busyAgents.length} busyAgentNames={busyAgents.map((s) => s.name)} onConfirmQuit={onConfirmQuit} + onConfirmQuitAndDelete={onConfirmQuitAndDelete} onCancel={onCancelQuit} /> )} @@ -1742,6 +1745,7 @@ export interface AppModalsProps { onCloseConfirmModal: () => void; quitConfirmModalOpen: boolean; onConfirmQuit: () => void; + onConfirmQuitAndDelete: () => void; onCancelQuit: () => void; // --- AppSessionModals props --- @@ -2097,6 +2101,7 @@ export function AppModals(props: AppModalsProps) { onCloseConfirmModal, quitConfirmModalOpen, onConfirmQuit, + onConfirmQuitAndDelete, onCancelQuit, // Session modals newInstanceModalOpen, @@ -2369,6 +2374,7 @@ export function AppModals(props: AppModalsProps) { onCloseConfirmModal={onCloseConfirmModal} quitConfirmModalOpen={quitConfirmModalOpen} onConfirmQuit={onConfirmQuit} + onConfirmQuitAndDelete={onConfirmQuitAndDelete} onCancelQuit={onCancelQuit} /> diff --git a/src/renderer/components/QuitConfirmModal.tsx b/src/renderer/components/QuitConfirmModal.tsx index 696ab527..245a491b 100644 --- a/src/renderer/components/QuitConfirmModal.tsx +++ b/src/renderer/components/QuitConfirmModal.tsx @@ -6,7 +6,7 @@ * Focus defaults to Cancel to prevent accidental data loss. */ -import { useEffect, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { AlertTriangle } from 'lucide-react'; import type { Theme } from '../types'; import { useLayerStack } from '../contexts/LayerStackContext'; @@ -20,6 +20,8 @@ interface QuitConfirmModalProps { busyAgentNames: string[]; /** Callback when user confirms quit */ onConfirmQuit: () => void; + /** Callback when user confirms quit and requests working directory deletion */ + onConfirmQuitAndDelete: () => void; /** Callback when user cancels (stays in app) */ onCancel: () => void; } @@ -35,6 +37,7 @@ export function QuitConfirmModal({ busyAgentCount, busyAgentNames, onConfirmQuit, + onConfirmQuitAndDelete, onCancel, }: QuitConfirmModalProps): JSX.Element { const { registerLayer, unregisterLayer, updateLayerHandler } = useLayerStack(); @@ -42,6 +45,12 @@ export function QuitConfirmModal({ const cancelButtonRef = useRef(null); const onCancelRef = useRef(onCancel); onCancelRef.current = onCancel; + const [confirmName, setConfirmName] = useState(''); + + // Check if typed name matches any busy agent name (case-insensitive) + const deleteEnabled = busyAgentNames.some( + (name) => name.toLowerCase() === confirmName.trim().toLowerCase() + ); // Focus Cancel button on mount (safer default action) useEffect(() => { @@ -98,7 +107,7 @@ export function QuitConfirmModal({ onKeyDown={handleKeyDown} >
+ {/* Agent name confirmation input for working directory deletion */} +
+ + setConfirmName(e.target.value)} + placeholder="" + className="w-full px-3 py-1.5 rounded-lg border text-xs outline-none focus:ring-1" + style={{ + backgroundColor: theme.colors.bgMain, + borderColor: theme.colors.border, + color: theme.colors.textMain, + }} + /> +
+ {/* Actions */} -
+
+