MAESTRO: Add FilePreviewTab type and unified tab system foundation

Phase 1 of file preview tabs feature:
- Add FilePreviewTab interface with id, path, name, extension, scrollTop,
  searchQuery, editMode, editContent, and createdAt fields
- Add UnifiedTabRef type for tab ordering across types
- Add filePreviewTabs, activeFileTabId, and unifiedTabOrder to Session
- Update all 13 session creation locations with new fields
- Update session restoration to hydrate new fields from persistence

This establishes the data model for coexisting AI tabs, file preview tabs,
and future terminal tabs in a unified tab bar.
This commit is contained in:
Pedram Amini
2026-02-02 03:08:58 -06:00
parent 04843b89f6
commit 942a9c0568
3 changed files with 72 additions and 0 deletions

View File

@@ -1111,6 +1111,9 @@ function MaestroConsoleInner() {
},
],
activeTabId: defaultTabId,
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: defaultTabId }],
};
}
@@ -1235,6 +1238,12 @@ function MaestroConsoleInner() {
agentError: undefined,
agentErrorPaused: false,
closedTabHistory: [], // Runtime-only, reset on load
// File preview tabs - initialize from persisted data or empty
filePreviewTabs: correctedSession.filePreviewTabs || [],
activeFileTabId: correctedSession.activeFileTabId ?? null,
unifiedTabOrder:
correctedSession.unifiedTabOrder ||
resetAiTabs.map((tab) => ({ type: 'ai' as const, id: tab.id })),
};
} else {
// Process spawn failed
@@ -1652,6 +1661,9 @@ function MaestroConsoleInner() {
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
customPath: parentSession.customPath,
customArgs: parentSession.customArgs,
customEnvVars: parentSession.customEnvVars,
@@ -7287,6 +7299,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
customPath: parentSession.customPath,
customArgs: parentSession.customArgs,
customEnvVars: parentSession.customEnvVars,
@@ -7468,6 +7483,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
customPath: session.customPath,
customArgs: session.customArgs,
customEnvVars: session.customEnvVars,
@@ -8756,6 +8774,10 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
// File preview tabs - start empty, unified tab order starts with initial AI tab
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
// Nudge message - appended to every interactive user message
nudgeMessage,
// Per-agent config (path, args, env vars, model)
@@ -8922,6 +8944,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
// Auto Run configuration from wizard
autoRunFolderPath,
autoRunSelectedFile,
@@ -10958,6 +10983,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
customPath: activeSession.customPath,
customArgs: activeSession.customArgs,
customEnvVars: activeSession.customEnvVars,
@@ -11133,6 +11161,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
customPath: activeSession.customPath,
customArgs: activeSession.customArgs,
customEnvVars: activeSession.customEnvVars,
@@ -11282,6 +11313,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
customPath: createWorktreeSession.customPath,
customArgs: createWorktreeSession.customArgs,
customEnvVars: createWorktreeSession.customEnvVars,
@@ -13215,6 +13249,9 @@ You are taking over this conversation. Based on the context above, provide a bri
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
// Custom agent config
customPath: data.customPath,
customArgs: data.customArgs,

View File

@@ -442,6 +442,29 @@ export interface ClosedTab {
closedAt: number; // Timestamp when closed
}
/**
* File Preview Tab for in-tab file viewing.
* Designed to coexist with AITab and future terminal tabs in the unified tab system.
* File tabs persist across session switches and app restarts.
*/
export interface FilePreviewTab {
id: string; // Unique tab ID (UUID)
path: string; // Full file path
name: string; // Filename without extension (displayed as tab name)
extension: string; // File extension with dot (e.g., '.md', '.ts') - shown as badge
scrollTop: number; // Saved scroll position
searchQuery: string; // Preserved search query
editMode: boolean; // Whether tab was in edit mode
editContent: string | undefined; // Unsaved edit content (undefined if no pending changes)
createdAt: number; // Timestamp for ordering
}
/**
* Reference to any tab in the unified tab system.
* Used for unified tab ordering across different tab types.
*/
export type UnifiedTabRef = { type: 'ai' | 'file'; id: string };
export interface Session {
id: string;
groupId?: string;
@@ -559,6 +582,15 @@ export interface Session {
activeTabId: string;
// Stack of recently closed tabs for undo (max 25, runtime-only, not persisted)
closedTabHistory: ClosedTab[];
// File Preview Tabs - in-tab file viewing (coexists with AI tabs and future terminal tabs)
// Tabs are interspersed visually but stored separately for type safety
filePreviewTabs: FilePreviewTab[];
// Currently active file tab ID (null if an AI tab is active)
activeFileTabId: string | null;
// Unified tab ordering - determines visual order of all tabs (AI and file)
unifiedTabOrder: UnifiedTabRef[];
// Saved scroll position for terminal/shell output view
terminalScrollTop?: number;
// Draft input for terminal mode (persisted across session switches)

View File

@@ -893,6 +893,9 @@ export function createMergedSession(
aiTabs: [mergedTab],
activeTabId: tabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: tabId }],
};
return { session, tabId };