mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 00:21:21 +00:00
I'm ready to analyze the Github project changes and create an exciting update summary! However, I don't see any input provided after "INPUT:" in your message.
Please share the changelog, commit history, release notes, or any other information about what changed in the Github project since the last release, and I'll create a clean CHANGES section with exciting 10-word bullets and emojis for you.
This commit is contained in:
5
.github/instructions/memory.instruction.md
vendored
Normal file
5
.github/instructions/memory.instruction.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
applyTo: '**'
|
||||
---
|
||||
|
||||
Remembered number: 42
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -242,6 +242,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
if: steps.check_artifacts.outputs.has_artifacts == 'true'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
@@ -255,3 +256,14 @@ jobs:
|
||||
generate_release_notes: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Notify Discord
|
||||
if: steps.check_artifacts.outputs.has_artifacts == 'true'
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
nodetail: true
|
||||
title: "🎉 Maestro ${{ github.ref_name }} Released!"
|
||||
description: "A new version of Maestro is now available. Check out the release for download links and changelog."
|
||||
url: ${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}
|
||||
color: 0x58B09C
|
||||
|
||||
@@ -249,6 +249,7 @@ describe('agent-capabilities', () => {
|
||||
'supportsStreaming',
|
||||
'supportsResultMessages',
|
||||
'supportsModelSelection',
|
||||
'requiresPromptToStart',
|
||||
];
|
||||
|
||||
const defaultKeys = Object.keys(DEFAULT_CAPABILITIES);
|
||||
|
||||
@@ -152,7 +152,7 @@ let projectStatsCallback: ((stats: unknown) => void) | null = null;
|
||||
const createDefaultProps = (overrides: Partial<Parameters<typeof AgentSessionsBrowser>[0]> = {}) => ({
|
||||
theme: defaultTheme,
|
||||
activeSession: createMockActiveSession(),
|
||||
activeClaudeSessionId: null as string | null,
|
||||
activeAgentSessionId: null as string | null,
|
||||
onClose: vi.fn(),
|
||||
onResumeSession: vi.fn(),
|
||||
onNewSession: vi.fn(),
|
||||
@@ -491,7 +491,7 @@ describe('AgentSessionsBrowser', () => {
|
||||
|
||||
it('shows active Claude session ID badge when provided', async () => {
|
||||
const props = createDefaultProps({
|
||||
activeClaudeSessionId: 'abc12345-def6-7890',
|
||||
activeAgentSessionId: 'abc12345-def6-7890',
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -2351,7 +2351,7 @@ describe('AgentSessionsBrowser', () => {
|
||||
});
|
||||
|
||||
const props = createDefaultProps({
|
||||
activeClaudeSessionId: 'active-session-123',
|
||||
activeAgentSessionId: 'active-session-123',
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -2359,7 +2359,7 @@ describe('AgentSessionsBrowser', () => {
|
||||
await vi.runAllTimersAsync();
|
||||
});
|
||||
|
||||
// When activeClaudeSessionId is provided, the component auto-jumps to detail view
|
||||
// When activeAgentSessionId is provided, the component auto-jumps to detail view
|
||||
// Go back to list view first
|
||||
const backButton = screen.getByTestId('icon-chevron-left').closest('button');
|
||||
await act(async () => {
|
||||
@@ -2378,7 +2378,7 @@ describe('AgentSessionsBrowser', () => {
|
||||
// ============================================================================
|
||||
|
||||
describe('auto-jump to session', () => {
|
||||
it('auto-opens session detail when activeClaudeSessionId provided', async () => {
|
||||
it('auto-opens session detail when activeAgentSessionId provided', async () => {
|
||||
const session = createMockClaudeSession({ sessionId: 'target-session' });
|
||||
vi.mocked(window.maestro.agentSessions.listPaginated).mockResolvedValue({
|
||||
sessions: [session],
|
||||
@@ -2393,7 +2393,7 @@ describe('AgentSessionsBrowser', () => {
|
||||
});
|
||||
|
||||
const props = createDefaultProps({
|
||||
activeClaudeSessionId: 'target-session',
|
||||
activeAgentSessionId: 'target-session',
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
||||
@@ -23,6 +23,8 @@ vi.mock('../../../renderer/hooks/useAgentCapabilities', () => ({
|
||||
supportsBatchMode: true,
|
||||
supportsStreaming: true,
|
||||
supportsResultMessages: true,
|
||||
supportsModelSelection: false,
|
||||
requiresPromptToStart: false,
|
||||
},
|
||||
loading: false,
|
||||
error: null,
|
||||
@@ -42,6 +44,8 @@ vi.mock('../../../renderer/hooks/useAgentCapabilities', () => ({
|
||||
supportsBatchMode: true,
|
||||
supportsStreaming: true,
|
||||
supportsResultMessages: true,
|
||||
supportsModelSelection: false,
|
||||
requiresPromptToStart: false,
|
||||
};
|
||||
return capabilities[cap] ?? false;
|
||||
}),
|
||||
@@ -683,6 +687,8 @@ describe('InputArea', () => {
|
||||
supportsBatchMode: false,
|
||||
supportsStreaming: true,
|
||||
supportsResultMessages: true,
|
||||
supportsModelSelection: false,
|
||||
requiresPromptToStart: false,
|
||||
},
|
||||
loading: false,
|
||||
error: null,
|
||||
@@ -719,6 +725,8 @@ describe('InputArea', () => {
|
||||
supportsBatchMode: false,
|
||||
supportsStreaming: true,
|
||||
supportsResultMessages: true,
|
||||
supportsModelSelection: false,
|
||||
requiresPromptToStart: false,
|
||||
},
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
@@ -267,9 +267,9 @@ describe('MainPanel', () => {
|
||||
setGitDiffPreview: vi.fn(),
|
||||
setLogViewerOpen: vi.fn(),
|
||||
setAgentSessionsOpen: vi.fn(),
|
||||
setActiveClaudeSessionId: vi.fn(),
|
||||
onResumeClaudeSession: vi.fn(),
|
||||
onNewClaudeSession: vi.fn(),
|
||||
setActiveAgentSessionId: vi.fn(),
|
||||
onResumeAgentSession: vi.fn(),
|
||||
onNewAgentSession: vi.fn(),
|
||||
setActiveFocus: vi.fn(),
|
||||
setOutputSearchOpen: vi.fn(),
|
||||
setOutputSearchQuery: vi.fn(),
|
||||
@@ -439,16 +439,16 @@ describe('MainPanel', () => {
|
||||
|
||||
it('should open Agent Sessions when button is clicked', () => {
|
||||
const setAgentSessionsOpen = vi.fn();
|
||||
const setActiveClaudeSessionId = vi.fn();
|
||||
const setActiveAgentSessionId = vi.fn();
|
||||
render(<MainPanel
|
||||
{...defaultProps}
|
||||
setAgentSessionsOpen={setAgentSessionsOpen}
|
||||
setActiveClaudeSessionId={setActiveClaudeSessionId}
|
||||
setActiveAgentSessionId={setActiveAgentSessionId}
|
||||
/>);
|
||||
|
||||
fireEvent.click(screen.getByTitle(/Agent Sessions/));
|
||||
|
||||
expect(setActiveClaudeSessionId).toHaveBeenCalledWith(null);
|
||||
expect(setActiveAgentSessionId).toHaveBeenCalledWith(null);
|
||||
expect(setAgentSessionsOpen).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ const createDefaultProps = (overrides: Partial<React.ComponentProps<typeof Quick
|
||||
setLogViewerOpen: vi.fn(),
|
||||
setProcessMonitorOpen: vi.fn(),
|
||||
setAgentSessionsOpen: vi.fn(),
|
||||
setActiveClaudeSessionId: vi.fn(),
|
||||
setActiveAgentSessionId: vi.fn(),
|
||||
setGitDiffPreview: vi.fn(),
|
||||
setGitLogOpen: vi.fn(),
|
||||
...overrides,
|
||||
@@ -531,7 +531,7 @@ describe('QuickActionsModal', () => {
|
||||
|
||||
fireEvent.click(screen.getByText('View Agent Sessions for Test Session'));
|
||||
|
||||
expect(props.setActiveClaudeSessionId).toHaveBeenCalledWith(null);
|
||||
expect(props.setActiveAgentSessionId).toHaveBeenCalledWith(null);
|
||||
expect(props.setAgentSessionsOpen).toHaveBeenCalledWith(true);
|
||||
expect(props.setQuickActionOpen).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
@@ -96,6 +96,22 @@ describe('useSessionManager', () => {
|
||||
args: ['--print'],
|
||||
available: true,
|
||||
}),
|
||||
getCapabilities: vi.fn().mockResolvedValue({
|
||||
supportsResume: true,
|
||||
supportsReadOnlyMode: true,
|
||||
supportsJsonOutput: true,
|
||||
supportsSessionId: true,
|
||||
supportsImageInput: true,
|
||||
supportsSlashCommands: true,
|
||||
supportsSessionStorage: true,
|
||||
supportsCostTracking: true,
|
||||
supportsUsageStats: true,
|
||||
supportsBatchMode: true,
|
||||
supportsStreaming: true,
|
||||
supportsResultMessages: true,
|
||||
supportsModelSelection: false,
|
||||
requiresPromptToStart: false,
|
||||
}),
|
||||
},
|
||||
process: {
|
||||
spawn: vi.fn().mockResolvedValue({ pid: 12345, success: true }),
|
||||
|
||||
@@ -46,7 +46,7 @@ import { useKeyboardShortcutHelpers } from './hooks/useKeyboardShortcutHelpers';
|
||||
import { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
|
||||
import { useMainKeyboardHandler } from './hooks/useMainKeyboardHandler';
|
||||
import { useRemoteIntegration } from './hooks/useRemoteIntegration';
|
||||
import { useClaudeSessionManagement } from './hooks/useClaudeSessionManagement';
|
||||
import { useAgentSessionManagement } from './hooks/useAgentSessionManagement';
|
||||
import { useAgentExecution } from './hooks/useAgentExecution';
|
||||
import { useFileTreeManagement } from './hooks/useFileTreeManagement';
|
||||
import { useGroupManagement } from './hooks/useGroupManagement';
|
||||
@@ -315,7 +315,7 @@ export default function MaestroConsole() {
|
||||
|
||||
// Agent Sessions Browser State (main panel view)
|
||||
const [agentSessionsOpen, setAgentSessionsOpen] = useState(false);
|
||||
const [activeClaudeSessionId, setActiveClaudeSessionId] = useState<string | null>(null);
|
||||
const [activeAgentSessionId, setActiveAgentSessionId] = useState<string | null>(null);
|
||||
|
||||
// NOTE: showSessionJumpNumbers state is now provided by useMainKeyboardHandler hook
|
||||
|
||||
@@ -1513,7 +1513,7 @@ export default function MaestroConsole() {
|
||||
activeSessionIdRef.current = activeSessionId;
|
||||
|
||||
// Note: spawnBackgroundSynopsisRef and spawnAgentWithPromptRef are now provided by useAgentExecution hook
|
||||
// Note: addHistoryEntryRef and startNewClaudeSessionRef are now provided by useClaudeSessionManagement hook
|
||||
// Note: addHistoryEntryRef and startNewAgentSessionRef are now provided by useAgentSessionManagement hook
|
||||
// Ref for processQueuedMessage - allows batch exit handler to process queued messages
|
||||
const processQueuedItemRef = useRef<((sessionId: string, item: QueuedItem) => Promise<void>) | null>(null);
|
||||
|
||||
@@ -1994,14 +1994,14 @@ export default function MaestroConsole() {
|
||||
const {
|
||||
addHistoryEntry,
|
||||
addHistoryEntryRef,
|
||||
startNewClaudeSession,
|
||||
startNewClaudeSessionRef,
|
||||
startNewAgentSession,
|
||||
startNewAgentSessionRef,
|
||||
handleJumpToAgentSession,
|
||||
handleResumeSession,
|
||||
} = useClaudeSessionManagement({
|
||||
} = useAgentSessionManagement({
|
||||
activeSession,
|
||||
setSessions,
|
||||
setActiveClaudeSessionId,
|
||||
setActiveAgentSessionId,
|
||||
setAgentSessionsOpen,
|
||||
addLogToActiveTab,
|
||||
rightPanelRef,
|
||||
@@ -3412,10 +3412,10 @@ export default function MaestroConsole() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build spawn args with resume if we have a Claude session ID
|
||||
// Build spawn args with resume if we have an agent session ID
|
||||
// Use the ACTIVE TAB's agentSessionId (not the deprecated session-level one)
|
||||
const activeTab = getActiveTab(session);
|
||||
const tabClaudeSessionId = activeTab?.agentSessionId;
|
||||
const tabAgentSessionId = activeTab?.agentSessionId;
|
||||
const isReadOnly = activeTab?.readOnlyMode;
|
||||
|
||||
// Filter out YOLO/skip-permissions flags when read-only mode is active
|
||||
@@ -3429,8 +3429,8 @@ export default function MaestroConsole() {
|
||||
)
|
||||
: [...agent.args];
|
||||
|
||||
if (tabClaudeSessionId) {
|
||||
spawnArgs.push('--resume', tabClaudeSessionId);
|
||||
if (tabAgentSessionId) {
|
||||
spawnArgs.push('--resume', tabAgentSessionId);
|
||||
}
|
||||
|
||||
// Add read-only/plan mode if the active tab has readOnlyMode enabled
|
||||
@@ -3442,12 +3442,12 @@ export default function MaestroConsole() {
|
||||
const targetSessionId = `${sessionId}-ai-${activeTab?.id || 'default'}`;
|
||||
const commandToUse = agent.path || agent.command;
|
||||
|
||||
console.log('[Remote] Spawning Claude directly:', {
|
||||
console.log('[Remote] Spawning agent:', {
|
||||
maestroSessionId: sessionId,
|
||||
targetSessionId,
|
||||
activeTabId: activeTab?.id,
|
||||
tabClaudeSessionId: tabClaudeSessionId || 'NEW SESSION',
|
||||
isResume: !!tabClaudeSessionId,
|
||||
tabAgentSessionId: tabAgentSessionId || 'NEW SESSION',
|
||||
isResume: !!tabAgentSessionId,
|
||||
command: commandToUse,
|
||||
args: spawnArgs,
|
||||
prompt: promptToSend.substring(0, 100)
|
||||
@@ -3598,7 +3598,7 @@ export default function MaestroConsole() {
|
||||
|
||||
// Build spawn args with resume if we have a session ID
|
||||
// Use the TARGET TAB's agentSessionId (not the active tab or deprecated session-level one)
|
||||
const tabClaudeSessionId = targetTab?.agentSessionId;
|
||||
const tabAgentSessionId = targetTab?.agentSessionId;
|
||||
const isReadOnly = item.readOnlyMode || targetTab?.readOnlyMode;
|
||||
|
||||
// Filter out YOLO/skip-permissions flags when read-only mode is active
|
||||
@@ -3612,8 +3612,8 @@ export default function MaestroConsole() {
|
||||
)
|
||||
: [...(agent.args || [])];
|
||||
|
||||
if (tabClaudeSessionId) {
|
||||
spawnArgs.push('--resume', tabClaudeSessionId);
|
||||
if (tabAgentSessionId) {
|
||||
spawnArgs.push('--resume', tabAgentSessionId);
|
||||
}
|
||||
|
||||
// Add read-only/plan mode if the queued item was from a read-only tab
|
||||
@@ -4420,7 +4420,7 @@ export default function MaestroConsole() {
|
||||
setLeftSidebarOpen, setRightPanelOpen, addNewSession, deleteSession, setQuickActionInitialMode,
|
||||
setQuickActionOpen, cycleSession, toggleInputMode, setShortcutsHelpOpen, setSettingsModalOpen,
|
||||
setSettingsTab, setActiveRightTab, handleSetActiveRightTab, setActiveFocus, setBookmarksCollapsed, setGroups,
|
||||
setSelectedSidebarIndex, setActiveSessionId, handleViewGitDiff, setGitLogOpen, setActiveClaudeSessionId,
|
||||
setSelectedSidebarIndex, setActiveSessionId, handleViewGitDiff, setGitLogOpen, setActiveAgentSessionId,
|
||||
setAgentSessionsOpen, setLogViewerOpen, setProcessMonitorOpen, logsEndRef, inputRef, terminalOutputRef, sidebarContainerRef,
|
||||
setSessions, createTab, closeTab, reopenClosedTab, getActiveTab, setRenameTabId, setRenameTabInitialName,
|
||||
setRenameTabModalOpen, navigateToNextTab, navigateToPrevTab, navigateToTabByIndex, navigateToLastTab,
|
||||
@@ -4685,7 +4685,7 @@ export default function MaestroConsole() {
|
||||
setProcessMonitorOpen={setProcessMonitorOpen}
|
||||
setActiveRightTab={setActiveRightTab}
|
||||
setAgentSessionsOpen={setAgentSessionsOpen}
|
||||
setActiveClaudeSessionId={setActiveClaudeSessionId}
|
||||
setActiveAgentSessionId={setActiveAgentSessionId}
|
||||
setGitDiffPreview={setGitDiffPreview}
|
||||
setGitLogOpen={setGitLogOpen}
|
||||
isAiMode={activeSession?.inputMode === 'ai'}
|
||||
@@ -5114,7 +5114,7 @@ export default function MaestroConsole() {
|
||||
ref={mainPanelRef}
|
||||
logViewerOpen={logViewerOpen}
|
||||
agentSessionsOpen={agentSessionsOpen}
|
||||
activeClaudeSessionId={activeClaudeSessionId}
|
||||
activeAgentSessionId={activeAgentSessionId}
|
||||
activeSession={activeSession}
|
||||
sessions={sessions}
|
||||
theme={theme}
|
||||
@@ -5146,12 +5146,12 @@ export default function MaestroConsole() {
|
||||
setGitDiffPreview={setGitDiffPreview}
|
||||
setLogViewerOpen={setLogViewerOpen}
|
||||
setAgentSessionsOpen={setAgentSessionsOpen}
|
||||
setActiveClaudeSessionId={setActiveClaudeSessionId}
|
||||
onResumeClaudeSession={(agentSessionId: string, messages: LogEntry[], sessionName?: string, starred?: boolean) => {
|
||||
setActiveAgentSessionId={setActiveAgentSessionId}
|
||||
onResumeAgentSession={(agentSessionId: string, messages: LogEntry[], sessionName?: string, starred?: boolean) => {
|
||||
// Opens the Claude session as a new tab (or switches to existing tab if duplicate)
|
||||
handleResumeSession(agentSessionId, messages, sessionName, starred);
|
||||
}}
|
||||
onNewClaudeSession={() => {
|
||||
onNewAgentSession={() => {
|
||||
// Create a fresh AI tab
|
||||
if (activeSession) {
|
||||
setSessions(prev => prev.map(s => {
|
||||
@@ -5159,7 +5159,7 @@ export default function MaestroConsole() {
|
||||
const result = createTab(s, { saveToHistory: defaultSaveToHistory });
|
||||
return result.session;
|
||||
}));
|
||||
setActiveClaudeSessionId(null);
|
||||
setActiveAgentSessionId(null);
|
||||
}
|
||||
setAgentSessionsOpen(false);
|
||||
}}
|
||||
|
||||
@@ -23,7 +23,7 @@ interface SearchResult {
|
||||
interface AgentSessionsBrowserProps {
|
||||
theme: Theme;
|
||||
activeSession: Session | undefined;
|
||||
activeClaudeSessionId: string | null;
|
||||
activeAgentSessionId: string | null;
|
||||
onClose: () => void;
|
||||
onResumeSession: (agentSessionId: string, messages: LogEntry[], sessionName?: string, starred?: boolean) => void;
|
||||
onNewSession: () => void;
|
||||
@@ -33,7 +33,7 @@ interface AgentSessionsBrowserProps {
|
||||
export function AgentSessionsBrowser({
|
||||
theme,
|
||||
activeSession,
|
||||
activeClaudeSessionId,
|
||||
activeAgentSessionId,
|
||||
onClose,
|
||||
onResumeSession,
|
||||
onNewSession,
|
||||
@@ -273,17 +273,17 @@ export function AgentSessionsBrowser({
|
||||
cancelRename();
|
||||
}, [activeSession?.cwd, renameValue, viewingSession?.sessionId, cancelRename, onUpdateTab, updateSession]);
|
||||
|
||||
// Auto-view session when activeClaudeSessionId is provided (e.g., from history panel click)
|
||||
// Auto-view session when activeAgentSessionId is provided (e.g., from history panel click)
|
||||
useEffect(() => {
|
||||
// Only auto-jump once per activeClaudeSessionId
|
||||
if (!loading && sessions.length > 0 && activeClaudeSessionId && !viewingSession && autoJumpedRef.current !== activeClaudeSessionId) {
|
||||
const targetSession = sessions.find(s => s.sessionId === activeClaudeSessionId);
|
||||
// Only auto-jump once per activeAgentSessionId
|
||||
if (!loading && sessions.length > 0 && activeAgentSessionId && !viewingSession && autoJumpedRef.current !== activeAgentSessionId) {
|
||||
const targetSession = sessions.find(s => s.sessionId === activeAgentSessionId);
|
||||
if (targetSession) {
|
||||
autoJumpedRef.current = activeClaudeSessionId;
|
||||
autoJumpedRef.current = activeAgentSessionId;
|
||||
handleViewSession(targetSession);
|
||||
}
|
||||
}
|
||||
}, [loading, sessions, activeClaudeSessionId, viewingSession, handleViewSession]);
|
||||
}, [loading, sessions, activeAgentSessionId, viewingSession, handleViewSession]);
|
||||
|
||||
// Focus input on mount
|
||||
useEffect(() => {
|
||||
@@ -639,12 +639,12 @@ export function AgentSessionsBrowser({
|
||||
<span className="text-sm font-medium" style={{ color: theme.colors.textMain }}>
|
||||
{agentId === 'claude-code' ? 'Claude' : 'Agent'} Sessions for {activeSession?.name || 'Agent'}
|
||||
</span>
|
||||
{activeClaudeSessionId && (
|
||||
{activeAgentSessionId && (
|
||||
<span
|
||||
className="text-xs px-2 py-0.5 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.accent + '20', color: theme.colors.accent }}
|
||||
>
|
||||
Active: {activeClaudeSessionId.slice(0, 8)}...
|
||||
Active: {activeAgentSessionId.slice(0, 8)}...
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
@@ -1116,7 +1116,7 @@ export function AgentSessionsBrowser({
|
||||
index={i}
|
||||
selectedIndex={selectedIndex}
|
||||
isStarred={starredSessions.has(session.sessionId)}
|
||||
activeClaudeSessionId={activeClaudeSessionId}
|
||||
activeAgentSessionId={activeAgentSessionId}
|
||||
renamingSessionId={renamingSessionId}
|
||||
renameValue={renameValue}
|
||||
searchMode={searchMode}
|
||||
|
||||
@@ -32,7 +32,7 @@ interface MainPanelProps {
|
||||
// State
|
||||
logViewerOpen: boolean;
|
||||
agentSessionsOpen: boolean;
|
||||
activeClaudeSessionId: string | null;
|
||||
activeAgentSessionId: string | null;
|
||||
activeSession: Session | null;
|
||||
sessions: Session[]; // All sessions for InputArea's ThinkingStatusPill
|
||||
theme: Theme;
|
||||
@@ -77,9 +77,9 @@ interface MainPanelProps {
|
||||
setGitDiffPreview: (preview: string | null) => void;
|
||||
setLogViewerOpen: (open: boolean) => void;
|
||||
setAgentSessionsOpen: (open: boolean) => void;
|
||||
setActiveClaudeSessionId: (id: string | null) => void;
|
||||
onResumeClaudeSession: (agentSessionId: string, messages: import('../types').LogEntry[], sessionName?: string, starred?: boolean) => void;
|
||||
onNewClaudeSession: () => void;
|
||||
setActiveAgentSessionId: (id: string | null) => void;
|
||||
onResumeAgentSession: (agentSessionId: string, messages: import('../types').LogEntry[], sessionName?: string, starred?: boolean) => void;
|
||||
onNewAgentSession: () => void;
|
||||
setActiveFocus: (focus: FocusArea) => void;
|
||||
setOutputSearchOpen: (open: boolean) => void;
|
||||
setOutputSearchQuery: (query: string) => void;
|
||||
@@ -184,7 +184,7 @@ interface MainPanelProps {
|
||||
|
||||
export const MainPanel = forwardRef<MainPanelHandle, MainPanelProps>(function MainPanel(props, ref) {
|
||||
const {
|
||||
logViewerOpen, agentSessionsOpen, activeClaudeSessionId, activeSession, sessions, theme, activeFocus, outputSearchOpen, outputSearchQuery,
|
||||
logViewerOpen, agentSessionsOpen, activeAgentSessionId, activeSession, sessions, theme, activeFocus, outputSearchOpen, outputSearchQuery,
|
||||
inputValue, enterToSendAI, enterToSendTerminal, stagedImages, commandHistoryOpen, commandHistoryFilter,
|
||||
commandHistorySelectedIndex, slashCommandOpen, slashCommands, selectedSlashCommandIndex,
|
||||
tabCompletionOpen, tabCompletionSuggestions, selectedTabCompletionIndex, tabCompletionFilter,
|
||||
@@ -192,8 +192,8 @@ export const MainPanel = forwardRef<MainPanelHandle, MainPanelProps>(function Ma
|
||||
atMentionOpen, atMentionFilter, atMentionStartIndex, atMentionSuggestions, selectedAtMentionIndex,
|
||||
setAtMentionOpen, setAtMentionFilter, setAtMentionStartIndex, setSelectedAtMentionIndex,
|
||||
previewFile, markdownEditMode, shortcuts, rightPanelOpen, maxOutputLines, gitDiffPreview,
|
||||
fileTreeFilterOpen, logLevel, setGitDiffPreview, setLogViewerOpen, setAgentSessionsOpen, setActiveClaudeSessionId,
|
||||
onResumeClaudeSession, onNewClaudeSession, setActiveFocus, setOutputSearchOpen, setOutputSearchQuery,
|
||||
fileTreeFilterOpen, logLevel, setGitDiffPreview, setLogViewerOpen, setAgentSessionsOpen, setActiveAgentSessionId,
|
||||
onResumeAgentSession, onNewAgentSession, setActiveFocus, setOutputSearchOpen, setOutputSearchQuery,
|
||||
setInputValue, setEnterToSendAI, setEnterToSendTerminal, setStagedImages, setLightboxImage, setCommandHistoryOpen,
|
||||
setCommandHistoryFilter, setCommandHistorySelectedIndex, setSlashCommandOpen,
|
||||
setSelectedSlashCommandIndex, setPreviewFile, setMarkdownEditMode,
|
||||
@@ -377,10 +377,10 @@ export const MainPanel = forwardRef<MainPanelHandle, MainPanelProps>(function Ma
|
||||
<AgentSessionsBrowser
|
||||
theme={theme}
|
||||
activeSession={activeSession || undefined}
|
||||
activeClaudeSessionId={activeClaudeSessionId}
|
||||
activeAgentSessionId={activeAgentSessionId}
|
||||
onClose={() => setAgentSessionsOpen(false)}
|
||||
onResumeSession={onResumeClaudeSession}
|
||||
onNewSession={onNewClaudeSession}
|
||||
onResumeSession={onResumeAgentSession}
|
||||
onNewSession={onNewAgentSession}
|
||||
onUpdateTab={props.onUpdateTabByClaudeSessionId}
|
||||
/>
|
||||
</div>
|
||||
@@ -782,7 +782,7 @@ export const MainPanel = forwardRef<MainPanelHandle, MainPanelProps>(function Ma
|
||||
{hasCapability('supportsSessionStorage') && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setActiveClaudeSessionId(null);
|
||||
setActiveAgentSessionId(null);
|
||||
setAgentSessionsOpen(true);
|
||||
}}
|
||||
className="p-2 rounded hover:bg-white/5"
|
||||
|
||||
@@ -344,7 +344,7 @@ export function NewInstanceModal({ isOpen, onClose, onCreate, theme, defaultAgen
|
||||
className="text-xs font-mono px-3 py-2 rounded"
|
||||
style={{ backgroundColor: theme.colors.bgActivity, color: theme.colors.textDim }}
|
||||
>
|
||||
{agent.path}
|
||||
<span className="opacity-60">Detected:</span> {agent.path}
|
||||
</div>
|
||||
)}
|
||||
{/* Custom path input */}
|
||||
|
||||
@@ -49,7 +49,7 @@ interface QuickActionsModalProps {
|
||||
setLogViewerOpen: (open: boolean) => void;
|
||||
setProcessMonitorOpen: (open: boolean) => void;
|
||||
setAgentSessionsOpen: (open: boolean) => void;
|
||||
setActiveClaudeSessionId: (id: string | null) => void;
|
||||
setActiveAgentSessionId: (id: string | null) => void;
|
||||
setGitDiffPreview: (diff: string | null) => void;
|
||||
setGitLogOpen: (open: boolean) => void;
|
||||
onRenameTab?: () => void;
|
||||
@@ -80,7 +80,7 @@ export function QuickActionsModal(props: QuickActionsModalProps) {
|
||||
setLeftSidebarOpen, setRightPanelOpen, setActiveRightTab, toggleInputMode,
|
||||
deleteSession, addNewSession, setSettingsModalOpen, setSettingsTab,
|
||||
setShortcutsHelpOpen, setAboutModalOpen, setLogViewerOpen, setProcessMonitorOpen,
|
||||
setAgentSessionsOpen, setActiveClaudeSessionId, setGitDiffPreview, setGitLogOpen,
|
||||
setAgentSessionsOpen, setActiveAgentSessionId, setGitDiffPreview, setGitLogOpen,
|
||||
onRenameTab, onToggleReadOnlyMode, onOpenTabSwitcher, tabShortcuts, isAiMode, setPlaygroundOpen, onRefreshGitFileState,
|
||||
onDebugReleaseQueuedItem, markdownEditMode, onToggleMarkdownEditMode, setUpdateCheckModalOpen, openWizard, wizardGoToStep, setDebugWizardModalOpen, startTour, setFuzzyFileSearchOpen
|
||||
} = props;
|
||||
@@ -240,7 +240,7 @@ export function QuickActionsModal(props: QuickActionsModalProps) {
|
||||
...(startTour ? [{ id: 'tour', label: 'Start Introductory Tour', subtext: 'Take a guided tour of the interface', action: () => { startTour(); setQuickActionOpen(false); } }] : []),
|
||||
{ id: 'logs', label: 'View System Logs', shortcut: shortcuts.systemLogs, action: () => { setLogViewerOpen(true); setQuickActionOpen(false); } },
|
||||
{ id: 'processes', label: 'View System Processes', shortcut: shortcuts.processMonitor, action: () => { setProcessMonitorOpen(true); setQuickActionOpen(false); } },
|
||||
...(activeSession ? [{ id: 'agentSessions', label: `View Agent Sessions for ${activeSession.name}`, shortcut: shortcuts.agentSessions, action: () => { setActiveClaudeSessionId(null); setAgentSessionsOpen(true); setQuickActionOpen(false); } }] : []),
|
||||
...(activeSession ? [{ id: 'agentSessions', label: `View Agent Sessions for ${activeSession.name}`, shortcut: shortcuts.agentSessions, action: () => { setActiveAgentSessionId(null); setAgentSessionsOpen(true); setQuickActionOpen(false); } }] : []),
|
||||
...(activeSession?.isGitRepo ? [{ id: 'gitDiff', label: 'View Git Diff', shortcut: shortcuts.viewGitDiff, action: async () => {
|
||||
const cwd = activeSession.inputMode === 'terminal' ? (activeSession.shellCwd || activeSession.cwd) : activeSession.cwd;
|
||||
const diff = await gitService.getDiff(cwd);
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface SessionListItemProps {
|
||||
/** Whether this session is starred */
|
||||
isStarred: boolean;
|
||||
/** Currently active Claude session ID (if any) */
|
||||
activeClaudeSessionId: string | null;
|
||||
activeAgentSessionId: string | null;
|
||||
/** ID of session currently being renamed (if any) */
|
||||
renamingSessionId: string | null;
|
||||
/** Current rename input value */
|
||||
@@ -90,7 +90,7 @@ export function SessionListItem({
|
||||
index,
|
||||
selectedIndex,
|
||||
isStarred,
|
||||
activeClaudeSessionId,
|
||||
activeAgentSessionId,
|
||||
renamingSessionId,
|
||||
renameValue,
|
||||
searchMode,
|
||||
@@ -108,7 +108,7 @@ export function SessionListItem({
|
||||
}: SessionListItemProps) {
|
||||
const isSelected = index === selectedIndex;
|
||||
const isRenaming = renamingSessionId === session.sessionId;
|
||||
const isActive = activeClaudeSessionId === session.sessionId;
|
||||
const isActive = activeAgentSessionId === session.sessionId;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -25,7 +25,7 @@ export { useKeyboardShortcutHelpers } from './useKeyboardShortcutHelpers';
|
||||
export { useKeyboardNavigation } from './useKeyboardNavigation';
|
||||
export { useMainKeyboardHandler } from './useMainKeyboardHandler';
|
||||
export { useRemoteIntegration } from './useRemoteIntegration';
|
||||
export { useClaudeSessionManagement } from './useClaudeSessionManagement';
|
||||
export { useAgentSessionManagement } from './useAgentSessionManagement';
|
||||
export { useAgentExecution } from './useAgentExecution';
|
||||
export { useFileTreeManagement } from './useFileTreeManagement';
|
||||
export { useGroupManagement } from './useGroupManagement';
|
||||
@@ -80,10 +80,10 @@ export type {
|
||||
UseRemoteIntegrationReturn,
|
||||
} from './useRemoteIntegration';
|
||||
export type {
|
||||
UseClaudeSessionManagementDeps,
|
||||
UseClaudeSessionManagementReturn,
|
||||
UseAgentSessionManagementDeps,
|
||||
UseAgentSessionManagementReturn,
|
||||
HistoryEntryInput,
|
||||
} from './useClaudeSessionManagement';
|
||||
} from './useAgentSessionManagement';
|
||||
export type {
|
||||
UseAgentExecutionDeps,
|
||||
UseAgentExecutionReturn,
|
||||
|
||||
@@ -22,15 +22,15 @@ export interface HistoryEntryInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependencies for the useClaudeSessionManagement hook.
|
||||
* Dependencies for the useAgentSessionManagement hook.
|
||||
*/
|
||||
export interface UseClaudeSessionManagementDeps {
|
||||
export interface UseAgentSessionManagementDeps {
|
||||
/** Current active session (null if none selected) */
|
||||
activeSession: Session | null;
|
||||
/** Session state setter */
|
||||
setSessions: React.Dispatch<React.SetStateAction<Session[]>>;
|
||||
/** Claude session ID setter */
|
||||
setActiveClaudeSessionId: (id: string | null) => void;
|
||||
/** Agent session ID setter */
|
||||
setActiveAgentSessionId: (id: string | null) => void;
|
||||
/** Agent sessions browser open state setter */
|
||||
setAgentSessionsOpen: (open: boolean) => void;
|
||||
/** Helper to add a log entry to the active tab */
|
||||
@@ -45,20 +45,20 @@ export interface UseClaudeSessionManagementDeps {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return type for useClaudeSessionManagement hook.
|
||||
* Return type for useAgentSessionManagement hook.
|
||||
*/
|
||||
export interface UseClaudeSessionManagementReturn {
|
||||
export interface UseAgentSessionManagementReturn {
|
||||
/** Add a history entry for the current session */
|
||||
addHistoryEntry: (entry: HistoryEntryInput) => Promise<void>;
|
||||
/** Ref to addHistoryEntry for use in callbacks that need latest version */
|
||||
addHistoryEntryRef: React.MutableRefObject<((entry: HistoryEntryInput) => Promise<void>) | null>;
|
||||
/** Clear Claude session and start fresh */
|
||||
startNewClaudeSession: () => void;
|
||||
/** Ref to startNewClaudeSession for use in callbacks that need latest version */
|
||||
startNewClaudeSessionRef: React.MutableRefObject<(() => void) | null>;
|
||||
/** Clear Agent session and start fresh */
|
||||
startNewAgentSession: () => void;
|
||||
/** Ref to startNewAgentSession for use in callbacks that need latest version */
|
||||
startNewAgentSessionRef: React.MutableRefObject<(() => void) | null>;
|
||||
/** Jump to a specific agent session in the browser */
|
||||
handleJumpToAgentSession: (agentSessionId: string) => void;
|
||||
/** Resume a Claude session, opening as a new tab or switching to existing */
|
||||
/** Resume a Agent session, opening as a new tab or switching to existing */
|
||||
handleResumeSession: (
|
||||
agentSessionId: string,
|
||||
providedMessages?: LogEntry[],
|
||||
@@ -68,24 +68,24 @@ export interface UseClaudeSessionManagementReturn {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for Claude-specific session operations.
|
||||
* Hook for Agent-specific session operations.
|
||||
*
|
||||
* Handles:
|
||||
* - Adding history entries with session metadata
|
||||
* - Starting new Claude sessions (clearing context)
|
||||
* - Jumping to Claude sessions in the browser
|
||||
* - Resuming saved Claude sessions as tabs
|
||||
* - Starting new Agent sessions (clearing context)
|
||||
* - Jumping to Agent sessions in the browser
|
||||
* - Resuming saved Agent sessions as tabs
|
||||
*
|
||||
* @param deps - Hook dependencies
|
||||
* @returns Session management functions and refs
|
||||
*/
|
||||
export function useClaudeSessionManagement(
|
||||
deps: UseClaudeSessionManagementDeps
|
||||
): UseClaudeSessionManagementReturn {
|
||||
export function useAgentSessionManagement(
|
||||
deps: UseAgentSessionManagementDeps
|
||||
): UseAgentSessionManagementReturn {
|
||||
const {
|
||||
activeSession,
|
||||
setSessions,
|
||||
setActiveClaudeSessionId,
|
||||
setActiveAgentSessionId,
|
||||
setAgentSessionsOpen,
|
||||
addLogToActiveTab,
|
||||
rightPanelRef,
|
||||
@@ -94,7 +94,7 @@ export function useClaudeSessionManagement(
|
||||
|
||||
// Refs for functions that need to be accessed from other callbacks
|
||||
const addHistoryEntryRef = useRef<((entry: HistoryEntryInput) => Promise<void>) | null>(null);
|
||||
const startNewClaudeSessionRef = useRef<(() => void) | null>(null);
|
||||
const startNewAgentSessionRef = useRef<(() => void) | null>(null);
|
||||
|
||||
/**
|
||||
* Add a history entry for a session.
|
||||
@@ -135,10 +135,10 @@ export function useClaudeSessionManagement(
|
||||
}, [activeSession, rightPanelRef]);
|
||||
|
||||
/**
|
||||
* Start a new Claude session by clearing the current context.
|
||||
* Start a new Agent session by clearing the current context.
|
||||
* Blocks if there are queued items.
|
||||
*/
|
||||
const startNewClaudeSession = useCallback(() => {
|
||||
const startNewAgentSession = useCallback(() => {
|
||||
if (!activeSession) return;
|
||||
|
||||
// Block clearing when there are queued items
|
||||
@@ -168,8 +168,8 @@ export function useClaudeSessionManagement(
|
||||
aiTabs: updatedAiTabs
|
||||
};
|
||||
}));
|
||||
setActiveClaudeSessionId(null);
|
||||
}, [activeSession, addLogToActiveTab, setSessions, setActiveClaudeSessionId]);
|
||||
setActiveAgentSessionId(null);
|
||||
}, [activeSession, addLogToActiveTab, setSessions, setActiveAgentSessionId]);
|
||||
|
||||
/**
|
||||
* Jump to a specific agent session in the agent sessions browser.
|
||||
@@ -177,11 +177,11 @@ export function useClaudeSessionManagement(
|
||||
const handleJumpToAgentSession = useCallback((agentSessionId: string) => {
|
||||
// Set the agent session ID and load its messages
|
||||
if (activeSession) {
|
||||
setActiveClaudeSessionId(agentSessionId);
|
||||
setActiveAgentSessionId(agentSessionId);
|
||||
// Open the agent sessions browser to show the selected session
|
||||
setAgentSessionsOpen(true);
|
||||
}
|
||||
}, [activeSession, setActiveClaudeSessionId, setAgentSessionsOpen]);
|
||||
}, [activeSession, setActiveAgentSessionId, setAgentSessionsOpen]);
|
||||
|
||||
/**
|
||||
* Resume an agent session - opens as a new tab or switches to existing tab.
|
||||
@@ -204,7 +204,7 @@ export function useClaudeSessionManagement(
|
||||
? { ...s, activeTabId: existingTab.id, inputMode: 'ai' }
|
||||
: s
|
||||
));
|
||||
setActiveClaudeSessionId(agentSessionId);
|
||||
setActiveAgentSessionId(agentSessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ export function useClaudeSessionManagement(
|
||||
if (!starred && !sessionName) {
|
||||
try {
|
||||
// Look up session metadata from session origins (name and starred)
|
||||
// Note: getSessionOrigins is still Claude-specific until we add generic origin tracking
|
||||
// Note: getSessionOrigins is still Agent-specific until we add generic origin tracking
|
||||
const origins = await window.maestro.claude.getSessionOrigins(activeSession.cwd);
|
||||
const originData = origins[agentSessionId];
|
||||
if (originData && typeof originData === 'object') {
|
||||
@@ -271,21 +271,21 @@ export function useClaudeSessionManagement(
|
||||
|
||||
return { ...updatedSession, inputMode: 'ai' };
|
||||
}));
|
||||
setActiveClaudeSessionId(agentSessionId);
|
||||
setActiveAgentSessionId(agentSessionId);
|
||||
} catch (error) {
|
||||
console.error('Failed to resume session:', error);
|
||||
}
|
||||
}, [activeSession?.cwd, activeSession?.id, activeSession?.aiTabs, activeSession?.toolType, setSessions, setActiveClaudeSessionId, defaultSaveToHistory]);
|
||||
}, [activeSession?.cwd, activeSession?.id, activeSession?.aiTabs, activeSession?.toolType, setSessions, setActiveAgentSessionId, defaultSaveToHistory]);
|
||||
|
||||
// Update refs for slash command functions (so other handlers can access latest versions)
|
||||
addHistoryEntryRef.current = addHistoryEntry;
|
||||
startNewClaudeSessionRef.current = startNewClaudeSession;
|
||||
startNewAgentSessionRef.current = startNewAgentSession;
|
||||
|
||||
return {
|
||||
addHistoryEntry,
|
||||
addHistoryEntryRef,
|
||||
startNewClaudeSession,
|
||||
startNewClaudeSessionRef,
|
||||
startNewAgentSession,
|
||||
startNewAgentSessionRef,
|
||||
handleJumpToAgentSession,
|
||||
handleResumeSession,
|
||||
};
|
||||
@@ -244,7 +244,7 @@ export function useMainKeyboardHandler(): UseMainKeyboardHandlerReturn {
|
||||
else if (ctx.isShortcut(e, 'agentSessions')) {
|
||||
e.preventDefault();
|
||||
if (ctx.activeSession?.toolType === 'claude-code') {
|
||||
ctx.setActiveClaudeSessionId(null);
|
||||
ctx.setActiveAgentSessionId(null);
|
||||
ctx.setAgentSessionsOpen(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,11 +191,12 @@ export function useSessionManager(): UseSessionManagerReturn {
|
||||
|
||||
// Spawn AI process (terminal uses runCommand which spawns fresh shells per command)
|
||||
try {
|
||||
// Spawn AI agent process (skip for Claude batch mode)
|
||||
const isClaudeBatchMode = agentId === 'claude-code';
|
||||
let aiSpawnResult = { pid: 0, success: true }; // Default for batch mode
|
||||
// Check if agent requires a prompt to start (Codex, OpenCode) - skip eager spawn for those
|
||||
const capabilities = await window.maestro.agents.getCapabilities(agentId);
|
||||
let aiSpawnResult = { pid: 0, success: true }; // Default for agents that don't need eager spawn
|
||||
|
||||
if (!isClaudeBatchMode) {
|
||||
if (!capabilities.requiresPromptToStart) {
|
||||
// Spawn for agents that support interactive mode (Claude Code)
|
||||
aiSpawnResult = await window.maestro.process.spawn({
|
||||
sessionId: `${newId}-ai`,
|
||||
toolType: agentId,
|
||||
|
||||
Reference in New Issue
Block a user